Whiteship's Note

'2009/07'에 해당되는 글 51건

  1. 2009.07.14 진부한 멘트는 가라... 달콤한 스윙이여 오라~
  2. 2009.07.14 스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 4
  3. 2009.07.14 스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 3
  4. 2009.07.14 스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 2 (2)
  5. 2009.07.13 스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 1 (6)
  6. 2009.07.11 스프링 슬라이스(Spring Slice)
  7. 2009.07.08 [jQuery] 날짜 선택하기
  8. 2009.07.08 스프링 WebContentGenerator로 자바스크립트 캐싱하기4 (4)
  9. 2009.07.08 스프링 WebContentGenerator로 자바스크립트 캐싱하기3
  10. 2009.07.08 스프링 WebContentGenerator로 자바스크립트 캐싱하기2 (2)
  11. 2009.07.07 스프링 WebContentGenerator로 자바스크립트 캐싱하기 (2)
  12. 2009.07.07 [파이어폭스 플러그인]Live HTTP headers
  13. 2009.07.07 벌써 한 달이 넘었군요. (12)
  14. 2009.07.06 하이버네이트, 스프링 MVC에서 enum 사용하기 4
  15. 2009.07.05 STS 2.1.0 RC1에서 DM Server에 초간단 웹 애플리케이션 띄우기 (2)
  16. 2009.07.03 database.properties 모음 (2)
  17. 2009.07.03 하이버네이트, 스프링 MVC에서 enum 사용하기 3
  18. 2009.07.03 하이버네이트, 스프링 MVC에서 enum 사용하기 2
  19. 2009.07.02 하이버네이트, 스프링 MVC에서 enum 사용하기 (4)
  20. 2009.07.02 결국 그냥 만들어버린 JPA 문서 자동화 툴 (4)
  21. 2009.07.01 [파폭 테마] 구글 크롬 테마 (6)

진부한 멘트는 가라... 달콤한 스윙이여 오라~



사실 스크린캐스팅의 묘미는 음성 보다는 화면입니다. blip.tv에 동영상을 올리는 이유도 고해상도 1280*1024를 지원하기 때문이죠. 요즘은 유투브도 HQ 버전이 있던데 안써봐서 모르겠습니다. 동영상 편집을 잘 하면 저해상도 동영상 서비스에서도 소스코드가 잘보이게 올릴 수 있겠지만.. 귀찮아서 원..;

아.. 주제는 그게 아니라. 멘트에 관한 것이었습니다. 사실 이해가 필요한 부분은 멘트가 필요하긴 하지만, 그 외에 간단한 것들은 멘트 없이 보는게 오히려 귀에 걸리적 거리지 않고 좋습니다. 처음 스크린 캐스팅을 찍을 때는 선풍기 소리나, 기침 소리 한 번에도 다시 찍기를 수도 없이 했었지만... 요즘은 뭐.. 중간 중간 실수를 해도 그냥 찍고 넘어가 버리는데 익숙해졌습니다.

아. 다시 또 이상한 곳으로 새는데.. 그래서. 멘트를 없애고 음악을 넣어봤습니다. 재밌더군요. 녹화도 음성없이 하니까 부담스럽지 않아서 좋았고, exporting 할 때 걸리는 시간도 줄어들었습니다. 저는 오직 맥북에서만 스크린 캐스팅을 제작하는데, 맥이 이쁘기 때문이죠. 동가면 다홍치마라잖아요. 후훗..

제가 스크린캐스팅을 제작하는 방법을 덤으로 말씀드리자면...

1. Screen Flow로 녹화 및 Export to MOV 고화질


2. VisualHub로 MOV to FLV


3. blip.tv에 업로드


이런 순서 입니다. 중간에 MOV를 FLV로 바꾸지 않고 바로 blip.tv에 올리면 blip.tv에서 자동으로 변환해주기도 하는데, 이 변환 작업이 길어지면 도중에 에러가 납니다. 유료 사용자가 아니여서 서버에서 인코딩을 다시 해주질 않습니다. 그래서 안전하게 아예 플래시 파일로 변환하는 두 번째 과정이 필요합니다.

Screen Flow에서 FLV로 export를 해주면 좋을텐데... 1.5 버전에서도 아직 안되는 듯 하네요..

그렇게 해서 만들어본 동영상 입니다.



top

Write a comment.


스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 4

모하니?/Coding : 2009. 7. 14. 18:35


마무리로 태그 파일화 작업을 했습니다.

             <o:textwithac label="이름" id="name" size="20" maxlength="30"
                 url="/ajax/user/names.do" model="users" width="200" selectFirst="true" />

이런 태그와..

<script type="text/javascript">
function formatItem(row, i, total){
    return row[1] + " " + row[2];
}
function formatResult(row){
    return row[1];
}
function result(event, row, formatted){
    if (row){
        $("#namedetail").text(row[0] + " " + row[2]);
    }
}
</script>

자바스크립트 함수 세 개로 자동완성 기능을 사용할 수 있습니다.

속성 중에서

url="/ajax/user/names.do" model="users" width="200" selectFirst="true"

이 녀석들이 자동완성과 관련된 속성들이며..

formatItem은 자동완성 목록을 어떤 형태로 보여줄지 코드를 작성해주면 되는데, 이 때 row는 현재 데이터 row이고, i는 인덱스, total은 총 갯수 입니다.

formatResult는 자동완성 목록에서 선택했을 때 text input 박스에 최종적으로 입력할 값을 return하도록 합니다.

마지막으로 result는 자동완성 목록을 선택했을 때 후 처리 이벤트 같은 것으로, result 타입의 이벤트와, 선택한 데이터 row, 그리고 formatResult에서 input 필드에 입력되도록 포맷팅한 값입니다. 이 녀석들을 이용해서 적당하게 코딩해주면 되겠습니다. 예제에서는 namedetila이라는 엘리먼트에 부가정보를 기입해주었습니다.



top

Write a comment.


스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 3

모하니?/Coding : 2009. 7. 14. 16:25


조금 더 개선해서, 화면에서 검색 조건을 한 글자 한 글자 입력하면, 해당 글자를 가지고 있는 모든 것들을 검색해 올지.. 아니면, 해당 글자로 시작하는 것들을 가져올지 설정할 수 있는 기능을 서버쪽과 연결 했습니다.

    $("#name").autocomplete("/ajax/user/names.do", {
        minChars: 1,
        width: 200,
        max: 100,
        model: "users",
        delay:10,
        selectFirst: true,
        formatItem: function(row, i, total) {
            return row[1] + " " + row[2];
        },
        formatResult: function(row){
            return row[1];
        }
    });

화면에서는 selectFirst의 값만 바꾸면 되지만, 저 값이 서버에서 검색을 할 때도 영향을 줘야 하기 때문에, 저 값을 서버로 보내도록 jquery autocomplete js를 수정했습니다. jqeury ajax의 getJSON 함수에 서버로 보낼 parameter 목록을 보낼 수 있기 때문에 이건 뭐 아주 간단하게 수정할 수 있었습니다.

그런 다음 컨트롤러에서 이 값을 받아서 Serivce -> Dao 로 쭉쭉쭉 보내면 되는데.. 

public ModelAndView userNames(ModelMap map, String keyword, Boolean selectFirst)

이런 시그너처 만으로도 바인딩이 된다는 건 스프링 MVC 유저라면 당연히 아시리라 생각합니다. 문제는 저게 계속 길어질 우려가 있다는 거죠. 그래서 AjaxParams라는 클래스를 만들고 자바빈 스펙에 맞게 게터, 세터를 추가해준 다음 컨트롤러의 메서드 시그너처를 다음과 같이 바꿨습니다.

