Whiteship's Note


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

분류없음 : 2009.07.03 18:53


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 서버나 돌려봐야겠네요. 방명록에 누가 요청하셔서;;
top

Write a comment.


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

모하니?/Coding : 2009.07.02 18:19


하이버네이트와 스프링 풀셋으로 구성되어 있는 웹 애플리케이션에서 자바 enum을 사용할 때 생기는 이슈가 뭘까?

1. DB에 어떤 값을 넣을 것이고,
2. 화면에는 어떤 값을 보여주고 어떻게 바인딩 할 것인가?

이 두 가지라고 한다. 그 밖에 이슈 될만한 것은.. 흠.. 뭐.. 없지 않을까 싶다. 왜 이슈일까?

1번 문제를 보자. DB에 잘 안 들어갈까? 하이버네이트로 맵핑을 해보자.

enum UserType {
 MEMBER, MANAGER
}

@Entity
class Member {
...
  @Column
  UserType userType;
}

이 상태로도 SessionFactory를 생성하는데 별 문제도 없을 뿐더러, 읽고 저장하기가 잘 된다. 문제는 DB에 들어가는 값이다. DB에 들어가는 값을 보면, UserType.MEMBER는 0, UserType.MANAGER는 1이 integer 컬럼에 저장된다. enum의 ordinal() 메서드가 반환해주는 값을 그대로 저장한 것이다. 문제는 ordinal() 값이 고정이 아니라, enum 순서에 따라 바뀐다는 것이다. 이런... 그럼 안 되겠다. ordinal 말고, String을 저장하고 싶다면, JPA의 @Enumerated 애노테이션을 추가해주면 된다. @Enumerated(EnumType.STRING) 이렇게 말이다. 이 것을 사용하면 방금 말한 ordinal 문제는 사라질 것이다. DB에는 ordinal이 반환하는 Integer대신 enum의 name이 저장될 것이다.

그런데.. 어떤 이유에선가 굳이 integer 값을 DB에 저장하고 싶다면 어찌해야 될까? 이제부터 복잡해진다. 일단 enum에 필드를 하나 추가하고, EJ2가 추천하는 방법으로 enum을 구현한다. 다음에는 하이버네이트의 UserType 인터페이스를 구현한 클래스를 하나 만들고,

    @Type(type="koma.domain.usertype.CodeCateUserType")
    @Column
    CodeCate codeCate;

이런식으로 하이버네이트의 @Type 애노테이션을 이용하여 맵핑 방법(db에 어떻게 저장하고, db에서 어떻게 꺼내 올 것인가)을 담고 있는 UserType 구현체를 지정해주어야 한다. 이 구현체를 만들 때는 UserType 인터페이스가 제공하는 메서드 10개 정도를 구현해야 된다. 귀찮은 일이다. 그래서 GenericEnumUserType 이라는 클래스를 만들었다. 간단하게 상속만 하고, 생성자만 만들면 되도록 귀찮을 일을 줄여놨다. 자 그럼 일단 첫 번째 문제는 해결이다.

두 번째 문제는 첫 번째에 비하면 비교적 쉽다. 지난 프로젝트에서 PropertyEditor와 씨름을 했던탓에 면역이 생긴 것 같다. 화면에 Enum을 보여줄 떄 enum의 name을 보여주고 싶진 않을것이다. 역시 새로운 필드를 추가해야겠다. 그리고 화면에 보여줄 때는 그 값을 출력하고, 화면에서 어떤 것을 선택했을 때에는 아까 DB에 입력한 값을 선택해서 가져오도록 화면 코드를 작성했다.

