[스프링 3.0 @MVC] 컨트롤러에 스프링 AOP가 적용되지 않는다는건 이제 거짓말

@MVC를 사용하면 좋은 점 중 하나가 스프링 AOP 적용이 쉽다는 겁니다. 아직도 여러 이유로 이전의 Controller 계층 구조를 이용해서 개발하시는 분들이 많겠지만 @MVC를 사용하시는 분들은 이점을 꼭 알고 계셔야 합니다. 스프링 @MVC도 이제 스프링 AOP가 아주 잘 먹힙니다.

@Controller
public class TestController {

    @RequestMapping(“/test”)
    @Transactional
    public void test() {
        System.out.println(“hi!!!!!!!!!!!!!!!!!!!!!!”);
    }

}

하지만 그렇다고 해서 이런 코드를 작성해 달라는 것은 아닙니다. 절대로.. 네버..

어찌됐든 위와 같은 코드도 동작하게 되어있는데 경우에 따라서는 안 될 수도 있습니다. 그런 경우는 스프링 트랜잭션이나 스프링 시큐리티 애노테이션에 문제가 있는것이 아니라 빈설정과 관련이 있을 수가 있으니 빈 설정을 잘 보셔야 합니다.

만약 위와 같은 경우라면.. @Controller 빈이 만들어지는 ApplicationContext와 tx:annotation 머시기가 등록되는 ApplicationContext가 같은지 확인해봐야 합니다.

정말,, 굳이.. 컨트롤러에 AOP를 적용해야 한다면 http://toby.epril.com/?p=934 이 글따라서 DS가 만드는 WebAC 하나로 모두 통합하는 것도 좋겠습니다.

하이버네이트, 스프링 MVC에서 enum 사용하기 3

1. Character 값을 DB에 저장하는 enum도 지원하도록 구현했고..
2. UserType 생성을 좀 더 간편화 했습니다.

public enum FamillyCate implements PersistentEnum {

    FATHER(‘f’, “부”), MOTHER(‘m’, “모”), BROTHER(‘b’, “형제”), SISTER(‘s’, “자매”);
   
    private final Character value;
    private final String descr;
   
    private FamillyCate(Character value, String descr) {
        this.value = value;
        this.descr = descr;
    }
   
    public Character getValue() {
        return value;
    }
    public String getDescr() {
        return descr;
    }

}

이렇게.. Character 값을 DB에 저장할 enum을 사용할 수 있습니다. 이 enum에 대한 UserType 생성은 다음과 같습니다.

public class FamillyCateType extends GenericEnumUserType<FamillyCate>{
}

이 enum에 대한 PropertyEditor는?

binder.registerCustomEditor(FamillyCate.class, new GenericEnumPropertyEditor<FamillyCate>(FamillyCate.class));

캬,.. enum에 대한 UserType과 PE를 전부 코드 한 줄로.. 끝낼 수 있습니다. GenericEnumUserType와 GenericEnumPropertyEditor 코드는 비공개입니다. 영원히~

자 그럼 오늘은 이만 하고,, 다음 번엔 enum 목록을 가져올 때 순서를 정해서 가져오는 방법을 마련해보도록 하겠습니다.

ps: 오랜만에 dm 서버나 돌려봐야겠네요. 방명록에 누가 요청하셔서;;

PropertyEditor 활용 예제

어제 올린 글에 이어지는 내용으로 스프링이 제공하는 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라는 속성에다가 잘 설정해 줄 겁니다.

스프링 MVC form 태그 써 보셨어요?

귿이에요.

<form:checkboxes items=”${allAuthorities}” path=”authorities” delimiter=”<br/>” itemLabel=”name”  itemValue=”id” />

단 한 줄로..


저렇게 출력해줍니다. 괜찮죠? EL로 넘겨준 allAuthorities 이 녀석은 List 타입으로 도메인 객체 타입의 객체들을 담고 있죠. 흠… 화면에 보이는 값이 어째 좀 ‘사용자 비친화적(and 개발자 친화적)’입니다. name 말고 note를 출력하도록 할까요? 아~~주 간단합니다.

<form:checkboxes items=”${allAuthorities}” path=”authorities” delimiter=”<br/>” itemLabel=”note”  itemValue=”id” />

JSP에서 단어 하나만 바꿔주면 되죠.


짜잔… OSAF의 커스텀 태그는 스프링 form 태그를 기반으로 만들었으며, 정형적인 화면 개발 속도를 극대화 할 수 있도록 만들어 두었습니다.

다음에는 PropertyEditor 활용법을 살펴보겠습니다.