블로그 이미지
Max.

calendar

          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

Notice

2012. 2. 23. 09:24 개발관련
블로그 쓸일이 점점 없어지는 요즘, 웬만한 것은 스킵해 버리는데, 웬만하지 않는 동영상이 공개(http://www.olccenter.or.kr/lec/detail.jsp?lec_idx=209) 되었다. 사실 이런 세미나가 자주 열렸으면 하는 바램이 있어 감상 내용을 간략히 쓴다. 세미나에 참석하진 못했지만, 이렇게 동영상으로 볼수 있으니 얼마나 좋은가 ^^

첫번째 강의인 'Spring-Test-MVC프로젝트 소개'는 부담없이 실무에서 적용해도 될만한 편리한 프로젝트인것 같다. web MVC를 테스트하는게 여간 귀찮은 작업이 아닌데, 빌더패턴을 이용한 테스트 방법이 인상적이다. 빨리 스프링 코어 프로젝트에 포함되었으면 좋겠다. 포함되지 않아도 선행 학습하여 Controller 구현을 빠르게 할수 있도록 하면 좋을듯 하다.

두번째 강의인 '스프링 3.1의 @Enable 기법을 활용한 설정 모듈화의 재사용 기법'는 정말 환상적이다.  이만한 강의를 한국어로 들을수 있다는게 정말 행운이 아닌가 싶다. 단순히 @Enable*  를 소개한것에 끝나는게 아니라, 현재 스프링 소스에서 적용하여 사용한 것까지 분석해서 그 통찰을 기반으로 모듈화 전략까지 이야기 하고 있다. 가만히 들어보고 생각해 보면, 이것이 뜻하는 그 가능성과 다양성을 대단히 크다.

내가 실로 오랫만이다. 이런 가능성에 전율했던 기억은 Spring Roo의 ITDs 기술 이후 처음이다(물론 그전에 AOP, @Configurable, DDD, @Hibernate 등 대충 여러개 있긴 하다). 현재 ITDs 기술이 내 학습 대상이듯, 이 @Enable*도 지속적인 학습 대상이 될듯 하다. 앞으로 시간이 허락하는 한 여러가지 기법들을 테스트해 보고 적용하기 위한 노하우를 쌓아야 겠다는 생각을 하게 된다.

아직 안보신 분들은, 다른 어떤 유료 강의나 책을 사보시기 전에 들어 보길 권한다. 지금 스프링에 어떤 디자인패턴을 적용할까 고민하는것 보다 중요한 영감을 받을수도 있으니까...짤리기 전에 어섯!...



 
posted by Max.

댓글을 달아 주세요

2011. 12. 21. 12:13 개발관련
Spring Roo 1.2.0.Release 를 이용한 Maven Multi Project에 대한 예시이다.

1) 실행 스크립트는 대충 아래와 같다.

E:\Projects\Test>mkdir max-roo

E:\Projects\Test>cd max-roo

E:\Projects\Test\max-roo>roo

roo> project --topLevelPackage net.max --packaging POM --projectName max-parent

roo> module create --moduleName max-core --topLevelPackage net.max.core --packaging JAR

max-core roo> module focus --moduleName ~

roo> module create --moduleName max-biz --topLevelPackage net.max.biz --packaging JAR

max-biz roo> module focus --moduleName ~

roo> module create --moduleName max-web --topLevelPackage net.max.web --packaging WAR

max-web roo> module focus --moduleName ~