다음은 그렇게 해서 가져온 integer 값을 Enum 객체로 샥 바꿔주는 일을 할 PropertyEditor를 만드는 것이다. 간단하다. getAsText()에서는 getValue()로 가져온 객체를 내가 사용하는 enum으로 타입을 변환 한 다음 아까 추가한 필드의 getter를 사용하여 String 값을 넘겨주었다. 이제 화면에서 사용자 친화적인 문구를 볼 수 있을 것이다. 다음은 setAsTest(String text)를 재정의 하여 text는 화면에서 선택한 enum이 DB에 입력하는 값인 integer 값일 것이다, 일단 Integer.parseInt()를 해야 겠다. 아.. 이런.. Enum 클래스에서 valueOf(Class, String) 메서드를 제공해준다. 하지만 난 int 값을 사용하기로 마음 먹었으니 저 클래스는 사용하지 못하겠다. 유틸을 하나 만들었다. Enum 클래스와 int 값을 받아서 해당 int 값을 가지고 있는 Enum을 돌려받는.. 그런 클래스다. 자 그럼 이제 이 유틸을 이용해서 setAsText(String text) 구현도 마칠 수 있다. 이러한 PropertyEditor 역시 매번 만들어 쓰기 귀찮으니깐, 아예 클래스를 만들지 않고 객체만 만들어 사용할 수 있는 GenericEnumPropertyEditor를 만들었다. 두 번째 문제도 해결됐다.

오늘 내가 할 일은 이게 끝인 듯 하다. 자 그럼 잠깐 회고를 해보자.

DB에 int 값이 아닌 enum의 name 문자열을 저장한다면 어떻게 될까?

일단, UserType을 만들 필요가 없어진다. 아까도 이야기 했듯이 @Column과 @Enumerated(EnumType.STRING)를 사용하면 UserType 없이고, 문자열로 enum을 DB에 저장할 수 있다. GenericEnumUserType도 필요가 없고, 매번 UserType 클래스를 만들어야 하는 수고도 줄어든다.

다음, 화면에서 enum 목록(Arrays.asList(enum.values());를 사용하면 간단)을 보여줄 때, enum에 추가한 사용자 친화적인 설명을 담고 있는 descr 속성에 담겨있는 값을 보여주고, 실제로 선택하는 값이 DB에 저장하는 int값이 아닌 enum의 name이라면 어떻게 바뀔까? getAsText() 구현은 동일하고, setAsText()에서 받아오는 값이 Enum의 name이니깐, Enum.valueOf(Class, String)을 사용할 수 있다. 굳이 Util 클래스를 만들 필요도 없고, setAsText() 구현도 간단해진다. 다만, Enum 마다 PropertyEditor 객체를 지정해 줘야 하는 건 어쩔 수 없다. 하지만 이건 정말 일도 아니다. 새로운 클래스를 추가하는 것도 아닌데 이 일이 뭐 크게 대수겠는가.

결국.. DB에 어떤 이유로 인해 enum의 interger 값을 저장하는 것이 enum의 name 문자열을 저장하는 것보다 훨씬 복잡하고, 귀찮은 것 같다.

DB에 int를 저장하는게 좋을까 string을 저장하는게 좋을까? integer 값을 저장해야 하는 별다른 이유가 없다면 나는 enum의 name을 저장하고 싶다.

수정은 내일.. 오늘은 이만 퇴근..

===========================

할려고 했으나.. 이게 끝이 아니란다. DB에 저장할 enum 필드를 선택할 수 있게 해야 되고(결국 위에서 실컷 고민한게.. 물거품처럼 하얘지는 느낌이다.),

enum 목록을 가져올 때 정렬을 할 수 있어야 한단다.(그럼 이것도 Arrays.asList(enum.values()); 만으로는 어림 없을 듯 하다.)

또한 i18n까지도..

@_@
top

  1. Favicon of http://toby.epril.com BlogIcon 2009.07.02 18:25 PERM. MOD/DEL REPLY

    벌써 가

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.02 18:40 신고 PERM MOD/DEL

    이제 가려구요.

  2. Favicon of http://sonegy.egloos.com BlogIcon 소내기 2009.07.03 11:01 PERM. MOD/DEL REPLY

    하이버네이트말고, iBatis도 enum은 항상 문제더라고, 그냥 이름으로 저장하면 편하지만 기존 필드가 막 int, varchar2(1) 아흑

    Favicon of http://whiteship.me BlogIcon 기선 2009.07.03 13:39 PERM MOD/DEL

    아 DB 스키마가 정해져 있어서 거기에 맞춰서 값을 넣어야 하는 경우가 있는거군요.

    그렇다면 역시;; DB에 저장할 필드를 지정해야겠네요. 필드의 타입에 따라 int/Integer는 SQL 타입 integer로 하고, String이면 VarChar, char/Charater면 char로...

    흠..

