@Data
public class MovieAddRequest {
@NotBlank(message = "MovieAddRequest.name은 빈 값일 수 없습니다")
private String name;
@NotBlank(message = "MovieAddRequest.category 빈 값일 수 없습니다")
private String category;
@NotBlank(message = "MovieAddRequest.useYn 빈 값일 수 없습니다")
private String useYn;
}
2. Response에 대한 DTO 생성
기본이 될 Base DTO 입니다.
ApiBase.java
@Builder
@Getter
public class ApiBase<T> {
private String message;
private T response;
}
영화 추가에 대한 응답 DTO 입니다.
MovieAddResponse.java
@Data
public class MovieAddResponse {
private String name;
}
3. Validation를 확인할 Controller 생성
ValidController.java
@RestController
public class ValidController {
@PostMapping("/")
public ResponseEntity<ApiBase> addMovie(@RequestBody @Valid MovieAddRequest request){
MovieAddResponse response = new MovieAddResponse();
response.setName(request.getName());
return ResponseEntity.status(HttpStatus.CREATED).body(ApiBase.builder().message("").response(response).build());
}
}
4. 전역으로 에러를 핸들링할, GlobalErrorHandler 생성
실제로 Validation 체크에 실패한 경우, Exception이 발생하는 정보에 대해서
Custom Exception 처리를 해줘야 합니다.
GlobalErrorHandler.java
@ControllerAdvice
@Slf4j
public class GlobalErrorHandler {
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResponseEntity<ApiBase> handleResponseBodyError(MethodArgumentNotValidException ex) {
log.error("Exception Caught in handleRequestBodyError : {}", ex.getMessage());
var error = ex.getBindingResult().getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.sorted()
.collect(Collectors.joining(", "));
log.error("Error is : {}", error);
return ResponseEntity.badRequest()
.body(ApiBase.builder().message(error).response("").build());
}
}
Validation 체크에 실패한 경우GlobalErrrorHandler에서, Http Status는 400 (Bad Request)가 되며
Annotation에 설정한 메시지들이 Body에 출력이 되어야 합니다.
⏰ Execute
이제 완성이 되었으면, localhost:8080/에 아래를 던져봅시다.
curl --location --request POST 'http://localhost:8080/' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "제목",
"category": "",
"useYn": "N"
}'
아래처럼, Validation 체크를 통과하지 못했고, 오류가 발생했습니다. (category가 빈 값으로 @NotBlank, 예외발생)
위에서 설정한 GlobalErrorHandler에 의해서 핸들링 된 값입니다.
ojaeseocBookPro:valid ojaeseong$ curl --location --request POST 'http://localhost:8080/' \
> --header 'Content-Type: application/json' \
> --data-raw '{
> "name": "제목",
> "category": "",
> "useYn": "N"
> }'
{"message":"MovieAddRequest.category 빈 값일 수 없습니다","response":""}
@NotBlank(message = "MovieAddRequest.category 빈 값일 수 없습니다")
private String category;
@NotBlank(message = "MovieAddRequest.useYn 빈 값일 수 없습니다")
private String useYn;
물론, Enum으로 설정하고, 기동을 하면 오류가 발생하기야 하지만..
Validation 체크가 아니고 맵핑, 파싱 오류입니다. 😰
(Servlet Container's Mapping → Validation 순서로 인한 예상 밖의 에러 발생)
그렇다면, 어떻게 하면 좋을까요? 🥺
저의 해결법은, String으로 설정하고 자체적으로 Validator를 개발하는 방법입니다.
이는 Bean Validation에서 제공하는 인터페이스를 통해서 구현이 가능합니다. (ConstraintValidator 사용)
이 과정을 거치면, 아래의 코드로 변환이 됩니다.
@NotBlank(message = "MovieAddRequest.name은 빈 값일 수 없습니다")
private String name;
@MovieCategoryValid(message = "MovieAddRequest.category이 유효한 값이 아닙니다")
private String category;
@StringValid(acceptedList = {"Y", "N"}, message = "MovieAddRequest.useYn이 유효한 값이 아닙니다")
private String useYn;