roo> perform eclipse

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] max-core
[INFO] max-biz
[INFO] max-web
[INFO] max-parent
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building max-core 0.1.0.BUILD-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:clean (default-cli) @ max-core ---
[INFO] Deleting file: .project
[INFO] Deleting file: .classpath
[INFO] Deleting file: .wtpmodules
[INFO] Deleting file: .component
[INFO] Deleting file: org.eclipse.wst.common.component
[INFO] Deleting file: org.eclipse.wst.common.project.facet.core.xml
[INFO] Deleting file: org.eclipse.jdt.core.prefs
[INFO] Deleting file: org.eclipse.ajdt.ui.prefs
[INFO]
[INFO] >>> maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-core >>>
[INFO]
[INFO] --- aspectj-maven-plugin:1.2:compile (default) @ max-core ---
[INFO]
[INFO] <<< maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-core <<<
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-core ---
[INFO] Adding support for WTP version 2.0.
[INFO] Using Eclipse Workspace: null
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] Wrote settings to E:\Projects\Test\max-roo\max-core\.settings\org.eclipse.jdt.c
[INFO] Wrote Eclipse project for "max-core" to E:\Projects\Test\max-roo\max-core.
[INFO]
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building max-biz 0.1.0.BUILD-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:clean (default-cli) @ max-biz ---
[INFO] Deleting file: .project
[INFO] Deleting file: .classpath
[INFO] Deleting file: .wtpmodules
[INFO] Deleting file: .component
[INFO] Deleting file: org.eclipse.wst.common.component
[INFO] Deleting file: org.eclipse.wst.common.project.facet.core.xml
[INFO] Deleting file: org.eclipse.jdt.core.prefs
[INFO] Deleting file: org.eclipse.ajdt.ui.prefs
[INFO]
[INFO] >>> maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-biz >>>
[INFO]
[INFO] --- aspectj-maven-plugin:1.2:compile (default) @ max-biz ---
[INFO]
[INFO] <<< maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-biz <<<
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-biz ---
[INFO] Adding support for WTP version 2.0.
[INFO] Using Eclipse Workspace: null
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] Wrote settings to E:\Projects\Test\max-roo\max-biz\.settings\org.eclipse.jdt.co
[INFO] Wrote Eclipse project for "max-biz" to E:\Projects\Test\max-roo\max-biz.
[INFO]
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building max-web 0.1.0.BUILD-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:clean (default-cli) @ max-web ---
[INFO] Deleting file: .project
[INFO] Deleting file: .classpath
[INFO] Deleting file: .wtpmodules
[INFO] Deleting file: .component
[INFO] Deleting file: org.eclipse.wst.common.component
[INFO] Deleting file: org.eclipse.wst.common.project.facet.core.xml
[INFO] Deleting file: org.eclipse.jdt.core.prefs
[INFO] Deleting file: org.eclipse.ajdt.ui.prefs
[INFO]
[INFO] >>> maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-web >>>
[INFO]
[INFO] --- aspectj-maven-plugin:1.2:compile (default) @ max-web ---
[INFO]
[INFO] <<< maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-web <<<
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-web ---
[INFO] Adding support for WTP version 2.0.
[INFO] Using Eclipse Workspace: null
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] Wrote settings to E:\Projects\Test\max-roo\max-web\.settings\org.eclipse.jdt.co
[INFO] Wrote Eclipse project for "max-web" to E:\Projects\Test\max-roo\max-web.
[INFO]
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building max-parent 0.1.0.BUILD-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:clean (default-cli) @ max-parent ---
[INFO]
[INFO] >>> maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-parent >>>
[INFO]
[INFO] <<< maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-parent <<<
[INFO]
[INFO] --- maven-eclipse-plugin:2.7:eclipse (default-cli) @ max-parent ---
[INFO] Not running eclipse plugin goal for pom project
[INFO] Adding support for WTP version 2.0.
[INFO] Using Eclipse Workspace: null
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] max-core .......................................... SUCCESS [1.701s]
[INFO] max-biz ........................................... SUCCESS [0.063s]
[INFO] max-web ........................................... SUCCESS [0.060s]
[INFO] max-parent ........................................ SUCCESS [0.273s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.569s
[INFO] Finished at: Wed Dec 21 12:04:25 KST 2011
[INFO] Final Memory: 7M/17M
[INFO] ------------------------------------------------------------------------
roo> roo> q

2) 생성된 소스코드를 import하면 이클립스에서 잘 인식된다. 아래 소스코드 첨부
posted by Max.

