일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- @SpyBean
- NotBlank
- @ControllerAdvice
- 데이터베이스
- JPA
- db
- 이펙티브 자바
- Connection Pool
- deleteById
- @MockBean
- springboot
- @Valid
- multi module
- Effective Java
- 플라이웨이트
- Service Locator 패턴
- Effetive Java
- Service Locator
- FCM
- SQL 삽입 공격
- java
- Web
- Proxy Patter
- 디자인 패턴
- Spring Boot
- Item04
- restTemplate
- Firebase
- 트랜잭션
- NotEmpty
- Today
- Total
NoTimeForDawdling
[Spring Boot] @ControllerAdvice를 이용한 @Valid Exception Handling 본문
[Spring Boot] @ControllerAdvice를 이용한 @Valid Exception Handling
Room_Energy 2021. 4. 28. 16:35오늘은 @ControllerAdvice를 이용해서 @Valid시 발생하는 에러를 처리해보겠습니다.
@Valid 사용법은 여기에 자세히 나와있습니다.
@ControllerAdvice란?
@ControllerAdvice는 @Controller 전역에서 발생할 수 있는 예외를 잡아 처리해주는 애너테이션입니다.
자 그럼 이제 코드를 통해 알아보겠습니다.
ExceptionController.class
@RestControllerAdvice
public class ExceptionController {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, ErrorResponse>> handelValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, ErrorResponse> errorMap = new HashMap<>();
ex.getBindingResult().getAllErrors()
.forEach(e -> errorMap.put(((FieldError) e).getField(), makeErrorResponse(e.getCode(), e.getDefaultMessage())));
return ResponseEntity.badRequest()
.body(errorMap);
}
private ErrorResponse makeErrorResponse(String validationCode, String detail) {
ErrorCode errorCode = ErrorCode.findByValidationCode(validationCode);
return new ErrorResponse(errorCode.getCode(), errorCode.getDescription(), detail);
}
}
@Valid의 유효성을 통과하지 못하면, MethodArgumentNotValidException이 발생합니다.
그렇기 때문에 해당 클래스에서는@ExceptionHandler 애너테이션으로 MethodArgumentNotValidException.class에 대한 에러를 잡아 처리합니다.
ResponseEntity 값은 Error가 발생한 Field 값(Stsring)과 직접 만든 에러 메시지(ErrorResponse)를 Map 형태로 만들어서 넣어주었습니다. 여기서 Map을 사용한 이유는 @Valid시 발생한 에러를 모두 리턴할 수 있도록 하기 위함입니다.
ErrorResponse.class
@Getter
public class ErrorResponse {
private String code;
private String description;
private String detail;
public ErrorResponse(String code, String description) {
this.code = code;
this.description = description;
}
public ErrorResponse(String code, String description, String detail) {
this.code = code;
this.description = description;
this.detail = detail;
}
}
해당 클래스는 API에 내려줄 에러 형태를 정의한 클래스입니다.
- code: Enum을 이용하여 정의한 에러 코드를 알려줍니다.
- description: 어떤 에러인지 알려줍니다.
- detail: 에러의 세부 내용을 알려줍니다.
ErrorCode.class(Enum)
public enum ErrorCode {
NOT_NULL("NotNull", "ERROR_CODE_0001", "필수값이 누락되었습니다."),
EMAIL("Email", "ERROR_CODE_0002", "올바른 이메일 형식이 아닙니다.");
private String validationCode;
private String code;
private String description;
ErrorCode(String validationCode, String code, String description) {
this.validationCode = validationCode;
this.code = code;
this.description = description;
}
public static ErrorCode findByValidationCode(String validationCode) {
return Arrays.stream(values())
.filter(errorCode -> errorCode.validationCode.equals(validationCode))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("유효하지 않은 검증 코드입니다."));
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
}
해당 클래스는 에러에 대한 코드 및 어떤 에러인지를 정의하고, 간단한 에러 설명을 넣었습니다.
validationCode를 이용해 @Email, @NotNull 등 어떤 에러인지 찾고, 해당 에러에 맞는 코드와 설명을 알려줍니다.
이제 간단한 컨트롤러와 DTO를 만들어서 위 코드가 잘 돌아가는지 확인해보겠습니다.
UserController.class
@RestController
public class UserController {
@PostMapping("/user")
public ResponseEntity<String> saveUser(final @Valid @RequestBody UserSaveRequest userSaveRequest) {
return ResponseEntity.ok()
.body("유저 검증 성공");
}
}
UserSaveRequest.class
@Getter
@NoArgsConstructor
public class UserSaveRequest {
@NotNull(message = "이름을 입력해 주세요.")
private String name;
@Email
private String email;
}
DTO를 보면 name과 email에 대한 검증을 합니다.
이제 Posman을 이용해서 API 호출을 해보겠습니다.
Valid가 잘 적용되는지 확인하기 위해, name값을 넣지 않고, email값을 이상하게 줘보겠습니다.
Response값을 보면, @Valid를 통과하지 못한 모든 필드 값에 대한 에러와, 커스텀한 에러 메시지가 잘 반영되었음을 알 수 있습니다.
참고
'SpringBoot' 카테고리의 다른 글
[Spring Boot] @NotNull, @NotEmtpy, @NotBlank 차이점 (0) | 2021.05.14 |
---|---|
[Spring Boot] Swagger Authorization header 설정 (0) | 2021.05.12 |
[Spring Boot] @Valid를 이용한 유효성 검증 (0) | 2021.04.27 |
[Spring Boot] RestTemplate Connection Pool 설정 (0) | 2021.04.19 |
[Spring Boot] RestTemplate 사용 방법 (0) | 2021.04.13 |