Springboot에서 유효성검사를 위해서는 Spring Boot Starter Validation이라는 라이브러리가 필요하다.
mvnrepository에서 다운로드 할 수 있다.
dependency를 추가하면 Controller에서 @valid라는 어노테이션을 사용할 수 있게된다.
(java.validation 어노테이션 종류는 여기서 확인할 수 있다.)
//SignupReqDto
@Data //lombok
public class SignupReqDto {
@Size(min = 2, max = 20)
@NotBlank()
private String username;
@NotBlank()
private String password;
}
//Controller
@PostMapping("/")
public String signup(@Valid SignupReqDto signupReqDto, BindingResult bindingResult){
if (bindingResult.hasErrors()) {
Map<String,String> errorMap = new HashMap<>();
for(FieldError error:bindingResult.getFieldErrors()) {
errorMap.put(error.getField(), error.getDefaultMessage());
}
throw new RuntimeException("유효성 검사 실패");
} else {
//회원가입 진행
return "signin";
}
}
SignupReqDto에 어노테이션을 붙여서 유효성 검사를 하여 문제가 생기면 BindingResult 클래스를 통해 전달 받을 수 있다.
Controller에서 다음 코드를 보자.
if (bindingResult.hasErrors()) {
Map<String,String> errorMap = new HashMap<>();
for(FieldError error:bindingResult.getFieldErrors()) {
errorMap.put(error.getField(), error.getDefaultMessage());
}
throw new RuntimeException("유효성 검사 실패");
} else {
//회원가입 진행
return "signin";
}
bindingResult에 error가 있으면 문제가 있는 필드 네임과 오류메시지를 Map에 저장하고 RuntimeException을 던진다.
하지만 이렇게 하면 사용자에게 오류 화면 전체가 넘어가게 된다. 이것을 더 깔끔하게 전달하기 위해서 다음과 같이 한다.
//ControllerExceptionHandler
@RestController
@ControllerAdvice //모든 exception을 낚아챔
public class ControllerExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public String validationException(RuntimeException e) {
return e.getMessage();
}
그런데 RunTimeException은 string만 받기 때문에 errorMap을 넘길 수가 없다.
따라서 RunTimeException을 상속한 클래스를 하나 만들어줘야한다.
//CustomValidationException
public class CustomValidationException extends RuntimeException{
// 객체를 구분할 때 사용
private static final long serialVersionUID = 1L;
private Map<String, String> errorMap;
public CustomValidationException(String message, Map<String, String> errorMap) {
super(message);
this.errorMap = errorMap;
}
public Map<String, String> getErrorMap() {
return errorMap;
}
}
RuntimeException에 메시지를 던지면 RuntimeException이 그 메시지를 부모(Exception)에게 던지고 Exception은 그것을 또 부모(Throwable)로 던진다. 그 후, Throwable의 getMessage함수를 통해 메시지를 받기 때문에 super(message)를 해주면 메시지를 받을 수 있다.
이렇게 CustomValidationException를 만들어주고 RuntimeException부분을 CustomValidationException로 바꿔준 후 return 타입을 Map<String, String>으로 바꿔준다
//ControllerExceptionHandler
@RestController
@ControllerAdvice //모든 exception을 낚아챔
public class ControllerExceptionHandler {
@ExceptionHandler(CustomValidationException.class)
public Map<String, String> validationException(CustomValidationException e) {
return e.getMessage();
}
"유효성 검사 실패" 라는 메시지도 같이 띄우고싶다면 공통Dto를 만들어서 ControllerExceptionHandler의 return 타입을 공통Dto로 바꿔 주면 된다.
//CommonResDto
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CommonResDto<T>{
private String message;
private T data;
}
//ControllerExceptionHandler
@RestController
@ControllerAdvice //모든 exception을 낚아챔
public class ControllerExceptionHandler {
@ExceptionHandler(CustomValidationException.class)
public CommonResDto<?>validationException(CustomValidationException e) {
return new CommpnResDto<Map<String, String>>(e.getMessage(), e.getErrorMap();
}