Write a comment.


PropertyEditor 활용 예제

Spring/Chapter 5 : 2008.11.27 15:46


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


'Spring > Chapter 5' 카테고리의 다른 글

PropertyEditor 활용 예제  (8) 2008.11.27
5. Validation, Data-binding, the BeanWrapper, and PropertyEditors  (0) 2007.03.21
top

  1. Favicon of http://kingori.egloos.com BlogIcon kingori 2008.11.27 16:52 PERM. MOD/DEL REPLY

    date 값 받아와서 처리하기 와 같은 단순한 propery 의 경우 헷갈리지 않는데, collection 형태의 경우 항상 헷갈리더라고요. 제시하신 예제와 같이 list 상의 하나의 item 에 대한 propertyEditor 인지, collection 에 대한 CustomCollectionEditor 의 형태인지. reference 의 property editor 부분을 읽어봐도 뭔가 개운치가 않고요.
    위의 예제의 경우에도 여러개의 role 이므로 받는 측의 role 속성도 collection 형태일텐데, 전에 작업할 때는 저런 형태가 잘 안먹히더군요. 제가 짠 코드를 다시 보니 하다하다 안되서 걍 req.getParameterValues 를 썼었네요. collection 을 다룰때 언제 CustomCollectionEditor 를 쓰고, 언제 그냥 collection 내의 하나의 항목에 대한 PropertyEditor 를 등록해야하는지 애매~하더군요.
    @조금 검색해보니 나오는 이 내용도 흥미롭네요. (쓰레드 마지막 부분)
    http://forum.springframework.org/showthread.php?t=40960

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.11.27 17:53 신고 PERM MOD/DEL

    컬렉션은(List, Set, Map까지) 스프링이 알아서 처리해줍니다. 대신 그 안에 들어있는 요소들의 타입들이 기본 타입이 아닐 경우에는 그런 처리를 하다가(첫번째 요소 처리 하다가) 캐스팅 에러가 발생합니다.

    즉 CollectionEditor가 필요한지는 모르겠구요. 위와 같이 컬렉션에 들어가는 엘리먼트에 대한 PropertyEditor만 만드시면 됩니다.

    링크 부분의 마지막 부분이 흥미롭다고 하셔서 그 부분만 봤더니, 마지막 분과 그 전 분 모두 위와 다중 선택이 필요하니 해결할 방법 있으면 알려달라는 거네요.ㅋㅋㅋ

    내용을 대충 보니까 위처럼 단순하게 속성의 값이 아니라 좀 더 조합해서 값을 보여줄 필요가 있나본데요 그럴 땐 PropertyEditor의 getAsText를 재정의해서 화면에 보여줄 형태를 만들어서 반환해주면 되는데요. 뭐가 문젠지 모르겠네요. @.@

  2. Favicon of http://kingori.egloos.com BlogIcon kingori 2008.11.27 19:23 PERM. MOD/DEL REPLY

    그런데 복잡한 editing 의 경우는 어렵더라고요. 링크의 department 내용이 그런 예 인데요, 복수개 dept. 의 이름,체크여부,그룹까지 모두 수정할 경우 PropertyEditor 를 어떤 식으로 접근해야 할 지 감이 잡히질 않더군요. (요런것도 되나요? 흠.. 전에 어떻게 한 것 같긴 한데 당췌 내부에서 어떻게 돌아가는지 감이 잡히질 않아서...) 그냥 화면단에서는 jstl, controller 단에서는 req.getParameterValues 로 후다닥 해치워버렸습니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.11.27 21:13 신고 PERM MOD/DEL

    링크의 내용과 왕오리님께서 하시는 이야기가 대응이 안되는 것 같아서 잘 이해가 안 되는데요;;

    링크 내용은 Member 수정/추가 화면에서 Department를 선택할 때 Department 목록에서 하나의 Dep을 선택해서 Mem에 설정해 줄 때 PropertyEditor를 어떻게 사용할지 얘기같은데.. 아마 왕오리님께서 말씀하시는 내용이.. 아래 댓글 같습니다.

    In the JSP, I loop through each department name using JSTL and want to display data in the HTML table model shown above. When the user selects multiple check-boxes I want the list departments to be filled with the selected data and made available in the employee object request. i.e. I want a department object to be filled with the name, group(from the drop-down) for every check-box selection and add it to the employee object's department list.

    이 내용을 보면 Dep 선택 리스트 박스에 group이랑 name이름 조합으로 dep 객체를 채우고 싶다는 거 아닌가요? 그럼 PropertyEditor(PE)의 getAsText에서 그 이름 조합해서 반환하도록 하던가 아님 toString()에 그렇게 구현해놓고 PE의 getAsText에서는 그것만 호출해주면 끝입니다.

    킹고리님께서 말씀하시는 "복잡한 editing 의 경우"라는 게 무엇인지 모르겠습니다. 뭘 "수정" 한다는 거죠?;; @.@

  3. Favicon of http://kingori.egloos.com BlogIcon kingori 2008.11.28 16:20 PERM. MOD/DEL REPLY

    제가 이해한 내용은, employee는 dept. 의 name 만을 가지고 있었는데, 수정화면에서 가지고 있는 dept name 목록 중 checkbox 로 선택한 dept에 대해서만 drop down에서 선택된 dept group을 설정하고, 이것을 저장하고자 하는 것 입니다. (저와 같이 이해하셨나요?)
    요걸 저는 복잡한 editing 이라고 생각했습니다. employee 가 가진 dept 중 check 된 dept. 를 가려내고, check된 dept에 대해선 선택된 group 을 매칭시켜주는 작업이지요.

    일단 기선님이 말씀하신 PE.getAsText / PE.setAsText 의 활용에 대해 아직 제가 정확하게 파악하지 못하고 있는 게 문제인 것 같아서 먼저 테스트를 좀 해 봐야 할 것 같네요. 예를 들면
    setValue(new Role(Integer.parseInt(text)));과 같이 단순히 text 를 interger 로 변한하는 것이 아닌, 좀 더 복잡한 parsing 을 해 보는 것이죠. setValue(new Dept( parseName(text), parseGroup(text) )); 형태가 제대로 동작하는지요. 테스트 해 보고 trackback 이나 커멘트를 남기도록 하겠습니다. :)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.11.28 17:15 신고 PERM MOD/DEL

    kingori님께서 뭔가 조금 잘못 이해하신 것 같은데요. 왜 employee가 dep의 name을 가지고 있어야 하죠? emp는 그냥 dep을 물고 있는게 정상적이고 dep에 있는 name으니까 그냥 . 타고 가서 참조하면 되자나요.

    그리고 댓글에 올라온 코드를 봐도..dep을 여러개 물고 있죠.

    public class Employee{
    private String id;
    private String name;
    private List<Department> departments;

    getter/setter stuff....

    }

    depName 같은 필드는 없습니다. 그냥 emp의 dep을 설정해야 하는데 dep의 name과 group 이름을 조합해서 각각의 emp를 드랍-다운 메뉴에 보여주겠다는 거죠.

    그런 경우에 제가 위에 쓴 글이 딱 제격입니다.

    setValue(new Dept( parseName(text), parseGroup(text) ));

    이런 코드 보다는

    setValue(new Dept(text)); 를 사용하고 text에서 name과 group을 파싱하는 작업은 Dept 도메인 객체에 맡기는게 더 좋치 않을까요?

    그리고 위의 코드는 하이버네이트가 아닐 경우 상당히 부적절합니다.

    실제로는

    setValue(deptDao.getDeptBy(text)); 이런식으로 실제 데이터를 가져와서 세팅해야 할 겁니다. 그렇게 해야 실제 Dept 객체를 가져다가 설정할 수 있을테니까요. JDBC를 사용할 경우이거나 하이버네이트를 사용하더라도 설정한 데이터의 id값 이외에 dep에 대한 다른 정보 조작이나 참조가 필요할 땐 위 코드처럼 작성해야 할 것입니다.

  4. Favicon of http://kingori.egloos.com BlogIcon kingori 2008.11.28 17:35 PERM. MOD/DEL REPLY

    자꾸 의견이 꼬이는 것 같은데, 서로 다른 requirement 에 대해서 이야기하는 것 같습니다.
    setValue(new Dept(text));
    이 부분은 실제 구현한다면 기선님 의견이 맞습니다. setValue(deptDao.getDeptBy(text)); 도 그렇고요. 단순 text를 parsing 해서 name과 dept를 알아내야 하지 않는가 정도의 의견으로 이해하시면 될 것 같습니다.
    employee와 deptName 의 관계는 원문에서의 "I'm putting an employee object in request, that has a list of empty departments, except for the dept name." 에서 나온 이야기입니다. 현재 dept에 설정된 것은 name밖에 없기 때문에 deptName 정도로 표현한 것이지, emp. 가 deptName field를 가지고 있다는 의견은 아닙니다. 사실 상세구현은 별로 중요한 것은 아니고, 전 spring framework이 넘나드는 parameter를 propertyEditor를 통해서 어떻게 처리하는 지가 궁금할 따름입니다.

    제가 생각이 좀 정리가 되고, 샘플 작업을 좀 더 해본 후에 이야기하는 것이 좋을 것 같습니다. 아무래도 서로 다른 이야기를 하는 것 같습니다. :)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.11.28 18:07 신고 PERM MOD/DEL

    넹.. 흠~ 제가 링크에 걸린 포럼 글을 자세하게 읽지않고 대강 읽어서 이런 의견 차이가 생긴 것 같네요.

    말씀하신대로 서로 다른 요구사항을 얘기하고 있는 것 같습니다. 링크에서 말하고 있는게 제가 생각한 것처럼 단순한 경우가 아닌것 같습니다. 흠~ 다음에 좀 더 자세히 읽어보고 글을 올리겠습니다.

