봄싹(Spring Sprout) 스웨거 스터디에서 '스프링 어디까지 써봤니?' 라는 다소 건방지 주제로 발표를 했습니다.

정확한 속뜻은 제가 어디까지 스프링을 사용을 하고 있는지에 대해서 공유하는 자리였습니다.
제가 그 동안 Spring @MVC를 사용해 웹 애플리케이션을 개발하면서 스프링을 어떻게 사용하고 있는지에 대한 내용으로 구성했습니다.

아마도 스프링을 더욱 잘 이해하고 사용하시는 분들이 보시기에는 많이 부족한 내용이었으리라고 생각됩니다.

저만의 고집이 녹아들어 있는 코드들이라서 아마도 마음에 안드시는 분들고 계실거라고 생각됩니다. 코드보다는 스프링의 @MVC 기술들을 어떻게 사용했는지에 대해서 주로 보시면 좋겠습니다.

발표에 사용한 장표는 Google Docs에 공개로 올려두었고, 소스코드는 Github에 올려두었습니다.

스프링 어디까지 써봤니?.PDF

스프링 어디까지 써봤니? - Source Code

Posted by Arawn Trackback 1 : Comment 3
지난 11월 25일에 진행된 DevOn에서 KSUG 대표로 발표를 할 수 있는 기회를 얻었습니다.

처음에는 주제를 'Spring @MVC의 Controller와 Data Binding"로 잡았으나, DevOn 행사에서 세부적인 개발 기술을 다루기에는 적합하지 않다라고 판단되어, Spring Social로 주제를 변경해서 발표를 했습니다.

요즘 어디를 가더라도 들을 수 있는 SNS에 대한 이야기와 애플리케이션에 SNS 서비스를 접목할때 어떤 것들이 필요한지, 그리고 Spring Social의 특징과 흐름에 대한 내용으로 구성했습니다.

발표자료는 Google Docs에 올려서 공개로 풀어두었습니다.

스프링소셜을 이용한 빠른 소셜앱 만들기.PDF

Posted by Arawn Trackback 6 : Comment 0
어제 팀내 맥북 사용자가 아주 독특한걸 쓰는걸 봤습니다.

파인더에서 뭔가 키를 툭 누르더니 커맨드 입력창이 스르륵 나타나고 거기에 "mvn eclipse:eclipse" 명령어를 날려서 빠르고 쉽게 작업을 하더군요.

전 파인더에서 터미널을 열어주는  OpenTerminal 이라는 어플리케이션을 사용하고 있었거든요.

팀원을 닥달해서 그 어플리케이션의 이름이 DTerm 이라는 것과 맥 앱스토어에서 무료로 배포되고 있다는 정보를 얻어냈습니다.

바로 설치해서 사용해보니 너무 편하더군요. ㅠㅠ

이 녀석을 보자말자 생각났던건 "IDE 에서 사용할 수 있으면 Git 를 쓰는게 한결 편하겠다!" 였습니다.
아직까지 IDE Git Plugin 중에는 쓸만한 녀석이 안보여서 항상 Terminal 을 열어서 사용하고 있거든요.

바로 XCode 를 띄워서 확인해 봅니다.

iOS 스터디에서 작성한 실습예제 프로젝트를 열어서 "git status" 명령을 내려봅니다.
저장소에서 아직 관리가 되지 않는 폴더라서 "git add" 로 추가하라고 하네요.


"git add ." 명령으로 추가 후 "git status" 로 확인해봤습니다.



훌륭하게 동작합니다!!!

이 기세를 몰아서 STS도 도전해봅니다.


OTL;;; 원했던 동작이 나오지 않습니다 ㅠㅠ
user home 의 위치만 가르키는군요.

혹시 누군가가 이걸 해결하지 않았을까!?
바로 구글링을 시도해서 "eclipse-cocoa-set-represented-filename plugin" 을 찾았습니다. 설치 후 시도해본 결과...!!


깔끔하게 동작하는 모습을 볼 수 있었습니다. ^^

IDE + DTerm 환경에서 이제 편하게 Git 를 쓸수있을거 같네요.



Posted by Arawn Trackback 0 : Comment 2
Spring Data Sqlmap 을 보완하다 런타임에서 메소드에다 애노테이션을 붙이거나 수정해야하는 이슈가 생겨서 한번 만들어 보았습니다.

소스사용법은 Github 에 있습니다. 
Posted by Arawn Trackback 0 : Comment 1
꽤 오래(?)전부터 SpringSource 에서 Spring Data 라는 프로젝트가 진행 중 입니다.
처음에는 NoSql DB 를 추상화해 사용하기 위해 시작된 프로젝트이었다고 기억하고 있는데 얼마전 fupfin 님께서 Spring Data JPA 가 나왔다고 하시면서 간단하게 소개를 해주셨습니다.

persistence framework 를 사용해서 DAO(Repository)를 구현하다보면 CRUD 는 대부분 persistence framework 의 누군가(sessionfactory, entitymanager, sqlmapclient 등)에게 위임할뿐 특별히 어떤 로직을 수행하는 경우는 드뭅니다.
계층을 구분하기 위해 DAO 가 필요하지만 구현 작업은 번거롭다는 문제점이 있는것이죠.

