Skip to content

Commit

Permalink
Merge pull request #240 from kookmin-sw/#239-bug
Browse files Browse the repository at this point in the history
[fix] 받은 매칭 요청 500 에러 해결 #239
  • Loading branch information
tmdtmdqorekf authored May 15, 2024
2 parents ed0ec01 + 0093b28 commit fff8bf6
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ public ResponseEntity<ApiResponse<List<MatchReceivedInfoDto>>> getMatchReceivedI
@RequestParam("receiverId") Long receiverId) {
DtoLogger.requestParam("receiverId", receiverId);

MatchListDto dto = new MatchListDto();
dto.setReceiverId(receiverId);

List<MatchReceivedInfoDto> response = matchService.getMatchReceivedInfo(dto);
List<MatchReceivedInfoDto> response = matchService.getMatchReceivedInfo(receiverId);
return ResponseEntity.ok(ApiResponse.success(response));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.coffee.backend.domain.match.service;

import com.coffee.backend.domain.company.entity.Company;
import com.coffee.backend.domain.fcm.service.FcmService;
import com.coffee.backend.domain.match.dto.MatchDto;
import com.coffee.backend.domain.match.dto.MatchIdDto;
import com.coffee.backend.domain.match.dto.MatchInfoDto;
import com.coffee.backend.domain.match.dto.MatchInfoResponseDto;
import com.coffee.backend.domain.match.dto.MatchListDto;
import com.coffee.backend.domain.match.dto.MatchReceivedInfoDto;
import com.coffee.backend.domain.match.dto.MatchRequestDto;
import com.coffee.backend.domain.match.dto.MatchStatusDto;
Expand All @@ -23,6 +21,7 @@
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
Expand All @@ -47,26 +46,30 @@ public class MatchService {
// 매칭 요청
public MatchDto sendMatchRequest(MatchRequestDto dto) {
log.trace("sendMatchRequest()");
String lockKey = LOCK_KEY_PREFIX + dto.getSenderId();

// 이미 락이 걸려 있는 경우 요청 처리 X
if (redisTemplate.opsForValue().get(lockKey) != null) {
throw new CustomException(ErrorCode.REQUEST_DUPLICATED);
}
validateRequest(dto); // 요청 검증

String lockKey = LOCK_KEY_PREFIX + dto.getSenderId();
validateLock(lockKey); // 락 검증

String matchId = UUID.randomUUID().toString();
Map<String, String> matchInfo = Map.of(
"matchId", matchId,
"senderId", dto.getSenderId().toString(),
"receiverId", dto.getReceiverId().toString(),
"requestTypeId", dto.getRequestTypeId(),
"status", "pending"
);

// 매칭 요청 정보
redisTemplate.opsForHash().putAll("matchId:" + matchId, matchInfo);
redisTemplate.expire("matchId:" + matchId, 600, TimeUnit.SECONDS);

// 수신자 ID에 대한 매칭 ID 리스트에 추가
redisTemplate.opsForList().rightPush("receiverId:" + dto.getReceiverId(), matchId);
// 매칭 요청 리스트를 위한 정보
redisTemplate.opsForHash()
.putAll("receiverId:" + dto.getReceiverId() + "-senderId:" + dto.getSenderId(), matchInfo);
redisTemplate.expire("receiverId:" + dto.getReceiverId() + "-senderId:" + dto.getSenderId(), 600,
TimeUnit.SECONDS);

// 알림
User toUser = userRepository.findByUserId(dto.getReceiverId()).orElseThrow();
Expand All @@ -87,8 +90,7 @@ public MatchInfoResponseDto getMatchRequestInfo(MatchInfoDto dto) {
User receiver = userRepository.findByUserId(dto.getReceiverId()).orElseThrow();

ReceiverInfoDto receiverInfo = mapper.map(receiver, ReceiverInfoDto.class);
Company company = receiver.getCompany();
receiverInfo.setCompany(company);
receiverInfo.setCompany(receiver.getCompany());

String key = "matchId:" + dto.getMatchId();
String requestTypeId = (String) redisTemplate.opsForHash().get(key, "requestTypeId");
Expand All @@ -102,34 +104,20 @@ public MatchInfoResponseDto getMatchRequestInfo(MatchInfoDto dto) {
}

// 받은 요청 정보
public List<MatchReceivedInfoDto> getMatchReceivedInfo(MatchListDto dto) {
log.trace("getReceivedMatchRequests() for receiverId: {}", dto.getReceiverId());

List<Object> matchIds = new ArrayList<>();
try {
matchIds = redisTemplate.opsForList().range("receiverId:" + dto.getReceiverId(), 0, -1);
} catch (Exception e) {
throw new CustomException(ErrorCode.REDIS_ACCESS_ERROR);
}
public List<MatchReceivedInfoDto> getMatchReceivedInfo(Long receiverId) {
log.trace("getReceivedMatchRequests() for receiverId: {}", receiverId);

if (matchIds == null || matchIds.isEmpty()) {
Set<String> keys = redisTemplate.keys("receiverId:" + receiverId + "-senderId:*");
if (keys == null || keys.isEmpty()) {
throw new CustomException(ErrorCode.REQUEST_NOT_FOUND);
}

List<MatchReceivedInfoDto> requests = new ArrayList<>();
for (Object matchIdObj : matchIds) {
String matchId = (String) matchIdObj;

Map<Object, Object> matchInfo;
try {
matchInfo = redisTemplate.opsForHash().entries("matchId:" + matchId);
} catch (Exception e) {
throw new CustomException(ErrorCode.REDIS_ACCESS_ERROR);
}

Object senderObj = matchInfo.get("senderId");
Long senderId = getLongId(senderObj);
for (String key : keys) {
Map<Object, Object> matchInfo = redisTemplate.opsForHash().entries(key);
String matchId = (String) matchInfo.get("matchId");

Long senderId = getLongId(matchInfo.get("senderId"));
User sender = userRepository.findById(senderId)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
SenderInfoDto senderInfo = mapper.map(sender, SenderInfoDto.class);
Expand All @@ -155,12 +143,8 @@ public MatchDto acceptMatchRequest(MatchIdDto dto) {
redisTemplate.opsForHash().put(key, "status", "accepted");
redisTemplate.opsForHash().put(key + "-info", "status", "matching");

Object sender = redisTemplate.opsForHash().get(key, "senderId");
Long senderId = getLongId(sender);
Object receiver = redisTemplate.opsForHash().get(key, "receiverId");
Long receiverId = getLongId(receiver);

redisTemplate.opsForList().remove("receiverId:" + receiverId, 1, dto.getMatchId());
Long senderId = getLongId(redisTemplate.opsForHash().get(key, "senderId"));
Long receiverId = getLongId(redisTemplate.opsForHash().get(key, "receiverId"));

// 알림
User toUser = userRepository.findByUserId(senderId).orElseThrow();
Expand All @@ -171,6 +155,9 @@ public MatchDto acceptMatchRequest(MatchIdDto dto) {
match.setSenderId(senderId);
match.setReceiverId(receiverId);
match.setStatus("accepted");

redisTemplate.delete("receiverId:" + receiverId + "-senderId:" + senderId);

return match;
}

Expand All @@ -183,21 +170,16 @@ public MatchDto declineMatchRequest(MatchIdDto dto) {
}

String key = "matchId:" + dto.getMatchId();
Object sender = redisTemplate.opsForHash().get(key, "senderId");
Long senderId = getLongId(sender);
Object receiver = redisTemplate.opsForHash().get(key, "receiverId");
Long receiverId = getLongId(receiver);
Long senderId = getLongId(redisTemplate.opsForHash().get(key, "senderId"));
Long receiverId = getLongId(redisTemplate.opsForHash().get(key, "receiverId"));

// 알림
User toUser = userRepository.findByUserId(senderId).orElseThrow();
fcmService.sendPushMessageTo(toUser.getDeviceToken(), "커피챗 매칭 실패", "커피챗 요청이 거절되었습니다.");

redisTemplate.delete(key);
redisTemplate.opsForList().remove("receiverId:" + receiverId, 1, dto.getMatchId());

// 락 해제
String lockKey = LOCK_KEY_PREFIX + senderId;
redisTemplate.delete(lockKey);
redisTemplate.delete("receiverId:" + receiverId + "-senderId:" + senderId);
redisTemplate.delete(LOCK_KEY_PREFIX + senderId); // 락 해제

MatchDto match = new MatchDto();
match.setMatchId(dto.getMatchId());
Expand All @@ -215,17 +197,12 @@ public MatchDto cancelMatchRequest(MatchIdDto dto) {
}

String key = "matchId:" + dto.getMatchId();
Object sender = redisTemplate.opsForHash().get(key, "senderId");
Long senderId = getLongId(sender);
Object receiver = redisTemplate.opsForHash().get(key, "receiverId");
Long receiverId = getLongId(receiver);
Long senderId = getLongId(redisTemplate.opsForHash().get(key, "senderId"));
Long receiverId = getLongId(redisTemplate.opsForHash().get(key, "receiverId"));

redisTemplate.delete(key);
redisTemplate.opsForList().remove("receiverId:" + receiverId, 1, dto.getMatchId());

// 락 해제
String lockKey = LOCK_KEY_PREFIX + senderId;
redisTemplate.delete(lockKey);
redisTemplate.delete("receiverId:" + receiverId + "-senderId:" + senderId);
redisTemplate.delete(LOCK_KEY_PREFIX + senderId); // 락 해제

MatchDto match = new MatchDto();
match.setMatchId(dto.getMatchId());
Expand All @@ -242,9 +219,41 @@ private boolean verifyMatchRequest(MatchIdDto dto) {
return ttl != null && ttl > 0; // true
}

// 락 검증
private void validateLock(String lockKey) {
// 이미 락이 걸려 있는 경우 요청 처리 X
if (redisTemplate.opsForValue().get(lockKey) != null) {
throw new CustomException(ErrorCode.REQUEST_DUPLICATED);
}
}

// 유저 검증
private void validateRequest(MatchRequestDto dto) {
// 본인에게 요청을 보내는 경우 처리 X
if (dto.getSenderId().equals(dto.getReceiverId())) {
throw new CustomException(ErrorCode.REQUEST_SAME_USER);
}
// 유저 DB에 없는 유저가 보낼 경우 처리 X
if (!userRepository.existsById(dto.getSenderId())) {
throw new CustomException(ErrorCode.USER_NOT_FOUND);
}
}

// 매칭 정보 생성
private Map<String, String> createMatchInfo(MatchRequestDto dto, String matchId) {
return Map.of(
"matchId", matchId,
"senderId", dto.getSenderId().toString(),
"receiverId", dto.getReceiverId().toString(),
"requestTypeId", dto.getRequestTypeId(),
"status", "pending"
);
}

// Object -> Long 타입 변환
private Long getLongId(Object result) {
log.trace("getLongId()");

Long id = null;
if (result != null) {
if (result instanceof Number) {
Expand All @@ -262,8 +271,8 @@ private Long getLongId(Object result) {

public MatchStatusDto finishMatch(MatchIdDto dto) {
log.trace("finishMatch()");
String key = "matchId:" + dto.getMatchId() + "-info";
redisTemplate.delete(key);

redisTemplate.delete("matchId:" + dto.getMatchId() + "-info");

MatchStatusDto match = new MatchStatusDto();
match.setMatchId(dto.getMatchId());
Expand All @@ -273,6 +282,7 @@ public MatchStatusDto finishMatch(MatchIdDto dto) {

public Boolean isMatching(MatchIdDto dto) {
log.trace("isMatching()");

String key = "matchId:" + dto.getMatchId() + "-info";
Object status = redisTemplate.opsForHash().get(key, "status");
return status != null; // true
Expand All @@ -281,6 +291,7 @@ public Boolean isMatching(MatchIdDto dto) {
@Transactional
public Review saveReview(ReviewDto dto) {
log.trace("saveReview()");

if (dto.getRating() < 1 || dto.getRating() > 5) {
throw new CustomException(ErrorCode.VALUE_ERROR);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public enum ErrorCode {
COMPANY_REQUEST_NOT_FOUND(HttpStatus.NOT_FOUND, "6404", "해당 COMPANY_REQUEST를 찾을 수 없습니다."),

REQUEST_DUPLICATED(HttpStatus.CONFLICT, "7409", "요청이 중복됩니다."),
REQUEST_SAME_USER(HttpStatus.CONFLICT, "7409", "본인에게 요청을 보낼 수 없습니다."),
REQUEST_NOT_FOUND(HttpStatus.NOT_FOUND, "7404", "해당 요청 정보를 찾을 수 없습니다."),
REQUEST_EXPIRED(HttpStatus.UNAUTHORIZED, "7401", "요청이 만료되었습니다."),

Expand Down

0 comments on commit fff8bf6

Please sign in to comment.