이제 dto별 유효성 검증을 하도록 하겠다.
이전에 만든 메서드가 있긴있지만 해당 메서드는 여러번 dto가 재사용될 때 유효성 검증 항목이 상이할 때만 사용하고 일반적으론 편하게 Spring Validation을 쓰도록 하겠다.
먼저 의존성을 받아준다
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-validation'
그리고 사용할 dto나 파일에 가서 붙여준다
public record CreateReq(
@NotBlank(message = "부서명은 빈 값일 수 없습니다.") String name,
@NotBlank(message = "부서설명은 빈 값일 수 없습니다.") String description,
@NotNull(message = "부서장을 선택해주세요.") Long managerUserId,
String tel
) {
}
가장 많이 사용하는게 @NotNull, @NotEmpty, @NotBlank 이렇게 세가지이다.
서로 역할이 조금씩 다르므로 주의하도록 한다.
@NotNull: Null값만 검증 실패
@NotEmpty: Null과 "" 빈 문자열만 검증 실패
@NotBlank: Null과 ""및 " "와 같이 공백문자만 존재하는 문자열도 검증 실패
여기서 NotEmpty, NotBlank는 검증하는 "" 자체가 이미 문자열이므로 문자열타입에만 적용 가능한 검증이다.
그 외 타입에서 null검사를 하고싶으면 @NotNull을 사용하자
그리고 컨트롤러에 가서
@Auth
@PostMapping
public Response<DepartmentResp> createDepartment(@RequestBody @Valid CreateReq createReq) {
return Api.success(200, "부서 생성 완료", departmentService.createDepartment(createReq));
}
@Valid 라는 어노테이션을 인자로 받을 dto앞에 붙여주면 끝
진짜 끝일까?
한번 실제로 api를 호출해보면
이와같이 정돈되지않은 에러메시지가 그대로 노출이 되어버리는데
Spring Validation에서 잡힌 Exception도 advice에서 따로 처리를 해줘야한다.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Response<Map<String, String>>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
Map<String, String> errors = new HashMap<>();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError fieldError : fieldErrors) {
errors.put(fieldError.getField(), fieldError.getDefaultMessage());
}
Response<Map<String, String>> errorResponse = Api.error(HttpStatus.BAD_REQUEST, "유효성 검증에 실패하였습니다.", errors);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
나는 이런느낌으로 만들었다. MethodArgumentNotValidException에서 유효성 검증이 실패한 필드와 해당 메시지는 List fieldErrors = e.getBindingResult().getFieldErrors(); List를 만들어 가져 올 수 있고
각 인덱스마다 getField()와 getDefaultMessage() 로 꺼내서 쓸 수 있다.
그럼 다시 API를 호출해보자
이제 원하는대로 잘 나온다. 프론트 개발자 입장에선 key을 통해 컴포넌트를 참조해서 에러이벤트를 화면에 띄어주면 될 거 같다.
아마 실제 개발환경이였다면 http status를 400이 아닌 999같이 커스텀해서 유효성 검증용 에러코드로 전달해드렸을듯..?