Spring Data JPA 사용해서 진행하는 개발을 간략하게 살펴보면 다음과 같습니다.
1. Entity 작성
2. JpaRepository 상속해 Repository interface 작성
3. Spring 설정에 Spring Data JPA 전용 네임스페이스로 몇줄 작성
4. Repository를 주입받아 사용

JpaRepository 인터페이스를 상속받아서 적절한 interface 만 만들어두면 구현체는 runtime 에 Spring Data JPA 에서 만들어 넣어줍니다.
개발이 매우 간결하게 진행된다는걸 느낄 수 있습니다.

그래서 국내에서 가장 많이 사용하는 persistence framework 인 iBatis 를 Spring Data 에 붙여보았습니다.

prototype 수준정도로 구현해보았지만 기본적인 기능은 대부분 동작합니다.
소스 및 예제는 여기서 볼 수 있습니다.
Posted by Arawn Trackback 0 : Comment 6


언제가 푸른 초원에서 감자와 강아지를 키우고 싶어하는 독특한 소녀에게 책을 빌린지 어언 ...개월이나 흘렀습니다. ( 응? 얼마나 오래되었는지 정확하게 기간도 못 집어내겠군요. 최소 3개월은 된듯한... ㅠ ) 이제야 다 읽고나서 책에 관한 이야기를 써봅니다.

슬랙은 우리시대의 조직이 비용절감, 초과근무, 공격적인 일정, 거짓된 생산성 등이 '효율성' 이라는 이름으로 포장되어 운영되고 있다고 한다. 조직이 효율성을 추구하면 할수록 더욱 견고하고 바쁘게 움직이게 되는데 이것은 조직이 변화를 불가능하게 만들고 또한 조직을 정체 상태에 빠지게 만든다고 한다. 이 책은 조직이 '느슨함(여유)'을 가짐으로 조금 덜 효율적으로 만드는 대신에 기업을 민첩하게 변화에 대응하고 재창조를 통해 훨씬 더 큰 효과를 얻을 수 있는 방법을 제시하고 있습니다.

지식근로자에게 성장은 급여만큼 필수불가결한것입니다. 급여 없이 일할 것이라고 기대할 수 없는것 처럼 성장할 수 있는 기회가 포함되지 않은 업무를 할 것이라고 기대해서는 안됩니다.

'빨리빨리' 정신을 가진 조직에는 끊임없이 지속되는 업무에 관한 '압박감'이 존재합니다. 이런 압박감이 근로자의 능력을 한계까지 끌어올릴 수 있을 것이라고 믿기 때문입니다. 이런 상황이 프로젝트의 공격적인 일정 수립으로 이어지고 곧 초과근무와 거짓된 생상성, 품질 저하, 이직 등로 확대되어 갑니다.   

이외에도 나쁜 관리자, 프로세스 강박증, 목표관리(MBO) 등의 이야기를 다루고 있습니다.
그리고 변화와 성장을 위한 이야기도 풀어놓고 있습니다.

이 책을 읽으면서 그 동안 제가 생각하던 여러가지를 정리할 수 있었고, 시야가 좁아 보지 못했던 부분까지 많은 것을 배울 수 있었습니다. 지금의 제 위치에서 모든걸 다 해볼 수는 없겠지만 조금씩 변화를 위한 행동을 모색해보아야겠습니다.

SLACK변화와재창조를이끄는힘
카테고리 경제/경영 > 경영관리 > 조직관리일반
지은이 톰 드마르코 (인사이트, 2010년)
상세보기


Posted by Arawn Trackback 0 : Comment 0
스칼라 스터디에서 예제 및 연습문제의 소스 공유, 관리를 위해 bitbucket 서비스에서 mercurial 을 사용 중이다.

bitbucket 리파지토리에서 최신 리비전을 받기위해서 pull 을 했더니 로컬 리파지토리에 3개의 head 가 생겨버렸다.
안내대로 merge 를 시도했지만 수행되지 않고 이해가 잘 되지 않는 문구를 뿜어낸다;;

abort: branch 'default' has 3 heads - please merge with an explicit rev
(run 'hg heads .' to see heads)


r55 가 현재 로컬 리파지토리에서 진행되던 가지이고, 리모트 리파지토리에서 2개의 head(r60, r61) 가 진행중인 상태이다.

머큐리얼 사이트를 통해서 이리저리 알아본 결과 다음과 같은 순서로 진행되어야 한다고 한다.

1. 현재 branch 닫기.
2. 순차적인 head merge


branches, branch 명령어를 통해서 현재 branch 확인하고 commit(ci) 명령어의 "--close-branch" 옵션을 통해서 branch 를 닫는다. 화면에서는 r61 이 현재 branch 라고 나오는데 실제 닫히는건 r55(로컬에서 내가 진행중이던 branch)가 닫힌다.

branch 를 닫은 후 남은 r60, r61 을 순차적으로 병합한다.


merge 의 rev 옵션을 통해서 r60부터 병합을 시도했다. head 를 자세히 보면 알겠지만 r60이 병합되면서 r63이 생성되었다. 따로 branch 명령을 안 넣어보았지만 아마도 현재 branch 로 지정되어 있을 것으로 예상된다.


