Struts開發技巧

在經歷了《中國電信大客戶貼心服務》項目的開發以及目前正在開發中的《中國電信經營分析》項目,已累計了一些對於Struts1.1Tiles開發的一些技術和技巧,特寫出來,方便以後的開發,同時也相信能給讀者在開發Struts方面提供一些幫助。

模塊配置

1.         Struts配置文件定義

     對於系統中的某個模塊,需要在開發前定義該模塊的配置,該struts的配置文件命名爲:

struts-config-xxx.xml

xxx爲模塊的小寫英文名或縮寫,如:struts-config-sysman.xml

注意:中間爲“-”,而不是“_”連接符<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

統一保存在“WEB-INF/xml”文件夾下,並需要在web.xml中添加相應的配置文件

地址,具體如下例:

           

    <init-param>

      <param-name>config</param-name>

      <param-value>/WEB-INF/struts-config.xml, /WEB-INF/xml/struts-config-pages.xml,/WEB-INF/xml/struts-config-sysman.xml</param-value>

            </init-param>

注意:需要用“,”連接符隔開各個配置文件名

另外,所有的靜態jsp需要通過配置文件定義其“.do”形式的訪問,保存在

struts-config-pages.xml文件中,內容如下例:

   

    <!--主頁轉向-->

  <action path="/main" type="org.apache.struts.actions.ForwardAction" parameter="/main.jsp"/>

   

2.         Tiles配置文件定義

系統的框架配置文件爲tiles-defs_zh_CN.xml(通過.properties屬性文件支持國際化應用,默認是tiles-defs.xml),模塊的框架結構需要定義在裏面,如下例:

<!-- 定義默認首頁 -->

    <definition name="default.frame" path="/layouts/defaultLayout.jsp">

        <put name="title"  value="歡迎進入電信經營分析系統" />

        <put name="header" value="/top.jsp" />

        <put name="body"   value="default.body" />

        <put name="footer" value="/buttom.jsp" />

    </definition>

<!-- 定義默認首頁的body -->   

    <definition name="default.body" path="/layouts/main.jsp" >

           <put name="logon"   value="/logon.jsp" />

           <put name="date" value="/layouts/date.jsp" />

       <put name="linkSite"   value="/layouts/link.html" />

    </definition>

框架命名規範按“系統(子系統).功能模塊.頁面模塊”,如上面的“default.frame

struts-config-pages.xml文件中的設置的頁面action可以這樣寫:

<action path="/main" type="org.apache.struts.actions.ForwardAction" parameter=" default.frame "/>

這樣就不必單獨寫一個tiles:insert的頁面,如下:

<tiles:insert definition="vip.warn.day" flush="true" />

3.         模塊中的註釋

不但需要在程序中添加必要的註釋,在定義配置文件的時候也必須需要添加相應註釋,主要是在struts-config-xxx.xmltiles-defs_zh_CN.xml這些文件中添加註釋,要把action或配置模塊的功能解釋清楚,放在配置項的前面,參見上面的配置文件

4.         對於配置文件的編輯

不能使用Jbuilder裏面的xml編輯功能,因爲JB會自動地改變xml裏面的編碼和內容,因此,對xml配置文件的編輯,要使用編輯軟件,如UE

事件定義

事件對應的類主要有ActionActionForm,還有jsp中提交的“.do”定義,以及頁面動作的提交,以login登錄爲例:

1.  類的命名定義(首字母需大寫)

形式爲“動作名+Action/Form

如:LoginAction.classLoginForm.class

2.  頁面地址定義(首字母需小寫)

如果有兩個單詞以上,第二個單詞首字母大寫,依此類推

形式爲“動作名”

如:login.dologinSys.do

jsp文件命名也按此規範

3.  頁面動作定義

因爲jsp頁面中的Form對應ActionForm,其本身有action這個屬性,所以頁面動作如果定義也爲action,會引起不必要的麻煩,所以,把頁面動作統一定義爲“act”,

如需要編輯某條記錄,地址如下:

/editRecord.do?act= Edit

如需要刪除,地址如下:

/editRecord.do?act=Delete

4.  對於菜單和操作事件觸發的控制機制

由於系統中的菜單和操作都是由“.do”形式向服務端發請求的,因此需要一套機制來控制哪些是對菜單的事件請求,哪些是對操作的事件請求;

我們在系統中引入了Filter過濾器,對所有請求進行控制,以及判斷用戶是否登錄和是否有對資源(菜單等)訪問權限等;

約定:

jsp頁面上對於系統中菜單的請求都是“GET”方法,對於操作的Action都是“POST”方法;

