[Spring] 데이터의 변환 WebDataBinder

Jeini·2023년 5월 24일
0

🍃  Spring

목록 보기
13/33
post-thumbnail

💡 WebDataBinder


✔️ 요청 매개변수(form 또는 query 데이터)를 모델 객체에 바인딩한다.

  • 브라우저를 통해서 요청받은 값이 실제 서버의 객체에 바인딩 될 때, 중간 역할을 함

1. 타입변환
2. 데이터 검증
➡️ 변환 결과나 에러는 BindingResult에 저장

  • 기본적으로 데이터가 String인데 타입이 불일치 할 때 타입을 적절하게 변환해주는 역할을 한다.

💡 RegisterController에 변환 기능 추가하기


✏️ 변환 메서드 만들기

@InitBinder
public void toDate(WebBinder binder) {
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
    // 스프링이 제공하는 CustomDateEditor를 이용해서 변환. String -> Date
    binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
}

✏️ User에 직접 바인딩할 객체에 직접 적어주기

  • @DateTimeFormat 어노테이션으로 직접 바꿔준다.

✏️ 예제

✔️ User클래스에 Date birth로 바꿔준다.

  • 저 입력 형식으로는 Date객체가 변환할 수 없어서 400 에러가 떴다.

⭐️ 해결 방법

✔️ BindingResult를 파라미터로 받아온다.

	@PostMapping("/register/save")
	// 사용자 정보 저장
	//@RequestMapping(value="/register/save", method=RequestMethod.POST)
	public String save(User user, BindingResult result, Model model) throws UnsupportedEncodingException {
		// 1. 유효성 검사
		if(!isValid(user)) {
			String msg = URLEncoder.encode("id를 잘못 입력하셨습니다.", "UTF-8");
			
			model.addAttribute("msg", msg); // = "redirect:/register/add?msg=" + msg; -> 스프링이 이렇게 바꿔준다.
			return "forward:/register/add";
			//			return "redirect:/register/add"; 
			
		}
		// 2. DB에 신규회원 정보를 저장
		return "registerInfo";
	}
	private boolean isValid(User user) {
		return true;
	}
  • ❗️ 바인딩 할 객체 바로 뒤에다가 BindingResult 를 써줘야 한다.
  • 예외가 발생했다고 에러 페이지로 가는 것이 아니라, Controller한테 바인딩 결과를 주고 Controller가 어떻게 할지 처리하게 하는 것.
  • 콘솔에는 미스매치 되었다고 뜨는 것을 확인 할 수 있다.
    : 에러가 있을 때는 다시 redirect하면서 메세지를 보내 줄 수도 있고
    : Controller 안에다가 @InitBinder가 붙은 메서드를 선언해 줄 수 있다.

✏️ @InitBinder 어노테이션 사용

	@InitBinder
	public void toDate(WebDataBinder binder) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, false));
	}
  • Date로 변환할 때, Spring이 제공하는 CustomDateEditor라는 클래스가 있다. 여기서 날짜 형식을 정해주고 집어넣어 주었다.

  • 매개변수는 WebDataBinder 사용하기

  • 해당 Controller 내에서만 사용 가능

  • false : 빈 값 허용 여부

  • 타입을 변환할 때, 우리가 등록한 커스텀 변환 메서드를 먼저 보게 된다.
    ➡️ 있으면 맞게 변환
    ➡️ 없으면 spring이 기본으로 가지고 있는 디폴트 변환 메서드 사용

✏️ 취미 추가

	@InitBinder
	public void toDate(WebDataBinder binder) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, false));
        // # 구분자 
		binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor("#"));
	}

💡 PropertyEditor


✔️ 양방향 타입 변환(String ➡️ 타입, 타입 ➡️ String)
✔️ 특정 타입이나 이름의 필드에 적용 가능

  • 자바빈에서 쓰던 것을 spring에서도 씀

  • defalut PropertyEditor
    : 스프링이 기본적으로 제공

  • Custom PropertyEditor:
    : 사용자가 직접 구현.
    : PropertyEditorSupport 상속하면 필요한 메서드만 오버라이딩하면 되니까 편리하다.
    : 모든 컨트롤러 내에서의 변환 ➡️ WebBindingInitializer 를 구현 후 등록
    : 특정 컨트롤러 내에서의 변환 ➡️ 컨트롤러에 @InitBinder가 붙은 메서드를 작성

많은 것을 제공하는 PropertyEditor

💡 Converter & ConversionService


✔️ Converter
: 단방향 타입 변환(타입A ➡️ 타입B)

: PropertyEditor의 단점을 개선(stateful ➡️ stateless)

  • property는 iv(인스턴스 변수)이다. [Java Beans]
    : 그것을 바꾸는 것이 propertyEditor.

  • stateful : 인스턴스 변수를 쓴다는 뜻
    : 싱글톤 사용 ❌
    : 변화할 때마다 새로운 객체를 계속해서 만들어야 함 ➡️ 별로 좋지 않음 👎
    : Converter는 iv를 사용하지 않음 ➡️ 단점 개선

➡️ 따라서, propertyEditor를 사용하는 것보다 Converter 를 사용하는 것이 낫다

✏️ String을 String[]로 Converter

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

❗️ Converter를 ConversionService에 등록

✔️ ConversionService
: 타입 변환 서비스를 제공
: 여러 Converter 등록 가능

  • WebDataBinderDefaultFormattingConversionService 이 기본으로 등록어져 있다.
    : 그걸 이용해서 타입 변환이 이루어진다.

  • 모든 컨트롤러 내에서의 변환
    : ConfigurableWebBindingInitializer 를 설정해서 사용

  • 특정 컨트롤러 내에서의 변환
    : 컨트롤러에 @InitBinder가 붙은 메서드를 작성

✏️ ConversionService 적용

	@InitBinder
	public void toDate(WebDataBinder binder) {
		ConversionService conversionService = binder.getConversionService();
		System.out.println(conversionService);
//		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//		binder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, false));
		// hobby에만 적용
		binder.registerCustomEditor(String[].class, "hobby" ,new StringArrayPropertyEditor("#"));
	}

  • ConversionService는 엄청나게 많은 Converter들이 등록되어져 있다.
    : 이러한 것들을 이용해서 자동 변환을 다 해 주고 있다.

💡 Formatter


✔️ 양방향 타입 변환(String ➡️ 타입, 타입 ➡️ String)
✔️ 바인딩할 필드에 적용 ➡️ @NumberFormat, @DateTimeFormat

  • propertyEditor와 비슷하다.

  • Printer: Object ➡️ String

  • Parser: String ➡️ Object

  • 어노테이션을 이용하여 포맷한다.

⭐️ 변환 기능 우선 순위


✔️ Custom PropertyEditor ➡️ ConversionService ➡️ defalut PropertyEditor

  • @initBinder 가 붙은 메서드가 있으면 해당 메서드를 우선

  • 항상 가까운 쪽이 우선


Reference
: https://fastcampus.co.kr/dev_academy_nks

profile
Fill in my own colorful colors🎨

0개의 댓글