posts - 41,  comments - 8,  trackbacks - 0
            置頂隨筆
               摘要: * 此框架采用前后臺分開,前后臺都可以單獨部署,前端采用輕量級的扁平化設(shè)計(html+javascript+Bootstrap), 會自動針對不同的屏幕尺寸調(diào)整頁面,使其在各個尺寸的屏幕上表現(xiàn)良好。
          * 后端采用Spring boot,它使我們更容易去創(chuàng)建基于Spring的獨立和產(chǎn)品級的可以即時運行的應(yīng)用和服務(wù)。直接嵌入Tomcat 或Jetty服務(wù)器,不需要部署WAR 文件,可直接運行jar文件。
          * 系統(tǒng)權(quán)限框架采用Shiro,實現(xiàn)前后臺權(quán)限校驗 * 持久層采用JPA ,并實現(xiàn)類ibatis的查詢功能;數(shù)據(jù)響應(yīng)該采用json格式。
          * 服務(wù)采用REST形式,能夠方便的與手機app進(jìn)行對接,集成swagger能夠在線查看RESTAPI 文檔和在線測試服務(wù)接口
          * 支持單點登錄,可以多系統(tǒng)進(jìn)行菜單集成,形成一個portal
          * 支持高并發(fā)和水平擴展,支持Session的統(tǒng)一存儲
          * 項目采用gradle構(gòu)建,能夠方便的將各項目進(jìn)行按需組裝  閱讀全文
          posted @ 2016-06-13 10:00 Loy Fu 閱讀(4040) | 評論 (0)編輯 收藏
            2016年6月13日
               摘要: * 此框架采用前后臺分開,前后臺都可以單獨部署,前端采用輕量級的扁平化設(shè)計(html+javascript+Bootstrap), 會自動針對不同的屏幕尺寸調(diào)整頁面,使其在各個尺寸的屏幕上表現(xiàn)良好。
          * 后端采用Spring boot,它使我們更容易去創(chuàng)建基于Spring的獨立和產(chǎn)品級的可以即時運行的應(yīng)用和服務(wù)。直接嵌入Tomcat 或Jetty服務(wù)器,不需要部署WAR 文件,可直接運行jar文件。
          * 系統(tǒng)權(quán)限框架采用Shiro,實現(xiàn)前后臺權(quán)限校驗 * 持久層采用JPA ,并實現(xiàn)類ibatis的查詢功能;數(shù)據(jù)響應(yīng)該采用json格式。
          * 服務(wù)采用REST形式,能夠方便的與手機app進(jìn)行對接,集成swagger能夠在線查看RESTAPI 文檔和在線測試服務(wù)接口
          * 支持單點登錄,可以多系統(tǒng)進(jìn)行菜單集成,形成一個portal
          * 支持高并發(fā)和水平擴展,支持Session的統(tǒng)一存儲
          * 項目采用gradle構(gòu)建,能夠方便的將各項目進(jìn)行按需組裝  閱讀全文
          posted @ 2016-06-13 10:00 Loy Fu 閱讀(4040) | 評論 (0)編輯 收藏
            2008年10月21日
               摘要: java nio的全稱是java new I/O,即一個全新的I/O控制系統(tǒng),它的API的包名為java.nio,是在jdk1.4后引入的。 nio之所以為為新,在于它并沒在原來I/O的基礎(chǔ)上進(jìn)行開發(fā),而是提供了全新的類和接口,除了原來的基本功能之外,它還提供了以下新的特征:         ? 多路選擇的非封鎖式...  閱讀全文
          posted @ 2008-10-21 17:44 Loy Fu 閱讀(839) | 評論 (0)編輯 收藏
            2008年10月20日
           作者:羅代均 ldj_work#126.com,轉(zhuǎn)載請保持完整性
          環(huán)境說明

                 Apache  :apache_2.0.55     1 個

                 Tomcat:  apache-tomcat-5.5.17 (zip版) 2個

                 mod_jk:: mod_jk-apache-2.0.55.so  1個

          第一部分:負(fù)載均衡

              負(fù)載均衡,就是apache將客戶請求均衡的分給tomcat1,tomcat2....去處理

             1.安裝apche,tomcat

             http://httpd.apache.org/ 下載Apache 2.0.55

              http://tomcat.apache.org/download-55.cgi 下載tomcat5.5 zip版本(解壓即可,綠色版)

             http://apache.justdn.org/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.15/  下載mod_jk,注意和  apache版本匹配

             按照jdk,我的路徑為:E:\ide\apache\Apache2

             解壓兩份Tomcat, 路徑分別為 E:\ide\tomcat1,E:\ide\tomcat2

          下載mod_jk

          2.修改Apache配置文件http.conf

             在apache安裝目錄下conf目錄中找到http.conf

             在文件最后加上下面一句話就可以了

            include "E:\ide\apache\Apache2\conf\mod_jk.conf"

          2. http.conf 同目錄下新建mod_jk.conf文件,內(nèi)容如下
            
          #加載mod_jk Module
          LoadModule jk_module modules/mod_jk-apache-2.0.55.so
          #指定 workers.properties文件路徑
          JkWorkersFile conf/workers.properties
          #指定那些請求交給tomcat處理,"controller"為在workers.propertise里指定的負(fù)載分配控制器
          JkMount /*.jsp controller
          3.在http.conf同目錄下新建 workers.properties文件,內(nèi)容如下
           
          worker.list = controller,tomcat1,tomcat2  #server 列表
          #========tomcat1========
          worker.tomcat1.port=8009         #ajp13 端口號,在tomcat下server.xml配置,默認(rèn)8009
          worker.tomcat1.host=localhost  #tomcat的主機地址,如不為本機,請?zhí)顚慽p地址
          worker.tomcat1.type=ajp13
          worker.tomcat1.lbfactor = 1   #server的加權(quán)比重,值越高,分得的請求越多
          #========tomcat2========
          worker.tomcat2.port=9009       #ajp13 端口號,在tomcat下server.xml配置,默認(rèn)8009
          worker.tomcat2.host=localhost  #tomcat的主機地址,如不為本機,請?zhí)顚慽p地址
          worker.tomcat2.type=ajp13
          worker.tomcat2.lbfactor = 1   #server的加權(quán)比重,值越高,分得的請求越多

          #========controller,負(fù)載均衡控制器========
          worker.controller.type=lb
          worker.controller.balanced_workers=tomcat1,tomcat2   #指定分擔(dān)請求的tomcat
          worker.controller.sticky_session=1
          4.修改tomcat配置文件server.xml
          如果你在不同電腦上安裝tomcat,tomcat的安裝數(shù)量為一個,可以不必修改tomcat配置文件
          我這里是在同一臺電腦上安裝兩個tomcat,所以需要更改其中一個的設(shè)置
          打開tomcat2/conf/server.xml文件
          5.編寫一個測試jsp
          建立一個目錄test.里面新建一個test.jsp,內(nèi)容為
          <%
             System.out.println("===========================");
          %>
          把test放到tomcat1,tomcat2的webapps下
          6.啟動apache,tomcat1,tomcat2,進(jìn)行測試
          通過 http://localhost/test/test.jsp 訪問,查看tomcat1的窗口,可以看到打印了一行"=========="
          再刷新一次,tomcat2也打印了一條,再刷新,可以看到請求會被tomcat1,tomcat2輪流處理,實現(xiàn)了負(fù)載均衡
          第二部分,配置集群
             只配置負(fù)載均衡還不行,還要session復(fù)制,也就是說其中任何一個tomcat的添加的session,是要同步復(fù)制到其它tomcat, 集群內(nèi)的tomcat都有相同的session
          1. 修改tomcat1, tomcat2的server.xml,將集群部分配置的在注釋符刪掉,并將tomcat2的4001端口改為4002,以避免與tomcat沖突,當(dāng)然,如果是兩臺電腦,是不用改端口的,去掉注釋符即可
            
          2,修改測試項目test
          修改test.jsp,內(nèi)容如下
            <%@ page contentType="text/html; charset=GBK" %>
          <%@ page import="java.util.*" %>
          <html><head><title>Cluster App Test</title></head>
          <body>
          Server Info:
          <%
          out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%>
          <%
            out.println("<br> ID " + session.getId()+"<br>");
            // 如果有新的 Session 屬性設(shè)置
            String dataName = request.getParameter("dataName");
            if (dataName != null && dataName.length() > 0) {
               String dataValue = request.getParameter("dataValue");
               session.setAttribute(dataName, dataValue);
            }
            out.print("<b>Session 列表</b>");
            Enumeration e = session.getAttributeNames();
            while (e.hasMoreElements()) {
               String name = (String)e.nextElement();
               String value = session.getAttribute(name).toString();
               out.println( name + " = " + value+"<br>");
                   System.out.println( name + " = " + value);
             }
          %>
            <form action="index.jsp" method="POST">
              名稱:<input type=text size=20 name="dataName">
               <br>
              值:<input type=text size=20 name="dataValue">
               <br>
              <input type=submit>
             </form>
          </body>
          </html>
          然后在test 新建WEB-INF目錄,WEB-INF下新建web.xml,內(nèi)容如下
          注意:在你的應(yīng)用的web.xml加入  <distributable/> 即可
          ok,講test復(fù)制到tomcat1,tomcat2的webapps下,重啟apache,tomcat1,tomcat2,
          新建一個 名稱為 xiaoluo  ,值為 cdut 的session,提交查詢,新開一個ie窗口,再提交查詢,如圖,可以看到,兩個tomcat 是負(fù)載均衡,并且session同步的
          posted @ 2008-10-20 08:49 Loy Fu 閱讀(530) | 評論 (0)編輯 收藏
            2008年10月15日

          在實際的網(wǎng)頁開發(fā)中,大部分時間都要涉及到Form表單的處理。在Ext框架中也提供了很多這方面的控件,而且還有一個專門的FormPanel布 局,該布局默認(rèn)為放在面板上面的所有控件都是換行放置,而在實際應(yīng)用中為了美觀,有些需要橫排,特別是Radio控件,這個時候就需要我們重新定制這些控 件的布局了,該例子中使用CSS來實現(xiàn)這些功能,先貼出一張效果圖。



          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
          <title>Ext中FormPanel面板及Form控件橫排測試(CSS)</title>
          <link rel="stylesheet" type="text/css" media="all" href="../ext/resources/css/ext-all.css" />
          <style type="text/css" media="all">
          .allow-float {clear:none!important;} /* 允許該元素浮動 */
          .stop-float {clear:both!important;} /* 阻止該元素浮動 */
          .sex-male {float:left;}
          .sex-female {float:left;padding:0 0 0 20px;}
          .age-field {float:left;padding:0 0 0 58px;*padding:0 0 0 50px!important;*padding:0 0 0 50px;}
          </style>
          </head>
          <body>
          <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
          <script type="text/javascript" src="../ext/ext-all.js"></script>
          <script type="text/javascript" src="../ext/build/locale/ext-lang-zh_CN.js"></script>
          <script type="text/javascript">Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';</script>
          <script type="text/javascript">
          Ext.onReady(function() {
          //創(chuàng)建Form面板
          var fp = new Ext.form.FormPanel({
          buttonAlign:'center',
          labelAlign:'right',
          labelWidth:40,
          frame:true,
          bodyStyle:'padding:8px 0 0 0;',
          items:[{
          xtype:'textfield',
          fieldLabel:'姓名',
          name:'n_username',
          id:'i_username',
          width:320
          },{
          xtype:'radio',
          fieldLabel:'性別',
          boxLabel:'男',
          name:'sex',
          id:'male',
          itemCls:'sex-male', //向左邊浮動,處理控件橫排
          clearCls:'allow-float', //允許兩邊浮動,在實際生成的HTML結(jié)構(gòu)中有專門的DIV阻斷浮動
          checked:true
          },{
          xtype:'radio',
          boxLabel:'女',
          name:'sex',
          id:'female',
          itemCls:'sex-female', //向左浮動,處理控件橫排
          clearCls:'allow-float', //允許兩邊浮動
          hideLabel:true //不顯示前面"性別"的標(biāo)簽
          },{
          xtype:'textfield',
          fieldLabel:'年齡',
          name:'n_age',
          id:'i_age',
          itemCls:'age-field', //向左浮動,處理控件橫排
          width:133
          },{
          xtype:'textfield',
          fieldLabel:'住址',
          name:'n_address',
          id:'i_address',
          itemCls:'stop-float', //不允許浮動,結(jié)束控件橫排
          width:320
          }],
          buttons:[{
          text:'確定',
          handler:onOK //實際應(yīng)用一般是處理fp.getForm.submit()事件
          }, {
          text:'重置',
          handler:function(){ fp.getForm().reset(); }
          }],
          keys:[{ //處理鍵盤回車事件
          key:Ext.EventObject.ENTER,
          fn:onOK,
          scope:this
          }]
          });

          //確定按鈕事件,這里只是簡單獲取各控件值,實際應(yīng)用一般和后臺腳本結(jié)合
          function onOK() {
          var strMsg;
          strMsg = ‘姓名:’ + fp.getComponent(’i_username’).getValue() + ‘,性別:’;
          if (fp.getComponent(’male’).checked) strMsg += ‘男’;
          if (fp.getComponent(’female’).checked) strMsg += ‘女’;
          strMsg += ‘,年齡:’ + fp.getComponent(’i_age’).getValue();
          strMsg += ‘,住址:’ + fp.getComponent(’i_address’).getValue();
          alert(strMsg);
          }

          //創(chuàng)建主窗口
          new Ext.Window({
          title:’Ext中FormPanel面板及Form控件橫排測試(CSS)’,
          width:400,
          closable:false,
          collapsible:true,
          draggable:false,
          resizable:false,
          modal:true,
          border:false,
          items:[fp],
          buttons:[]
          }).show();
          });
          </script>
          </body>
          </html>

          posted @ 2008-10-15 13:03 Loy Fu 閱讀(738) | 評論 (0)編輯 收藏
            2008年10月8日
          Java下的框架編程之cglib的應(yīng)用
           

          Proxy可以看作是微型的AOP,明白提供了在繼承和委托之外的第三個代碼封裝途徑,只要有足夠的想象力,可以做得非常好玩,Spring的源碼里用Proxy就用得很隨便,看得我非常眼紅??上roxy必須基于接口。因此Spring的做法,基于接口的用proxy,否則就用cglib。AOP么,一般小事非compoent一級的就不麻煩AspectJ出手了。

          cglib的Enhancer說起來神奇,用起來一頁紙不到就講完了。

          它的原理就是用Enhancer生成一個原有類的子類,并且設(shè)置好callback到proxy, 則原有類的每個方法調(diào)用都會轉(zhuǎn)為調(diào)用實現(xiàn)了MethodInterceptor接口的proxy的intercept() 函數(shù):

                                  

          public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)

          在intercept()函數(shù)里,你可以在執(zhí)行Object result=proxy.invokeSuper(o,args);來執(zhí)行原有函數(shù),在執(zhí)行前后加入自己的東西,改變它的參數(shù)值,也可以瞞天過海,完全干別的。說白了,就是AOP中的around advice。

          AOP沒有出現(xiàn)以前,該領(lǐng)域經(jīng)典的設(shè)計模式是Decorator,像Java IO Stream的設(shè)計就是如此。不過,如果為每個DAO, 每個方法的寫Decorator函數(shù)會寫死人的,所以用上cglib的好處是一次過攔截所有方法。 

          另外,cglib除了Enhancer之外,還有BulkBean和Transform,都是Hibernate持久化的基礎(chǔ),但文檔貧乏,一時還沒去看怎么用。

          1.AOP里講了一百遍啊一百遍的log aspect在cglib是這樣做的:

                                  

          public class LogDAOProxy implements MethodInterceptor
             {
                 
          private Logger log=Logger.getLogger(LogDAOProxy.class);
                 
          private Enhancer enhancer=new Enhancer();
                  
          //返回DAO的子類
                 public Object getDAO(Class clz)
                 {
                     enhancer.setSuperclass(clz);
                     enhancer.setCallback(
          this);
                     
          return enhancer.create();
                 }
                 
          //默認(rèn)的攔截方法
                public Object intercept(Object o,Method method,Object[] args,

          MethodProxy proxy) throws Throwable
                {
                     log.info(
          "調(diào)用日志方法"+method.getName());
                     Object result
          =proxy.invokeSuper(o,args);
                     
          return result;
                }
             }


          應(yīng)用的代碼:

                                  

          LogDAOProxy proxy = new LogDAOProxy();
            GoodsDAO  dao 
          = (GoodsDAO)proxy.getDAO(GoodsDAO.class);
            dao.insert(goods);


          2.而在Spring的管理下應(yīng)該略加修改的高級Decorator

          上面的例子用return enhancer.create();創(chuàng)建子類實例,但在Spring管理下,一些Bean的實例必須由Spring來創(chuàng)建和管理,而不由enhancer來創(chuàng)建的。所以我對上述用法略加修改,使它真正當(dāng)一個Proxy的角色,請對比黑體字的部分。

                                  

          public class LogDAOProxy implements MethodInterceptor
            {
                 
          private Logger log=Logger.getLogger(LogDAOProxy.class);
                 
          private Object dao=null;
                 
          private Enhancer enhancer=new Enhancer();
                  
          //返回DAO的子類
                 public Object getDAO(Class clz,Object dao)
                 {
                     
          this.dao = dao;
                     enhancer.setSuperclass(clz);
                     enhancer.setCallback(
          this);
                     
          return enhancer.create();
                 }      
                 
          //默認(rèn)的攔截方法
                public Object intercept(Object o,Method method,Object[] args,

          MethodProxy proxy) throws Throwable
                {
                     log.info(
          "調(diào)用日志方法"+method.getName());
                     Object result
          =proxy.invoke(dao, args);
                     
          return result;
                }
          }


          可見,原來模式里在getDao()時由enhancer創(chuàng)建dao,而 調(diào)用intercept時則將enhancer創(chuàng)建的dao以O(shè)bject o參數(shù)傳回。
          而新模式里,dao在getDao()時從外面?zhèn)魅?,enhancer.create()返回的是一個proxy. 而調(diào)用intercept時,實際會用之前傳入的dao進(jìn)行操作,而忽略O(shè)bject o參數(shù)傳入的proxy。

          有點遺憾, intercept函數(shù)里MethodProxy的Signature是固定的,即客戶如果調(diào)用foo(String),你不可以用proxy.invoke偷換成foo(String,String);

          posted @ 2008-10-08 10:38 Loy Fu 閱讀(406) | 評論 (0)編輯 收藏
            2008年10月4日

          前臺:

          Store:

          var resource = new Ext.data.Store({
                fields: ['imgpath','typeImage','title', 'type'],
                url: 'teaching/resource/resourceAction.evi?method=getResourceList',
                reader: new Ext.data.XmlReader(
                  {
                    record: "Item",
                    totalRecords: "TotalCount"
                  },
                [{name:'title',mapping: 'title'}, {name:'type',mapping: 'type'},{name:'imgpath',mapping: 'imgpath'},{name:'typeImage',mapping: 'typeImage'} ]
              )
          });

          resource.addListener('load', function(st, rds, opts) {
                  // st 是當(dāng)前的store, rds是讀到的Record[], opts是store的配置
             for( var c=0; c<rds.length; c++ ) {
                 rds[c].set('typeImage', "<img src='./images/33.gif' width='12' height='12' />");
                 //待定類別,先定死類別圖片
                }
          });

          resource.load({params:{start:0,limit:10}});

          var resourceType = new Ext.data.Store({
          ,
                reader: new Ext.data.XmlReader({
                record: "Item"
               }, [
                {name: 'resourceTypeId', mapping: 'resourceTypeId'},
                 {name: 'resourceType', mapping: 'resourceType'}
                ])
             });
          resourceType.load();
          var languageType = new Ext.data.Store({
          ,
                reader: new Ext.data.XmlReader({
                record: "Item"
               }, [
                 {name: 'languageTypeId', mapping: 'languageTypeId'},
                 {name: 'languageType', mapping: 'languageType'}
                ])
             });
          languageType.load();

          列表:

          resourcePanel = new Ext.grid.GridPanel({
          id: 'resources',
          frame: true,
          header: false,
          width: 288,
          autoWidth: true,
          autoHeight: true,
          loadMask:{msg:'正在加載數(shù)據(jù),請稍侯……'},
          iconCls:'icon-grid',
          viewConfig: { forceFit: true },
             columns:[
            {header: " ",dataIndex: 'typeImage' , width:20},
            {header: "資源標(biāo)題", width: 190, sortable: true, dataIndex: 'title'},
            {header: "類別", width: 80, sortable: true, dataIndex: 'type'}
             ],
            store: resource,
            selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
               bbar: new Ext.PagingToolbar({
            pageSize: 10,
            store: resource,
            displayInfo: false,
            //displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',
            emptyMsg: "沒有記錄" 
                }),
            listeners: {
            rowclick:function(e) {
             try {
              window.parent.parent.Ext.ux.MyTips.msg("提示", "雙擊該行可預(yù)覽該資源");
              } catch(e) {}
              },
            rowdblclick:function(g, rIdx, e) {
             var rd = g.getStore().getAt(rIdx);
             var html = "<img src='./images/" + rd.get('imgpath') + "' />";
            window.parent.showWin({
                layout: 'fit',
                maximizable: true,
                title: rd.get('title'),
                width: 400,
                height: 400,
                //modal: true,
                //closeAction: 'hide',
                plain: true,
                items: [ {html: html} ]
              });
            }
          }
          });

          FormPanel:

          var rform = new Ext.form.FormPanel({
                        id:'rform',
                     header: false,
                     frame: true,
                     hideBorders: false,
                     items: [
                      new Ext.form.TextField({
                       fieldLabel: '關(guān)鍵字',
                       name:'keyword'
                      }),
                      new Ext.form.ComboBox({
                       fieldLabel: '資源類別',
                       mode: 'local',
                       triggerAction: 'all',
                       store: resourceType,
                       typeAhead: true,
                       hiddenName:'resourceTypeId',
                       displayField: 'resourceType',
                       valueField: 'resourceTypeId',
                       readOnly: true,
                       selectOnFocus: true
                      }),
                      new Ext.form.ComboBox({
                       fieldLabel: '語言',
                       mode: 'local',
                       triggerAction: 'all',
                       typeAhead: true,
                       hiddenName:'languageTypeId',
                       displayField:'languageType',
                       valueField:'languageTypeId',
                       readOnly: true,
                       selectOnFocus: true,
                       store:languageType
                      }),
                      new Ext.Panel({
                       layout: 'table',
                       buttonAlign: 'center',
                       layoutConfig: { colspan: 3 },
                       buttons:[{text: '搜  尋',
                        handler: function() {
                                       var keyword = Ext.get('keyword').dom.value;
                                       var resourceTypeId = Ext.get('resourceTypeId').dom.value;
                                       var languageTypeId = Ext.get('languageTypeId').dom.value;
                                resource.reload({params:{start:0,limit:3,keyword:keyword,resourceTypeId:resourceTypeId,languageTypeId:languageTypeId}});
             //這里不用再寫ajax,Ext已經(jīng)封裝了ajax,只要把參數(shù)傳進(jìn)去就行了  
                        }},
                        {
                          text: '重  置',
                          handler: function() {
                             Ext.getCmp('rform').form.reset();
                         }
                         }
                        ]
                      })
                     ]
                    })

          后臺:

          public ActionForward getResourceList(ActionMapping mapping,
             ActionForm form, HttpServletRequest request,
             HttpServletResponse response) throws IOException {

            Document document = DocumentHelper.createDocument();
            String start = request.getParameter("start");
            String limit = request.getParameter("limit");
            String keyword = request.getParameter("keyword");
            String resourceTypeId = request.getParameter("resourceTypeId");
            String languageTypeId = request.getParameter("languageTypeId");

            List<HqlCondition> hqlFilter = new LinkedList<HqlCondition>();
            if(keyword != null && keyword.length()>0){
             hqlFilter.add( new HqlCondition("and", "rs.title", "like", "%" + keyword + "%", HqlCondition.String) );
             hqlFilter.add( new HqlCondition("or", "rs.remarks", "like", "%" + keyword + "%", HqlCondition.String) );
            }
            if(resourceTypeId != null && resourceTypeId.length()>0){
             hqlFilter.add( new HqlCondition("and", "rs.resourceType.resourceTypeId", "=", new Long(resourceTypeId), HqlCondition.Long) );
            }
            if(languageTypeId != null && languageTypeId.length()>0){
             hqlFilter.add( new HqlCondition("and", "rs.languageType.languageTypeId", "=", new Integer(languageTypeId), HqlCondition.Integer) );
            }
            int pageno =1;
            int pagesize = 10;
            if(limit != null && limit.length()>0){
                pagesize = Integer.parseInt(limit);
            }

            if(!start.equalsIgnoreCase("0") && start != null && start.length()>0){
               int bpos = Integer.parseInt(start);
               pageno = (bpos + pagesize)/pagesize;
            }
            int total = this.rse.getResourceTotalCount(hqlFilter);
            Collection<BaseVO> coll = this.rse.getResourceList(hqlFilter,pageno,pagesize);
            Iterator<BaseVO> it = coll.iterator();
            while(it != null && it.hasNext()){
             BaseVO bv = it.next();
             ResourceType rt = this.rts.getResourceType(((ResourceType)bv.get("resourceType")).getResourceTypeId());
             bv.set("type", rt.getResourceType());
            }
            document.addElement("type");
            new OutputVOXml().writeXML(total,new LinkedList<BaseVO>(coll), response);
            return null;
          }

          查看更多精彩圖片
          posted @ 2008-10-04 22:43 Loy Fu 閱讀(1381) | 評論 (0)編輯 收藏
           Apache提供的一個插件包,可以把Action中的數(shù)據(jù)以JSON做個封裝然后返回。

          它會將整個action中的變量轉(zhuǎn)化為JSON數(shù)據(jù)(根對象在JSON中數(shù)據(jù)添加一個”root”標(biāo)識)。如果要使用它,Action必須遵循以下幾點:

          1.       返回的頁面類型中”content-type”必須是”application/json”.(這個已經(jīng)Internet Community采用).

          2.       JSON內(nèi)容必須是符合格式要求的.

          3.       Actionfield必須有publicset方法.(是不是沒有set方法就不會將field添加到JSON數(shù)據(jù)中,有待驗證).

          4.       它支持的類型有: 基本類型(int,long...String), Date, List, Map, Primitive Arrays, 其它class, 對象數(shù)組.

          5.       JSON中任何的Object會被封裝在listmap中,數(shù)據(jù)會被封裝程Long,如果是含有的數(shù)據(jù)則會被封裝程Double,數(shù)組會被封裝程List.

          下面給出JSON的數(shù)據(jù)格式:

          {

             "doubleValue": 10.10,

             "nestedBean": {

                "name": "Mr Bean"

             },

             "list": ["A", 10, 20.20, {

                "firstName": "El Zorro"

             }],

             "array": [10, 20]

          }

          說明:

          a.       這個插件支持以下幾個注釋:

          注釋名

          簡介

          默認(rèn)值

          序列化

          反序列化

          name

          配置JSONname

          empty

          yes

          no

          serialize

          serialization

          true

          yes

          no

          deserialize

          deserialization

          true

          no

          yes

          format

          格式化Date字段

          "yyyy-MM-dd'T'HH:mm:ss"

          yes

          yes

          可以通過配置來顯示指出要放在JSONfield,其中有個自己的驗證規(guī)則需要研究.

          <!-- Result fragment -->

          <result type="json">

           <param name="excludeProperties">

              login.password,

              studentList.*".sin

           </param>

          </result>

          <!-- Interceptor fragment -->

          <interceptor-ref name="json">

           <param name="enableSMD">true</param>

           <param name="excludeProperties">

              login.password,

              studentList.*".sin

           </param>

          </interceptor-ref>

          b.       根對象

           <result type="json">

           <param name="root">

              person.job

           </param>

          </result>

          也可以使用攔截器配置操作父對象

          <interceptor-ref name="json">

           <param name="root">bean1.bean2</param>

          </interceptor-ref>

          c.       JSON數(shù)據(jù)用注釋封裝

          如果wrapWithComments設(shè)置為true(默認(rèn)值為false),則生成的JSON數(shù)據(jù)會變成這樣:

          /* {

             "doubleVal": 10.10,

             "nestedBean": {

                "name": "Mr Bean"

             },

             "list": ["A", 10, 20.20, {

                "firstName": "El Zorro"

             }],

             "array": [10, 20]

          } */

          這樣做可以避免js中一些潛在的風(fēng)險,使用時需要:

          Var responseObject = eval("("+data.substring(data.indexOf(""/"*")+2, data.lastIndexOf(""*"/"))+")");

          d.       父類

          “root”對象中父類的field不會默認(rèn)存放到JSON數(shù)據(jù)中,如果不想這樣做,需要在配置時指定ignoreHierarchyfalse:

          <result type="json">

           <param name="ignoreHierarchy">false</param>

          </result>

          e.       枚舉類型

          默認(rèn)處理枚舉類型時,會被處理成JSON數(shù)據(jù)中name等于枚舉中valuevalue等于枚舉中name.

          public enum AnEnum {

               ValueA,

               ValueB

           }

           JSON: "myEnum":"ValueA"

          如果在處理枚舉類型時,在xml中配置了enumAsBean,則會被當(dāng)作一個Bean處理,在JSON數(shù)據(jù)中會有一個特別的屬性”_name”值為name().這個枚舉中的所有屬性都會被處理.

          public enum AnEnum {

               ValueA("A"),

               ValueB("B");

               private String val;

               public AnEnum(val) {

                  this.val = val;

               }

               public getVal() {

                  return val;

               }

             }

           JSON: myEnum: { "_name": "ValueA", "val": "A" }

          Xml中配置:

          <result type="json">

           <param name="enumAsBean">true</param>

          </result>

          f.        例子

          a)         Action

          import java.util.HashMap;

          import java.util.Map;

          import com.opensymphony.xwork2.Action;

          public class JSONExample {

              private String field1 = "str";

              private int[] ints = {10, 20};

              private Map map = new HashMap();

              private String customName = "custom";

              //'transient' fields are not serialized

              private transient String field2;

              //fields without getter method are not serialized

              private String field3;

              public String execute() {

                  map.put("John", "Galt");

                  return Action.SUCCESS;

              }

              public String getField1() {

                  return field1;

              }

              public void setField1(String field1) {

                  this.field1 = field1;

              }

              public int[] getInts() {

                  return ints;

              }

              public void setInts(int[] ints) {

                  this.ints = ints;

              }

              public Map getMap() {

                  return map;

              }

              public void setMap(Map map) {

                  this.map = map;

              }

              @JSON(name="newName")

              public String getCustomName() {

                  return this.customName;

              }

          }

          b)        Xml配置

           <?xml version="1.0" encoding="UTF-8" ?>

          <!DOCTYPE struts PUBLIC

              "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

              "http://struts.apache.org/dtds/struts-2.0.dtd">

          <struts>

           <package name="example" extends="json-default">

               <action name="JSONExample" class="example.JSONExample">

                  <result type="json"/>

               </action>

           </package>

          </struts>

          這里有兩個地方需要注意:

          1)      需要繼承json-default

          2)      <result>簽的定義

          c)         JSON數(shù)據(jù)

           { 

             "field1" : "str",

             "ints": [10, 20],

             "map": {

                 "John":"Galt"

             },

             "newName": "custom"

          }

          d)        JSON RPC

          JSON插件可以在js中調(diào)用action方法,返回執(zhí)行結(jié)果。這個已經(jīng)在dojo中有了實現(xiàn),可以用Simple Method Definition調(diào)用遠(yuǎn)程服務(wù)。來一起看看下面的例子:

          首先寫一個Action

          package smd;

          import com.googlecode.jsonplugin.annotations.SMDMethod;

          import com.opensymphony.xwork2.Action;

          public class SMDAction {

              public String smd() {

                  return Action.SUCCESS;

              }

              @SMDMethod

              public Bean doSomething(Bean bean, int quantity) {

                  bean.setPrice(quantity * 10);

                  return bean;

              }

          }

          e)         方法必須用SMDMethod加上注解,這樣才能被遠(yuǎn)程調(diào)用,為了安全因素。這個方法會產(chǎn)生一個bean對象,實現(xiàn)修改價格的功能。Action被添加上SMD注解會生成一個SMD,同時參數(shù)也會被加上SMDMethodParameter注解。像你所看到的,Action中定義了一個空方法:smd。這個方法是作為Simple Method Definition (定義class中提供的服務(wù)),在struts.xml配置<result>時使用type屬性值為”json”。

          下面是bean的定義:

          package smd;

          public class Bean {

              private String type;

              private int price;

              public String getType() {

                  return type;

              }

              public void setType(String type) {

                  this.type = type;

              }

              public int getPrice() {

                  return price;

              }

              public void setPrice(int price) {

                  this.price = price;

              }

          }

          Xml文件:

          <package name="RPC" namespace="/nodecorate" extends="json-default">

              <action name="SMDAction" class="smd.SMDAction" method="smd">

                  <interceptor-ref name="json">

                      <param name="enableSMD">true</param>

                  </interceptor-ref>

                  <result type="json">

                       <param name="enableSMD">true</param>

                  </result>

              </action>

          </package>

          這里需要注意一點:” enableSMD”這個必須在interceptorresult都要配置.

          Js代碼:

          <s:url id="smdUrl" namespace="/nodecorate" action="SMDAction" />

          <script type="text/javascript">

              //load dojo RPC

              dojo.require("dojo.rpc.*");

              //create service object(proxy) using SMD (generated by the json result)

              var service = new dojo.rpc.JsonService("${smdUrl}");

              //function called when remote method returns

              var callback = function(bean) {

                  alert("Price for " + bean.name + " is " + bean.price);

              };

              //parameter

              var bean = {name: "Mocca"};

              //execute remote method

              var defered = service.doSomething(bean, 5);

              //attach callback to defered object

              defered.addCallback(callback);

          </script>

          JsonService會發(fā)出一個請求到action加載SMD,同時遠(yuǎn)程方法會返回一個JSON對象,這個過程是Dojoaction中的方法創(chuàng)建了一個Proxy。因為這是異步調(diào)用過程,當(dāng)遠(yuǎn)程方法執(zhí)行的時候,它會返回一個對象到callback方法中。

          f)         代理的對象

          當(dāng)使用的注解不是繼承自Java,可能你使用代理會出現(xiàn)一些問題。比如:當(dāng)你使用aop攔截你的action的時候。在這種情況下,這個插件不會自動發(fā)現(xiàn)注解的方法。為了避免這種情況發(fā)生,你需要在xml中配置ignoreInterfacesfalse,這樣插件會自己查找注解的所有接口和父類。

          注意:這個參數(shù)只有在Action執(zhí)行的過程是通過注解來運行的時候才應(yīng)該設(shè)為false。

          <action name="contact" class="package.ContactAction" method="smd">

             <interceptor-ref name="json">

                <param name="enableSMD">true</param>

                <param name="ignoreInterfaces">false</param>

             </interceptor-ref>

             <result type="json">

                <param name="enableSMD">true</param>

                <param name="ignoreInterfaces">false</param>

             </result>

             <interceptor-ref name="default"/>

          </action>

          posted @ 2008-10-04 14:45 Loy Fu 閱讀(7748) | 評論 (2)編輯 收藏
          struts2json plugin的位置在:http://code.google.com/p/jsonplugin/
          下載json plugin的jar包,放到/WEB-INF/lib/目錄下就可以了

          Spring + Struts + JPA的項目結(jié)構(gòu)如其他例子中的一致
          首先是web.xml
          xml 代碼
           
          1. <?xml version="1.0" encoding="UTF-8"?>  
          2. <web-app id="WebApp_ID" version="2.4"  
          3.     xmlns="http://java.sun.com/xml/ns/j2ee"  
          4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
          5.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
          6.     <display-name>quickstart</display-name>  
          7.     <filter>  
          8.         <filter-name>struts2</filter-name>  
          9.         <filter-class>  
          10.             org.apache.struts2.dispatcher.FilterDispatcher  
          11.         </filter-class>  
          12.     </filter>  
          13.     <filter>  
          14.         <filter-name>jpaFilter</filter-name>  
          15.         <filter-class>  
          16.             org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter  
          17.         </filter-class>  
          18.         <init-param>  
          19.             <param-name>entityManagerFactory</param-name>  
          20.             <param-value>entityManagerFactory</param-value>  
          21.         </init-param>  
          22.     </filter>  
          23.     <filter-mapping>  
          24.         <filter-name>jpaFilter</filter-name>  
          25.         <url-pattern>*.action</url-pattern>  
          26.     </filter-mapping>  
          27.     <filter-mapping>  
          28.         <filter-name>struts2</filter-name>  
          29.         <url-pattern>/*</url-pattern>  
          30.     </filter-mapping>  
          31.     <welcome-file-list>  
          32.         <welcome-file>index.jsp</welcome-file>  
          33.     </welcome-file-list>  
          34.     <listener>  
          35.         <listener-class>  
          36.             org.springframework.web.context.ContextLoaderListener  
          37.         </listener-class>  
          38.     </listener>  
          39. </web-app>  

          加入jpaFilter,是為了不讓hibernate的session過早關(guān)閉,因為有的action會通過ajax動態(tài)調(diào)用。
          下面是struts.xml,注意struts.xml需要放在源代碼目錄下面:

          xml 代碼
           
          1. <?xml version="1.0" encoding="UTF-8" ?>  
          2. <!DOCTYPE struts PUBLIC  
          3.     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"  
          4.     "http://struts.apache.org/dtds/struts-2.0.dtd">  
          5. <struts>  
          6.     <constant name="struts.objectFactory" value="spring" />  
          7.     <constant name="struts.devMode" value="true" />  
          8.     <constant name="struts.i18n.encoding" value="UTF-8"/>  
          9.     <package name="person" extends="json-default">  
          10.         <action name="list" method="execute" class="personaction">  
          11.             <result type="json"/>  
          12.         </action>         
          13.     </package>  
          14. </struts>  

          這里注意,
          struts.objectFactory告訴struts所有的action都到spring的上下文里面去找,另外還需要注意,我們自己的包要繼承自json-default,這樣才可以在result的type屬性中使用json
          下面是spring的配置文件applicationContext.xml:
          xml 代碼
           
          1. <?xml version="1.0" encoding="UTF-8"?>  
          2. <beans xmlns="http://www.springframework.org/schema/beans"  
          3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
          4.     xmlns:aop="http://www.springframework.org/schema/aop"  
          5.     xmlns:tx="http://www.springframework.org/schema/tx"  
          6.     xsi:schemaLocation="  
          7.     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
          8.     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd  
          9.     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">  
          10.     <bean  
          11.         class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />  
          12.     <bean id="entityManagerFactory"  
          13.         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">  
          14.         <property name="dataSource" ref="dataSource" />  
          15.         <property name="jpaVendorAdapter">  
          16.             <bean  
          17.                 class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">  
          18.                 <property name="database" value="MYSQL" />  
          19.                 <property name="showSql" value="true" />  
          20.             </bean>  
          21.         </property>  
          22.     </bean>  
          23.     <bean id="dataSource"  
          24.         class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
          25.         <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
          26.         <property name="url" value="jdbc:mysql://localhost/extjs" />  
          27.         <property name="username" value="root" />  
          28.         <property name="password" value="" />  
          29.     </bean>  
          30.   
          31.       
          32.     <bean id="transactionManager"  
          33.         class="org.springframework.orm.jpa.JpaTransactionManager">  
          34.         <property name="entityManagerFactory"  
          35.             ref="entityManagerFactory" />  
          36.     </bean>  
          37.     <tx:annotation-driven transaction-manager="transactionManager" />  
          38.     <!--Service 開始 -->  
          39.     <bean id="personService" class="com.myext.service.impl.PersonServiceJpaImpl"/>  
          40.     <bean id="personaction" class="com.myext.action.PersonPageAction">  
          41.         <property name="person" ref="personService"/>  
          42.     </bean>  
          43. </beans>  

          這里的bean personaction和strutx.xml中的action class一致就可以了,下面是代碼:
          action:
          java 代碼
          1. package com.myext.action;
          2. import java.util.ArrayList;
          3. import java.util.List;
          4. import com.myext.service.PersonService;
          5. public class PersonPageAction {
          6. private int limit=10;
          7. private int start=0;
          8. private PersonService person;
          9. private int total=0;
          10. private List persons = new ArrayList();
          11. private boolean success=true;
          12. public boolean getSuccess(){
          13. return this.success;
          14. }
          15. public void setLimit(int limit) {
          16. this.limit = limit;
          17. }
          18. public void setStart(int start) {
          19. this.start = start;
          20. }
          21. public void setPerson(PersonService person) {
          22. this.person = person;
          23. }
          24. public int getTotal() {
          25. return total;
          26. }
          27. public void setTotal(int total) {
          28. this.total = total;
          29. }
          30. public List getPersons() {
          31. return persons;
          32. }
          33. public void setPersons(List persons) {
          34. this.persons = persons;
          35. }
          36. public String execute(){
          37. this.total = person.getTotal();
          38. this.persons = person.getPage(this.start, this.limit);
          39. return "success";
          40. }
          41. }
          service:
          java 代碼
          1. package com.myext.service.impl;
          2. import java.util.List;
          3. import javax.persistence.EntityManager;
          4. import javax.persistence.PersistenceContext;
          5. import javax.persistence.Query;
          6. import com.myext.model.Person;
          7. import com.myext.service.PersonService;
          8. public class PersonServiceJpaImpl implements PersonService {
          9. private EntityManager em;
          10. private static String poname = Person.class.getName();
          11. @PersistenceContext
          12. public void setEntityManager(EntityManager em){
          13. this.em = em;
          14. }
          15. @SuppressWarnings("unchecked")
          16. @Override
          17. public List getPage( int start, int limit) {
          18. Query q = this.em.createQuery("from " + poname );
          19. q.setFirstResult(start);
          20. q.setMaxResults(limit);
          21. return q.getResultList();
          22. }
          23. @Override
          24. public int getTotal() {
          25. return this.em.createQuery("from " + poname).getResultList().size();
          26. }
          27. }
          頁面的代碼:
          xml 代碼
          1. xml version="1.0" encoding="UTF-8" ?>
          2. <%@ page language="java" contentType="text/html; charset=UTF-8"
          3. pageEncoding="UTF-8"%>
          4. >
          5. <html xmlns="http://www.w3.org/1999/xhtml">
          6. <head>
          7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
          8. <title>Grid3title>
          9. <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css" />
          10. <script type="text/javascript" src="extjs/adapter/ext/ext-base.js">script>
          11. <script type="text/javascript" src="extjs/ext-all.js">script>
          12. <script type="text/javascript" src="extjs/ext-lang-zh_CN.js">script>
          13. head>
          14. <body>
          15. <script type="text/javascript" src="grid3.js">script>
          16. <div id="grid3" >
          17. div>
          18. body>
          19. html>
          grid3.js代碼
          js 代碼
          1. /**
          2. * @author fox
          3. */
          4. Ext.onReady(function(){
          5. Ext.BLANK_IMAGE_URL = 'extjs/resources/images/default/s.gif';
          6. Ext.QuickTips.init();
          7. var sm = new Ext.grid.CheckboxSelectionModel(); //CheckBox選擇列
          8. var cm = new Ext.grid.ColumnModel([
          9. new Ext.grid.RowNumberer(), //行號列
          10. sm,
          11. {header:'編號',dataIndex:'id'},
          12. {header:'性別',dataIndex:'sex',renderer:function(value){
          13. if(value=='male'){
          14. return "";
          15. }else{
          16. return "";
          17. }
          18. }}, //增加性別,自定義renderer,即顯示的樣式,可以加html代碼,來顯示圖片等。
          19. {header:'名稱',dataIndex:'name'},
          20. {header:'描述',dataIndex:'descn'}
          21. ]);
          22. var ds = new Ext.data.Store({
          23. proxy: new Ext.data.HttpProxy({url:'list.action'}),//調(diào)用的動作
          24. reader: new Ext.data.JsonReader({
          25. totalProperty: 'total',
          26. root: 'persons',
          27. successProperty :'success'
          28. }, [
          29. {name: 'id',mapping:'id',type:'int'},
          30. {name: 'sex',mapping:'sex',type:'string'},
          31. {name: 'name',mapping:'name',type:'string'},
          32. {name: 'descn',mapping:'descn',type:'string'} //列的映射
          33. ])
          34. });
          35. var grid = new Ext.grid.GridPanel({
          36. el: 'grid3',
          37. ds: ds,
          38. sm: sm,
          39. cm: cm,
          40. width:700,
          41. height:280,
          42. bbar: new Ext.PagingToolbar({
          43. pageSize: 10,
          44. store: ds,
          45. displayInfo: true,
          46. displayMsg: '顯示第 {0} 條到 {1} 條記錄,一共 {2} 條',
          47. emptyMsg: "沒有記錄"
          48. }) //頁腳顯示分頁
          49. });
          50. //el:指定html元素用于顯示grid
          51. grid.render();//渲染表格
          52. ds.load({params:{start:0, limit:10}}); //加載數(shù)據(jù)
          53. });
          注意,這里的gridpanel一定要設(shè)置高度,否則數(shù)據(jù)是顯示不出來的。
          最后啟動tomcat,在瀏覽器里輸入http://localhost:8080/extjs/grid3.jsp,就可以看到效果
          posted @ 2008-10-04 14:35 Loy Fu 閱讀(4537) | 評論 (2)編輯 收藏
               摘要: http://prototype.conio.net/dist/ 下載(對Ajax支持的prototype--js函數(shù)庫): prototype-1.4.0.js 或 prototype-1.4.0.tar.gz   http://code.google.com/p/jsonplugin/downloads/list 下載(Struts2...  閱讀全文
          posted @ 2008-10-04 14:19 Loy Fu 閱讀(2061) | 評論 (0)編輯 收藏
          關(guān)鍵字: Struts2 COC
          摘要:介紹Struts2中的零配置(Zero Configuration),以及如何用COC來更好地簡化Struts2的配置。在第一章,我使用Maven來創(chuàng)建一個起點項目;第二章,以該項目為例,講解如何使用Struts2的零配置;第三章,論述第二章中的實現(xiàn)方式的缺陷,然后講解如何使用COC來改進(jìn)這些缺陷,并進(jìn)一步簡化Struts2的配置。附件是這篇文章用到的示例代碼。

          一、從零開始

          這里,我將建立一個新的示例項目,作為講解的起點。我使用JDK 6、Maven 2、Eclipse 3.3來建立這個示例,如果讀者對Maven2不熟也沒關(guān)系,這只是個示例。
          首先,運行下邊的命令:
                          mvn archetype:create -DgroupId=demo.struts -DartifactId=demo-struts-coc -DarchetypeArtifactId=maven-archetype-webapp
          這會建立如下的目錄結(jié)構(gòu):
           |- POM.xml
           |- src
               |- main
                   |- resources
                   |- webapp
                       |- index.jsp
                       |- WEB-INF
                           |- web.xml
          然后我們在src/main目錄下新建一個名為java的目錄,用來放置java代碼。在src下建立test目錄,并在test目錄下建立java目錄,用來放置測試代碼。另外,我這個示例不想使用JSP,所以我將src/main/webapp目錄下的index.jsp改為index.html。
          現(xiàn)在,需要配置該項目要用到哪些lib。在POM.xml中加入struts2-core:
          xml 代碼
           
          1. <dependency>  
          2.     <groupId>org.apache.struts</groupId>  
          3.     <artifactId>struts2-core</artifactId>  
          4.     <version>2.0.9</version>  
          5. </dependency>  

          另外,我想在Eclipse里使用jetty來啟動項目并進(jìn)行測試,所以在POM.xml中再加入jetty、jetty-util、servlet-api等的依賴,詳情見附件。
          我希望使用Eclipse來作為這個項目的IDE,所以,我在命令行狀態(tài)下,進(jìn)入這個項目所在的目錄,運行:
                          mvn eclipse:eclipse
          然后使用Eclipse導(dǎo)入這個項目。如果你是第一次用Eclipse導(dǎo)入用Maven生成的項目,那你需要在Eclipse里配置一個名叫M2_REPO的Variable,指向你的Maven 2的repository目錄。缺省情況下,它應(yīng)該位于${user.home}/.m2/repository。
          OK!現(xiàn)在我們已經(jīng)可以在Eclipse中進(jìn)行工作了。
          修改src/main/webapp/WEB-INF/web.xml,加入struts2的FilterDispatcher并設(shè)置filter-mapping。在這個示例中我將url-pattern設(shè)為"/app/*",也就是說,url的匹配是基于路徑來做的。這只是我的個人喜好而已,你也可以將它設(shè)成"*"。
          既然是在講struts2的零配置,當(dāng)然是可以不要任何配置文件的。但是為了更好地進(jìn)行“配置”,我還是建立了struts.xml文件(在src/main/resources目錄下)。我不喜歡url最后都有個action后綴,現(xiàn)在,我在struts.xml中配置struts.action.extension,將這個后綴去掉:
          xml 代碼
           
          1. <struts>  
          2.     <constant name="struts.action.extension" value="" />  
          3. </struts>  

          然后我在src/test/java下建立demo/RunJetty.java文件,main方法如下:
          java 代碼
           
          1. public static void main(String[] args) throws Exception {  
          2.     Server server = new Server(8080); //也可以改成其它端口  
          3.     File rootDir = new File(RunJetty.class.getResource("/").getPath()).getParentFile().getParentFile();  
          4.     String webAppPath = new File(rootDir, "src/main/webapp").getPath();  
          5.     new WebAppContext(server, webAppPath, "/");  
          6.     server.start();  
          7. }  

          現(xiàn)在,在Eclipse里運行或調(diào)試這個RunJetty.java,用瀏覽器打開http://localhost:8080/看看吧。如果不出問題,應(yīng)該可以訪問到webapp目錄下的index.html了。有了Jetty,你還在用MyEclipse或其它插件么?

          二、零配置

          首先要澄清一點,這里說的零配置并不是一點配置都沒有,只是說配置很少而已。
          Struts2(我只用過Struts 2.0.6和2.0.9,不清楚其它版本是否支持零配置)引入了零配置的新特性,元數(shù)據(jù)可以通過規(guī)則和注解來表達(dá):A "Zero Configuration" Struts application or plugin uses no additional XML or properties files. Metadata is expressed through convention and annotation.
          目前,這個新特性還在測試階段,但經(jīng)過一段時間的使用,我覺得這個特性已經(jīng)可用。下面我講一下如何使用它。
          1. Actions的定位
          以前需要在xml配置文件中配置Action的name和class,如果使用零配置,所帶來的一個問題就是如何定位這些Action。我們需要在web.xml中找到struts2的filter的配置,增加一個名為actionPackages的init-param,它的值是一個以逗號分隔的Java包名列表,比如:demo.actions1,demo.actions2。struts2將會掃描這些包(包括這些包下邊的子包),在這些包下,所有實現(xiàn)了Action接口的或者是類名以“Action”結(jié)尾的類都會被檢查到,并被當(dāng)做Action。
          以前,我們寫Action必須要實現(xiàn)Action接口或者繼承ActionSupport。但是,上面提到的類名以"Action"結(jié)尾的類并不需要這樣做,它可以是一個POJO,Struts2支持POJO Action!
          下面是actionPackages的配置示例:
          xml 代碼
           
          1. <filter>  
          2.   <filter-name>struts2</filter-name>  
          3.   <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>  
          4.   <init-param>  
          5.     <param-name>actionPackages</param-name>  
          6.     <param-value>demo.actions1,demo.actions2</param-value>  
          7.   </init-param>  
          8. </filter>  

          2. 示例
          現(xiàn)在我們建立demo.actions1.app.person和demo.actions2.app.group兩個包,在demo.actions1.app.person包下建立ListPeopleAction.java,在demo.actions2.app.group下建立ListGroupAction.java。作為示例,這兩個類只是包含一個execute方法,返回"success"或"error",其它什么都不做:
          java 代碼
           
          1. public String execute() {  
          2.     return "success";  
          3. }  

          在Filter的配置中,我指定actionPackages為demo.actions1,demo.actions2,當(dāng)系統(tǒng)啟動時,Struts2就會在這兩個包下掃描到demo.actions1.app.person.ListPeopleAction和demo.actions2.app.group.ListGroupAction。

          3. Action and Package name
          Struts2掃描到Action后,從actionPackages指定的包開始,子包名會成為這個Action的namespace,而Action的name則由這個Action的類名決定。將類名首字母小寫,如果類名以Action結(jié)尾,則去掉"Action"后綴,形成的名字就是這個Action的名字。在如上所述的示例中,actionPackages指定為demo.actions1,demo.actions2,那么你可以這樣訪問demo.actions1.app.person.ListPeopleAction:
                          http://localhost:8080/app/person/listPeople

          4. Results
          Struts2是通過"Result"和"Results"兩個類級別的annotations來指定Results的。
          作為示例,我們在webapp目錄下建兩個html文件:success.html和error.html,隨便寫點什么內(nèi)容都可以?,F(xiàn)在假設(shè)我們訪問/app/person/listPeople時,或Action返回success就轉(zhuǎn)到success.html頁面,若是error就轉(zhuǎn)到error.html頁面,這只需要在ListPeopleAction類上加上一段注解就可以了:
          java 代碼
           
          1. @Results({  
          2.     @Result(name="success", type=NullResult.class, value = "/success.html", params = {}),  
          3.     @Result(name="error", type=NullResult.class, value = "/error.html", params = {})  
          4. })  
          5. public class ListPeopleAction {  
          6.     public String execute() {  
          7.         return "success";  
          8.     }  
          9. }  

          同上,我們給ListGroupAction也加上注解。
          現(xiàn)在,我們已經(jīng)完成了一個零配置的示例。我們并沒有在xml文件里配置ListPeopleAction和ListGroupAction,但它們已經(jīng)可以工作了!
          用Eclipse運行RunJetty,然后用瀏覽器訪問http://localhost:8080/app/person/listPeople和http://localhost:8080/app/group/listGroup看看,是不是正是success.html(或error.html)的內(nèi)容?

          5. Namespaces
          如上所述,namespace由包名所形成,但我們可以使用"Namespace"注解來自己指定namespace。

          6. Parent Package
          這個配置用得較少。Struts2提供一個"ParentPackage"注解來標(biāo)識Action應(yīng)該是屬于哪個package。

          三、使用COC

          如上所述,Struts2用注解來實現(xiàn)零配置。然而,這不是我喜歡的方式。在我看來,這不過是將配置從XML格式換成了注解方式,并不是真的零配置。而且,這種方式也未必比XML形式的配置更好。另外,對元數(shù)據(jù)的修改必然會導(dǎo)致項目的重新編譯和部署。還有,現(xiàn)在的Struts2版本似乎對Result注解中的params的處理有些問題。
          其實,Struts2的actionPackages配置已經(jīng)使用了COC,那為什么不能為Results也實現(xiàn)COC,從而去除這些每個Action都要寫的注解?
          在嚴(yán)謹(jǐn)?shù)捻椖恐?,package、action的名稱和頁面的路徑、名稱一定存在著某種關(guān)系。比如,頁面的路徑可能和package是對應(yīng)的,頁面的名稱可能和action的名稱是對應(yīng)的,或是根據(jù)某種法則運算得到。我們知道webwork2和struts2有個配置叫g(shù)lobal-results。我們?yōu)槭裁床荒芨鶕?jù)這些對應(yīng)規(guī)則寫個Result,將它配到global-results中,從而真正免去result的配置?
          事實上,我推薦Struts2的使用者只用Struts2輸出XML或JSON,放棄UI,頁面這層還是使用標(biāo)準(zhǔn)的HTML、CSS和一些JS組件來展現(xiàn)。許多人反映Struts2慢,確實,Struts2是慢,很慢!慢在哪兒?很大一部分因素是UI這層引起的,特別是使用了過多的Struts2的tag,并使用了ajax theme。但是,如果我們放棄了Struts2的笨拙的UI,Result只輸出XML或JSON,UI則使用標(biāo)準(zhǔn)的HTML+CSS,使用JS組件(DOJO、Adobe Spry Framework、YUI-Ext等)來操作Struts2的輸出數(shù)據(jù),情況將會如何?我們會得到一個高性能、高可配的、UI和應(yīng)用服務(wù)器的職責(zé)分割更為明確、合理的、更易于靜態(tài)化部署的開發(fā)組合。
          這似乎是閹割了Struts2,但是這樣閹割過的Struts2擺脫了性能低下的包袱,更輕、更現(xiàn)代化。
          有些扯遠(yuǎn)了,言歸正傳,不管是讓Struts2輸出XML或JSON,還是輸出頁面,我們都有辦法根據(jù)項目的規(guī)則寫一個Result,將它配到global-results中,從而大大減少Result的配置。
          假設(shè)我們讓Struts2只輸出JSON,有個jsonplugin可以做這件事。使用JsonResult時,不再需要知道頁面的位置、名稱等信息,它僅僅是數(shù)據(jù)輸出,那么我們就可以將這個Result配成全局的,大部分Action將不再需要Result的配置。
          作為示例,我假設(shè)我的例子中輸出的兩個html頁面(success.html和error.html)是JSON,我們看看怎么免去我例子中的兩個Action的Result注解。
          首先,我們刪去ListPeopleAction和ListGroupAction兩個Action的注解,并修改struts.xml文件,加入:
          xml 代碼
           
          1. <package name="demo-default" extends="struts-default">  
          2. <global-results>  
          3. <result name="success">/success.html</result>  
          4. </global-results>  
          5. </package>  

          請記住這只是一個示例,為了方便,我沒在項目中加入jsonplugin來作真實的演示,我只是假設(shè)這個success是json輸出,讀者可以自行使用jsonplugin來作實驗。

          現(xiàn)在,離成功不遠(yuǎn)了,但是項目仍然不能正常運行。我們的Action返回success,但并不會匹配到global-results中配置。為什么呢?因為,我們這里是把global-results配置到"demo-default"這個package下的,而Struts2根據(jù)actionPackages找到的Action不會匹配到這個package上。解決辦法也很簡單,還記得上面講到的Parent Package吧?給Action加個注解,指定ParentPackage為"demo-default"。但這樣可不是我喜歡的,其實有更好的辦法,我們在struts.xml中加個constant就好了:
          xml 代碼
           
          1. <constant name="struts.configuration.classpath.defaultParentPackage" value="demo-default" />  

          現(xiàn)在,大功告成!運行RunJetty來測試下吧!你可以訪問/app/person/listPeople,可以訪問/app/group/listGroup,而所有的配置僅僅是web.xml和struts.xml中的幾行,我們的Java代碼中也沒有加注解。如果再加上幾百個Action呢?配置仍然就這幾行。
          可是,某些Action確實需要配置怎么辦?對這些Action,你可以加注解,也可以針對這些Action來寫些XML配置。一個項目中,大部分Action的配置是可以遵從一定規(guī)則的,可以使用規(guī)則來簡化配置,只有少部分需要配置,這就是COC。

          posted @ 2008-10-04 14:08 Loy Fu 閱讀(1040) | 評論 (0)編輯 收藏
          僅列出標(biāo)題  下一頁
          主站蜘蛛池模板: 威宁| 新余市| 象州县| 澄江县| 二连浩特市| 博湖县| 象山县| 平邑县| 塔河县| 广昌县| 吉木乃县| 凤冈县| 宁陕县| 和田县| 防城港市| 岑巩县| 井研县| 仁化县| 桐梓县| 德安县| 太和县| 巴东县| 临武县| 清丰县| 桦南县| 全椒县| 乌拉特中旗| 安泽县| 比如县| 盖州市| 道真| 西乌珠穆沁旗| 沧源| 辽中县| 新丰县| 建水县| 基隆市| 怀安县| 锡林郭勒盟| 东平县| 祁门县|