남은 r61을 병합하면 head 가 정리된다.
Posted by Arawn Trackback 0 : Comment 0
[출처 : 한빛미디어]

책을 받은지 거의 두달이 다되어가는데 이제서야 책에 관한 이야기를 한번 풀어보려합니다.
책에 관해서 무언가를 적어보는 것은 초등학교 방학숙제로 끄적였던 독후감 이후로 처음이네요. (국어 실력이 썩 좋지 못한 저로서는 무언가를 적어는다는 대해서 익숙하지 못하답니다. ㅎㅎ)

저는 TDD(Test Driven Development)를 봄싹 스터디에서 처음 들었습니다. 초기에 두어번의 참석이후 회사일이 바빠지면서 스터디가 끝나기까지 한번도 가보지 못했습니다. 덕분에 테스트 자동화와 TDD는 비슷한 것으로 알고있었습니다. ( 어설프게 아는 지식은 독이 된다지요? ;; )

TDD를 잘 모르기 때문에 확신을 가지고 말하지 못하겠지만 이 책을 읽고나서 바로 'TDD란 무엇이다!' 라고 말하지는 못하겠습니다. 하지만 'TDD란 이렇게 해나가는거다!' 라는걸 배울 수 있었습니다. TDD에 관한 다른 글을 찾아보면 이론 위주로 설명을 어렵게 해놓은 것에 비해 이 책은 TDD을 해나가는 길을 제시하고 그 즐거움을 얻을 수 있도록 해주고 있습니다.

이 책의 또 하나의 장점은 다양한 테스트 방법에 대해서 알려준다는 것입니다. 꼭 TDD 를 배우는 것이 아니더라도 테스트를 작성함에 있어 다양한 도구를 활용해 보다 높은 수준의 테스트 작성 방법을 배울 수 있습니다.

스프링을 통해서 테스트를 작성하는 것에는 조금 익숙해진 상태이지만 너무나도 많은 것이 얽히고 설켜있는 현장에서는 테스트를 작성하는 것이 쉽지 않은 경우도 많았고, 특정 객체의 값을 비교해보기 위해서 Assert 구문 수십개를 사용했던 적도 많았습니다. 하지만 책을 통해서 복잡한 의존성 문제를 해결해주는 mock, 데이터베이스 테스트를 위한 dbunit, 다양한 단위 테스트 라이브러리 unitils 등의 도구를 알게되고 사용법을 배움으로써 테스트를 보다 더 정확하고 빠르게 작성을 할 수 있게 되었습니다.

책의 내용에는 저자가 현장에서 TDD를 보급하기 위해서 고군분투하며 얻은 경험이 그대로 책의 곳곳에 녹아들어 있습니다. TDD에 관한 부분뿐만이 아니라 소프트웨어를 설계와 개발 등의 다양한 부분을 아우르는 내용으로 인해 독자에게 여러가지 많은 생각을 해볼 수 있는 기회도 주신거 같습니다. 그리고 특유의 독특한 유머감각이 흘러넘치는 글로 인해서 책을 읽는 동안 재미있었습니다.

국내의 많은 자바 개발자분들이 이 책을 통해서 많은것을 얻을 수 있을거라고 생각합니다. 저자분에게 무한한 감사의 뜻을 전하며 이만 줄이겠습니다.


테스트주도개발TDD실천법과도구
카테고리 컴퓨터/IT > 프로그래밍/언어 > JAVA > JAVA일반
지은이 채수원 (한빛미디어, 2010년)
상세보기

Posted by Arawn Trackback 0 : Comment 1
ROO 는 Maven 으로 프로젝트가 관리되고 있습니다. 저장소에서 소스를 받아 /pom.xml 을 열어보시면 modules 엘리먼트에 루가 관리하는 모든 모듈이 등록되어 있습니다.


    annotations
    support
    model
    shell
    shell-jline
    metadata
    file-undo
    file-monitor
    file-monitor-polling
    project
    process-manager
    classpath
    classpath-javaparser
    addon-maven
    addon-plural
    addon-propfiles
    addon-beaninfo
    addon-configurable
    addon-email
    addon-javabean
    addon-jpa
    addon-jms
    addon-finder
    addon-logging
    addon-entity
    addon-property-editor
    addon-security
    addon-tostring
    addon-web-flow
    addon-web-mvc-controller
    addon-web-mvc-jsp
    addon-web-menu
    addon-web-selenium
    addon-dod
    addon-test
    addon-backup

    bootstrap


parent 에서는 무언가를 구현하고 있지 않고 하위 모듈에 루의 모든것이 구현되어있습니다. 크게보면 bootstrap 을 선두로 shell, metadata, classpath 등의 루의 몸체(?)를 구성하는 모듈들과 addon-[...] 으로 시작되는 팔다리(?) 모듈로 볼 수 있는것 같습니다. addon-[...] 모듈은 몸체 모듈에서 필요한 몇가지를 의존성으로 가지고 구현되어있습니다.
Posted by Arawn Trackback 0 : Comment 0