public ModelAndView userNames(ModelMap map, AjaxParams ajaxParams)

짜잔... 이렇게 해도 스프링 MVC는 똑똑해서 자동으로 바인딩 해줍니다. 그럼 이제 service랑 dao에는 ajaxParam을 넘겨주고 저기서 값을 꺼내서 검색해오면 되겠습니다.

이정도면.. 이제 대충 쓸만하게는 만든 것 같습니다.
혹시 모르죠. 뭔가 또 빠져서 다시 손을 대야할지도..


top

Write a comment.


스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 2

모하니?/Coding : 2009. 7. 14. 15:32


jQuery 플러그인 중에 autocomplete가 있는데, 이 녀석은 배열을 사용하기 때문에 URL에서 넘어온 JSON 데이터를 제대로 인식하지 못할 뿐더러, JSON을 인식한다쳐도 스프링 JSONView가 만들어주는 JSON에서 모델이름으로 값을 꺼내와야 하는데, 그런 장치가 전혀 없기 때문에... 뜯어 고쳤습니다.

새로운 option을 추가하고, Ajax 요청을 보내는 부분을 고치고, Ajax로 받아온 데이터를 파싱하는 부분을 수정했더니 잘 동작했습니다. 스프링 JsonView에 특화된 jQuery 자동완성 플러긴으로 보면 되겠군요.


목록에 보여줄 형태를 옵션으로 지정해 줄 수 있어서 이름 + " " + 이메일 형태를 보여주도록 설정했습니다. 넓이도 조정할 수 있으니.. 글자가 잘리지 않게 너비를 조정할 수도 있겠네요.

자세한 옵션은 http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

여러가지 사용 예제는 http://jquery.bassistance.de/autocomplete/demo/

모든 옵션을 확인하진 않았지만, 대부분의 옵션(목록 갯수 설정, 검색할 때 필요한 최소 글자 수, 등등등)이 제대로 동작했습니다.

기본으로 화살표 이동도 되고, 캐싱도 지원해주니.. 이 정도면 썩 괜찮으 듯 합니다. 선택이 했을 때는 선택한 데이터 row를 가지고 function을 실행할 수 있게 해주는데, 그걸 이용해서 입력한 값 주변에 기타 정보를 출력하도록 만들 수 있었습니다.

그러나 한글값을 넘겨봤더니 깨지더군요. 그래서 encodeURIComponent()로 값을 감싸서 UTF-8로 보냈습니다. 그런 다음 컨트롤러에서 받아서 디코딩을 했죠.

keyword = URLDecoder.decode(keyword,"UTF-8");

디코딩 하는 방법은 성윤이가 도와줬습니다. 흠.. 사부님 말씀으로는 이렇게 UTF-8로 인코딩/디코딩 하지 않고도 처리할 수 있는 방법이 있는 것 같은데.. 일단 거기까진 신경쓰지 않기로 했습니다. 지금도 충분히 어지러우니까요. @_@

라이선스가 GPL하고 mit 라이선스던데 소스를 공개해야 라이선스를 위반하지 않는거 아닌지 모르겠네요. 대충 고친건데.. 흠..

이젠 테스트 데이터를 왕창 넣고 확인해 봐야겠습니다.
top

  1. Favicon of http://starplatina.tistory.com BlogIcon reperion 2009.07.28 16:13 PERM. MOD/DEL REPLY

    jquery가 기본적으로 파라미터를 보낼 때 encodeURIComponent()로 싸서 보내게 되어 있습니다.
    jquery.js 파일 param: 으로 검색 해 보시면 확인하실 수 있는데요.

    저같은 경우는 web.xml에 인코딩 필더를 euc-kr에서 utf-8로 바꿔 주니깐 잘 동작 하더라구요.
    만약 euc-kr로 인코딩 필터를 계속 쓸려면
    자바스크립트에선 utf-8로 보내 주고 필터에서 euc-kr로 변경 하니깐 euc-kr로 디코딩한 다음에
    다시 utf-8로 디코딩 하면 될려나..요? 에고 -,.-

    여튼 다른거 없어 인코딩 필터만 utf-8로 하니깐 잘 됬습니다.
    FF에서는 인코딩 필터 변경없이 잘 되지만 IE8에서는 필터 변경해야 되네요.
    IE 참 -,.-

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

    엇.. 그렇군요.

    어차피 태그파일로 만들어 둬서 한 군대만 수정하면 되는데.. 한 번 encodeURIComponent() 이거 빼고 보내봐야겠네요.

    감사합니다~

Write a comment.


스프링 JSON view와 jQuery 이용하여 자동완성 기능 만들기 1

모하니?/Coding : 2009. 7. 13. 23:29


간만에 11시에 집에 왔습니다. 음... 오랜만이네요.

오늘은 jQuery Ajax로 자동완성 기능을 만들다가 왔습니다. 스프링 JSONView를 이용해서 스프링이 보내준 JSON을 가지고 자동완성을 만드는 겁니다.

1. MappingJacksonJsonView 라는 클래스가 있는데, 좀 전까지만 해도 BindingJacksonJsonVIew였습니다. 아직은 배포된 버전에 이 클래스가 없고, 개발중인 프로젝트에 fisheye에 접속해서 보면 소스를 볼 수 있습니다. 또는 톱님이 배포하시는 최신 스프링을 사용하시면 이용할 수 있을 겁니다.

2. 일단 필요한 라이브러리를 구합니다. 최신 스프링 or 저 파일만 구하면 됩니다. 또 Jackson 관련 라이브러리를 추가합니다.

3. 컨트롤러를 만들고, ModelAndView를 반환합니다. ModelMap에는 컬렉션을 주던, 필요한 모델 객체를 주던 주면 되고, viewname에는 MappingJacksonJsonView의 빈 이름을 설정해 줍니다.

4. xxx-servlet.xml에서 MJJV 빈을 등록하고, 빈 이름은 jsonView라고 했습니다. 3번 컨트롤러에서도 jsonView란 이름을 사용했죠. 그리고 뷰리졸버를 하나 추가했습니다. BeanName머시기 뷰리졸버가 있죠. 그걸 추가했습니다.

5. jQuery.getJson(url, param, function)를 이용해서 저 컨트롤러에 요청을 보내고, 컨트롤러가 돌려주는 값을 확인해 봤습니다.

usernames:List<String> => {"userNames":["aaa", "vvv", "dddd"]}
users:List<User> => {"users":[["1", "기선", "whiteship@email.com"],["2", "toby", "toby@email.com"]]}
user:User => {"user":[name:"기선", "id":1, "email":email]}
user1:User, user2:User=> {"user1":[name:"기선", "id":1, "email":email],"user2":[name:"기선", "id":1, "email":email]}

이런 형태의 결과가 나왔습니다.(기억으로 적은거라 틀릴 수도 있습니다.) 주로 사용하게 될 첫 번째 형태를 보니, 맵(문자열-배열) 형태의 JSON으로 보입니다. 필드명이 없어서 인덱스로 접근해야 한다는게 불편해 보입니다. 세번째 결과를 보면 객체 하나를 줬을 때는 필드명까지 읽어서 넣어주는데 말이죠. 컬렉션도 그렇게 해주면 좋을텐데.. 좀 아쉽습니다.

