Skip to content

Commit 48e76fb

Browse files
committed
feat: 예외 처리 개선 (로깅, 파라미터, 상위 예외)
1 parent 679d9ae commit 48e76fb

File tree

10 files changed

+134
-49
lines changed

10 files changed

+134
-49
lines changed

reservation-admin-api/src/main/java/com/f1v3/reservation/admin/AdminReservationControllerAdvice.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import com.f1v3.reservation.common.api.error.ErrorCode;
44
import com.f1v3.reservation.common.api.error.ReservationException;
55
import com.f1v3.reservation.common.api.response.ApiResponse;
6+
import jakarta.servlet.http.HttpServletRequest;
67
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.core.Ordered;
9+
import org.springframework.core.annotation.Order;
710
import org.springframework.http.ResponseEntity;
811
import org.springframework.web.bind.MethodArgumentNotValidException;
912
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -21,23 +24,36 @@
2124
@RestControllerAdvice
2225
public class AdminReservationControllerAdvice {
2326

27+
@Order(Ordered.HIGHEST_PRECEDENCE)
2428
@ExceptionHandler(ReservationException.class)
2529
public ResponseEntity<ApiResponse<?>> handleReservationException(ReservationException e) {
26-
ApiResponse<?> response = ApiResponse.error(e.getCode(), e.getMessage());
30+
String logMessage = e.getLogMessage();
31+
e.getLogLevel().accept(logMessage);
2732

2833
return ResponseEntity
2934
.status(e.getStatus().getCode())
30-
.body(response);
35+
.body(ApiResponse.error(e.getCode(), e.getMessage()));
3136
}
3237

3338
@ExceptionHandler(MethodArgumentNotValidException.class)
34-
public ResponseEntity<ApiResponse<?>> handleArgumentNotValidException(MethodArgumentNotValidException e) {
39+
public ResponseEntity<ApiResponse<?>> handleArgumentNotValidException(
40+
MethodArgumentNotValidException e, HttpServletRequest request) {
3541

3642
ErrorCode errorCode = ErrorCode.INVALID_REQUEST_PARAMETER;
3743

3844
Map<String, String> errors = new HashMap<>();
39-
e.getBindingResult().getFieldErrors().forEach(error ->
40-
errors.put(error.getField(), error.getDefaultMessage())
45+
Map<String, Object> parameters = new HashMap<>();
46+
e.getBindingResult().getFieldErrors().forEach(error -> {
47+
errors.put(error.getField(), error.getDefaultMessage());
48+
parameters.put(error.getField(), error.getRejectedValue());
49+
}
50+
);
51+
52+
log.info("Validation error | URL: {} | Method: {} | Errors: {} | Parameters: {}",
53+
request.getRequestURI(),
54+
request.getMethod(),
55+
errors,
56+
parameters
4157
);
4258

4359
ApiResponse<?> response = ApiResponse.error(
@@ -51,20 +67,21 @@ public ResponseEntity<ApiResponse<?>> handleArgumentNotValidException(MethodArgu
5167
.body(response);
5268
}
5369

70+
@Order(Ordered.LOWEST_PRECEDENCE)
5471
@ExceptionHandler(Exception.class)
55-
public ResponseEntity<ApiResponse<?>> handleGeneralException(Exception e) {
56-
57-
log.error("Unexpected error = {}", e.getMessage(), e);
58-
59-
ErrorCode errorCode = ErrorCode.SERVER_ERROR;
72+
public ResponseEntity<ApiResponse<?>> handleGeneralException(
73+
Exception e, HttpServletRequest request) {
6074

61-
ApiResponse<?> response = ApiResponse.error(
62-
errorCode.getCode(),
63-
errorCode.getMessage()
75+
log.error("Unexpected error | URL: {} | Method: {} | Error: {}",
76+
request.getRequestURI(),
77+
request.getMethod(),
78+
e.getMessage(),
79+
e
6480
);
6581

82+
ErrorCode errorCode = ErrorCode.SERVER_ERROR;
6683
return ResponseEntity
6784
.status(errorCode.getStatus().getCode())
68-
.body(response);
85+
.body(ApiResponse.error(errorCode.getCode(), errorCode.getMessage()));
6986
}
7087
}

reservation-admin-api/src/main/java/com/f1v3/reservation/admin/term/TermService.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.springframework.transaction.annotation.Transactional;
1818

1919
import java.util.List;
20+
import java.util.Map;
2021

2122
import static com.f1v3.reservation.common.api.error.ErrorCode.TERM_CODE_INVALID;
2223

@@ -43,7 +44,7 @@ public List<TermResponse> getPagedTerms(Pageable pageable) {
4344
@Transactional
4445
public CreateTermResponse create(CreateTermRequest request) {
4546
TermCode termCode = TermCode.getCode(request.code())
46-
.orElseThrow(() -> new ReservationException(TERM_CODE_INVALID));
47+
.orElseThrow(() -> new ReservationException(TERM_CODE_INVALID, log::warn));
4748

4849
int nextVersion = termRepository.findMaxVersionByCode(termCode)
4950
.map(version -> version + 1)
@@ -72,8 +73,12 @@ private Term saveWithConstraintCheck(Term term) {
7273
try {
7374
return termRepository.save(term);
7475
} catch (DataIntegrityViolationException e) {
75-
log.error("Term constraint violation: {}", e.getMessage());
76-
throw new ReservationException(ErrorCode.TERM_VERSION_CONSTRAINT_VIOLATION);
76+
Map<String, Object> parameters = Map.of(
77+
"termCode", term.getCode(),
78+
"termVersion", term.getVersion()
79+
);
80+
81+
throw new ReservationException(ErrorCode.TERM_VERSION_CONSTRAINT_VIOLATION, log::error, parameters, e);
7782
}
7883
}
7984
}

reservation-api/src/main/java/com/f1v3/reservation/api/ReservationControllerAdvice.java

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import com.f1v3.reservation.common.api.error.ErrorCode;
44
import com.f1v3.reservation.common.api.error.ReservationException;
55
import com.f1v3.reservation.common.api.response.ApiResponse;
6+
import jakarta.servlet.http.HttpServletRequest;
67
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.core.Ordered;
9+
import org.springframework.core.annotation.Order;
710
import org.springframework.http.ResponseEntity;
811
import org.springframework.web.bind.MethodArgumentNotValidException;
912
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -21,21 +24,36 @@
2124
@RestControllerAdvice
2225
public class ReservationControllerAdvice {
2326

27+
@Order(Ordered.HIGHEST_PRECEDENCE)
2428
@ExceptionHandler(ReservationException.class)
2529
public ResponseEntity<ApiResponse<?>> handleReservationException(ReservationException e) {
30+
String logMessage = e.getLogMessage();
31+
e.getLogLevel().accept(logMessage);
32+
2633
return ResponseEntity
2734
.status(e.getStatus().getCode())
2835
.body(ApiResponse.error(e.getCode(), e.getMessage()));
2936
}
3037

3138
@ExceptionHandler(MethodArgumentNotValidException.class)
32-
public ResponseEntity<ApiResponse<?>> handleArgumentNotValidException(MethodArgumentNotValidException e) {
39+
public ResponseEntity<ApiResponse<?>> handleArgumentNotValidException(
40+
MethodArgumentNotValidException e, HttpServletRequest request) {
3341

3442
ErrorCode code = ErrorCode.INVALID_REQUEST_PARAMETER;
3543

3644
Map<String, String> errors = new HashMap<>();
37-
e.getBindingResult().getFieldErrors().forEach(error ->
38-
errors.put(error.getField(), error.getDefaultMessage())
45+
Map<String, Object> parameters = new HashMap<>();
46+
e.getBindingResult().getFieldErrors().forEach(error -> {
47+
errors.put(error.getField(), error.getDefaultMessage());
48+
parameters.put(error.getField(), error.getRejectedValue());
49+
}
50+
);
51+
52+
log.info("Validation error | URI = {} | Method = {} | Errors = {} | Parameters = {}",
53+
request.getRequestURI(),
54+
request.getMethod(),
55+
errors,
56+
parameters
3957
);
4058

4159
ApiResponse<?> response = ApiResponse.error(
@@ -49,19 +67,21 @@ public ResponseEntity<ApiResponse<?>> handleArgumentNotValidException(MethodArgu
4967
.body(response);
5068
}
5169

70+
@Order(Ordered.LOWEST_PRECEDENCE)
5271
@ExceptionHandler(Exception.class)
53-
public ResponseEntity<ApiResponse<?>> handleGeneralException(Exception e) {
54-
log.info("Unexpected error = {}", e.getMessage(), e);
55-
56-
ErrorCode code = ErrorCode.SERVER_ERROR;
72+
public ResponseEntity<ApiResponse<?>> handleGeneralException(
73+
Exception e, HttpServletRequest request) {
5774

58-
ApiResponse<?> response = ApiResponse.error(
59-
code.getCode(),
60-
code.getMessage()
75+
log.error("Unexpected error | URL = {} | Method = {} | Message = {}",
76+
request.getRequestURI(),
77+
request.getMethod(),
78+
e.getMessage(),
79+
e
6180
);
6281

82+
ErrorCode errorCode = ErrorCode.SERVER_ERROR;
6383
return ResponseEntity
64-
.status(code.getStatus().getCode())
65-
.body(response);
84+
.status(errorCode.getStatus().getCode())
85+
.body(ApiResponse.error(errorCode.getCode(), errorCode.getMessage()));
6686
}
6787
}

reservation-api/src/main/java/com/f1v3/reservation/api/phoneverification/PhoneVerificationService.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,30 @@ public SendPhoneVerificationResponse sendVerifyCode(SendPhoneVerificationRequest
4949
@Transactional
5050
public void incrementAttempt(String phoneNumber) {
5151
PhoneVerification verification = phoneVerificationRepository.findByPhoneNumber(phoneNumber)
52-
.orElseThrow(() -> new ReservationException(PHONE_VERIFICATION_NOT_FOUND));
52+
.orElseThrow(() -> new ReservationException(PHONE_VERIFICATION_NOT_FOUND, log::info));
5353

5454
verification.incrementAttempt();
5555
}
5656

5757
@Transactional
5858
public void verifyCode(VerifyPhoneVerificationRequest request) {
5959
PhoneVerification verification = phoneVerificationRepository.findByPhoneNumber(request.phoneNumber())
60-
.orElseThrow(() -> new ReservationException(PHONE_VERIFICATION_NOT_FOUND));
60+
.orElseThrow(() -> new ReservationException(PHONE_VERIFICATION_NOT_FOUND, log::info));
6161

6262
if (verification.isAlreadyVerified()) {
63-
throw new ReservationException(PHONE_VERIFICATION_ALREADY_VERIFIED);
63+
throw new ReservationException(PHONE_VERIFICATION_ALREADY_VERIFIED, log::info);
6464
}
6565

6666
if (verification.isExpired()) {
67-
throw new ReservationException(PHONE_VERIFICATION_CODE_EXPIRED);
67+
throw new ReservationException(PHONE_VERIFICATION_CODE_EXPIRED, log::info);
6868
}
6969

7070
if (verification.isExceededMaxAttempts()) {
71-
throw new ReservationException(PHONE_VERIFICATION_ATTEMPTS_EXCEEDED);
71+
throw new ReservationException(PHONE_VERIFICATION_ATTEMPTS_EXCEEDED, log::info);
7272
}
7373

7474
if (!verification.checkCode(request.verificationCode())) {
75-
throw new ReservationException(PHONE_VERIFICATION_CODE_INVALID);
75+
throw new ReservationException(PHONE_VERIFICATION_CODE_INVALID, log::info);
7676
}
7777

7878
userValidationService.checkPhoneNumberExists(request.phoneNumber());
@@ -84,14 +84,14 @@ public void verifyCode(VerifyPhoneVerificationRequest request) {
8484
@Transactional(readOnly = true)
8585
public void checkVerified(String phoneNumber) {
8686
PhoneVerification verification = phoneVerificationRepository.findByPhoneNumber(phoneNumber)
87-
.orElseThrow(() -> new ReservationException(PHONE_VERIFICATION_NOT_FOUND));
87+
.orElseThrow(() -> new ReservationException(PHONE_VERIFICATION_NOT_FOUND, log::info));
8888

8989
if (!verification.isAlreadyVerified()) {
90-
throw new ReservationException(PHONE_VERIFICATION_NOT_VERIFIED);
90+
throw new ReservationException(PHONE_VERIFICATION_NOT_VERIFIED, log::info);
9191
}
9292

9393
if (verification.isExpiredForVerifiedDuration()) {
94-
throw new ReservationException(PHONE_VERIFICATION_INFO_EXPIRED);
94+
throw new ReservationException(PHONE_VERIFICATION_INFO_EXPIRED, log::info);
9595
}
9696
}
9797

reservation-api/src/main/java/com/f1v3/reservation/api/phoneverification/strategy/ResendVerificationStrategy.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.f1v3.reservation.common.api.error.ReservationException;
55
import com.f1v3.reservation.common.domain.phoneverification.PhoneVerification;
66
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
78

89
import java.time.LocalDateTime;
910

@@ -12,6 +13,7 @@
1213
*
1314
* @author Seungjo, Jeong
1415
*/
16+
@Slf4j
1517
@RequiredArgsConstructor
1618
public class ResendVerificationStrategy implements PhoneVerificationStrategy {
1719

@@ -27,7 +29,7 @@ public PhoneVerification execute(String phoneNumber) {
2729
.isBefore(LocalDateTime.now());
2830

2931
if (!isResendAllowed) {
30-
throw new ReservationException(ErrorCode.PHONE_VERIFICATION_RESEND_NOT_ALLOWED);
32+
throw new ReservationException(ErrorCode.PHONE_VERIFICATION_RESEND_NOT_ALLOWED, log::info);
3133
}
3234

3335
existingVerification.resend(newCode);

reservation-api/src/main/java/com/f1v3/reservation/api/term/TermValidationService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.f1v3.reservation.common.api.error.ReservationException;
66
import com.f1v3.reservation.common.domain.term.enums.TermCode;
77
import lombok.RequiredArgsConstructor;
8+
import lombok.extern.slf4j.Slf4j;
89
import org.springframework.stereotype.Service;
910

1011
import java.util.Set;
@@ -18,6 +19,7 @@
1819
*
1920
* @author Seungjo, Jeong
2021
*/
22+
@Slf4j
2123
@Service
2224
@RequiredArgsConstructor
2325
public class TermValidationService {
@@ -32,14 +34,14 @@ public void validateRequiredTermsAgreed(Set<SignupUserRequest.SignupTermRequest>
3234

3335
Set<TermCode> agreedTermIds = termRequests.stream()
3436
.map(request -> TermCode.getCode(request.termCode())
35-
.orElseThrow(() -> new ReservationException(TERM_CODE_INVALID))
37+
.orElseThrow(() -> new ReservationException(TERM_CODE_INVALID, log::warn))
3638
)
3739
.collect(Collectors.toSet());
3840

3941
requiredTermIds.removeAll(agreedTermIds);
4042

4143
if (!requiredTermIds.isEmpty()) {
42-
throw new ReservationException(TERM_REQUIRED_NOT_AGREED);
44+
throw new ReservationException(TERM_REQUIRED_NOT_AGREED, log::info);
4345
}
4446
}
4547
}

reservation-api/src/main/java/com/f1v3/reservation/api/user/UserTermAgreementService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.f1v3.reservation.common.domain.user.UserTermAgreement;
1111
import com.f1v3.reservation.common.domain.user.repository.UserTermAgreementRepository;
1212
import lombok.RequiredArgsConstructor;
13+
import lombok.extern.slf4j.Slf4j;
1314
import org.springframework.stereotype.Service;
1415
import org.springframework.transaction.annotation.Transactional;
1516

@@ -23,6 +24,7 @@
2324
*
2425
* @author Seungjo, Jeong
2526
*/
27+
@Slf4j
2628
@Service
2729
@RequiredArgsConstructor
2830
public class UserTermAgreementService {
@@ -44,10 +46,10 @@ public void createAgreements(User user, Set<SignupUserRequest.SignupTermRequest>
4446

4547
private UserTermAgreement createAgreement(User user, SignupUserRequest.SignupTermRequest request) {
4648
TermCode termCode = TermCode.getCode(request.termCode())
47-
.orElseThrow(() -> new ReservationException(TERM_NOT_FOUND));
49+
.orElseThrow(() -> new ReservationException(TERM_NOT_FOUND, log::warn));
4850

4951
Term term = termRepository.findByCodeAndVersion(termCode, request.version())
50-
.orElseThrow(() -> new ReservationException(TERM_NOT_FOUND));
52+
.orElseThrow(() -> new ReservationException(TERM_NOT_FOUND, log::warn));
5153

5254
return UserTermAgreement.builder()
5355
.user(user)

reservation-api/src/main/java/com/f1v3/reservation/api/user/UserValidationService.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.f1v3.reservation.common.api.error.ReservationException;
44
import com.f1v3.reservation.common.domain.user.repository.UserRepository;
55
import lombok.RequiredArgsConstructor;
6+
import lombok.extern.slf4j.Slf4j;
67
import org.springframework.stereotype.Service;
78

89
import static com.f1v3.reservation.common.api.error.ErrorCode.USER_EMAIL_ALREADY_EXISTS;
@@ -13,6 +14,7 @@
1314
*
1415
* @author Seungjo, Jeong
1516
*/
17+
@Slf4j
1618
@Service
1719
@RequiredArgsConstructor
1820
public class UserValidationService {
@@ -21,13 +23,13 @@ public class UserValidationService {
2123

2224
public void checkPhoneNumberExists(String phoneNumber) {
2325
if (userRepository.existsByPhoneNumber(phoneNumber)) {
24-
throw new ReservationException(USER_PHONE_ALREADY_EXISTS);
26+
throw new ReservationException(USER_PHONE_ALREADY_EXISTS, log::info);
2527
}
2628
}
2729

2830
public void checkEmailExists(String email) {
2931
if (userRepository.existsByEmail(email)) {
30-
throw new ReservationException(USER_EMAIL_ALREADY_EXISTS);
32+
throw new ReservationException(USER_EMAIL_ALREADY_EXISTS, log::info);
3133
}
3234
}
3335
}

0 commit comments

Comments
 (0)