데이터 변환 & 검증

ikyeong·2023년 5월 25일
0

Spring-Study

목록 보기
9/9

01.WebDataBinder

  1. 타입변환
  2. 데이터 검증

두가지의 기능을 수행. 변환과 검증의 결과를 Binding Result에 저장한다.

💡 이때 BindingResult 매개변수를 메서드에 넣은 경우 바인딩 과정에서 예외가 발생해도 컨트롤러가 처리하도록 하고 에러 페이지로 이동하지 않음


02.데이터 변환

📌 PropertyEditor

양방향 타입 변환 (문자열->타입, 타입->문자열)

  • defaultPropertyEditor : 스프링이 기본적으로 제공
  • customPropertyEditor : 사용자가 직접 등록

💡 모든 컨트롤러 내에서의 변환

WebBindingInitializer 구현 후 등록

💡 특정 컨트롤러 내에서의 변환

컨트롤러 내부에 @InitBinder 어노테이션이 붙은 메서드를 작성

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

📌 Converter

단방향 타입 변환 (타입A->타입B)

💡 PropertyEditor의 단점을 개선

PropertyEditor는 인스턴스 변수를 이용하는 것 -> stateful하기 때문에 싱글톤으로 사용할 수 없음 (인스턴스가 생성될때마다 다시 에디터를 추가해줘야됨)
-->convert는 stateless

public class StringToStringArrayConverter implements Converter<String, String[]>{
	@Override
    public String[] convert(String source){ //string -> string 배열
    	return source.split("#"); 
    }
}

💡 ConversionService

타입 변환 서비스 제공. 여러 Converter를 등록할 수 있고 WebDataBinder에 DefaultFormattingConversionService가 기본적으로 등록되어 있다.


📌 Formatter

양방향 타입 변환 (문자열->타입, 타입->문자열)
바인딩할 필드에 적용 (ex. @NumberFormat, @DateTimeFormat)

@DateTimeFormat(pattern = "yyyy/MM/dd")
Date birth;

@NumberFormat(pattern = "###,###")
BigDecimal salary;

03. 데이터 검증

📌 Validator

객체를 검증하기 위한 인터페이스. 객체 검증기 구현에 사용된다.

  • boolean supports(Class<?> clazz) : 검증가능한 객체인지 알려줌
  • void validate(Object target, Errors errors) : target은 검증할 객체, errors는 검증하며 발생한 에러를 저장하는 곳
public class UserValidator implements Validator {
	@Override
	public boolean supports(Class<?> clazz) {			
		return User.class.isAssignableFrom(clazz); // clazz가 User나 User의 자손인지 확인
	}

	@Override
	public void validate(Object target, Errors errors) { 
		System.out.println("LocalValidator.validate() is called");
		// support 메서드를 통해 User로 캐스팅이 가능한 객체만 들어와있기 때문에 
        // instanceof를 사용하지 않아도 된다
		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");
		}
	}
}

Validator를 이용한 수동검증

UserValidator userValidator = new UserValidator();
userValidator.validate(user, result);

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

Validator를 이용한 자동검증

@InitBinder
public void toDate(WebDataBinder binder){
	...
    //validator 등록
    binder.setValidator(new UserValidator()); 
    ...
}

@PostMapping("/register/save")
//검증하려는 매개변수 앞에 @Valid 어노테이션
public String save(Model m, @Valid User user, BindingResult result){
	if (result.hasErrors()) return "registerForm";
	return "registerInfo";
}

📌 글로벌 Validator

하나의 Validator로 여러 객체를 검증하고자 할 때 이용

  • servlet-context.xml
<annotation-driven validator="globalValidator"/>
<beans:bean id="globalValidator" class="com.fastcampus.ch2.GlobalValidator"/>

💡 글로벌 Validator와 로컬 Validator를 같이 등록?

@InitBinder
public void toDate(WebDataBinder binder){
	...
    //꼭 addValidator 메서드를 이용해야됨!!
    binder.addValidator(new UserValidator());  
    ...
}

0개의 댓글