댓글을 달아 주세요

  1. 오늘... SS에 멀티모듈에 대한 스캐가 올라 왔군... https://www.youtube.com/watch?v=U2L82-D7uxY&feature=player_embedded

2011. 11. 15. 15:53 개발관련
1) 템플릿으로 사용할 적당한 maven 예제 프로젝트를 선택한다.

d:\projects\test

ex)  

  <groupId>com.max.sample</groupId>

  <artifactId>sample-max</artifactId>
  <version>1.0.0.M1</version>  



2) archetype create 로 템플릿 프로젝트 생성하기

mvn archetype:create-from-project

ex)
  <groupId>com.max.sample</groupId>

  <artifactId>sample-max-archetype</artifactId>
  <version>1.0.0.M1</version> 



3) install 로 local repository에 등록하기

mvn clean install



4) archetype generate 로 템플릿 가져오기, (적당한 위치에...)

mvn archetype:generate -DarchetypeGroupId=com.max.sample -DarchetypeArtifactId=sample-max-archetype -DarchetypeVersion=1.0.0.M1


아래와 같은 대화창에 정보를 입력한다.

Define value for property 'groupId': : net.max.test
Define value for property 'artifactId': : max-test
Define value for property 'version':  1.0-SNAPSHOT: : 1.0.0-SNAPSHOT
Define value for property 'package':  net.max.test: : <Enter> or net.max.test.sample

Confirm properties configuration:
groupId: net.max.test
artifactId: max-test
version: 1.0.0-SNAPSHOT
package: net.max.test
 Y: : Y <Enter>
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
... 



5) Test 확인
   - IDE에서 import하고, 예제 Unit Test를 돌려서 확인한다.


덤) 
 - 만약 원격 저장소에 넣고 싶다면, 3)에서 deploy 하고, 4)에서 -DremoteRepositories={repository url} 을 추가 하면 된다.
 - 4)번 명령어가 복잡하다면, mvn archetype:generate -DarchetypeCatalog=local 로 단순하게 할수도있다.
 
posted by Max.

댓글을 달아 주세요

2011. 10. 17. 08:31 개발관련
어디를 보든, Roo 에 대한, 최대 장점은 생산성이 아주 높아진다는 것에 있다. 처음 접할때 가장 눈에 띄는 것도 그점이다. 한두줄의 명령어로 엄청난 소스코드를 생성해 버리니까 그럴만한 강력한 인식이 생겨나는것도 무리가 아니다. 그러나, 생산량의 엄청난 증가가 생산성 향상에 관련이 있을까? 생산성에 대한 정의를 잘~ 해보면, 약간 다른 관점으로 볼수 있다. 생산성에 대한 정의는 사람마다, 조직마다 다를수 있다. 적어도 나는 단순한 생산량의 증가가 생산성 증가를 가져다 준다고 생각하지 않는다.


그럼 Roo 에서 말하는 생산성은 어떤 관점일까? 그것은 생산량에 대한 관리의 용의성이 높이는 것을 하나의 생산성의 관점으로 본것이라 생각한다. (정확히 한 관점이지 모든 것을 뜻하는게 아니다. 적어도 품질관점에 관해서는 언급하지 않았으니까...) 그러니까, 단순히 모든 관점에서의 생산성을 높여준다고 이해하기 보다는, 특정한 측면에서 생산성을 높여준다고 생각해야 하는데, 그게 단순히 코드량를 뜻하진 않는다는 것을 강조하고 싶은것이다. Roo 하면 그런 코드량 때문에 생산성 이야기가 화두인데, 그것이 핵심이 아니라는  것이다. 무엇이 핵심일까?


'생산량에 대한 관리의 용의성'은 복잡성과도 관련되어 있다. 복잡성은 생산성과도 관련되어 있고...어쨌든, 저 문장에 집중해 보면, 아니 풀이해 보면, Roo에서 생산한 소스코드에 대해 관리를 잘한다는것이다. 관리를 잘 한다는것이 바로 핵심이다. 