6. 다음은 jQuery Ajax로 JSON 데이터를 받아왔으니, 이제 자동완성 기능만 구현하면 됩니다.

6-1. 텍스트 박스에 어떤 값을 입력하면, 서버로 요청을 보내고 그 결과를 리스트로 뿌리고, 그 중에 하나를 선택하면 텍스트 박스에 채워주고, 텍스트 박스 옆에 기타 자세한 정보를 뿌려줍니다.

6-2. 텍스트 박스에 값을 입력해서 검색 리스트가 나왔을 때, 키보드의 화살표로 상하 이동이 가능해야 합니다.

6-3. 캐시 설정을 통해 같은 검색어의 경우 매번 요청을 보내는 것이 아니라, 특정 시간동안은 캐시에서 데이터를 읽어서 보여줍니다. 캐시 유효 시간을 설정할 수 있어야겠네요.

대략 이정도 기능인데, 여기서 좀 시간이 많이 걸리고 있네요. 내일은 꼭 마무리 해야겠습니다.
비도 오는데 허리가 쑤실만큼 앉아있었지만 결과는 좀 허무하네요.
에잇... 내일은 파이팅.
top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.14 01:20 신고 PERM. MOD/DEL REPLY

    오홋;;; 야근을 ?
    자동완성의 꽃은 검색하는 자료에 대한 인덱싱을 얼마나 잘 해놓느냐 인데..;;
    뭐~ 많은 내용의 정보가 아니라면 상관없지만요 ;;ㅋㅋ
    잘못하면 트래픽이 ㄷㄷㄷㄷㄷ ㅋㅋ

    마니 바쁜데~ 스터디 장소도 좀 ^^ 알아봐주시면 탱삼해요 ~~
    파이팅 하3333333 ㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.14 16:05 신고 PERM MOD/DEL

    자동완성 어렵더라 어려워..
    스터디 장소 마련했어. 공지할께.

  2. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.07.14 01:26 PERM. MOD/DEL REPLY

    아... 스프링에 JSONView도 있었군요. JSON을 안 써서 몰랐습니다...^^;
    얼마전에 로드 존슨이 트위터에 마이클잭슨 언급한걸로 봐서 혹시
    MappingJackson 이란 이름은 '마이클잭슨'의 느낌을 살리기 위한
    로드 존슨의 지시가 아니었을까 하는 생각이... @_@;;;

    기존에 만든 어플은 잘 알려진 자바스크립트 라이브러리나 프레임워크 없이
    같이 일하는 친구가 직접 만든 자바스크립트 라이브러리를 사용하고
    저는 server-side에서 XML로 자료를 전송해서 JSON 쓸일이 없었는데,
    (XML 없는 Ajax는 Ajax가 아니다 라는 신념으로... :D )
    jQuery 쓰면서 JSON 지원하길래 한번 써봐야겠다 생각하다가
    마침 엊그제 jQuery용 트리를 찾다가 발견한 jsTree가 JSON 지원하는걸 보고
    JSON을 써야겠구나 하고 살펴보고 있었는데,
    마침 기선님께서 이런 좋은 글을...:)
    고맙습니다.

    그나저나 5번같은 문제가 있다면, AbstractView 상속해서 개인적으로
    만든 JSON 라이브러리 같은걸 이용하는 View를 따로 만들어도 좋지 않을까 싶군요.
    Annotation을 써서 원하는데로 변환 할수 있게 만든다거나...
    저의 경우는 비슷한 이유로 XML Serialisation을 하는데,
    JAXB나 XStream 혹은 XOM 같은
    Object-XML Mapping이나 Bindding 기술을 사용하지 않고,
    직접 만든 간단한 XML generator를 사용하고 있습니다.
    JAXP에 DOM API를 쓰다가 성능이 더 잘 나오는 SAX쪽으로 바꿨구요.

    Annotation으로 가능한거 보다 더 많은 제어를 원해서
    Annotation대신 Template Method Pattern을 사용해서
    XML Object을 만들고 Object 별로 설정된대로 Serialisation을 하는거죠.
    별도로 원하는 XML형태에 따라 class 작성이 필요해서,
    XStream 같은 걸로 이미 있는 JavaBean이나 Domain Object을
    그대로 그냥 XML로 변환하는것처럼은 안 되지만,
    XML Object class 작성할때 XML 형태를
    원하는데로 마음대로 할수 있기 때문에 좋죠.
    (e.g. JavaBean에 없던 필드를 attribute에 추가한다거나
    합계 attribute를 XML 생성시 계산해서 추가한다거나 등등)

    암튼 기선님께서 언급하신 JSONView도 한번 써봐야겠네요.
    정보 고맙습니다. :)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.14 16:12 신고 PERM MOD/DEL

    ㅎㅎㅎ맵핑잭슨가 마이클잭슨..캬.. 이전 이름이 빌딩XXX뷰였는데. 맵핑도 사실 그닥.. 그냥 잭슨제이손뷰 또는 라고 해도 될 것 같은데 그 안에서 해주는 일 때문에 빌딩이니 맵핑이니 고민하는 것 같아요.

    JSON이 무척이나 편할 줄 알았는데, JSON도 여러 형태가 있어서 제가 원하는 형태로 JSON을 편집해서 보낼 수 있다면 편하겠지만, 지금 스프링이 지원하는 MJJV가지고는... 좀 불편하더라구요. 그냥 MJJV가 만들어주면 거기에 맞게 jQuery 플러긴 만들고 지지고 볶고.. 그런 생쑈를 했네요. @_@

    네 JSON을 제가 원하는 형태로 만들어 보내고 싶다면, AbstractControlle를 사용하던 @Controller를 사용해서 직접 만들어 보내는 방법도 괜찮을 것 같네요. 하지만 이미 전 스프링 JSON 뷰에 맞춰서 뷰쪽 코드를 개발해버렸네요. 이젠 마무리 해야 할 시간이라 더이상 다른 시도는 ... 나중으로 기약하는 수밖에... ㅋ

    스프링에서 OXM도 지원하니까 그걸 한 번 사용해 보시죠.

    Favicon of http://toby.epril.com BlogIcon 2009.07.14 19:54 PERM MOD/DEL

    JacksonJsonView이라는 이름은 Jackson(http://jackson.codehaus.org/)이라는 Json 라이브러리를 사ㅇ해서 변환했기 때문에 붙은 이름입니다.

    Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.07.14 20:28 PERM MOD/DEL

    아, 전 Jackson이란 이름에 촛점을 둔게 아니라...
    Binding을 굳이 Mapping으로 바꾼이유가
    Michael Jackson처럼 느껴지게
    M쪽 사운드를 만들기 위한거 아닌가? 하는 농담이었는데,
    농담이 재미가 하나도 없어서 그런지 아무도 이해를 못 하신듯 ㅠ_ㅠ
    죄송합니다. 썰렁한 농담을 해서...@_@;;;
    근데 썰렁한 농담덕에 Jackson이란 라이브러리를 알게 됐네요. :)
    고맙습니다. Toby님

    아, 그리고 스프링에서 지원하는 OXM도 살펴봤는데,
    제가 원하는게 없더군요. 제가 좀 까다로워요... :)
    단순히 annotation만 가지고 가능했어도
    그냥 XStream 같은걸 썼을텐데...

Write a comment.


스프링 슬라이스(Spring Slice)

Spring DM/etc : 2009. 7. 11. 11:36


참조
http://blog.springsource.com/2009/07/10/pluggable-styling-with-springsource-slices/
http://blog.springsource.com/2009/06/22/modular-web-applications-with-springsource-slices/

