Terry.Li-彬

          虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks
          Spring3.0之前大家集成GWT基本上都是用 GWT- Widget/Server Library ,現在最新的Spring發布包提供了REST支持,使用這種方式更自然。其實這是一個老外的博客上提出來 的:http://bigohno.blogspot.com/2009/04/gwt-spring-mvc-and-rest-on-google- app.html

          只是這位同志哥只提出了一個概念和其中使用到的一些技術,但是沒有細節和代碼,我幾乎花了近兩周的時間才把一個完整的業務流程順利跑通。當然這也是由于我是第一次使用Gwt1.6,Spring MVC,REST,JSONlib,Restlet,Maven。

          也 許你們注意到了,除了后臺的openCRX/MDX是我研究多年的技術,其他技術除了spring,幾乎都是完全沒有接觸過。然而,也因為這樣,當我完成 了整個框架基本功能的調試運行之后,得出的結論是:其他技術可以不用,Maven2一定要用,Gwt可以不用,SpringMVC/REST一定要用。

          當然了,很多只使用過Ant的同志,對于Maven可能覺得可有可無,夠用就好。但是,Maven絕不僅僅是構建,而是幫你管理了整個項目的外部資源、內部構建和單元測試的自動化過程。可以這樣說,一旦用過Maven,你就再也不愿意去做沒有Maven的項目。

          SpringMVC是一個較早出現的技術,以前大家習慣使用Struts1或者2作為MVC的實現框架,Spring技術與之相比并沒有太大的優勢,所以很多人沒有用過SpringMVC包括很多老革命在內。在最新的Spring3.0M2中已經加入了REST,這使得我第一次體驗到了AnnotationViewResolver的強大,當然最關鍵的起因在于REST本身就是一個非常吸引人的技術框架。而Rest的出現,個人認為是來自于對Ajax框架最好的支持。

          前面是宣傳一下新技術,下面先給大伙兒上張系統架構圖:


          對 于使用其他后臺程序的項目,可以簡單的用自己的Service替換openCRX API。說到這里,如果使用Maven進行以來管理和打包,那么會有一個很直接的好處,就是GWT的幾個包,不需要手工編寫腳本來區分開發時使用和部署時 使用,而是簡單的配置一下scope屬性就可以了。另外需要更新spring最新版本的jar包時,也不需要手工去下載更新,只是簡單的修改一下版本號就 可以了。
          特別要說的是:當使用SpringAOP特性的時候,需要一個cglib2的包,當我自己從網上搜索時下載的包死活無法正常運行,而我簡 單的加入了SpringAOP自己的pom中所使用的依賴之后,就很順利的啟動了。這讓我不禁暢想,如果所有的項目都使用maven發布自己的庫,那是多 美妙的事情呀。
          很遺憾,opencrx/mdx就沒有一個自己的maven repository——還好我在網上偶然發現一篇博客介紹一款maven repository代理軟件,這下可好了,對于一個項目組的成員或者整個公司來說,都可以搭建這樣一個本地庫,就可以“一次導入,到處更新”了,哈 哈。。。
          到這里,相信大家對于這個“最新技術”所組成的“最新框架”應該有一個大致的印象了,下次介紹如何建立一個基于maven 的GWT1.6+Spring3.0的Eclipse工程。


          這次就是關于如何 使用Maven2快速搭建一個支持GWT1.6和Spring3.0的Eclipse工程,這可以幫助我們用最快的速度開始真正的開發。

          1.這里,Maven for Google Appengine Java,是一篇介紹如何基于Maven搭建基于google appengine的工程,我們可以利用它先建好一個gwt的工程,照著圖文教程一步步做,之后就會得到一個標準的maven工程。

          2. 執行mvn eclipse:eclipse,這樣可以生成eclipse所需要的工程文件和classpath.這里要注意:如果你不需要支持google appengine那么就需要修改pom.xml文件中,把有關appengine的三個dependency注釋掉,并且工程目錄下的 build.xml也是可以刪除的

          3.仍然是修改pom.xml文件,加入對于spring3.0的依賴。這里要注意兩點:一、前面提到 的那篇博客里面所說的加入一個dependency來加入spring3.0的支持,似乎已經過時了,結果是一個包都加不進來。我在網上搜索過很多有關 spring3.0 maven的文章,最后只有一個spring官方論壇中的帖子是有效的,但是連接已經找不到了,我就直接貼出這一段dependency了:
          <dependency>
          ??? ??? ??? <groupId>asm</groupId>
          ??? ??? ??? <artifactId>asm-commons</artifactId>
          ??? ??? ??? <version>2.2.3</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>asm</groupId>
          ??? ??? ??? <artifactId>asm</artifactId>
          ??? ??? ??? <version>2.2.3</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.core</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.web</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.transaction</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.orm</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.jdbc</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.web.servlet</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.context</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.aop</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.expression</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework</groupId>
          ??? ??? ??? <artifactId>org.springframework.test</artifactId>
          ??? ??? ??? <version>${spring.version}</version>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>org.springframework.webflow</groupId>
          ??? ??? ??? <artifactId>org.springframework.js</artifactId>
          ??? ??? ??? <version>${webflow.version}</version>
          ??? ??? </dependency>
          <dependency>
          ??? ??? ??? <groupId>net.sourceforge.cglib</groupId>
          ??? ??? ??? <artifactId>com.springsource.net.sf.cglib</artifactId>
          ??? ??? ??? <version>2.1.3</version>
          ??? ??? </dependency>
          注 意:asm和cglib都是spring的依賴包,但有于是可選,所以不能在默認情況下加進工程庫中。本來也可以修改相應的spring dependency條目,但是我在公司機器上沒有maven pom編輯器,就偷一下懶,直接引用了。大家記得,有條件一定要裝一個maven eclipse的插件,特別是pom編輯器的插件,能夠極大提高生產力。

          4.加入restlet和jsonlib的dependency條目,這兩個都可以在網上找到,但是要注意一點:因為他們會依賴spring2.5.6的包,這會和我們現在的spring3.0沖突,所以需要加入一個exclusion條目

          5.加入opencrx/mdx依賴,但是實際上opencrx/mdx開發小組沉迷于cvs/ant之中,給我的答復是:現狀很好,無須改變。沒辦法只好自食其力了.
          首先,自行定義opencrx/mdx的groupId,artifactId,下面可以參考:
          <dependency>
          ??? ??? ??? <groupId>opencrx</groupId>
          ??? ??? ??? <artifactId>opencrx-application</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>opencrx</groupId>
          ??? ??? ??? <artifactId>opencrx-base</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>opencrx</groupId>
          ??? ??? ??? <artifactId>opencrx-extension</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>opencrx</groupId>
          ??? ??? ??? <artifactId>opencrx-kernel</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>opencrx</groupId>
          ??? ??? ??? <artifactId>opencrx-mail</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>opencrx</groupId>
          ??? ??? ??? <artifactId>opencrx-security</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.core</groupId>
          ??? ??? ??? <artifactId>openmdx-application</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.core</groupId>
          ??? ??? ??? <artifactId>openmdx-base</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.core</groupId>
          ??? ??? ??? <artifactId>openmdx-base-ext</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.core</groupId>
          ??? ??? ??? <artifactId>openmdx-system</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.core</groupId>
          ??? ??? ??? <artifactId>tomcat-juli</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.portal</groupId>
          ??? ??? ??? <artifactId>openmdx-portal</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.security</groupId>
          ??? ??? ??? <artifactId>openmdx-ldap</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.security</groupId>
          ??? ??? ??? <artifactId>openmdx-radius</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          ??? ??? <dependency>
          ??? ??? ??? <groupId>openmdx.security</groupId>
          ??? ??? ??? <artifactId>openmdx-security</artifactId>
          ??? ??? ??? <version>2.4.1</version>
          ??? ??? ??? <scope>provided</scope>
          ??? ??? </dependency>
          其次,手工安裝相應的jar包到maven repository。這里有一個可選項,就是在本地網上安裝maven repository代理服務器,那么可以統一安裝在這臺服務器上,所有開發人員可以從這里統一更新所有的開發用jar包。

          6. 以上整個過程中,如果你是在eclipse環境中,并且安裝了maven-elcipse插件,那么每次修改了pom.xml文件,都會自動進行 maven upate,這樣會驗證其中所有的依賴包的有效性。如果沒有問題,那么可以執行:mvn install,把整個工程構建并打包到本地maven repository之中。因為本人對于Maven研究還不深入,所以把部署的任務也放到了install之中執行。理論上說,可以增加maven build的run命令在eclipse里面,這樣可以更方便。大家如果有知道這個方法的,請告知。

          最后總結一下:如果你對maven有 更深的了解,就會發現更多的驚喜。同樣限于時間,我還沒有加入編譯gwt的任務到pom中,簡單嘗試下,可以進行編譯但是不能生成靜態頁面到我指定的目 錄,等有時間再加上這個吧,這樣就可以整合gwt compile和deploy into tomcat的任務了。另外,順便對比一下maven和ant的build,在maven下一旦包安裝好整個過程不超過10s.但是如果沒有注釋掉 appengine就會耗費2分鐘以上,我也沒去研究這到底是什么原因,大家可以自己研究看看,相信其中可以發現更多的功能和收獲更多的開發樂趣。


          第一篇中,有一張整個架構的示意圖,其中聯系前臺和后臺的是http/Rest標準協議。現在我們就先從前臺所使用的技術GWT和Restlet開始。

          1.GWT 作為一種基于java開發Ajax頁面的技術框架,真正的發展是開始于1.5版本(支持了大部分java5的特性和庫),到了1.6又再一次進行了大的修 訂。目前來說,它的最大優勢就是支持大量開源的控件,包括gwt-ext,smartgwt等等,和另外一個要強調的,所見即所得的編輯器GWT Designer(目前似乎已經被更名為window builder),有了這兩點,對于java/j2ee開發人員來說幾乎是接近了C/S時代RAD的開發效率了。可惜的是,對于一個完整的web應用來說 web ui僅僅是前臺的一部分,在webservice/rest協議出現前,前端展現和后臺程序耦合性達到了令人發指的地步。GWT也因此沒有更大范圍的流行 起來,特別是國內,幾乎看不到使用gwt成功的案例。難以設計/改變風格,不熟悉/適應這種開發方式,都是讓人難以接近的原因。

          2.Restlet 本身是一個完整的Rest實現框架,包括了前端、后臺以及和其他技術的集成模塊,我們在這里僅僅使用了和GWT集成的Restlet-GWT模塊,大家有 興趣也可以去restlet官方網站查看其它解決方案。不得不說,restlet在對于REST支持的領域上已經遠遠領先,特別是和GWT的集成上,幾乎 為開發人員周到的考慮到了方方面面的需求,簡化了GWT遠程調用的繁瑣(2個接口類、一個實現類再加上servlet的申明),對于get/post /put/delete來說,都僅僅幾行代碼就可以實現,下面是一個get方法的例子:
          ?? ? ? ? ? ?public void onClick(Widget sender) {
          ?? ? ? ? ? ? ? ?// Add an AJAX call to the server
          ?? ? ? ? ? ? ? ?final Client client = new Client(Protocol.HTTP);
          ?? ? ? ? ? ? ? ?client.get("http://localhost:8888/ping", new Callback() {
          ?? ? ? ? ? ? ? ? ? ?@Override
          ?? ? ? ? ? ? ? ? ? ?public void onEvent(Request request, Response response) {
          ?? ? ? ? ? ? ? ? ? ? ? ?button.setText(response.getEntity().getText());
          ?? ? ? ? ? ? ? ? ? ?}
          ?? ? ? ? ? ? ? ?});
          ?? ? ? ? ? ? ? ?dialogBox.hide();
          ?? ? ? ? ? ?}

          3.對于頁面流程、驗證/異常處理以及權限控制,在GWT框架下,都是一種新的挑戰,但是也可以借鑒C/S的開發經驗。
          基 于角色和頁面的編號,可以處理功能權限,基于角色的參數管理,可以控制相應的數據權限,基于opencrx可以提供SaaS的數據分區控制。驗證和異常處 理依然可以分成前后臺,分別處理。基于GWT,已經簡化了web flow的處理,但是也同時綁定了業務處理的部分流程,只有通過盡可能多的重用頁面組件來提供工作流程的靈活性。


          服務器的現在最流行的框架就是Spring了,在Spring3.0 MVC中推出了REST的支持,正好可以和前端GWT+Restlet實現緊密而又松耦合的集成。
          加 上提供JSONView的JSON-lib和后臺持久層的opencrx,一個完整的后臺框架由Spring+Jsonlib+opencrx來實現。其 中所有的service和controller以及opencrxContext對象都是由spring進行管理,但是對于數據庫事務,由于 opencrx api的使用,需要顯式的在代碼中聲明,這是一個小小的遺憾,好在所有的業務已經是對于Opencrx api的封裝了,所以事務處理是獨立且無需互相引用了。下面是spring配置文件的部分(包括了 jsonview,opencrxContext,controller等等的聲明):
          <!-- Dispatches requests mapped to POJO @Controllers implementations -->
          <bean
          class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

          <!-- ?gwt handler -->
          <bean name="jsonView" class="com.omdasoft.core.ui.server.view.EISCoreJsonView" />
          <!--
          Maps request paths to @Controller classes; e.g. a path of /person
          looks for a controller named PersonController
          -->
          <bean
          class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
          <property name="order" value="0" />
          </bean>
          <context:component-scan base-package="com.omdasoft.core.ui.server.mvc"
          use-default-filters="false">
          <context:include-filter expression="org.springframework.stereotype.Controller"
          type="annotation" />
          </context:component-scan>
          <!--
          Service beans list
          -->
          <context:property-placeholder location="classpath:common.properties" />
          <bean id="opencrxContext" class="com.omdasoft.core.ui.server.common.OpenCrxContext"
          scope="session">
          <aop:scoped-proxy />
          </bean>
          <bean id="baseService" abstract="true">
          <property name="context" ref="opencrxContext"></property>
          </bean>
          <bean id="userService" class="com.omdasoft.core.ui.server.service.UserService"
          parent="baseService" />
          是 不是覺得很簡單?個人認為,一個好的框架應該是越簡單越好,能夠用最少的步驟完成大多數業務流程,并且在需要的時候可以擴展。一個試圖包羅萬象的框架除了 增加開發人員的學習和調試難度之外,沒有任何好處。而一個無法替換的技術更是增加了框架擴展功能的難度。在我們開發的這個框架中,除了spring mvc是作為REST服務的提供者和服務端的管理容器無法替換之外,其他部分都可以按照需求更換為其他技術框架。例如,web層可以換成spring mvc管理的jsp等View,后臺opencrx api可以更換成hibernate管理的持久層和自行設計的數據庫,而中間的service(業務邏輯部分),幾乎不需要大的修改。這也讓我們更專注于 業務邏輯的定義和后臺API接口的通用化、統一化。
          由于本人對于Spring ViewResolver認識還不深入,所以在Controller中,方法直接返回了ModelAndView(JsonView),而不是簡單的String,這也是進一步優化框架的方向之一。下面是一段用戶注冊的代碼:
          @RequestMapping(value = "/user", method = RequestMethod.POST)
          public ModelAndView addUser(@ModelAttribute("account") Contact contact) {
          Map model = new HashMap();
          try {
          userService.createContact(contact);

          ?? ? ? ? ? ?model.put(ResultConstant.REDIRECT_SCREEN, contact);
          } catch (ServiceException e) {
          model.put(ResultConstant.ERROR_CODE, "/account/"
          + contact.getId());
          }
          return new ModelAndView("jsonView", model);
          }
          另 外要注意的是,和spring mvc處理異常的方式不同,基于Rest/Json對象來處理前臺請求時,返回值和異常必須統一在一個類型格式下,這樣才方便前臺獲取對應的數據和異常信 息,而Validation異常可以采用GWT-VL框架的方式來處理,直接拋出ValidationException異常,然后在GWT中,可以用 GWT-VL的方法來捕獲這個異常。


          posted on 2010-12-20 00:01 禮物 閱讀(1595) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。

          網站導航:
           
          主站蜘蛛池模板: 东平县| 清丰县| 寻甸| 敖汉旗| 茂名市| 万全县| 曲阳县| 永宁县| 玉环县| 江口县| 鹤岗市| 苍梧县| 高青县| 樟树市| 精河县| 阳原县| 龙岩市| 湘阴县| 治县。| 皮山县| 牙克石市| 万年县| 调兵山市| 沛县| 凤台县| 吉安市| 双桥区| 滁州市| 祁连县| 双柏县| 安阳市| 黑龙江省| 陕西省| 二手房| 梁山县| 恩施市| 深州市| 台州市| 西畴县| 平定县| 股票|