생성되는 코드는 특정한 기준으로 분리되어 있다가 조합 되어진다. 마치 레고 블럭과도 같다. 이것이 주는 장점은 무엇일까, 이것은 우리가 객체를 클래스 단위로 분리하는 이유와 비슷하고, 패키지(네임스페이스) 단위로 분류하는 것과도 비슷하며, Layered Architecture와도 비슷하다. 우리는 이런것으로 부터 많은 이점을 얻는다. Roo는 그것을 클래스 단위까지 적용시킨 것이다. 너무 비약일지 모르지만, 단순이 세부 기술인 ITDs를 이용했다느니, finder 같은 엑티브 레코드 패턴 구현체로만 인식하기엔 서운함이 있다.


결과적으로 Roo 에서의 생산성 극대화는 소스코드의 생산량의 극대화가 아니라, 관심의 분리(SOC)로 인한 복잡성 관리의 극대화를 노리고 있는게 합당하다.



'왜 이렇게 보고 있는가'에 대한 다른 도움말로는, '도메인주도개발(DDD)' 과 '소프트웨어 복잡성'에 대한 사전 이해가 도움이 될텐데, 나는 이 두가지에 대해 설명할수 있을 정도로 이분야에 대해 아는게 없다. 인터넷에서 관련해서 좋은 글을 본적이 있는것 같은데, 어디서 봤는지 알수 없다.(어쩌면 책에서 봤는지도 모르겠다)



posted by Max.

댓글을 달아 주세요

2011. 10. 11. 17:28 개발관련
나는 Spring Roo을 다양한 관점에 바라볼 필요가 있다고 생각한다. 혹자는 DDD 관점에서 Roo에 대해 툴 관점의 특징만 비교하기도 한다. 분명히 잘못되었다. 태생의 루와 지금의 루가 형식이 다르더라도 철학은 함께하고 있다고 믿기 때문이다. 어쨌든 그것은 나중에 이야기 하자. 이제, 루에 대해 툴 관점에서 바라보고 이야기해 보자.


제목의 복잡하다는 것과 단순하다는 것에 대한 정의가 모호하지만, 일반적인 웹 프로젝트라고 할수 있는 것에 적용이 불가능할것이라는 생각이 지배적인것 같다.  이유는 가끔 뻑이 나는 빌드 스크립트와 다양한 도메인에 맞게 자동생성되어야 하는 소스코드의 기능이 안전하게 제공되지 않는것에 대한 불안감에서 나오는 것이다. 즉, 입맞에 맞게(다양한 환경에 적응 가능하게) 제대로 실행되는걸 기대하기 어렵기 때문인것 같다. 그래서 아주 단순한 웹사이트나 가능한 툴로 인식해버리려 할것이다. 아마도 원하는 기대는 완전한 소스코드가 생성되고, 어떤 도메인이든, 어떤 경우에도 알맞게 코드가 생성되어야 만족할만한 툴로 인식할 것이다.

내 생각에 아마도 위와 같은 기대를 채워줄수 있는 툴은 세상에 나올수 없다. 설령 기술적으로 가능하더라도 지향해서는 안될일이다.

몇가지 의문을 품어 보자. Spring Roo는 무엇일까? 어떻게 세상에 나왔나?, Spring Roo가 왜 addon 기반으로 발전할수 있게 구성 하였을까(단순히 OSGi를 지향하기 위해서는 아닐것이다)?, Spring Roo 커뮤니티가 활발한 이유는 무엇일까?...



특정 도메인의 뼈대가 되는 구조는 그 도메인 특성이 반영되야 한다. 같은 RESTful 기반의 시스템도 특성에 따라 하부 주조가 너무나 다양하게 구성될수 있다. 또한 특정기능에 대한 공통기능도 다 차이가 있을수 밖에 없다. Spring Roo는 그런 뼈대 구조와 반복적인 기능을 효과적으로 제공할수 있는 기틀을 마련해 주는 것이다(이것이 의미하는 것은 무엇인가). 따라서 기본 addon을 수정할수 있어야 하고, 필요에 따라 추가적인 addon을 만들어 낼수 있어야 한다. 그렇치 못한다면, Roo는 실무 프로젝트에서 사용할수 없은 교육용 툴에 지나지 않는 것이다. 


