본문 바로가기
Spring

[Spring] WebDataBinder로 데이터 타입 변환, 검증하기

by eunoo 2022. 6. 22.

회원가입 페이지에서 User의 정보를 POST로 요청했다.

데이터는 WebDataBinder로 타입변환과 검증을 거쳐

그 결과는 BindingResult에 저장이 되고, 타입변환과 검증을 거친 데이터는 User에 저장된다.

 

타입 변환과 검증을 어떻게 하는지 알아보자.

1. 타입 변환

User클래스의 필드인 birth의 타입은 Date이다. 

스프링에선 2022/01/01 형식으로 데이터를 입력했을 때 Date타입으로 자동 변환이 된다.

2022-01-01 형식으로 데이터를 입력해도 Date타입으로 들어올 수 있게 변환해보자.

@Controller
@RequestMapping("/register")
public class RegisterController {
	
	@InitBinder
	public void toDate(WebDataBinder binder) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(df,false));
	}
	
...
	
}

RegisterController에 toDate 메소드를 추가해주었다.

생일을 2022-01-01 이렇게 입력해도 Date로 변환하여 저장이 된다.

(import java.util.Date; 주의하자. sql.Date로 해서 시간 잡아먹음ㅠㅠ)

 

이건 PropertyEditor를 이용해서 타입 변환을 해주었는데 이외에도 Converter, Formatter를 사용할 수 있다.

Formatter를 이용하면 아주 간단하다.

public class User {
	private String id;
	private String pwd;
	private String name;
	private String email;
	@DateTimeFormat(pattern="yyyy-MM-dd")
	private Date birth;
	private String[] sns;
	private String [] hobby;
...
}

다음과 같이 birth 필드에 @DateTimeFormat(pattern="yyyy-MM-dd") 만 붙여주면 된다!

 

2. 검증

 

그 전에는 isValid()라는 메서드를 따로 만들어서 검증을 했다.

이제는 Validator를 이용하여 검증을 하자.

Validator는 스프링이 제공하는 객체를 검증하기 위한 인터페이스이다. 다음과 같이 작성되어 있다.

public interface Validator{
	//검증 가능한 객체인가를 검증해줌.
	boolean supports (Class<?> clazz);
    	// target은 검증할 객체이고, 검증 시 발생한 에러를 errors에 저장.
    	void validate(Object target, Errors errors);
}

 

다음과 같이 UserValidator를 생성했다.

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class UserValidator implements Validator{

	@Override
	public boolean supports(Class<?> clazz) {
		//clazz가 User또는 자손인지 검증
		return User.class.isAssignableFrom(clazz);
	}

	@Override
	public void validate(Object target, Errors errors) {
		System.out.println("UserValidator.validate() is called");
		
		User user= (User)target;
		String id = user.getId();
		//id 필드가 비었거나 공백이면, "required"라는 에러 코드로 저장.
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required");
        	//pwd 필드가 비었으면 "required"라는 에러 코드로 저장.
		ValidationUtils.rejectIfEmpty(errors, "pwd", "required");
		 //아이디가 null, 길이가 5~12사이가 아니라면, "invalidLength"라는 에러 코드로 저장.
		if(id==null|| id.length()<5 || id.length()>12) {
			errors.rejectValue("id", "invalidLegnth");
		}
	}
}

그리고 @InitBinder 메소드에 setValidator로 검증을 추가하고 save메서드에서 User user 매개변수 앞에 @Valid를 붙여주면 끝이다.

@Controller
@RequestMapping("/register")
public class RegisterController {
	
	@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());
	}

 	@PostMapping("/add")
	public String save( @Valid User user,BindingResult result, Model m) throws Exception {
 		System.out.println("result= "+result);
 		System.out.println("user= "+user);

		if(result.hasErrors()) {
			return "registerForm";
		}
		return "registerInfo";
	}
}

@Valid에 빨간줄이 뜰텐데 maven repository에서 다음의 API를 pom.xml에 추가해주어야한다. 

(pom.xml 수정 후 업데이트 해주는 걸 잊지말자!)

 

추가로 GlobalValidator도 생성해보자.  

public class GlobalValidator implements Validator{

	@Override
	public boolean supports(Class<?> clazz) {
		return User.class.isAssignableFrom(clazz);
	}

	@Override
	public void validate(Object target, Errors errors) {
    
    	System.out.println("UserValidator.validate() is called");
		
		User user= (User)target;
		String id = user.getId();
        
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required");
		ValidationUtils.rejectIfEmpty(errors, "pwd", "required");

		if(id==null|| id.length()<5 || id.length()>12) {
			errors.rejectValue("id", "invalidLegnth");
		}
	}
}

이는 모든 객체를 검증할 때 사용한다.  GlobalValidator로 모든 객체 검증을 하기 위해서는

servlet-context.xml에 다음 코드를 추가해줘야 한다. 그리고 검증할 객체에 @Valid만 붙여주면 끝이다.

<annotation-driven validator="globalValidator" />
<!-- <beans:bean id="globalValidator" class="GlobalValidator 위치" /> -->
<beans:bean id="globalValidator" class="com.hyoding.ch2.GlobalValidator" />

 

GlobalValidator도 있고 UserValidator도 있을 때는 더 가까운 UserValidator를 실행하니 주의하자.

 

GlobalValidator와 로컬 Validator를 동시에 사용하고 싶다면 GlobalValidator를 등록하고,

setValidator대신 addValidators를 이용하여 검증 객체를 등록한다.

 

	@InitBinder
	public void toDate(WebDataBinder binder) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(df,false));
		
		binder.addValidators(new UserValidator());
	}

댓글