Roo 는 JDK 1.5 에 Maven 2.0.9 이상을 필요로 합니다!

여기에 적당히 Eclipse + m2eclipse 만 준비하시면 됩니다.
(전 SpringSource Tool Suite 2.3.0을 썼습니다.)

1. Roo 소스 구하기
    svn co
https://anonsvn.springframework.org/svn/spring-roo/trunk/ spring-roo
    (체크아웃 받아보시면 spring-roo 폴더에 readme.txt 가 있습니다. 더 자세히 나옵니다 ^^)

2. 컴파일 및 이클립스 프로젝트로 변환
    mvn clean eclipse:clean eclipse:m2eclipse compile

3. 환경변수 등록(총 두곳에다가 셋팅을 했는데 안해되 되는 녀석이 하나... 해야지 되는 녀석이 하나 더군요;;)
    ROO_CLASSPATH_FILE roo_source_dir/bootstrap/target/roo_classpath.txt
    * 붉은색부분은 source 를 check out 받은 폴더 path 를 넣어야합니다.

4. Eclipse File > Import > Existing Projects into Workspace 로 roo_source_dir 를 지정하면 37개 프로젝트가 들어옵니다. Maven Module 화가 정말 잘 되어있네요;;

5. 프로젝트 중 org.springframework.roo.bootstrap 를 찾아가서 다음 클래스를 실행합니다.
    org.springframework.roo.bootstrap.Bootstrap.java
    main(...) 메소드로 되어있으니 Java Application 으로 구동하시면 Console 창에서 Roo Shell 을 보실 수 있을겁니다. ^^ 쉘은 나왔지만 아직 커맨드 입력이 되지 않습니다.

6. Run Configurations 창을 열고 Bootstrap 어플에 VM 옵션을 넣어주세요. (ctrl + 3(단축키) > run configurations)
    -Djline.WindowsTerminal.directConsole=false
    -Djline.terminal=jline.UnsupportedTerminal

   그리고, Working directory 에 roo 가 구동될 빈 디렉토리를 잡아주세요.
   roo가 생성하는 파일들이 이 디렉토리에 생성됩니다.




    



       
  

Posted by Arawn Trackback 0 : Comment 0

OS 로 Windows 7 64bit 를 사용하고 있습니다.

32bit JDK 먼저 설치하고 64bit 를 설치한 상황에서 roo 를 실행하니 다음과 같은 오류가 발생는군요.

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependen
cyException: Error creating bean with name 'bootstrapCommands' defined in URL .... 생략!!
Caused by: java.lang.UnsatisfiedLinkError: C:\Users\izwork\AppData\Local\Temp\jl
ine_.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform ... 생략!

현재 시스템변수상에는 32bit 를 JAVA_HOME 으로 설정했고 path 를 봐도 32bit 를 보고있지만 console 에서 java -version 을 치면 64bit 가 실행이 되는군요. -_- 

윈도우즈가 어디에선가 잡고있나봅니다;;

roo.bat 를 찾아가서 다음 라인을 수정해서 처리했습니다.

before

java -Djline.nobell=true -Djava.ext.dirs="%ROO_HOME%\dist;%ROO_HOME%\lib;%ROO_HOME%\work;%ROO_JRE%\lib\ext" %ROO_OPTS% -Droo.home="%ROO_HOME%" org.springframework.roo.bootstrap.Bootstrap "classpath:roo-bootstrap.xml" %*


after

D:\izwork\common_tools\java\jdk\bin\java -Djline.nobell=true -Djava.ext.dirs="%ROO_HOME%\dist;%ROO_HOME%\lib;%ROO_HOME%\work;%ROO_JRE%\lib\ext" %ROO_OPTS% -Droo.home="%ROO_HOME%" org.springframework.roo.bootstrap.Bootstrap "classpath:roo-bootstrap.xml" %*
Posted by Arawn Trackback 0 : Comment 0
1. http://www.springsource.org/roo 최신 버전이나 마음(?)에 드는 버전을 다운로드 받습니다.
    아침에 1.0.1 을 받았는데... 지금 들어가보니 1.0.2 가 올라와있네요. :)

2. 하드디스크의 적당한 곳에 압축을 풀어줍니다.

3. 환경변수에 잡아줍니다.
   


4. console 창을 꺼내서 roo 를 실행해봅니다!
Posted by Arawn Trackback 0 : Comment 0
ORA-12154: TNS:could not resolve the connect identifier specified

64bit 윈도우에 Oracle Database 10g Express Edition 과 Toad for Oracle 9.7.2 Suite Commercial 를 설치 후에

위의 메시지로 인해 한참 고생했다.

상황을 해결하기 위해서 몇가지 취한 행동은 다음과 같다.

1. 설치 디렉토리 변경
64bit 윈도우에 설치되는 프로그램이 32bit체제일 경우 C:\Program Files (x86) 에 설치된다.
구글링을 통해서 검색해본 결과 Toad 설치경로에 특수문자[(x86) 라고 예상]가 들어갔을 경우에
위와 같은 에러코드(ORA-12154)가 발생할 수 있다고 한다.

그래서 설치위치를 c:\oraclexe\toad 로 변경 후에 설치하였다.