음.. 웹 애플리케이션을 OSGi 번들로 구성할 때, web 번들 하나랑 기타 서비스 번들 여러 개로 쪼개야 하는구나.. 라고 만 생각하고 있었는데, 그렇지 않았네요.

스프링 슬라이스를 이용해서 하나의 웹 애플리케이션에서 여러 개의 웹 번들을 구성할 수 있도록 해주는 프레임워크라고 보면 될 것 같습니다. 웹 번들이 여러 개라고 해서 ServletContext가 여러 개 생기는 건 아니고, parent/child 구조로 여러 슬라이스가 호스트의 ServletContext를 이용해서 쓰게 해주는가 봅니다. 설정은 호스트 쪽 web.xml 에 스프링 슬라이스 필터를 추가하면 되고, 슬라이스 쪽에서는 Manifest.mf에 Slice-Host와 Slice-ContextPath를 설정하면 되는 정도로 간단한 편인듯 하네요.

요즘은 이것 저것 볼 여력이 없기 때문에.. 이정도만 살펴보고 패스~
top

Write a comment.


[jQuery] 날짜 선택하기

View/JavaScript : 2009. 7. 8. 20:33


jQuery UI 위젯이 제공하는 기본 달력은 다음과 같습니다.


흠.. 이것까진 간단했습니다. 이 것을 이용한 태그 파일 두개를 만들었습니다. 하나는 검색 필드용 하나는 폼 필드용. 검색 필드는 get 방식으로 url뒤에 줄줄이 붙여서 가져올 것이고 폼 필드는 post 방식에서 사용하여 model의 특정 속성에 바로 바인딩 할 겁니다. 둘 다.. 자바스크립트 코드 부분은 다음과 같습니다.

    $(function() {
        $("#${id}").datepicker({
            dateFormat: 'yy/mm/dd',
            changeMonth: true,
            changeYear: true,
            yearRange: '${fromNS}:${toNS}'
         });
    });

적당한 포맷을 설정하고, 연도와 달을 좀 더 변경하기 쉽게 드랍다운으로 설정했고, 연도 범위를 설정했는데, 이 값은 태그에 전달해준 값을 쓰기로 했습니다. 값을 전달해 주지 않으면 기본값을 쓰도록 했지요.

복잡한건, 날짜 범위를 선택하는 것인데, 이건 Ajaxian에서 10가지 date picker중 하나로 선정된 filament group의 daterangepricker를 이용했습니다.


    $(function() {
        $("#${id}").daterangepicker({
            dateFormat: 'yy/mm/dd',
            datepickerOptions: {
                changeMonth: true,
                changeYear: true,
                yearRange: '${fromNS}:${toNS}'
            }
        });
    });

대충 이렇게 보여집니다. 옵션이 다양해서 이 녀석을 써봤습니다. 문제는 하나의 필드에 두 개 날짜 값을 넣어주고 있어서 DateRange라는 클래스를 만들고, DateRangePropertyEditor도 만들어줬습니다. DateRange 클래스는 테스트를 통해서 문자열 값을 생성자에 넣어줬을 때 제대로 동작하는지 확인을 해보았고, DRPE를 등록해서 돌아가는지 웹에서 확인도 해봤습니다.

이 녀석은 검색용 태그파일만 만들었는데.. 만들고 보니 날짜를 한 개만 받는 녀석이랑 용도가 겹치더군요. Today랑 Specific Date는 메뉴에서 빼고 싶어서 옵션들을 살펴봤는데 영~~ 시원찮네요. 흠.. 뺄 수 있을텐데 말이죠.


top

Write a comment.


스프링 WebContentGenerator로 자바스크립트 캐싱하기4

모하니?/Coding : 2009. 7. 8. 14:42


이번엔 정말 마지막이라는 느낌입니다.

스프링 ResourceEditor라는 PropertyEditor가 있었군요. ResourceEditor는 ResoruceLoader를 사용해서 Resource 인스턴스를 만드는데, 이 때 resourcePath의 prefix에 맞게 적절한 Resource 인스턴스를 만들어 줍니다. ResourceLoader가 읽어들이는 기본 prefix는 레퍼런스에 잘 설명이 되어 있으니 참고해 보시기 바랍니다. file:, classpath:, http: 입니다.

재미있는건, prefix가 붙어있지 않을 때 인데, 이 때는 applicationContext 객체의 타입을 보고서 기본 Resource 타입을 결정짓습니다. ClassPathApplicationContext인 경우에는 ClassPathResource로 보는거죠. WebApplicationContext인 경우에는 ServletContextResource로 봅니다. 따라서...

이전에 만든 컨트롤러에 전부 Stirng 타입 목록을 받고 type 또한 String으로 받아서 Resource를 판단하는 작업까지 했었다면, 이제 그 작업들은 전부 스프링이 기본으로 제공하는 ResourceEditor로 넘기고 List<Resource>를 받으면 끝납니다. 그렇다고 해서 xml에 별도로 등록해줘야 할 빈이 있는 것도 아니고, 이로인해 좀 더 유연한 설정이 가능해졌고, 설정이 짧아졌으며, 컨트롤러 코드도 줄어들었습니다.

    <bean name="/js.do" class="koma.base.main.JavaScriptController" p:cacheSeconds="300">
        <property name="jsResources">
            <list>
                <value>js/koma.js</value>
                <value>file:c:/springsource/workspace/koma/webapp/js/jquery-1.3.2.min.js</value>
                <value>js/jquery-ui-1.7.2.min.js</value>
            </list>
        </property>
    </bean>

테스트 삼아 이렇게 등록해 보았는데 잘 동작합니다. 이젠 정말 끝인 것 같다는 느낌이네요. 후훗

top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.08 17:24 신고 PERM. MOD/DEL REPLY

    어려운 내용이라 태클은 pass ㅋㅋ
    수고했어요 ~~ㅋㅋㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.08 20:35 신고 PERM MOD/DEL

    스프링 Resource를 발표하고 싶다는거구나.
    잘해봐 파이팅!

    Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.08 22:27 신고 PERM MOD/DEL

    그러게요 ;;; 하음.. 발표 한번 해야 하는데;; 게을러 져버렸네요ㅠ ㄷㄷㄷ;; 계획~ ㄱㄱㅆ~

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

    스프링 Resource와 PropertyEditor까지 같이 발표하면 되겠네~
    고맙다. 잘 들을께!ㅋㅋ

Write a comment.


스프링 WebContentGenerator로 자바스크립트 캐싱하기3

모하니?/Coding : 2009. 7. 8. 13:04


2차 작업이 끝인 줄 알았으나... 컨트롤러에 직접 속성으로 js 리소스 위치 목록과 리소스 타입을 알려도록 설정할 수 있는 기능을 추가했습니다.

    <bean name="/js.do" class="koma.base.main.JavaScriptController" p:cacheSeconds="300">
        <property name="resourceType" value="servlet"/>
        <property name="jsResourceNames">
            <list>
                <value>js/koma.js</value>
                <value>js/jquery-1.3.2.min.js</value>
                <value>js/jquery-ui-1.7.2.min.js</value>
            </list>
        </property>
    </bean>

2차까지의 기능도 유효하고 위와 같이 컨트롤러에 리소스 타입과 리소스 path 목록을 넘겨주면 리소스 타입에 따라 적절한 스프링 Resource를 사용해서 파일들을 읽어줍니다.

