[Spring] 검증(Bean Validation)
Bean Validation이란?
우리는 이전에 Validator를 통해 검증을 하는 것을 해보았다.
간단하게 Validator를 사용하고자 하는 컨트롤러에 등록하여 사용하기도 했지만 실제로 MainApplication에 Global Validator로 적용하여 사용하는 것도 가능하다.
Spring에서는 이를 활용하여 간단하게 애노테이션으로 검증할 수 있는 기법을 제공한다.
이를 Bean Validation이라고 하며, Spring에서는 LocalValidatorFactoryBean을 Global Validator로 등록하여 검증을 진행한다.
우리가 실제로 객체의 속성위에 애노테이션을 적용함으로써 이를 간단하게 해결가능하다.
적용가능한 애노테이션은 @NotBlank, @Max, @Range등 다양한데 자세한 애노테이션들은 애노테이션확인에서 확인할 수 있다.
이제 이 방법이 어떻게 메세지를 뿌려주는지 알아보자.
Bean Validation 에러 코드
메세지를 출력하는데 있어 간단하게 @NotBlank(message = "공백이면 안됩니다.")와 같이 메세지를 설정해줄 수도 있고 메세지 소스를 활용할 수도 있다.
Bean Validation에서는 어떻게 메세지 소스 코드를 활용하는지 간단한 예제를 통해 확인해보자.
우리는 이전에 이름에 대한 입력을 필수로 해야했다.
우리는 이것을 메세지 소스코드로 required.person.name으로 나타냈다.
Bean Validation에서는 이와 유사하게 MessageCodesResolver를 활용하여 @NotBlank애노테이션을 기반으로 메세지 소스코드를 구성해준다.
- NotBlank.person.name
- NotBlank.name
- NotBlank.java.lang.String
- NotBlank
다른 애노테이션도 이전의 예시와 같은 방식으로 코드를 구성하고 세부적인 순으로 메세지 소스 코드에 있는 것을 꺼내와서 사용한다.
이를 실제로 메세지 소스 코드로 작성하여 보자.
NotBlank.person.name = 이름을 입력하세요.
NotBlank.person.emailId = 이메일을 입력하세요.
DepartmentMajorError = 학과나 전공 둘 중 하나를 입력하세요.
typeMismatch.java.lang.Integer = 숫자를 입력하세요.
typeMismatch.java.lang.String = 문자를 입력하세요.
- 1, 2번째 라인은 가장 세부적인 형태로 @NotNull이 적용될 것이다.
- 3번째 라인은 글로벌 오류를 적용할 것이다.
- 4, 5번째 라인은 타입 오류를 적용할 것이다.
필드 오류, 글로벌 오류
이제 실제로 적용하는 것을 살펴보자.
필드 오류는 다음과 같이 단순히 애노테이션을 설정함으로써 진행할 수 있다.
public class Person {
@NotBlank
private String name;
private Integer age;
private String department;
private String major;
private Boolean notebook;
private List<String> lang;
private Environment envs;
@NotBlank
private String emailId;
private String platform;
}
하지만, 글로벌 오류의 경우 다양한 속성의 조합으로 이루어질 수 있기 때문에 애노테이션으로는 불가능하다.
그에 따라, @ScriptAssert라는 애노테이션을 제공해주어 글로벌 오류를 설정할 수 있고 그냥 자바 코드로 이전처럼 작성하는 방법이 존재한다.
애노테이션을 사용할 경우 이 클래스 내부의 변수 말고는 사용이 불가한다는 점 등의 제약이 많고 불편한 점이 존재해 자바 코드로 작성하는 것이 더 좋다고 한다.
자바 코드로 작성하면 다음과 같이 처리할 수 있다.
@PostMapping("/home")
public String receive(@Validated @ModelAttribute Person person, BindingResult bindingResult, Model model) {
if (!StringUtils.hasText(person.getDepartment()) && !StringUtils.hasText(person.getMajor())) {
bindingResult.reject("DepartmentMajorError", null);
}
if (bindingResult.hasErrors()) {
setBoxes(model);
return "home";
}
return "intro";
}
- 학과, 전공 둘 다 비어있을 경우 오류를 저장한다.
그리고 뷰에 적용하는 부분은 Validator를 직접 등록했을 때와 동일하기 때문에 까먹었다면 검증(Validator)을 참고하자.
결과
- 이름에 값을 기입하지 않은 경우(필드 오류)
- 나이가 문자로 입력된 경우(타입 오류)
- 학과, 전공이 둘 다 기입되지 않은 경우(글로벌 오류)
- 이메일이 기입되지 않은 경우(필드 오류)
- 정상적으로 처리된 경우