티스토리 뷰

SPRING/정리

요청 파라미터 바인딩

란텔 2016. 4. 27. 16:19
  • @InitBinder


스프링프레임워크에서의 바인딩이란 모델 클래스(오브젝트)의 프로퍼티(메서드 set)에 값을 넣는 것을 말한다.


두가지 바인딩을 제공하는데..


첫 번째는 xml설정 파일을 통해 <bean>의 <property>에 값을 넣는 것이다. 하지만 xml자체가 문자열이기 때문에 해당 빈클래스의 property값이 기본형 타입이나 String이라면 괜찮지만 그 외의 타입이라면 바인딩 하기전에 적절한 변환이 필요하다.


두번째는 Http를 통해 전달되는 헤더, 쿠키, 파라미터 같은 정보인데 이런 것들도 전부 문자열로 전달되는 값이다. 해서 이 경우에도 특정 타입으로 매칭시키려면 바인딩 과정 중에 적절한 변환이 필요하다.




컨트롤러 메서드에서는 @RequestParam, @PathVariable, @ModelAttribute등이 메서드의 매개변수에 지정되어 있다면 WebDataBinder라는 인스턴스를 만든다.

WebDataBinder는 여러가지 기능을 제공하고, 그 중에서도 요청 파라미터의 문자열을 컨트롤러 메서드의 매개변수에 지정된 변수 타입과 같은 형태로 변환하는 기능도 포함되어 있다.


WebDataBinder의 바인딩 적용대상은 다음과 같다.

@RequestParam파라미터 

@RequestHeader파라미터

@CookieValue파라미터

@PathVariable파라미터

@ModelAttribute파라미터


이 변환작업을 입맛에 맞게 수행하려면 하려면 PropertyEditor라는 인터페이스의 도움이 필요하다.

PropertyEditor의 도움을 받아서 오브젝트 클래스를 만들고 나면 그 다음에는 WebDataBinder에 등록이 필요하다.




PropertyEditor인터페이스를 구현하는 클래스인 PropertyEditorSupport를 이용해서 클래스를 작성해 보겠다.

public class CustomPropertyEditor extends PropertyEditorSupport {

     @Override
     public void setAsText(String text) throws java.lang.IllegalArgumentException {
         System.out.println("text pre : "+text);
         char[] cArr = text.toLowerCase().toCharArray();
         
         boolean b = true;
         
         for(char c : cArr){
             if(c > 'a' && c < 'z'){
                 System.out.println("문자열 숫자로 형변환 목함");
                 b = false;
                 break;
             }
         }
         
         if(b == false){
             this.setValue(text);
             return;
         }
         
             int i = Integer.parseInt(text);
             if(i > 19){
                 i=19;
             }
             System.out.println("text next : "+i);
         
         this.setValue(i);
     }
    
     /*@Override
     public String getAsText() {
            return "ss"; 
     }*/
    
}

위의 오버라이딩 메서드인 setAsText를 요청 파라미터 문자열이 거치게 되면 해당 클래스(PropertyEditorSupport)의 인스턴스 변수인 Object 타입인 변수명 value에 파라미터가 저장되고, 이 value가 해당 모델 클래스(Student)에 저장된다.




테스트 해 볼 대상이 되는 POJO스타일 모델 오브젝트이다.

public class Student {
    
    private String name;
    private int age;
    
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}



다음은 @InitBinder어노테이션이 적용된 메서드와 테스트 해 볼 컨트롤러 메서드이다.

   @InitBinder
    public void initBinding(WebDataBinder b){
        CustomPropertyEditor cpe = new CustomPropertyEditor();
        b.registerCustomEditor(String.class, cpe);
        b.registerCustomEditor(int.class, cpe);
        //b.registerCustomEditor(int.class, "age", new CustomPropertyEditor());
        //(필드의 타입, 적용할 변수 이름, 프로퍼티에디터 구현체 오브젝트)
    }
    
    
    @RequestMapping(value="testBinder")
    public String testBinder(@ModelAttribute Student student){
        System.out.println("name >>> "+student.getName());
        System.out.println("age >>> "+student.getAge());
        
        return "/home";
    }

@InitBinder메서드는 요청 파라미터를 바인딩 하기전에 자동으로 호출되며, 이곳에 registerCustomEditor메서드를 이용해서  WebDataBinder에 직접 정의한 PropertyEditor구현 클래스를 등록할 수 있다.



*타입에 따라서 적용되는 프로퍼티 에디터 등록방식(Student의 String타입과 int타입에 CustomPropertyEditor가 적용됨)

CustomPropertyEditor cpe = new CustomPropertyEditor();

b.registerCustomEditor(String.class, cpe);

b.registerCustomEditor(int.class, cpe);



*특정 필드의 프로퍼티에만 프로퍼티 에디터 등록방식(Student의 int타입이고 필드명이 age인 프로퍼티에 CustomPropertyEditor 적용)

b.registerCustomEditor(int.class, "age", new CustomPropertyEditor());






@InitBinder메서드는 사용자의 요청 파라미터를 컨트롤러 메서드에 던져주기 전에 호출 된다. 그리고 @InitBinder메서드에서는 PropertyEditorSupport클래스를 상속받는 클래스의 인스턴스를 생성해서 파라미터의 적절한 변환을 위해 에디터를 등록해야 한다.

여기에서 PropertyEditorSupport클래스를 상속받는 클래스의 인스턴스를 생성해야 하기 때문에 new를 이용하여 매번 인스턴스를 생성함을 알 수 있을 것이다.


이렇게 생각해서 코딩하는 사람들도 있을 것이다.

"new를 이용해 객체를 매번 새로 생성하는 대신에 해당 프로퍼티 에디터를 스프링 컨텍스트에 싱글톤빈으로 등록해 놓고 사용하면 안될까?"



결론적으로는 안된다.

Comments
최근에 올라온 글
최근에 달린 댓글
TAG
more
Total
Today
Yesterday