2. sqlnet.ora 에 아래 문구 추가
NAMES.DIRECTORY_PATH= (TNSNAMES, ONAMES, HOSTNAME)
Posted by Arawn Trackback 0 : Comment 0
봄싹 스터디의 HelolS 님이 던지신 화두 'OOP에 대해서..' 에 대해서 한번 생각해보았습니다.

그 동안 OOP에 관해 책을 비롯해서 많은 자료를 읽어보고 뜻을 헤아려보기 위해 많은 시간을 보냈지만 아직까지 OO 에 대해 개념을 확실히 정립하기엔 많이 모자라네요. ^^

내가 알고(단지 외우고 있을뿐이지도 모르는...)있는 것을 정리해보니 짤막한 몇 줄만 나옵니다.


객체 지향이란 작지만 하나의 일을 책임질 수 있는 객체가 모여서 하나의 완전한 프로그램으로 만들어져 나아가는 것이다. 서로가 모르고 있더라도 일을 수행함이 있어 드러나는 문제를 최소화 시키고(낮은 결합도), 서로가 모여서 함께 일을 행함에 있어서도 좋은 틀을 제공해야한다.(높은 응집력)
하나의 언어를 통해 이야기 함으로 대화의 이해도를 높이고(인터페이스), 유별나게 변화를 좋아하는 녀석들을 위해서 항시 문을 열어둔다.(상속or확장)


세세하게 들어가면 이것저것 더 많은 것이 나오겠지만 지금은 저 정도밖에 정리가 되지를 않네요.

"지나친 것은 미치지 못한 것과 같다."라는 뜻을 가진 과유불급(過猶不及)이라는 고사 성어가 있습니다. 가끔 공부를 위해서 프로그램을 작성하다보면 내가 무리하게 분할해서 시스템을 오히려 복잡하는 만드는게 아닌가 라는 생각을 할때가 많습니다.

어디가 가장 적당한지를 긋는 선을 정하는게 참 어려운것 같습니다.
Posted by Arawn Trackback 1 : Comment 0
오전에 업무로 부랴부랴 시간을 보내고 오후부터 저번 스터디에서 발표했던 타칭 ORM 으로 불리우는 GenericDao에 주석을 정리하면서 시간을 보내던 중 HelloIS님으로부터 메시지가 왔다.

간단히 줄이자면 @Controller 에 대한 테스트를 방법을 찾아보고 계신다는 것이다.

얼마전에 whiteship님의 블로그에 포팅된 스프링 2.5 @MVC 컨트롤러 테스트에 관한 글도 비슷한 맥락에서 방법을 찾아보고 계신것 같았다. 덧글 중 토비님께서는 프레임워크의 테스트를 믿고 나가는게 맞지 않느냐를 말씀도 있으셨다.

테스트가 필요할까? 필요하지 않을까? 내 생각도 아직까지 정리가 되지 않고 있다. 애초에 프레임워크를 쓰는 이유 중 하나인 높은 생산성도 있을텐데 믿지 못하고 일일히 테스트를 한다면 어느 세월에 다 할것인가 싶기도 하지만 은근히 궁금하다. ^^;;

그리고 개발자도 사람인 이상 오타는 분명이 있을테니 @RequestMapping 어노테이션에 엉뚱한 URL 을 적어두고 딴데서 삽질하는 일이 있을수도 있지 않은가! -0-

그럼 어떻게 테스트를 할 수 있을까?

집에오면서 생각한게 가장 단순하게 생각하면 스프링 @MVC 는 DispatcherServlet 에서부터 시작된다는 것이다.

그럼 테스트 코드에서 DispatcherServlet 을 생성해서 사용하면 되지 않을까?

그래서 우선 다음과 같은 @Controller 을 만들었다.

@Controller
@RequestMapping("/hello/hello.htm")
public class HelloController {
   
    @RequestMapping(method=RequestMethod.GET)
    public String helloGet(HttpServletRequest req, HttpServletResponse res, ModelMap modelMap){
        modelMap.addAttribute("hello", "hi~ my name is GET");
        return "hello/get";
    }
   
    @RequestMapping(method=RequestMethod.POST)
    public String helloPost(HttpServletRequest req, HttpServletResponse res, ModelMap modelMap){
        modelMap.addAttribute("hello", "hi~ my name is POST");
        return "hello/post";
    }
}

그리고 설정 파일을 다음과 같이 만들었다.

<context:annotation-config />
<context:component-scan base-package="controllertest.controller" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"
          p:alwaysUseFullPath="true" />
         
<bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/view/jsp/"
          p:suffix=".jsp" />

마지막으로 테스트 코드를 다음과 같이 작성했다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/**/ApplicationContext.xml"})
public class HelloControllerTest {
   
    @Autowired
    ApplicationContext applicationContext;
   
    DispatcherServlet dispatcher;
   