Roo에 대한 특징 중 소스코드 생성 때문에 생산성이 상당히 향상되리라 믿는 사람도 있다. 하지만, 생산량이 많을진 몰라도 생산성이 그리 높지는 않다. 이부분도 나중에 한번 이야기해 보자...

(초창기 Roo에 대한 토비님이 남겨 놓은 귀중한 자료도 있다.  http://toby.epril.com/?p=346 여기를 참조해 보자.)
posted by Max.

댓글을 달아 주세요

2011. 9. 22. 08:53 개발관련
ContentNegotiatingViewResolver 를 사용하면서 BeanNameViewResolver를 사용한다는게 단순하게 되지 않았다. 아래처럼 설정하면 될것 같지만,

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
   <map>
       <entry key="html" value="text/html"/>
       <entry key="xml" value="text/xml"/>
       <entry key="json" value="application/json"/>
                        <entry key="xls" value="#{ themeExcelView.getContentType() }"/> 
   </map>
</property>
<property name="viewResolvers">
   <list>
   <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>
   </list>
</property>
<property name="defaultViews">
   <list>
      <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
    </list>
</property>
</bean>



안된다. 무슨 이유인지  viewResolvers 들이 제대로 동작 하지 않는다. 아마도 적절한 key(Header)를 찾지 못하여 매핑이 이루어 지지 않는듯 하다. 해서, ContentNegotiatingViewResolver 에서 매핑되지 않는것을 다시 BeanNameViewResolver로 매핑하게 하면 해결된다. 즉 아래처럼 설정하면, 
 

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
   <map>
       <entry key="xml" value="text/xml"/>
       <entry key="json" value="application/json"/>
   </map>
</property>
<property name="viewResolvers">
   <list>
    <ref bean="beanNameViewResolver"/>
    <ref bean="internalResourceViewResolver"/>
   </list>
</property>
<property name="defaultViews">
   <list>
      <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
    </list>
</property>
<property name="order" value="1"/>
<property name="ignoreAcceptHeader" value="true"/>
</bean>
    <bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="2"/>
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>


ContentNegotiatingViewResolver 에서 매핑되지 않은 뷰들은 아래 뷰리졸버(BeanNameViewResolver)에 의해서 다시 매핑을 시도할것이다. 설정이 어째 중복되는듯해서 찜찜하지만, 어노테이션으로 AbstractExcelView를 확장한 각종 Excel뷰를 매핑하기 위해 어쩔수는 선택이였다.

ContentNegotiatingViewResolver 를 제대로 알면, 우화한 방법이 있을듯 한데...  ContentNegotiatingViewResolverTests.java 를 보면서 좀더 학습해야 할듯 하다. 


 
posted by Max.

댓글을 달아 주세요

  1. 홍창민 2012.04.09 15:59  Addr Edit/Del Reply

    역시 윤부장님 정보가 깔끔하구먼요 ㅋㅋㅋ '-')b

2011. 9. 5. 11:39 개발관련
사실은 jeus5에서 사용하는 java 버전 스팩에 관한 문제이다.

1) JSTL, EL Exception
Jeus5.0에서 JSTL 1.2  을지원 하지 않는 문제이다. 1.1로 낮추고, apache의 taglibs.jar를 별도로 추가해야 된다.

2) jersey-json 1.2 에서 JAXB Exception
Jeus5.0에서 JAXB2.x 버전을 지원 하지 않는 문제이다. jersey-json 소스를 수정하여 JAXB2.X 와 의존성를 제거해야 한다. 쉽지 않다. 차라리 Spring RestTemplate를 사용하고, .Castor 같은 걸로 처리하는게 빠르다.  Hibernate validation 같은 JAXB2 관련 의존성을 사용해도 무방하다. JAXB1과 충돌하지 않으니까...



 
posted by Max.
TAG jeus5

