어제 올린 글에 이어지는 내용으로 스프링이 제공하는 form 태그와 PropertyEditor를 조합하는 방법입니다. PropertyEditor로 할 수 있는 일 중 하나를 스프링 form 태그가 해줍니다. 그게 뭐냐면.. getAsText죠.

<form:checkboxes items="${allRoles}" path="roles" delimiter="<br/>" itemLabel="note"  itemValue="id" /><br/>

여기서 보시면, itemValue에 설정한 id 값을 보고 자바빈 스펙에 따라 getId를 호출하여 해당 값을 각각의 체크박스 아이템의 value로 사용합니다. 편하죠, 대신 다른 반쪽이 없기 때문에 바인딩에러가 발생할 겁니다.

form 태그를 사용하여 값을 바인딩할 속성 roles는 Set<Role> 타입이거든요. id가 실제로는 int 값이지만, 화면에서는 String 값 형태로 전달되겠죠. 그 String 값을 Role 타입으로 캐스팅하려니까 에러가 발생하는 겁니다. 이 에러는 <form:errors path="roles" /> 이런 코드를 화면에 붙여두면 확인할 수 있습니다.

자.. 그럼 어떻게 해야되나요? HttpServletRequest 타입 객체를 메소드 매개변수로 추가해주고 거기서 roles라는 파라미터의 값 빼와서 파싱하고 어쩌구 저쩌구.. @.@ 그렇게 하실건가요? 스프링 2.5 이전 이라면 뭐.. 그럴수도 있겠다 싶지만, 서블릿 API에 의존하지 않은 아주 깔끔한 스프링 2.5 애노테이션 기반 컨트롤러에 저 것 때문에 서블릿 API를 사용할 건가요?? 아니죠. 그러고 싶지 않습니다.

네 그러지 않아도 됩니다. setAsText를 구현한 PropertyEditor를 등록해주면 깔끔하게 해결할 수 있습니다.

public class RolePropertyEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if(!text.isEmpty())
            setValue(new Role(Integer.parseInt(text)));
    }

}

하이버를 사용하고 있으니 불 필요한 쿼리를 날리지 않도록 Fake Association Object를 활용하여 PropertyEditor를 구현합니다. 꼭 실제 객체가 필요하다면 DAO를 이용해서 가져올 수도 있겠죠. OSAF에는 두 종류의 GenericPropertyEditor로 그 두 가지 경우를 모두 지원합니다.

자 그리고 이 프로퍼티에디터를 바인더에 등록해주면 끝납니다.,

   @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Role.class, new RolePropertyEditor());
    }

끝~.. 이제 스프링이 Role이라는 도메인 객체를 알아보고 잘 파싱해서 Member의 Set<Role> 타입의 roles라는 속성에다가 잘 설정해 줄 겁니다.