이렇게 하면 성윤이가 2차 작업에서 말한대로 js가 여러 곳에 분산되어 있을 경우에 resourceType을 url로 설정하고, value에 js 리소스를 나타내는 url 목록을 주면 되겠습니다.

(흠... map 형태로 가야 하는 건가... 이 리소스는 이 타입 저 리소스는 저 타입... 설정하기도 귀찮을 테니 그냥 한 타입으로 가도록 하죠. 일단은.)

url 뒤에 붙이던 것 중에 고정적으로 사용하는 js의 경우 위와같이 컨트롤러에 설정해주고, 페이지에 따라 사용하고 안 하고 하는 것은 url 뒤에 붙여주면 되겠습니다.

기본 js만 사용하는 페이지에서는 이렇게..

<script language="JavaScript" src="/js.do"></script>

부가적인 js까지 사용하는 페이지에서는 이렇게..

<script language="JavaScript" src="/js.do?name=springsprout.js"></script>


top

Write a comment.


스프링 WebContentGenerator로 자바스크립트 캐싱하기2

모하니?/Coding : 2009. 7. 8. 11:12


어제의 문제들을 해결했습니다.

문제1 해결: 파일 경로 문제는 스프링 Resource를 이용해서 해결했습니다. 스프링이 제공하는 Resource 중에 ServletContextResource가 있는데, 웹 루트를 기준으로 리소스를 가져올 수 있도록 해주는 편리한 클래스입니다.

Resource jsFolderResource = new ServletContextResource(getServletContext(), getJsFolder());

이런식으로 사용하면 되는데 여기서 ServletContext 객체는 reqeust -> session -> servletRequest로 쭉쭉 타고가서 가져와도 되지만, AbstractController가 상속받은 WebContentGenerator가 상속받은 WebApplicationObjectSupport가 스프링의 ServletContextAware 인터페이스를 구현했기 때문에, 위와같이 getServletContext()만 호출하면 가져다 쓸 수 있습니다.

문제2 해결: 뷰에서 js를 요청할 때 사용하는 URL 중에서 프로토콜과 서버명을 빼고 리소스 부분만 보냈습니다.

        <script language="JavaScript" src="http://localhost:8080/js.do?name=koma.js&name=jquery-1.3.2.js">
        </script>

이상태에서

        <script language="JavaScript" src="js.do?name=koma.js&name=jquery-1.3.2.js">
        </script>

이렇게 말이죠. 잘 동작합니다~ 캬캬캬

아.. cacheSeconds 속성에 입력한 값은 밀리초가 아니라 정말 '초' 단위더군요. 자칫하면 예상보다 너무 오래 캐시를 유지하는 일이 발생할 수도 있습니다. 주의하세요~

자바스크립트 캐싱하기 끝!
top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.08 12:38 신고 PERM. MOD/DEL REPLY

    js 파일이 다른 장비에 나누어져서 포팅되었을경우는 못쓰는거잖아요 ;;ㅋㅋ
    머 그런거 고려 안 한다면 PASS 영원히~ㅋㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.07.08 12:56 PERM MOD/DEL

    3차 수정 들어갔다.

Write a comment.


스프링 WebContentGenerator로 자바스크립트 캐싱하기

모하니?/Coding : 2009. 7. 7. 18:41


http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/support/WebContentGenerator.html

링크를 보면, WebContentGenerator가 해주는 일을 대략 알 수 있습니다. HTTP cache 헤더를 제어할 수 있는 옵션들을 제공해 줍니다.

여러가지 속성들에 따라 HTTP cache-control 헤더 내용이 달라지는데, 그 중 중요한 녀석으로 cacheSeconds가 있습니다. 이 녀석은 기본 값이 -1로 되어 있고, 그 내용인 즉슨 cache 관련 헤더를 전혀 사용하지 않겠다는 것입니다.

캐시를 유지할 기간만 설정해주면 캐시 관련 헤더들이 다시 설정 되는데, 이 떄 설정되는 녀석들 중 하나가 HTTP 1.1에 추가된 cache-control이라는 헤더입니다.

스펙에서는 다음과 같이 정의하고 있습니다.
The Cache-Control general-header field is used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain.
요청/응답 체인과 관련된 모든 캐싱 매커니즘이 반드시 따라야 하는 지시를 설정한다고 요약해도 될 듯 합니다.

자바스크립트가 들어있는 어떤 페이지를 요청하면, 해당 자바스크립트 파일을 브라우저가 매번 읽어오는데, 그걸 좀 더 효율적으로 개선하기 위해, 자바스크립트를 어떤 url을 통해 가져오도록 src="js.do?name=base.js" 이런식으로 설정하고, 컨트롤러에서는 요청한 자바스크립트를 찾아서 response에 write해 줍니다. 이 때 캐시를 사용하도록 하는거죠.

컨트롤러는 WebContentGenerator를 상속 받은 AbstractController를 상속받는 클래스를 하나 만들고, 내용은 name이라는 매개변수의 값에 해당하는 File을 읽어와서, HttpServletResponse에 쭉~ write() 해주고, 컨텐츠 타입을 자바스크립트로 response.setContentType("application/javascript"); 이렇게 설정해줍니다. 그리고 WebContentGenerator를 가 제공해주는 setCacheSeconds로 캐시를 유지할 시간 설정을 해 줍니다.

파폭과 live HTTP 헤더 플러긴으로 확인해본 결과, 초기 한 번 만 js를 읽어오고 그 뒤 요청 부터는 js를 읽어오지 않았습니다.

문제 1. 컨트럴러에서 자바스크립트 파일을 읽어오는 부분이 녹녹치 않더군요. @_@.. 그래서 자바스크립트가 담겨있는 폴더를 컨트롤러에 설정해줘야 합니다. 개발 환경은 사람 마다 다를테고 배포 환경도 다를텐데.. 이 값을 안 쓰는 방법(상대 경로로 웹 루트에서 부터 js 파일을 찾아가면 좋을 텐데, 제 이클립스에서 돌려보니까 이클립스 루트 폴더부터 경로를 탐색하더군요. @_@)

문제 2. 자바스크립트를 요청하는 URL이 역시 개발 환경과 배포 환경 마다 다를텐데 이건 또 어떻게 해결해야 할지.. 고민입니다.

        <script language="JavaScript" src="http://localhost:8080/js.do?name=koma.js">
        </script>

이런 URL이 되버리는데.. 개발할 때는 이렇게 써도 돌아갈테지만, 배포하면?... @_@

일단 이 두 문제가 맘에 많이 걸리네요.


top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.08 10:24 신고 PERM. MOD/DEL REPLY

    2번은 봄싹 스타일 처럼 이렇게 해도 될 것 같은디;; 안되려나? ;;
    <script language="JavaScript" src="<c:url value="/js.do?name=koma.js"/>">
    </script>

    그리고 1번은.. 절대 경로도 괜찮을 것 같은데요~ ;;;
    웹서버랑... was 랑 다른 서버가 다른 장비에 포팅 되어 있는경우를 보면..
    상대경로로는 js 파일을 참조 할 수 없으니까요..
    그렇지 않은 경우는 상대경로가 좋긴 하겠지만요 ~

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

    캬캬 2번은 그렇게 했어.
    1번도 해결했어. 영원히~

Write a comment.


[파이어폭스 플러그인]Live HTTP headers

Good Tools : 2009. 7. 7. 11:56


https://addons.mozilla.org/en-US/firefox/addon/3829