有了這樣的約定,在Filter中先判斷request的請求方法,如果是“GET”方法,則認爲是對菜單的請求,所以去“菜單表”根據請求地址讀取相應的記錄,並讀取用戶的權限表,判斷用戶的菜單權限;

如果是“POST”的方法,則認爲是對操作的請求,並提取request中的“act”動作,進行對用戶的權限點的判定。

 

參數信息獲取

1.         公共參數信息通過Plugin方式在Web服務啓動時將變量放入application中,使得在任何需要該變量的jsp中都可以調用;

方式如下:

public void setServletContext(ActionServlet actionServlet) {

try {

           ServletContext sc = actionServlet.getServletContext();

        //SysInitPwd

   sc.setAttribute(Constants.SYS_INIT_PWD,SelectLists.getSysConfig("PWDINIT"));

action等程序中的調用方式:

getServlet().getServletContext().getAttribute(“…”);

 

2.         對於頁面上需要展示的數據儘量存放在request這個範圍裏,可以減輕服務器端內存負載,方式如下:

//調用員工處理類

StaffDeal sd=new StaffDeal();

//根據員工狀態查詢員工

ArrayList al=sd.qryStaff(strState);

//放入request

    request.setAttribute("staffInfo",al);

3.         私有的或需要根據用戶的屬性來獲取參數信息的,可以在tiles的定義中使用“controlClass=xxx”這個方式獲取,配置如下例:

<definition name="vip.welcome" path="/vip/welcome.jsp" controllerClass="viptx.logic.vip.welcomeAction" />

implements Controller中的perform方法,代碼如下例:

public void perform(ComponentContext componentContext,

                      HttpServletRequest request,

                      HttpServletResponse response,

                      ServletContext servletContext) throws IOException,ServletException  {

    HttpSession session = request.getSession();

    // Get current session.

    User user = (User) session.getAttribute(Constants.USER_KEY);

    if (user == null) {

      return null;

    }

    String uid = user.getUserid();

    String sql = "select userid,content from ti_salutatory where userid='"+uid+"'";

    try {

     

    }

    catch (Exception ex) {

      throw new ServletException(ex.getMessage());

    }

}

4.         對於後臺出錯信息在前臺頁面顯示的技巧

首先在properties配置“message.common={0}

然後在Action類中使用ActionErrorsActionMessages時,方法如下:

ActionMessages ams = new ActionMessages(); //例外處理

Try{

}

catch (Exception ex) {

    ex.printStackTrace();

    ams.add(ActionMessages.GLOBAL_MESSAGE,

                 new ActionMessage("message.common", ex.getMessage()));

}

            finally {

if (!ams.isEmpty()) {

           saveMessages(request, ams);

     }

}

       jsp頁面中使用方法如下:

       <html:messages id="msg" message="true">

              <font color="red"><bean:write name="msg"/></font>

       </html:messages>

       如果有後臺的messages產生,前臺頁面就可以出現報錯信息

5.         系統配置文件

系統參數如數據庫連接等在sysConfi.xml文件中配置,存放在“WEB-INF/xml”文件夾下,請參見該文件。

開發規範和公用方法

關於java的開發規範參見《Java 編程規範.doc》,這裏僅給出用struts開發中一些的規範:

1.         java文件存放按業務邏輯劃分,並用模塊作爲包名的形式,如:telecombi.logic.sysman.security

包名都爲小寫形式

所有的ActionActionForm都存放在同一包下,便於管理,不要跨包調用

2.         所有ActionForm中的屬性均爲“首單詞小寫+第二個單詞首字母大寫+…”的形式,如:staffIdstaffName,不允許使用“_”爲單詞連接符

3.         需要驗證的頁面,均需要客戶端和服務端兩次驗證(即對jsp中的Form進行javascript驗證和Action中的excute方法中進行驗證),不能只採用其中一種方法,防止客戶繞過js直接提交;

在驗證登錄提交的form時,必須使用staticJavascript="false",否則就會把javascript寫到頁面裏,如:

<html:javascript formName="logonForm"

        dynamicJavascript="true"

         staticJavascript="false"/>

<script language="Javascript1.1" src="staticJavascript.jsp"></script>

驗證的formName必須和validation.xml中的Form的名字對應起來,否則驗證無效

4.         ActionForm是代表html中的Form的,其中的變量需要和Form中的屬性對應起來,如:要在jsp中使用<form:text property="userName"/>,則使用的ActionForm中就必須有userName這個變量

5.         對於Action中的邏輯,如果處理方法在一個以上,需要另外新建一個處理類,負責對Action中的邏輯集中處理,命名爲xxxDeal,如:LoginDeal;

Action通過調用該處理類的方法,實現業務邏輯處理

6.         對數據庫的操作使用DBManager這個類,對其中的一些方法,具體介紹如下:

n         查詢結果對象化的Select操作,使用Select(String sql,String className)方法

StringBuffer sql = new StringBuffer(

        "select staff_id staffId from ts_m_staff ")

        .append("where staff_id='").append(uid).append("'");

    try {

/**

*     User是一個用戶對象類,其中有staffId這個屬性,以及對應的get/set方法,通過

*     DBManagerSelect方法獲得一個UserArrayList集合

*/

ArrayList rs = DBManager.Select(sql.toString(), User.class.getName());

/**

*     如果確定返回的只有一個對象,則可以使用

*

*/

User user=(User)rs.get(0);

    }

    catch (Exception ex) {

      throw new ServletException(ex.getMessage());

}

取出來的數據可以存放在sessionpage等裏,供jsp頁面調用,方法爲session.setAttribute(“user”,user1)

n         InsertUpdate等操作

使用DBManager裏面的executeSql(String sql)方法,如果是批量處理,使用executeBatchSql(String[] sqls)方法,返回成功標誌爲Constants.OPERATE_SUCCESS

失敗標誌爲Constants.OPERATE_FAILED

暫無其它信息返回

n         ResultSet對象向Hashtable集合對象的轉化,使用select(String sql)方法:

除了可以使用DBManagerSelect把查詢結果轉爲對象以外,還可以使用以前的直接使用ResultSet對象的方式,不過這裏返回的數據集對象爲Hashtable

Hashtable存放的數據結構爲:

columnName1 ArrayList1(該字段的結果集)

columnName2 ArrayList2(該字段的結果集)

       系統中使用該方法的比較多的是用在生成下拉框數據,從select方法返回的Hashtable取到字段值,並生成LabelValueBean,具體方法如下:

       /**公用函數 Hashtable 轉換成 ArrayList (LabelValueBean)*/

   private static ArrayList hashToLVB(Hashtable ht, String id, String name,boolean hasBlank) {

      if (ht!=null){

         ArrayList al = new ArrayList();

         ArrayList alId = (ArrayList) ht.get(id.toUpperCase());

         ArrayList alName = (ArrayList) ht.get(name.toUpperCase());

         int iLen = alId.size();

         if (hasBlank)

            al.add(new LabelValueBean("未知", "-1"));

         for (int i = 0; i < iLen; i++) {

            al.add(new LabelValueBean( (String) alName.get(i),

                                      (String) alId.get(i)));

         }

         return al;

      }

      else{

         return null;

      }

   }

n         AutoSetFormString sql, Object frm)方法介紹:

a)         該方法可以返回一個查詢數據庫後已對其中的屬性賦值的對象,使用方法如下:

User user=DBManager. AutoSetForm(sql,new User());

sql爲查詢語句

b)        該方法還可以對頁面操作後的Form進行賦值,比如在頁面上提交一個對某條記錄進行編輯的操作,當Action得到該條記錄的Id號並查詢數據庫成功後,需要把各個詳細信息setActionForm的屬性變量中去,這個時候就可以使用該方法,方法如下:

form= DBManager. AutoSetForm(sql,form);

formActionexcute方法中傳入的ActionForm

 

7.         調用存儲過程

使用DBManager中的execProc(String procName,ArrayList procPrts)方法

procName爲存儲過程名,procPrts是該存儲過程的入口參數集,返回的是ProcOuts的對象,其中有ResultExceptionInfo兩個屬性,表示返回的處理標記和異常信息(如果有的話)

8.         數據操作返回信息的處理

在對數據操作完成後,需要返回操作是否成功等信息,具體步驟如下:

n         使用屬性文件中的“messages.comm”這個key,可以對該key添加具體返回信息

n         程序中使用“ActionMessages”這個對象,java程序如下:

ActionMessages ams = new ActionMessages();

//執行結果

         ProcOuts pResult=null;

//是否調用成功

         if (pResult.getResult() == -1) {

               ams.add(ActionMessages.GLOBAL_MESSAGE,

                       new ActionMessage("message.common",

                                         pResult.getExceptionInfo()));

         }

if (!ams.isEmpty()) {

            saveMessages(request, ams);

         }

Jsp中調用方法如下:

<html:messages id="msg" message="true">

  <font color="red"><bean:write name="msg"/></font>

</html:messages>

發佈了42 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章