
"Spring에서 어떻게 브라우져가 보낸 HTTP Request를 Controller 메서드의 인자 객체 타입에 맞춰서 데이터를 주입해줄까?" 라는 궁금증으로부터 시작되어 해당 글을 적게 되었다.
WebDataBinder는 Request로 받은 값을, 컨트롤러 메서드의 인자 객체에 맞게 매핑시켜주는 객체이다.
만약 카카오톡과 인스타그램을 토글로 선택한 값을 Request로 받았다고 해보자. → 이 Request는 [”카카오”, “인스타”] 이런 배열에 담아서 전달된다.
WebDataBinder 는 Binding 되는 객체의 필드가 String이면, “카카오,인스타” 이렇게 자동으로 변환해주고WebDataBinder 는 Binding 되는 객체의 필드가 String []이면, [”카카오”, “인스타”] 이렇게 자동으로 변환해준다.날짜는 변환해주기 어렵기에 직접 format을 지정해줘서(=@DateTimeFormat(pattern=”yyyy/MM/dd”)), Binding 해주어야 한다.
@Controller // ctrl+shift+o 자동 import
@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()); // UserValidator를 WebDataBinder의 로컬 validator로 등록
// List<Validator> validatorList = binder.getValidators();
// System.out.println("validatorList="+validatorList);
}
@GetMapping("/add")
public String register() {
return "registerForm"; // WEB-INF/views/registerForm.jsp
}
@PostMapping("/add")
public String save(@Valid User user, BindingResult result, Model m) throws Exception {
System.out.println("result="+result);
System.out.println("user="+user);
// User객체를 검증한 결과 에러가 있으면, registerForm을 이용해서 에러를 보여줘야 함.
if(result.hasErrors()) {
return "registerForm";
}
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}
private boolean isValid(User user) {
return true;
}
}
@initBinder → 타입을 등록할 때 커스텀 데이터 변환 메서드를 통해 타입을 커스텀하게 변환할 수 있게 해주는 어노테이션양방향 타입 변환(String → 타입, 타입 → String) 특정 타입이나 이름의 필드에 적용 가능Default PropertyEditor → 스프링이 기본적으로 제공Custom PropertyEditor → 사용자가 직접 구현, PropertyEditorSupport를 상속하면 편리모든 컨트롤러 내에서의 변환 - WebBindginInitializer를 구현 후 등록
특정 컨트롤러 내에서의 변환 - 컨트롤러에 @initBinder 를 붙은 메서드 작성
@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()); // UserValidator를 WebDataBinder의 로컬 validator로 등록
// List<Validator> validatorList = binder.getValidators();
// System.out.println("validatorList="+validatorList);
}
단방향 타입 변환(타입A→타입B)PropertyEdiitor의 단점을 개선(stateful → stateless)
public class StirngToStringArrayConverter implements Converter<String, String[]>{
@Override
public String[] convert(String source) {
return source.split("#"); // String -> String []
}
}
Converter<String, String[]> 코드는 String을 String[]으로 변환하겠다는 의미
ConversionService - 타입 변환 서비스를 제공. 여러 Converter를 등록 가능
양방향 타입 변환(String → 타입, 타입 → String), 어노테이션 기반@NumberFormat, @DateTimeFormat@DateTimeFormat(pattern=”yyyy/MM/dd”)
Date birth;public class UserValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
// return User.class.equals(clazz); // 검증하려는 객체가 User타입인지 확인
return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인
}
@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");
}
}
}자동으로 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()); // UserValidator를 WebDataBinder의 로컬 validator로 등록
// List<Validator> validatorList = binder.getValidators();
// System.out.println("validatorList="+validatorList);
}
수동으로 Validator를 등록
@PostMapping("/add")
public String save(@Valid User user, BindingResult result, Model m) throws Exception {
System.out.println("result="+result);
System.out.println("user="+user);
// User객체를 검증한 결과 에러가 있으면, registerForm을 이용해서 에러를 보여줘야 함.
if(result.hasErrors()) {
return "registerForm";
}
// 2. DB에 신규회원 정보를 저장
return "registerInfo";
}