댓글을 달아 주세요

2011. 9. 1. 08:40 개발관련

1) ExternalInterface.call 예제

최초 Flex App이 웹화면에 띄워질때 Javascript function을 읽어 들인다. 

mxml

private function getData(event:MouseEvent):void{
searchDate = ExternalInterface.call( "getFlexDate", "test");
if(searchDate.context == null){
searchDate = new Object();
searchDate.context = "http://localhost:8088";
searchDate.startDate = "2011-08-01";
searchDate.endDate = "2011-08-29";
searchDate.selectId="";
}
searchDate.context = searchDate.context + amf;
//Alert.show(searchDate.context + " : " + searchDate.startDate + " ~ " + searchDate.endDate); 
callChanel(searchDate);
}
private function callChanel(sd:Object):void{
var ch:AMFChannel = new AMFChannel();
ch.url = sd.context;
ch.id = "amf";
remotingChannels  = new ChannelSet();
remotingChannels.addChannel(ch);
channelHandler(sd.startDate, sd.endDate);


Html(Javascript)

function getFlexDate(txt){
var searchDate = new Object();
searchDate.startDate = "2011-08-01";
searchDate.endDate = "2011-08-19";
searchDate.context="http://localhost:8088";
searchDate.country="";
return searchDate;
}


최초 시작시 관련 값을 읽을때 편리한다. 

 
2)  ExternalInterface.addCallback  예제

Javascript 로 특정 Flex(Actionscript) function을 호출 하고자 할때, 예를 들어 검색폼이 Html이고, 그값을 Flex에 전달하고 싶을때 사용한다.

mxml

       //creationComplete="init()" 이 상단에 선언되 있음.

            [Bindable] public var searchDate:Object;
    public var realFunction:Function = callFlexReal;
 
private function init():void{
ExternalInterface.addCallback("callFlex", realFunction);
}
 
  public function callFlexReal(sd:Object):void {
sd.context = sd.context + amf;
searchDate = sd;
//Alert.show(searchDate.context + " : " + searchDate.startDate + " ~ " + searchDate.endDate); 
callChanel(searchDate);
}


Html(Javascript)


function callFlex() {
            var searchDate = new Object();
searchDate.context = "http://localhost:8088";
searchDate.startDate = "2011-08-01";
searchDate.endDate = "2011-08-29";
searchDate.country="";
alert(searchDate);
            getMovieName("${application}").callFlex(searchDate); 
            }

            function getMovieName(movieName) {
           if (navigator.appName.indexOf("Microsoft") != -1) {
            return window[movieName]
           }else {
            return document[movieName]
           }
            }

<a href="#" onclick="callFlex()">callFlex()</a>


 
 ${application}는 flash object tag 아이디 명이다. flex builder를 사용한다면, index.template.html 에당 코드를 볼수 있고, 대략 정의하면 된다.   ExternalInterface.addCallback은 한번에 안되었는데, 이유가 이 플래시 Object 아이디명을 정확하게 설정하지 않아서 였다.
posted by Max.

댓글을 달아 주세요

2011. 8. 26. 12:07 개발관련

먼저 업데이트할 기능을 추가하고, 저장소에 결과물을 반영한다.

1) addon 소스 수정
    - 'max web' 명령어에 '--entity' 옵션항을 추가하고 기능을 업데이트 함.

2) compile
   - 도스창에서 mvn assembly:assembly 실행하여, jar 생성

3) 결과물을 repository에 전송
    - eclipse를 이용하여 커밋 



최신 번들을 다운받아 사용한다.

1) 기존 OSGi 번들 제거
    - 'max osgi uninstall'

2) 새로 업데이트된 번들 넣기
    - 'max osgi install --version 1.0.0.M2'