HTTP 헤더 정보를 보여주는 창을 띄울 수 있습니다. 도구 -> Live HTTP headers를 클릭하면 되죠.
그런 다음 파폭 아무 탭에서 URL을 날리면 Headers 탭에서 HTTP 헤더 정보를 보여줍니다.


전 이제 이것과 스프링의 AbstarctController와 WebContentGenerator를 보면서 HTTP 공부를 해야 하고, js 파일들을 캐싱해서 보내주는 컨트롤러를 만들어야 합니다. 오늘 안에 꼭!!! 파이팅!

이것도 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

top

Write a comment.


벌써 한 달이 넘었군요.

모하니?/Thinking : 2009. 7. 7. 09:33



깃털처럼 가벼운 새색시를 업고 찍었습니다.
결혼한지 한 달이 조금 넘은 상태라 아직도 좀 어리둥절 합니다.

부모님 집에서 살 때와는 많은 것들이 다른데 일단, 집안일을 충실히 하고 있습니다.
부모님 집에서는 설겆이도 잘 안 했었는데, 요즘은 밥하기, 설겆이하기, 청소기 돌리기, 걸레질하기, 강아지 목욕 시키기, 세탁기 돌리기, 세탁물 털어서 널기, 걷어서 게어놓기 정도는 하고 있습니다.
물론 와이프는 이 보다 더 많은 일들을 하기 때문에 전혀 불만이나 불평은 없습니다. 내가 예전에 얼마나 편하게 살았었던가... 하는 반성을 하게 되더군요.

또 하나 다른건 돈 문제인데, 가장으로써, 집에 벌어다 주는 돈이 적을 때 위축 됩니다. 아.. 내가 이래가지고 애들은 나아서 잘 키우겠나... 무슨 돈으로 키우나... 이런 고민이 생기더군요. 그 동안 결혼 준비하랴 신혼 여행 가랴 여기 저기 돈 쓸 곳이 많아서 월급을 제대로 가져다 준 적이 별로 없습니다.
하지만, 둘 다 쇼핑을 별로 안 좋아라하고 와이프가 알아서 잘 관리하고 있기 때문에 꾸준히 노력해서 실력을 쌓다보면 어떻게든 살아날 구멍이 있겠거니 긍정적으로 생각하고 있습니다.

이 두 가지는 가장 큰 변화 들 중에 앞으로 짊어져야 할 짐이었다면, 마지막 변화는 저에게 큰 힘이 되어주는 동반자를 얻었다는 겁니다. 저녁에 퇴근해서 옹알종알 담소도 나누고, 같이 베드민턴을 치며 땀을 빼고, 샤워 할 때 등도 밀어주고, 아침에는 닭백숙을 끓여주는 동반자.. 캬~~ 아내가 차려준 밥을 때 제일 행복하답니다. 크하하



top

  1. Favicon of http://toby.epril.com BlogIcon 2009.07.07 09:43 PERM. MOD/DEL REPLY

    아침부터 닭백숙? 넘 호강하는 거 아냐~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.07 10:59 신고 PERM MOD/DEL

    어제 밤에 먹고 남은거에요.
    둘이서 한 마리(5천원)로 두 끼를 떼울 수 있더라구요.

  2. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.07 16:22 신고 PERM. MOD/DEL REPLY

    "샤워 할 때 등도 밀어주고"..... ㄷㄷㄷㄷㄷ;;;

    아 내가 결혼을 안해서 등간지러운 가봐욥!! ㅋ

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

    그런거에 너무 집착하지마.. 중요한 건 닭백숙이라고!

  3. 김재진 2009.07.08 13:09 PERM. MOD/DEL REPLY

    닭백숙을 아침부터!!..남들도 다 그만큼 해주진 않아요 T^T

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

    나도 뭐 맨날 닭백숙을 먹진 않아.

  4. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.07.14 01:20 PERM. MOD/DEL REPLY

    와... 제대로 염장이네요. :)
    두분 행복한 모습이 보기 좋습니다.

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

    ㅎㅎㅎ감사합니다.
    사진을 간만에 다시 보니 즐겁군요.

  5. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.03 23:02 PERM. MOD/DEL REPLY

    아래서 두번째줄 마지막에 오타지요?

    굶긴후 밥을 줘서 배불러서 행복하지요? keke

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

    굶기기는~ 잘 챙겨주면서 ㅋㅋ

  6. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.03 23:03 PERM. MOD/DEL REPLY

    별로 잘 챙기는거 없는데..남들도 다 이만큼은 해줘요!!

    Favicon of http://whiteship.me BlogIcon 기선 2009.07.08 12:56 PERM MOD/DEL

    ㅇㅇ그렇구나!

Write a comment.


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

모하니?/Coding : 2009. 7. 6. 15:00


아마 이번이 시리즈의 마지막이 아닐까 싶습니다. 지난번까지 DB에 저장할 값으로, Integer, String, Character를 지원하는 enum을 만들었고, 이번에는 enum의 목록을 특정 기준으로 정렬할 수 있는 기능을 추가했습니다.

enum 목록을 가져올 때, enum의 valus() 메서드를 사용하면, enum에 등록되어 있는 순서대로 상수들을 가져옵니다. 그러나 새로운 enum을 추가하고 변경하다보면 그 목록 순서도 변경되겠죠. 사용자가 특정 순서대로 목록이 보여지길 원한다면, 상수를 등록한 순서를 조정하는것이 아니라, 특정한 필드 기준으로 정렬을 해야겠다는 판단을 내렸습니다. 결국 새로운 필드를 하나 추가했습니다.

public enum UserCate implements PersistentEnum {
   
    ADMIN("admin", "관리자", 3), STAFF("staff", "직원", 1), SUPP("supp", "협력업체", 2);

...

    private UserCate(String value, String descr, int order) {
        this.value = value;
        this.descr = descr;
        this.order = order;
    }

...

    public int getOrder(){
        return order;
    }

}

이렇게 order라는 int 타입 변수를 하나 추가하고, 이 값으로 순서를 비교하는 Comparator를 만들었습니다. PersistentEnumUtils라는 클래스에 sortedListOf(Class<E> enumClass)를 추가로 만들어 줬습니다.

이제 정렬된 enum 목록이 필요할 떄는 다음과 같이 한 줄이면 됩니다.

    public List<CodeCate> getCodeCate(){
        return PersistentEnumUtil.sortedListOf(CodeCate.class);
    }

    public List<UserCate> getUserCate() {
        return PersistentEnumUtil.sortedListOf(UserCate.class);
    }

    public List<FamillyCate> getFamillyCate(){
        return PersistentEnumUtil.sortedListOf(FamillyCate.class);
    }

이런식으로 말이죠.

스프링, 하이버에서 enum 쓰기... 편하게 하기 위해 만들어 낸 결과물 구조는 다음과 같습니다.

- PersistentEnum 인터페이스
- PersistentEnumUtils 클래스
- PersistentEnumComparator 클래스
- GenericEnumPropertyEditor 클래스

PersistentEnum 인터페이스

    String getDescr();
   
    Object getValue();
   
    int getOrder();

이 셋은 스프링, 하이버네이트에서 enum을 사용할 때 거의 대부분 필요로 하게 될 것이며, GenericEnumPropertyEditor와 PersistentEnumUtils에서 사용할 인터페이스가 필요하기 때문에 만들었습니다.

PersistentEnumUtils 클래스

public static <E extends PersistentEnum> E valueOf(Class<E> enumType, Object value)

public static <E extends PersistentEnum> List sortedListOf(Class<E> enumType)