    @SuppressWarnings("serial")
    public HelloControllerTest(){
        this.dispatcher = new DispatcherServlet() {
            protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
                GenericWebApplicationContext wac = new GenericWebApplicationContext();
                wac.setParent(applicationContext);
                wac.refresh();
                return wac;
            }
        };
        try {
            this.dispatcher.init(new MockServletConfig());
        } catch (ServletException e) {
            e.printStackTrace();
        }

    }
   
    @Test
    public void helloGet() throws Exception {     
       
        MockHttpServletRequest req = new MockHttpServletRequest("GET", "/hello/hello.htm");
        MockHttpServletResponse res = new MockHttpServletResponse();
       
        dispatcher.service(req, res);
       
        // HTTP 상태 검사
        Assert.assertEquals(200, res.getStatus());
       
        // Attribute 검사
        Object obj = req.getAttribute("hello");
        Assert.assertNotNull(obj);
       
        System.out.println(String.format("AttributeName : hello, Value : %s", obj));
       
        // 포워드 주소...
        System.out.println(res.getForwardedUrl());
    }
   
    @Test
    public void helloPost() throws Exception {

        MockHttpServletRequest req = new MockHttpServletRequest("POST", "/hello/hello.htm");
        MockHttpServletResponse res = new MockHttpServletResponse();
       
        dispatcher.service(req, res);
       
        // HTTP 상태 검사
        Assert.assertEquals(200, res.getStatus());
        // Attribute 검사
        Object obj = req.getAttribute("hello");
        Assert.assertNotNull(obj);
        System.out.println(String.format("AttributeName : hello, Value : %s", obj));
        // 포워드 주소...
        System.out.println(res.getForwardedUrl());
    }
   
    @Test
    public void hello() throws Exception {
       
        MockHttpServletRequest req = new MockHttpServletRequest("POST", "/hello/hello.ht");
        MockHttpServletResponse res = new MockHttpServletResponse();
       
        dispatcher.service(req, res);
       
        // HTTP 상태 검사
        Assert.assertEquals(404, res.getStatus());
    }   
}

위와 같이 작성 후 테스트를 실행하면 다음과 같은 결과를 얻을 수 있었다.

AttributeName : hello, Value : hi~ my name is GET
/WEB-INF/view/jsp/hello/get.jsp

AttributeName : hello, Value : hi~ my name is POST
/WEB-INF/view/jsp/hello/post.jsp

마지막 테스트 함수의 경우 올바른 경로를 입력하지 않았기 때문에 HTTP 상태는 404(파일없음)이 나오는 것이다.

이것이 올바른 방법으로 테스트가 되었고 결과값이 나온건이 대해서는 아직 확신이 없다.
Posted by Arawn Trackback 1 : Comment 3
ERP 에 관련된 업무를 해온지도 3년차로 접어들고 있다.

"서당개 3년이년 풍월을 읊는다."는 속담이 있다.

3년간 ERP 업무만 지속적으로 한 것은 아니지만, 상당한 시간을 해온 것에 비해 아직도 큰 틀의 흐름만 알뿐 세부적인 맥을 집어내기에는 많이 어설프다. 어떤 특정한 파트를 담당한게 아니라 두루뭉실하게 전 파트를 손을 담고 있어야 했기 때문이라고 변명은 해보지만 왠지 스스로가 더 초라해진다.

개발 능력도 중요하지만 그 만큼 중요한것은 업무적 능력도 있어야 한다고 들어왔고, 그렇게 생각하고 있지만 현실은 동떨어져 있다.

월요일에 책을 주문해서 어제 받았다. 그나마 오래 봐온 부분은 인사/급여와 회계 부분에 대한 공부를 해보려고 산 책이다.


이제 겨우 초입부분을 읽어보고 있지만 그간 업무 중 궁금했던 부분들이 풀리는거 같다. 용어가 상당히 어려워서 쉬이 접근은 힘들듯 하지만 몇번이고 읽어보고 근무중에도 짬짬히 참조해서 본다면 나 자신에 대한 또 한번의 발전을 기대 할 있을것 같다.

현재 의욕을 마지막까지 끌고나가기 위해 마음을 다잡아봐야겠다!
Posted by Arawn Trackback 0 : Comment 0
스터디 발표를 준비를 위해 예제를 작성하던 중 다음과 같은 오류를 만났다.

must override a superclass method

오버라이드를 하기 위해서는 슈퍼클래스의 메소드가 필요하다?

예제 소스를 살펴보니 상속받아서 슈퍼클래스가 존재하는 메소드의 경우에는 @Override 어노테이션이 오류가 나지 않지만 인터페이스 기반에서는 오류가 난다.

구글링을 통해서 알아보니 다음과 같은 글을 발견했다.


Annotation은 Java code만으로 전달할 수 없는 부가적인 정보를 컴파일러나 개발툴로 전달할 수 있다. @Override annotationsuper classinterface의method를 override하고 있음을 명시한다. 하지만, 사소한 syntax 실수 등으로 orverride가 구현되지 않는경우가 있는데, 이는 runtime 레벨에서 오작동 등으로 드러나게 되므로 그 원인을 찾기가 쉽지 않다. 여기에@Override annotation을 사용하면 compile 레벨에서 상위 메소드를 정확히 구현하고 있는지를 체크할 수 있다.@Override annotation이 컴파일러에게 Override method임을 알려주기 때문이다.

