1. Validator : 객체를 검증하기 위한 인터페이스, 객체 검증기(validator)구현에 사용
public interface Validator {
// 이 검증기로 검증가능한 객체인지 알려주는 메서드
boolean supports(Class<?> clazz);
// 객체를 검증하는 메서드 - target : 검증할 객체, errors:검증시 발생한 에러저장소
void validate(@Nullable Object target, Errors errors);
}
- Errors - BindingResult인터페이스의 부모
public class UserValidator implements Validator {
@Override
public boolean supports(Class<?> clazz){
// equals를 써도 된다.
return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인
}
@Override
public void validate(Object target, Errors errors){
User user = (User)target;
String id = user.getId();
// if(id==null || "".equals(id.trim())) {
// errors.rejectValue("id", "required");
// }
// 비었거나 공백이면 id필드에 required라는 에러코드로 저장
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required");
if(id==null || id.length() < 5 || id.length() > 12) {
errors.rejectValue("id", "invalidLength");
}
}
}
public interface Errors {
//...
void reject(String errorCode);
void rejectValue(String field, String errorCode);
}
- reject : 객체 전체에대한 에러
- rejectValue : 필드에러
- 컨트롤러 메서드에서 검증 하던 것을 Validator를 이용해 검증을 분리 - 수동
UserValidator userValidator = new UserValidator();
userValidator.validate(user, result); // validator로 검증
if(result.hasErrors()) { // 에러가 있으면,
return "registerForm";
}
- <form: errors> 폼으로 result 에러를 불러 올 수 있다.
2. Validator를 이용한 검증 - 자동
@InitBinder
public void toDate(WebDataBinder binder) {
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
binder.setValidator(new UserValidator()); // validator를 WebDataBinder에 등록
List<Validator> validators = binder.getValidators();
System.out.println("validators="+validators);
}
@PostMapping("/register/add") // 신규 회원 등록
public String save(Model m, @Valid User user, BindingResult result) {
if(result.hasErrors()) { // 에러가 있으면,
return "registerForm";
}
}
- binder.setValidator(new UserValidator()) - Validator를 등록
- 검증할 객체 앞에 @Valid애너테이션만 붙여주면 된다.
3. 글로벌 Validator : 하나의 Validator로 여러 객체를 검증할 때, 글로벌 Validator로 등록
- servlet-context.xml에 빈 등록
<annotation-driven validator="globalValidator"/>
<beans:bean id="globalValidator" class="com.fastcampus.ch2.GlobalValidator"/>
- 글로벌 Validator와 로컬 Validator를 동시에 적용하는 방법
@InitBinder
public void toDate(WebDateBinder binder) {
SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
// binder.setValidator(new UserValidator()); // validator를 WebDataBinder에 등록
binder.addValidators(new UserValidator())); // validator를 WebDataBinder에 등록
}
- binder.addValidators(로컬 Validator)를 등록
4. 실습
@PostMapping("/register/save") // 4.3부터
public String save(User user, BindingResult result, Model m) throws Exception{
System.out.println("result="+result);
System.out.println("user="+user);
// // 1. 유효성 검사
// if(!isValid(user)) {
// String msg = URLEncoder.encode("id를 잘못입력하셨습니다.","UTF-8") ;
//
// m.addAttribute("msg", msg);
// return "forward:/register/add";
//// return "redirect:/register/add?msg="+msg; // URL재작성(rewriting)
// }
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
- 컨트롤러 내에서 유효성 검사를 분리해준다.
- 수동 검증
public class UserValidator implements Validator {
@Override
public boolean supports(Class<?> clazz){
// return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors){
System.out.println("LocalValidator.validate() is called");
User user = (User)target;
String id = user.getId();
// if (id == null || "".equals(id.trim())) {
// errors.rejectValue("id", "required");
// }
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required");
if(id==null || id.length() < 5 || id.length() > 12){
errors.rejectValue("id", "invalidLength");
}
}
}
- 자동 검증
@InitBinder
public void toDate(WebDataBinder binder){
ConversionService conversionService = binder.getConversionService();
System.out.println("conversionService="+conversionService);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(df,false));
binder.setValidator(new UserValidator()); // UserValidator를 WebDataBinder의 로컬validator로 등록
}
- setValidator로 WebDataBinder의 로컬 validator를 등록해준후
@PostMapping("/register/save") // 4.3부터
public String save(@Valid User user, BindingResult result, Model m) throws Exception{
System.out.println("result="+result);
System.out.println("user="+user);
UserValidator userValidator = new UserValidator();
userValidator.validate(user, result); // BindingResult는 Errors의 자손
// User객체를 검증한 결과 에러가 있으면, registerForm을 이용해서 에러를 보여줘야 함.
if(result.hasErrors()){
return "registerForm";
}
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
- @Valid에서 빨간 불이 들어올텐데 @Valid가 Java표준 애너테이션이라서 그렇다.
- maven repository에서 validation을 검색 2번째의 Bean Validation API
- 복사 해서
- pom.xml파일에
- <dependencies> 아래에 붙여넣기 해준다.
- 위에 Maven Update버튼을 클릭해주면(미리 눌러버려서 사진을 찍지 못했다.)
- 방금 받아온 validation 2.0.1 Final이 잘 설치되었다.
- 빨간 불이 사라졌다.
- 검증...
- 검증이 잘 된다.
- GlobalValidator
public class GlobalValidator implements Validator {
@Override
public boolean supports(Class<?> clazz){
// return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인
return User.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors){
System.out.println("GlobalValidator.validate() is called");
User user = (User)target;
String id = user.getId();
// if (id == null || "".equals(id.trim())) {
// errors.rejectValue("id", "required");
// }
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required");
if(id==null || id.length() < 5 || id.length() > 12){
errors.rejectValue("id", "invalidLength");
}
}
}
- binder.addValidators(new UserValidator()) 추가
@InitBinder
public void toDate(WebDataBinder binder){
ConversionService conversionService = binder.getConversionService();
// System.out.println("conversionService="+conversionService);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(df,false));
// binder.setValidator(new UserValidator()); // UserValidator를 WebDataBinder의 로컬validator로 등록
binder.addValidators(new UserValidator());
List<Validator> validatorList = binder.getValidators();
System.out.println("validatorList:"+validatorList);
}
- List<Validator>의 import는 spring-context-5.0.7이다
- servlet-context.xml에 추가
<mvc:annotation-driven validator="globalValidator"/>
<beans:bean id="globalValidator" class="com.fastcampus.ch2.GlobalValidator"/>
- servlet-context.xml에 추가 하기 전에는 validatorList에 한개밖에 없는 모습
- 추가 후 재시작했더니
- validatorList에 두개의 validator가 잘 들어간 모습
5. MessageSource : 다양한 리소스에서 메시지를 읽기 위한 인터페이스
public interface MessageSource {
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
- servlet-context.xml에 프로퍼티 파일을 메시지 소스로 하는 ResourceBundleMessageSource를 등록
- error_message.properties 파일 생성 -> /src/main/resources/error_message.properties 경로
required=필수 항목입니다.
required.user.pwd=사용자 비밀번호는 필수 항목입니다.
invalidLenth.id=아이디의 길이는 {1}~{2}사이어야 합니다.
- Locale locale : 지역
- error_message.properties - 디폴트
- error_message_ko.properties
- error_message_en.properties... 여러개 만들 수 있다.
- Object[] args : new String[] {"5", "11"}이렇게 주면 -> invalidLenth.id=...{5}~{11}...
- String errorCode : "required"이면 ...
- required.user.id -> required.id -> required.java.lang... -> required -> String defaultMessage 순서로 찾는다.
- servlet-context.xml파일에 추가
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basenames">
<beans:list>
<beans:value>error_message</beans:value> <!-- /src/main/resources/error_message.properties -->
</beans:list>
</beans:property>
<beans:property name="defaultEncoding" value="UTF-8"/>
</beans:bean>
- 제일 아래에 추가해 주었다.
- /src/main/resources 폴더에 error_message.properties생성
6. 검증 메시지의 출력
- 스프링이 제공하는 커스텀 태그 라이브러리를 사용
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
- <form> 대신 <form:form>사용
<form:form modelAttribute="user"> // "user"=검증할 객체
- 아래로 변환된다.
<form id="user" action="/ch2/register/save" method="post">
- <form:errors>로 에러를 출력. path에 에러 발생 필드를 지정(*은 모든 필드의 에러)
<form:errors path="id" cssClass="msg"/>
- 아래로 변환된다.
<span id="id.errors" class="msg">필수 입력 항목입니다.</span>
- 실패... 다음에 다시 이어서 해보겠습니다.
'Spring' 카테고리의 다른 글
37. 데이터의 변환과 검증(1) - 패스트캠퍼스 백엔드 부트캠프 3기 (6) | 2025.02.17 |
---|---|
36. DispatcherServlet - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.17 |
35. 예외처리/이론 - 패스트캠퍼스 백엔드 부트캠프 3기 (2) | 2025.02.17 |
34. 예외처리/실습 - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.17 |
33. 세션(session)/실습(3) - 패스트캠퍼스 백엔드 부트캠프 3기 (2) | 2025.02.16 |