Write a comment.


찾았다. WebBindingInitializer

Spring/Chapter 13 : 2008.04.22 18:52


이 녀석이 였구나.. 여러 컨트롤러에 PropertyEditor 적용할 때 필요한 녀석이..

레퍼런스를 저 키워드로 뒤지면 다음과 같은 코드가 나옵니다.

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="cacheSeconds" value="0" />
    <property name="webBindingInitializer">
        <bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer" />
    </property>
</bean>

헤헷 이것만 가지고는 뭐.. 어쩌라는 건지 알 수 없죠. 저 클래스를 찾아봐야 합니다. 저 클래스를 찾는 방법은 여러 방법이 있지만, 제가 올려드리죠.

public class ClinicBindingInitializer implements WebBindingInitializer {

    @Autowired
    private Clinic clinic;

    public void initBinder(WebDataBinder binder, WebRequest request) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
        binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinic));
    }

}

우왕~~ 귿이다~~ 이제 컨트롤러 마다 똑같은 프로퍼티 에디터 등록 안해도 되겠당.
top

Write a comment.


PropertyEditorSupport 살펴보기 2

모하니?/Coding : 2008.01.15 23:33


이전 글에 이어서 먼저 setValue(Object) 메소드를 보겠습니다. 이 녀석이 뭐하는 녀석인지... API에 써있지만 별로 와닿지 않습니다.