enum 클래스와 value로 enum을 찾아주는 메서드와 PersistentEnumComparator로 정렬한 list를 넘겨주는 메서드가 있습니다.

PersistentEnumComparator 클래스

    @Override
    public int compare(E e1, E e2) {
        return e1.getOrder() - e2.getOrder();
    }

이게 전부입니다.

GenericEnumPropertyEditor 클래스

PersistentEnum 인터페이스와 enum 클래스를 받아서 생성자, getAsText, setAsText를 재정의했습니다.

이렇게 네 개의 파일만 추가하면... enum을 다음과 같이 구현할 수 있습니다.

public enum UserCate implements PersistentEnum {
   
    ADMIN("admin", "관리자", 3), STAFF("staff", "직원", 1), SUPP("supp", "협력업체", 2);
   
    private final String value;
    private final String descr;
    private final int order;
   
    private UserCate(String value, String descr, int order) {
        this.value = value;
        this.descr = descr;
        this.order = order;
    }

    public String getValue() {
        return value;
    }
    public String getDescr() {
        return descr;
    }
    public int getOrder(){
        return order;
    }

}

뭐 특별한 건 없습니다. 그냥 enum에 인터페이스 하나 추가했을 뿐입니다.

하이버네이트를 사용할 땐, UserType 클래스가 필요하니까 UserType을 다음과 같이 만들어 줍니다.

public class UserCateType extends GenericEnumUserType<UserCate>{
   
}

이게 전부입니다. 클래스도 만들고 싶지 않지만, 하이버네이트 설정에 클래스 풀 패키지 경로를 줘야 하기 때문에 클래스를 안 만들 수가 없습니다.

    @Type(type="koma.domain.usertype.UserCateType")
    UserCate userCate;

자 이렇게 하면 하이버네이트 UserType 설정이 끝났습니다. 아무런 추가 구현도 없이 클래스 하나 만들었을 뿐인데 말이죠. DB 컬럼 타입과 그 안에 들어가는 값은 모두 getValue() 메서드의 리턴타입과 값에 맞게 정해집니다.

스프링 MVC에서 사용할 땐 PropertyEditor가 필요할 텐데.. 이건 전에도 말했듯이 클래스도 만들 필요없이 binder 설정하는 부분에 한 줄만 추가하면 됩니다.

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

끝~

top

Write a comment.


STS 2.1.0 RC1에서 DM Server에 초간단 웹 애플리케이션 띄우기





top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.07.14 01:16 PERM. MOD/DEL REPLY

    제가 전에 말씀드렸던 STS 버그가 project 폴더 펼치면 있는 Web Resources에
    WebContent 폴더 밑에 있는 META-INF, WEB-INF와 기타 jsp 폴더 등등이 존재한다면
    다 나타나야 하는데, 3.4기반의 STS 2.1.0 RC1에서는 잘 나타나는데,
    3.5기반은 안 나타나네요.
    별거 아닌거 같지만, 아시다시피 Maven을 쓰면 src/main/webapp 을 타고 한참
    들어가야 해서 좀 번거롭죠...ㅡ_ㅡ;;;

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.07.14 16:04 신고 PERM MOD/DEL

    흠.. 그럼 3.5기반 STS에서는 웹 폴더 밑에 있는 META-INF랑 WEB-INF 등이 나타나질 않는건가요?? 어허.. 저런;;

    메이븐 폴더 구조는 살짝쿵 요령만 부리면 일반 자바 플젝과 같은 구조로 사용하실 수 있습니다. 전 요즘 항상 그렇게 해놓고 쓰고 있지요.

Write a comment.


database.properties 모음

모하니?/Coding : 2009. 7. 3. 19:34


외울 수가 없어서 항상 이전에 만들었던 프로젝트들을 뒤적거리는데.... 그게 귀찮아서 한 곳에 모아둡니다.

HSQL

db.driver=org.hsqldb.jdbcDriver
db.url=jdbc:hsqldb:mem:springsprout
db.username=sa
db.password=
hibernate.dialect=org.hibernate.dialect.HSQLDialect

PostgreSQL

db.driver=org.postgresql.Driver
db.url=jdbc:postgresql://localhost/springsprout
db.username=springsprout
db.password=springsprout
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

MySQL

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/springsprout?autoReconnect=true&characterEncoding=euckr
db.username=springsprout
db.password=springsprout
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

오라클이 없군요. Derby는 패스 합니다. 비추에요. 대충 이 셋 중에서 골라 쓸 듯. HSQL은 테스트 용이고, 실제 DB 용으로 둘 중 하나.. 혹은 오라클 쓰시면 될 듯.




top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.07.04 00:30 신고 PERM. MOD/DEL REPLY

    오라클용!
    jdbc.driverClassName=oracle.jdbc.OracleDriver
    jdbc.url=jdbc:oracle:thin:@localhost:1521:springsprout
    jdbc.username=springsprout
    jdbc.password=springsprout

    훔냥.. 2주가 정신없이 지나 버렸네요 ;;;ㅋ
    간만에 여유를 찾아 구글 리더를 보니.. 엄청 밀려 있네;;ㅋ
    다시 정신 차려서 봄싹에 다시 전념을 ㅋㅋ
    낼 스터디때 봅시다!

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.07.04 11:38 PERM MOD/DEL

    오우 썡큐!!

Write a comment.


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

카테고리 없음 : 2009. 7. 3. 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 사용하기 2

모하니?/Coding : 2009. 7. 3. 16:37


어제에 이어 오늘도 물고 늘어진다. 이번에 해결한 문제는, DB에 저장할 값을 int 타입 뿐만이 아니라 String 타입을 사용해도 무방하도록 코드를 수정했다.

public enum UserCate implements PersistentEnum {
   
    ADMIN("admina", "관리자"), STAFF("staff", "직원"), SUPP("supp", "협력업체");
   
    private final String value;
    private final String descr;
   
    private UserCate(String value, String descr) {
        this.value = value;
        this.descr = descr;
    }

    public String getValue() {
        return value;
    }
    public String getDescr() {
        return descr;
    }
   
...

}

이건 DB에 저장할 값으로 String 값을 사용할 enum 이고..

public enum CodeCate implements PersistentEnum {

    COLOR(10, "색상"), SIZE(20, "사이즈"), PAYTERM(30, "지불조건"), SHIPVIA(40, "운송방식");
   
    private final Integer value;
    private final String descr;
   
    private CodeCate(Integer value, String descr) {
        this.value = value;
        this.descr = descr;
    }
   
    public int getValue() {
        return value;
    }
    public String getDescr() {
        return descr;
    }

...

}

이건 DB에 저장할 값으로 int 값을 사용할 enum이다.

하이버네이트가 필요로 하는 UserType을 만들어 보자.

public class CodeCateType extends GenericEnumUserType<CodeCate>{

    public CodeCateType() {
        super(CodeCate.class);
    }
   
}

public class UserCateType extends GenericEnumUserType<UserCate>{

    public UserCateType() {
        super(UserCate.class);
    }
   
}

끝이다. 도메인 객체 타입에 설정해보자. 구현에 필요한 코드만 파란색으로 강조를 했다. 생성자 만드는 부분까지 없앨 수 있을 것 같다. 3차 구현에서 해보자.

Code.java

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

User.java

    @Column
    @Type(type="koma.domain.usertype.UserCateType")
    UserCate userCate;

