요청 핸들러 메서드로 기본형 타입이 아닌 Date 타입을 받을 경우 Exception Report 오류가 뜬다


Type Exception Report

Message Failed to convert value of type 'java.lang.String' to required type 'java.sql.Date'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.sql.Date': no matching editors or conversion strategy found

Description The server encountered an unexpected condition that prevented it from fulfilling the request.


해당 오류가 뜨는 이유는 브라우저 요청 파라미터의 타입은 문자열인데 이 문자열을 frontController가 다른 기본형 타입으로는 바꿔줄 수는 있는데 Date타입으로 바꾸는 변환 메서드가 존재하지 않기 때문이다.


그렇기에 Date로 넘어온 파라미터를 처리하기 위한 변환 메서드가 필요하다


@InitBinder // 이렇게 표시를 해야만 프론트 컨트롤러가 요청 핸들러를 호출하기 전에 먼저 이 메서드를
                호출한다.
public void initBinder(WebDataBinder binder) {
// 이 메서드는 요청이 들어올 때 마다 파라미터 값을 준비하기 위해
// 파라미터의 개수 만큼 호출된다.
System.out.println("파라미터 개수 만큼 호출됨");
// java.lang.String ===> java.sql.Date 변환시켜주는 프로퍼티 에디터 등록
binder.registerCustomEditor(
java.sql.Date.class, /* 요청 핸들러의 파라미터 타입 */
new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
// "text" 파라미터는 클라이언트가 보낸 데이터이다.
// 이렇게 문자열로 보낸 데이터는 java.sql.Date 객체로 바꿔야 한다.
this.setValue(Date.valueOf(text));
}
});


@InitBinder를 메서드 앞에 선언하면 페이지 컨트롤러의 메서드를 호출하기 전에 해당 메서드가 먼저 호출된다.

Spring에 존재하는 custom property editor 인 WebDataBinder binder 받아서 넘어온 Date값을 변환할 것이다.

WebDataBinder 클래스 안에 있는 registerCustomEditor를 사용하여 첫번째 인자로는 바꿀 파라미터 타입, 두번째 인자로는 해당 파라미터를 바꿀 메서드를 작성해준다.

* 파라미터 값을 받기전에 호출되고 String 값을 다른 타입으로 바꾸기 위한 도우미 객체인 custom property editor라고도 함

* @InitBinder를 붙인 메서드는 해당 pageController에서만 실행된다

- 다른곳에서 사용하고 싶으면 @ControllerAdvice를 사용해야한다.

* 메서드가 한개만 존재하므로 익명클래스를 사용하여 소스를 간략화시킨다

* @InitBinder 를 붙인 메서드는 파라미터 갯수만큼 호출된다.

* binder에는 문자열을 바꿀 수 있는 메서드들이 내장돼있다.



만약 다른 pageController에서도 @InitBinder 메서드를 사용하고 싶으면??

@ControllerAdvice 애노테이션을 붙인 클래스를 구현한다.


한 pageController에서 작동하는 변환 메서드를 작성했을 때는 인스턴스 메서드를 사용했었는데

공용으로 사용하는 변환 메서드를 사용하기 위해서는 클래스를 작성해주고 클래스 위에 @ControllerAdvice를 붙여줘야한다!

- @ControllerAdvice를 붙여주면 iocContainer에 객체를 저장할 때 해당 클래스는 Controller에 도움을 줄 수 있는 클래스임을 인지하고 객체를 생성해 뒀다가 frontController가 pageController를 실행하기전에 RequestHandler를 실행하기 전 이 클래스를 실행한다. 



@ControllerAdvice
public class Exam05_5_GlobalControllerAdvice {
@InitBinder
public void initBinder(WebDataBinder binder) {
System.out.println("Exam05_5_GlobalControllerAdvice.initBinder()");
binder.registerCustomEditor(
java.sql.Date.class,
new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
this.setValue(Date.valueOf(text));
}
});
}
}




BELATED ARTICLES

more