그래서 그냥 소스코들 봤습니다. 즉 PropertyEditor 인터페이스의 구현체인 PropertyEditorSupport 클래스를 살펴봤습니다.

    public void setValue(Object value) {
    this.value = value;
    firePropertyChange();
    }

위와같이 구현되어 있습니다. value라는 이름으로 객체를 받아와서 '속성 바꿔치기'를 하고 있군요. 저 메소드도 보이지만, 먼 산으로 갈까봐 관 둡니다. 이런.. 소스를 봐도 별 소득이 없네요. 예제 코드를 봐야겠습니다. 스프링의 Petclinic을 뒤져보면 다음과 같은 코드가 나옵니다.

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        for (PetType type : this.clinic.getPetTypes()) {
            if (type.getName().equals(text)) {
                setValue(type);
            }
        }
    }

setAsText에서 setValue()를 호출하고 있군요. 이 때 넘겨주는 객체는 PetType이라는 객체인 걸 보니, 이 프로퍼티 에디터는 PetType을 다루기 위해 작성된 것 같습니다. 잠깐 딴 길로 새서.. setAsText()를 보겠습니다.

    public void setAsText(String text) throws java.lang.IllegalArgumentException {
    if (value instanceof String) {
        setValue(text);
        return;
    }
    throw new java.lang.IllegalArgumentException(text);
    }