자.. 이러면 하이버네이트가 CodeCate는 Integet SQL 타입 컬럼을 만들어 주고 UserCate는 String SQL 타입(varchar)를 만들어 줄 것이다.

스프링 MVC에서 바인딩 할 때 사용할 PropertyEditor는 어떨까? 한 줄 씩이다.

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

끝인가?? 글쎄.. 모르곘다. Charater를 추가하는 것도 별 문제 없을 듯 하다. 해보자. 이러다가 모든 타입을 지원해야 하는건 아니겠지?? Char까지만 해보자. 여기서도 생성자에 클래스를 주고 있는데 3차에서는 저 코드를 없앨 수 있게 구현해보자.

자.. 하이버, 스프링에서 자바 enum 사용 간편화 3차 구현 ㄱㄱㅆ
top

Write a comment.


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

모하니?/Coding : 2009. 7. 2. 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.


결국 그냥 만들어버린 JPA 문서 자동화 툴

모하니?/Coding : 2009. 7. 2. 11:42


지난 번에 살펴본 hbm2doc로는 사부님이 원하는 문서를 만들기가 버거워서, 예전에 물개선생님이 만드셨다는 코드를 참조해서 비슷하게 만들었습니다.

@Entity
@Table(name = "users", uniqueConstraints = @UniqueConstraint(columnNames = { "loginid" }))
@SequenceGenerator(name="user_sq", sequenceName="user_sq")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Integer id;
    @Version
    Integer version;
    @ColumnInfo(value = "아이디", description="중복 되는 값은 사용할 수 없음")
    @Column(length = 50, unique = true)
    String loginid; // identity

    @ColumnInfo("이름")
    @Column(length = 50)
    String name;
    @Column(length = 50)
    String pwd;
    @Column(length = 50)
    @Index(name="email_idx")
    String email;
    @Column
    int usertype;
    @Column(length = 50)
    String title;
    @Column(length = 50)
    String dept;
    @Column(length = 50)
    String tel;
    @Column(length = 50)
    String mobile;
    @Column(length = 50)
    String addr;
    @Column
    @Temporal(TemporalType.DATE)
    Date birthday;

    @ManyToMany
    Set<Role> roles;

    @OneToMany(cascade = { CascadeType.ALL})
    Set<Familly> famillies;

이렇게 애노테이션이 난무 하는 도메인 클래스에 대한 정보 + 새로 추가한 애노테이션 @ColumnInfo를 사용하여 화면에서 해당 필드를 보여주는 이름(또는 도메인 전문가가 사용하는 용어)과 설명을 추가할 수 있습니다.

어제 하루 종일 만들고 오늘 아침에 조금 다듬은 결과물은 다음과 같습니다.


코딩은 TDD로 시작했는데, 저 위에 보이는 HTML 만드는 코드는 참조하던 코드를 짜집기해서 만들었습니다.

클래스 구조는 대충.

DocGenerator ---> DocWriter ---> EntityInfo

이렇습니다. DocGenerator에 엔티티 클래스 목록을 주면, DocWriter로 문서를 생성해 내는데, 이 때 new EntityInfo(엔티티 클래스) 생성자를 사용하여 애노테이션에서 정보를 축출하여 담고 있는 Info 클래스를 만들어 사용합니다.

DocGenerator는 기초 정보(Dialect, 엔티티 클래스, 타겟 폴더, ...) 수집 및 퍼사드 역할을 하고, DocWriter는 실제로 문서 생성을 책임지는데, 인터페이스를 둬서 여러 형태의 문서 작성기를 사용할 수 있도록 했습니다. 현재는 HTMLDocWriter만 구현되어 있습니다. EntityInfo는 리플렉션을 사용하여 주어진 클래스와 그 클래스에 붙어있는 애노테이션을 활용하여 화면 출력에 필요한 정보들을 수집해 두는 역할을 합니다. 일종의 DTO라고 봐야하나..

실행은 DocGeneratorRunner의 main 메서드를 약간 수정해서 실행하면 되겠습니다.


의존성, 프로젝트 이런거 없이 그냥 소스 코드만 묶었습니다. 아마.. 하이버네이트 애노테이션.jar, persistence.jar, 그리고 HTML을 처리할 때 사용한 hq-1.jar라는 라이브러리가 필요할 겁니다.

코드에 보시면 Writer 쪽에 심각한 중복 코드가 있는데.. 아직 해결하진 않았습니다. 캬캬캬
Info 쪽 코드도 전혀 깔끔하지 않습니다. 애노테이션에서 정보를 축출하여 초기화 하는 부분(생성자)을 일관성 있게 수정하고 싶은데.. 하진 않았습니다.
HTML에 어떤 DB 스키마에 해당하는 컬럼 타입인지 알려주기 위해 Dialect도 출력할까 했지만.. 역시 아직 하지 않았습니다. 이건 뭐 간단할 것 같으니 금새 추가할 수 있을지도 모르겠네요.
top

  1. Favicon of http://seal.tistory.com BlogIcon 물개 2009.07.02 14:04 PERM. MOD/DEL REPLY

    예전에 만든 코드를 누군가 읽어줄 줄 알았다면, 그렇게 엉망으로 짜진 않았을텐데.. ㅋㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.07.02 14:30 PERM MOD/DEL

    엇 저는 쉽게 쉽게 볼 수 있어서 좋았는데요.
    그 코드가 없었다면.. 아직도 헤매고 있었을 것 같아요.
    감사합니다~ ^^

  2. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.07.03 09:58 PERM. MOD/DEL REPLY

    좋은일 많이 하시는군요. :) 복 받으실껍니다.

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

    아직 지원하는 애노테이션이 몇 개 없습니다.ㅋㅋ

    @Embedded나, @SuperClassType인가.. 머시기도 지원해야 정확하게 필드를 모두 뽑아 낼 수 있을 것 같습니다.
    그런 점에서는 hbm2doc이 역시 좋더군요.

    JPA 애노테이션이랑 하이버 애노테이션이 몇개더라.. @_@

Write a comment.


[파폭 테마] 구글 크롬 테마

Good Tools : 2009. 7. 1. 21:51


https://addons.mozilla.org/en-US/firefox/addon/8782


음~~ 귿!! 가끔씩 테마를 바꿔주는 센스..
top

  1. Favicon of http://selic.pe.kr BlogIcon selic 2009.07.02 08:21 PERM. MOD/DEL REPLY

    파폭3.5로 검색했다가 우연히 들어왔네요. 좋은글 많이 읽고 갑니다. ^ 0 ^..

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

    넵~ 방문 감사합니다.

  2. Favicon of http://sonegy.egloos.com BlogIcon 소내기 2009.07.02 09:57 PERM. MOD/DEL REPLY

    탭위치가 어색해.

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

    탭은 원래 파폭 자리에 있어요. 그냥 색이랑 탭 모양만 크롬 형태로 바뀌는 듯.

  3. 대한민국토리 2009.07.14 12:22 PERM. MOD/DEL REPLY

    네이버 테마도 그럭저럭 괜찮던데요. 이제 크롬 스타일로 바꿔 볼 때가 된건가요?? 좋은 정보 감사합니다.~~~

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

    요즘 파폭보다 빠를 것 같은 크롬이나 사파리로 갈아타고 싶긴한데 그쪽 플러긴들이 파폭 플러긴처럼 검색, 설치, 업데이트, 기능미가 나은 것 같은 느낌이 들지 않아서 고민입니다.

    플러긴을 포기하고 속도를 얻을 걷인가.. 말 것인가..

Write a comment.