하지만, @Override annotation을 사용했을 때, must override a superclass method라는 에러가 발생한다면, 컴파일러의 버전을 의심할 필요가 있다. J2Se 5.0, 그러니까 JDK 1.5는 @Overrider annotation을 지원하지만, super class에 대해서 지원할뿐, Interface에 대해서는 지원하지 않는다. Interface에 대한 지원은 JDK 1.6을 사용할 때 가능하다.


예제 소스는 1.5 기반이었다. -0-;;

Posted by Arawn Trackback 0 : Comment 1

매번 신규 프로젝트를 생성할때마다 디렉토리 구조를 작성하고 POM 파일을 작성하고 dependency 를 설정하는 등의 불편함을 해소하고 위해 Maven 은 archetype 플러그인을 통한 프로젝트 생성을 지원한다.

Whiteship님이 archetype에 자세한 글을 올려놓으셨다. 글을 마지막부분을 보면 다음과 같이 적혀있다.

위에있는 Atchetype 중에서 맘에 드는 것이 없거나, 자신이 자주 사용하는 프로젝트 템플릿이 있다면 그것을 mvn install로 등록하여 사용할 수도 있습니다.

오호라... 자신만의 archetype 생성이 가능하다라. 이제까지 기본 형태를 만들어두고 zip 압축을 해놓았다가 복사해서 풀어서 쓰곤 했었는데 이번 기회에 archetype 으로 만들어보기로 했다.

작성법은 메이븐 공식 홈페이지Whiteship님의 글을 참고했다.

1. archetype 프로젝트 생성

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes
                               -DarchetypeArtifactId=maven-archetype-archetype
                               -DarchetypeVersion=1.0
                               -DgroupId=net.arawn
                               -DartifactId=arawn-springweb-base

위 명령을 실행하면 아래와 같은 구조의 프로젝트가 생성된다.

사용자 삽입 이미지

여느 일반적인 maven 프로젝트와는 구조가 조금 다르다. arawn-springweb-base/pom.xml 은 여느 maven 프로젝트와 유사한 내용을 가지고 있다. 후에 버전 변경이나 배포 저장소를 변경시에는 몇가지 추가할 내용이 있겠지만 기본값을 그대로 사용해도 문제없다. src/main/resources/ 하위의 디렉토리들이 실제 archetype 으로 생성될 내용들이다.

2. archetype 프로젝트 작성(pom.xml, .java 등)

빌드시 src/main/resources/META-INF/maven/archetype.xml 에 정의된 내용을 바탕으로 archetype-resources 의 파일들을 packing 한다.

src/main/resources/archetype-resources/pom.xml 에 소스 디렉토리 설정, 플러그인, 라이브러리 의존성 등을 설정하고 하위에 java source 나  resources file 들을 작성한다.

src/main/resources/META-INF/maven/archetype.xml 에는 archetype-resources 디렉토리에 있는 파일들을 목록을 정의해주어야한다.

<archetype>
    <id>arawn-springweb-base</id>
    <sources>
        <source>src/main/java/WebApplicationContext.xml</source>
        <source>src/main/java/controller/HelloController.java</source>
        <source>src/main/java/webservice/HelloService.java</source>
    </sources>
    <testSources>
        <source>src/test/java/ApplicationContext.xml</source>
        <source>src/test/java/webservice/HelloServiceTest.java</source>
    </testSources>
    <resources>
        <resource>src/main/webapp/WEB-INF/view/jsp/hello.jsp</resource>
        <resource>src/main/webapp/WEB-INF/web.xml</resource>
        <resource>src/main/webapp/index.jsp</resource>
    </resources>
</archetype>

sources, testSources 는 source(src/main/java, src/test/java) 디렉토리에 넣어준다. 기본적으로 프로젝트 생성시 설정한 groupId 를 기본값으로 package 를 배치해주는데 아래와 같이 프로젝트 생성시...

mvn archetype:create -DarchetypeGroupId=net.arawn
                               -DarchetypeArtifactId=arawn-springweb-base
                               -DarchetypeVersion=1.0.0
                               -DgroupId=net.arawn
                               -DartifactId=webtest

HelloController.java 의 위치는 아래와 같이 생성된다.

src/main/java/net/arawn/webservice/HelloService.java

여기서 주의해야 할 점이 있다. HelloService.java 파일의 내용은 아래와 같다.

package webservice;

public class HelloService {
    ...
}

소스를 작성하는 시점에서의 package 구조는 단순히 webservice 만이 존재한다. 배포 후 프로젝트를 생성시에는 패키지 구조가 변해버리면서 오류가 발생한다. 이 문제를 해결하는 방법은 아직까지 두가지 밖에 찾지 못했다. 첫번째는 모든 작업을 종료하고 배포 직전에 아래와 같이 소스를 변경하는것이다.

package ${groupId}.webservice;

public class HelloService {
    ...
}

${groupId} 는 프로젝트 생성시 자동적으로 설정한 groupId 의 값으로 변경될 것이다. 두번째 방법은 프로젝트 생성시 pkackageName 옵션을 설정해주는 것이다. 소스는 변경없이 아래 같이 pkackageName 값을 비워놓고 생성하면 된다.

mvn archetype:create ... -DpackageName=