3) 테스트 하기
    - 'max web --class ~.template.web.TemplateController --service ~.template.service.TemplateService --entity ~.template.domain.ContentPage' 을 실행하여 jsp 페이지까지 생성되면 성공이다.


 
SNG 프로젝트에 필요할때마다 수정해서 적용중인데, 불편하거나, 버그가 있을때 바로 수정해서 사용하기 편리하다. OSGi 번들의 장점을 어느정도 느낄수 있다. 특히 여러가지 과정을 max osgi install로 묶어놔서 더욱 편리하게 사용할수 있는 점이 좋은 것 같다.


 
posted by Max.
TAG ROO, Spring

댓글을 달아 주세요

2011. 8. 22. 19:56 개발관련
1) 현재 환경이 JDK1.5 이므로, jersey 버전이 낮다(1.2 버젼이다. 1.3은 JDK1.6부터 지원한다). 해당 버전에서는 잘 알려진 버그가 있는데, json으로 array를 전송시, 한개 이상만, array로 보내고, 미만은 일반 객체로 넘겨 버린다. 클라이언트에서 관련 처리를 해주면 좋겠지만, 일관성 측면에서 서버측에서 지속적으로 array로 보낼 필요가 있을 때 이와 같은 방법을 사용해 볼수 있다.


2) 간단히 확장 클래스를 만든다. 아래는 인터넷에 뒤져보면 흔히 볼수 있는 코드와 비슷하다.

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final JAXBContext context;
    private final Set<Class> types;
    private Class<?>[] cTypes ;
    public JAXBContextResolver(Class<?>[] __cTypes) throws Exception {
this.cTypes = __cTypes;
        this.types = new HashSet(Arrays.asList(cTypes));
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), cTypes);
    }
    
    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}



3) DI 한다. 이때 변환될 모델을 필요한 만큼 등록한다.

    <bean class="com.xxx.jersey.resolver.JAXBContextResolver" scope="singleton">
    <constructor-arg>
    <list>
<value>xxx.domain.ChannelDsResponse</value>
<value>zzz.domain.CategoryDsResponse</value>
<value>yyy.domain.CountryDsResponse</value>
<value>www.DirtyWordsDsResponse</value>
</list>
    </constructor-arg>
    </bean>


 4) Test 코드
 

  @Test
    public void testResponseJson() throws IllegalArgumentException, IOException {
        ClientResponse clientResponse = webResource.path("/webservice/rest/Channel/KR/Channels/Category/01000000/1")
        .accept("application/json").get(ClientResponse.class);
        System.out.println("just 1: ===============================================");
    System.out.println(clientResponse.getHeaders());
    System.out.println(clientResponse.getEntity(String.class));
    System.out.println("just 1: ===============================================");
   
    clientResponse = webResource.path("/webservice/rest/Channel/KR/Channels/Category/01000000/2")
    .accept("application/json").get(ClientResponse.class);
    System.out.println("over 2: ===============================================");
    System.out.println(clientResponse.getHeaders());
    System.out.println(clientResponse.getEntity(String.class));
    System.out.println("over 2: ===============================================");
    }


5) 결과

just 1: =============================================== {Date=[Mon, 22 Aug 2011 10:46:50 GMT], Server=[Apache-Coyote/1.1], Content-Type=[ {"resultCode":0,"resultMessage":"","channels":[{"categories":[{"id":"01000000"}], just 1: =============================================== over 2: =============================================== {Date=[Mon, 22 Aug 2011 10:46:50 GMT], Server=[Apache-Coyote/1.1], Content-Type=[ {"resultCode":0,"resultMessage":"","channels":[{"categories":[{"id":"01000000"}], over 2: ===============================================


@Autowired로 DI 할수 있겠으나, 추가할 모델(Bean)들을 언제 늘어날지 모르므로 XML 설정파일로 하는게 편리할듯 싶다. 다른 버전에서는 잘 되는지 확인하지 않았다. 
posted by Max.
TAG array, jersey, JSON

댓글을 달아 주세요