이 메소드는 String을 받아온 다음에 객체를 만들어서 setValue() 메소드에 넘겨주고 있습니다.

이제 조금 감이 잡힙니다.
사용자 삽입 이미지
어디에선가 입력된 텍스트를 가지고 객체를 만들어서 setValue() 메소드에 그 객체를 넘겨주는 메소드인가 봅니다. 그리고 setValue()는 아마도 해당 객체를 어딘가에서 값으로 사용하도록 넘겨줄 겁니다.

이제 String getAsText() 하나만 남아있군요. 이 메소드는 setAsText(String)과 반대일 것 같다는 느낌이 팍팍 듭니다. 다음과 같이 구현되어 있습니다.

    public String getAsText() {
    if (value instanceof String) {
        return (String)value;
    }
    return ("" + value);
    }

흠.. value 객체를 이번에는 거꾸로 String 타입으로 변환해서 반환하는 메소드입니다. PetType으로 예를 들자면,

    @Override
    public String getAsText() {
        Object value = getValue();
        if(value instanceof PetType)
            return ((PetType)value).getName();
        else
            throw new RuntimeException();
    }

이런식으로 구현할 수도 있겠습니다. PetType 객체가 오면 이 객체가 가지고 있는 name 속성이 이 객체를 대변하도록 말이죠.
사용자 삽입 이미지

그럼 대체 객체의 어떤 값이 해당 객체를 대신하도록 하는것이 좋을까요? 당연히 유일한 값이 좋겠죠. 흠..

다음에는 이런 PropertyEditor를 사용한 PetClinic 예제를 살펴보겠습니다.
top

Write a comment.


PropertyEditorSupport 살펴보기 1

모하니?/Coding : 2008.01.15 22:49


이 클래스는 JDK 1.5에 추가된 클래스 입니다. 이 클래스를 좀 살펴보겠습니다. 이 클래스는 PropertyEditor 인터페이스를 구현하고 있습니다. 아마도 PropertyEditor를 쌩으로 구현하기는 불편하니까 Custom Editor를 구현하기 편하게 만들어둔 클래스로 유추 됩니다.
사용자 삽입 이미지


PropertyEditor 인터페이스를 보겠습니다.

사용자 삽입 이미지

API 대강 번역

PeopertyEditor 클래스는 GUI에 사용자가 주어진 타입의 속성 값을 편집하고 싶을 때 이를 지원하기 위해 제공된다

PropertyEditor는 속성 값을 보여주거나 수정할 수 있는 다양한 방법을 제공한다. 대부분의 PropertyEditor는 본 API 문서에서 가용한 옵션 중에 일부만 사용해도 충분할 것이다.

간단한 PropertyEditor들은 getAsTest와 setAsText 메소드만 사용할 것이고 복잡한 타입일 경우에는 paintValue와 getCustomEditor를 사용할 것이다.

모든 PropertyEditor는 반드시 다음의 세 가지 방법 중에 한 가지 스타일로 속성을 보여주어야 한다.
1. isPaintable
2. getTags()에서 null이 아닌 String[]을 반환하고 getAsText()에서 null이 아닌 값을 반환한다.
3. getAsText()에서 null이 아닌 값을 반환한다.

모든 Property Editor들은 반드시 setValue메소드에 이 PropertyEditor를 적용할 객체를 넘겨주어야 한다. 또한 반드시 custom editor를 지원하거나 setAsText를 지원해야 한다.

각각의 PropertyEditor들은 기본 생성자를 가지고 있어야 한다.


복잡한것 같지만 대강 요약하면 다음과 같습니다.
1. 기본 생성자가 있어야 한다.
2. setValue(Object) 메소드에 넘겨줄 Object 객체는 해당 PropertyEditor가 처리할 객체여야 한다.
3. getAsText()를 구현하거나 isPaintable()을 구현해야 한다.
4. setAsText()를 구현해야 한다.