어떤 방법을 사용하던 그리 깔끔하지 못한거 같다. 좀 더 좋은 방법을 찾아봐야겠다.

resources 는 디렉토리 구조 그대로 복사해준다. 만약 eclipse 프로젝트 형태로 archetype 을 만들생각이라면 이 태그에 eclipse 설정 파일(.project, .classpath 등)들을 등록하면된다.

3. archetype 설치 및 배포

Local Repository 에 설치하려면 /arawn-springweb-base 에서 mvn install 명령만 내리면 된다. 만약 mvn archetype:generate 명령을 통해서 프로젝트를 생성하려면 archetype-catalog.xml 파일을 작성해주어야 한다. 수동으로 작업해서 등록해도 되지만 mvn archetype:update-local-catalog 명령을 통해서 간단하게 등록 할 수 있다.

만약 사내(또는 본인)에서 운영하는 Repository(Artifactory, Nexus)가 있다면 deploy Goal 을 통해서 배포가 가능하다. 배포 방법에 관해서는 javajigi 님의 강좌글을 참고!

4. 새로운 Archetype 으로 프로젝트 생성하기

mvn archetype:create -DarchetypeGroupId=net.arawn
                               -DarchetypeArtifactId=arawn-springweb-base
                               -DarchetypeVersion=1.0.0
                               -DgroupId=net.arawn
                               -DartifactId=webtest

archetype-catalog.xml 를 작성했다면 mvn archetype:generate 도 가능하다.
Posted by Arawn Trackback 0 : Comment 2

처음 maven 을 접했을때 그 생소한 디렉토리 구조에 적응하기가 참 힘들었다. 그간 공부한다고 꾸역꾸역 해보면서 많이 적응했지만 솔직히 두어단계나 더 들어간 디렉토리 구조로 인해서 이클립스의 네비게이션의 영역을 줄이거나 늘리는 일이 빈번해 조금 짜증이 나기도 했다.

변경해서 사용할 방법을 찾아보던 중에 토비님의 Maven의 default directory layout 변경하기 를 발견하고는 간단한 테스트 프로젝트를 만들어서 적용해보니 깔금하게 적용이된다.

root에 src, test directory 를 두고 resource 와 testResource 는 해당되는 source directory 에 포함시켜버리고 나니 한결 깔끔해보인다. 남은건 src/main/webapp directory 를 root로 가져오는건데 생각외로 간단하게 변경이 가능하다.

이클립스의 m2eclipse 플러그인을 통해 import 나 maven-eclipse-plugin 을 통해서 변환 후 디렉토리를 보면 이클립스 프로젝트 파일들이 생성되어 있는데 그 중에서 .settings/org.eclipse.wst.common.component 를 열어보면 내용이 다음과 같다.



Maven 의 pom.xml 에서 packaging 타입을 war 로 변경 후 다시 변환하니 다음과 같이 변경되어 있다.



webapp 의 디렉토리가 src/main/webapp 로 설정되어 있다. 수작업으로 webapp 로 변경 후 root directory 에 webapp directory  를 복사 후 이클립스 내부에서 테스트해보니 문제없이 가동한다. 실제 tomcat 서버에 올려보기 위해서 mvn package 명령을 내리니 다음과 같은 오류가 발생했다.

[INFO] Error assembling WAR: Deployment descriptor: D:\...\maventest\target\test-1.0.0\WEB-INF\web.xml does not exist.

이클립스는 변경된 webapp 를 인식했지만 메이븐은 인식하지 못하고 src/main/webapp 를 찾다보니 일어난 현상인거 같다.

메이븐에게 webapp 의 알려주기 위한 방법은 다음과 같다. POM 의 build - plugins 에 추가한다.



이후 mvn package 내리면 오류없이 완료된다.

TAG maven
Posted by Arawn Trackback 3 : Comment 0
Annotation 기반 Controller 에서는 HTTP 요청 파라미터를 @RequestParam 을 사용해서 메소드의 파라미터로 바로 전달 할 수 있다.

@RequestParam 은 Key=Value 형태의 HTTP 요청 파라미터를 메소드의 파라미터에 전달해준다.





getBoard 메소드 호출시 Request 파라미터에서 "board_seq" 를 찾아 int board_seq 에 넣어둔다.

만약 HTTP 요청 중에 "board_seq" 가 없다면 Exception 이 발생한다.

org.springframework.web.bind.MissingServletRequestParameterException: Required int parameter 'board_seq' is not present

파라미터의 값이 필수가 아니라면 required 속성의 값을 설정해주면 된다. 기본값은 true 이다.



전달받는 파라미터 타입 또한 아주 민감하다. int 형으로 선언된 타입에 숫자가 아닌 다른값이 들어가면 유연한 행동을 보이지 않고 바로 Exception 을 발생시킨다. 그외에도 원시 유형의 변수에 null 값이 들어가도 마찬가지로 Exception 이 발생한다. ( int 보다는 Integer 래퍼(warpper) 를 사용하는게 안전할듯... )

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type [java.lang.String] to required type [int]; nested exception is java.lang.NumberFormatException: For input string: ""
Posted by Arawn Trackback 0 : Comment 3