그럼 다음에는 저 많은 메소드들 중에서 딱 저 세 개의 메소드만(isPaintable()은 생략) 살펴보겠습니다.
top

Write a comment.


Non-String DataBinding 테스트하기



참조 : Spring MVC

객체가 속성으로 String 타입이 아닌 속성을 가지고 있을 때 데이터 바인딩을 하려면 별도의 조취가 취해져야 합니다. request에 담고 있는 데이터는 모두 문자열이기 때문에 이전 글에서 살펴보았던 간단한 DataBinding일 경우에는 정말 간단하게 바인딩을 할 수 있었습니다. 하지만 이번 경우에는 PropertyEditor의 도움을 받아서 역시 간단하게 문자열을 특정 타입으로 변환하여 바인딩 해줍니다.

다음의 표는 ServletRequestDataBinder가 기본으로 사용하는 PropertyEditor들 입니다.
사용자 삽입 이미지
따라서 위 표의 Result에 있는 타입들은 별도의 PropertyEditor를 바인더에 등록하지 않더라도 알아서 문자열을 해당 타입으로 변환하여 바인딩해줍니다.

간단한 클래스 작성

테스트 클래스 작성


'Spring MVC > 6장 Controller' 카테고리의 다른 글

AbstractController  (0) 2007.06.21
Non-String DataBinding 테스트하기  (0) 2007.06.21
간단한 DataBinding 테스트하기  (0) 2007.06.20
MultiactionController  (0) 2007.06.19
SimpleFormController's onSubmit()  (0) 2007.04.11
SimpleFormController  (0) 2007.02.28
Controller  (0) 2007.02.28
top

Write a comment.


숙제 3

Hibernate/study : 2007.03.01 23:43


Controller
- Spring reference :: Chapter 13
- Spring API :: Controller
- Spring MVC :: p52(71)
- Pro Spring :: p531
- 영회형 전 블로그 :: Spring MVC컨트롤러 탐험기[1] Controller와 ModelAndView

SimpleFormController
- Spring reference
- Spring API :: SimpleFormController
- Spring MVC :: p65(84)
- Pro Spring :: p547

PropertyEditor
- Spring Reference :: Chapter 5
- Java API :: PropertyEditor
- 영회형 블로그 :: Spring 기본 지원 Property type
- 영회형 전 블로그 :: Spring MVC 사용시 다수의 문자열을 List로 받기
- Whiteship 전 블로그 ::  Spring reference 5장 정리
- Spring MVC :: p124(143)
- Pro Spring :: p126

CoC
- Convention over Configuration 의 약어로 "설정을 능가하는 규약" 정도의 의미.
- http://softwareengineering.vazexqi.com/files/pattern.html
- Convention vs Configuration
- CoC in Spring MVC

top

  1. Favicon of http://humbleprogrammer.net/blog BlogIcon 정지웅 2007.03.04 00:35 PERM. MOD/DEL REPLY

    와~ 엄청난 분량이네요^^ 스터디 모임에서 하시는 숙제인지, 아니면 기선님 스스로 내시는 건지요? 공부하시고 숙제하시는 결과 공유해주셔서 많이 배워가고 있습니다^^ CoC에 대한 내용이 제일 궁금해지네요

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.03.04 11:14 신고 PERM MOD/DEL

    아.. 숙제는 물개 선생님께서 내주신 거구요. OpenSeed에서 하는 온라인 스터디를 진행하는데 필요한 사전 지식을 말씀해 주셔서 그부분에 대해 공부를 한 겁니다.

    CoC는 http://whiteship.tistory.com/512 여기에 매우 단순하게 요약해 뒀습니다.

  2. Favicon of http://humbleprogrammer.net/blog BlogIcon 정지웅 2007.03.04 20:22 PERM. MOD/DEL REPLY

    아 그렇군요^^ 좋은 내용 감사드립니다.

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.03.04 22:58 PERM MOD/DEL

    에고 별거 아닌걸요 :);;

Write a comment.