1. 程式人生 > >Struts MVC 框架 (讓你一步步成為高手)

Struts MVC 框架 (讓你一步步成為高手)





web應用的分層


互動層,表現資料,收集資料,也就是檢視層,接受請求,通過處理層完成相應的響應。(V,C)


處理層,完成資料的處理,也就是業務層(M)。

MVC設計模式(應用觀察者模式的框架模式)

M model,模型,操作資料的業務處理層。

V view,示圖,採集和顯示資料,為業務層提供資料,表現業務層輸出的資料,只關心資料的型別,不管新資料的來源。

C ctrl,控制器,也就是檢視層和模型層橋樑,控制資料的流向,接受檢視層發出的事件,並重繪檢視。


MVC框架的實現模型


模型一:


JSP+JavaBean,JSP既充當控制,又充當檢視,以頁面為核心,JSP使用jsp:useBean,他不能夠實現不同的頁面,顯示不同的資料,需要藉助於中間類來呼叫JavaBean的方法才能實現。

模型二:

JSP+Servlet+JavaBean,以控制為核心,JSP只負責顯示和收集資料,sevlet,連線檢視和模型,將檢視層資料,傳送給模型層,JavaBean,分為業務類和資料實體,業務類處理業務資料,資料實體,承載資料,基本上大多數的專案都是使用這種MVC的實現模式。

StrutsMVC框架

Struts是使用MVC的實現模式二來實現的,也就是以控制器為核心。

Struts提供了一些元件使用MVC開發應用程式:


Model:Struts沒有提供model類。這個商業邏輯必須由Web應用程式的開發者以JavaBean或EJB的形式提供

View:Struts提供了action form建立form bean, 用於在controller和view間傳輸資料。此外,Struts提供了自定義JSP標籤庫,輔助開發者用JSP建立互動式的以表單為基礎的應用程式,應用程式資原始檔保留了一些文字常量和錯誤訊息,可轉變為其它語言,可用於JSP中。

Controller:Struts提供了一個核心的控制器ActionServlet,通過這個核心的控制器來呼叫其他使用者註冊了的自定義的控制器Action,自定義Action需要符合Struts的自定義Action規範,還需要在struts-config.xml的特定配置檔案中進行配置,接收JSP輸入欄位形成Action form,然後呼叫一個Action控制器。Action控制器中提供了model的邏輯介面。


寫一個基於Struts的web應用

1,建立一個符合標準的web應用的結構,也就是一個有WEB-INF資料夾的應用資料夾,在應用中需要使用到Struts的一些jar檔案,要放到WEB-INF的lib資料夾下,這些jar檔案都在struts的zip檔案中的/struts-1.2.9-bin/lib下還有struts-1.2.9-bin/contrib/struts-el/lib下的standard.jar、jstl.jar和struts-el.jar。

2,在web.xml中配置Struts的核心控制器ActionServlet,並指明Struts的配置檔案的所在位置WEB-INF下,在struts的檔案中有一個樣板的web.xml檔案,使用這個web.xml檔案來部署應用就可以了 ,這個樣板在struts的zip檔案中的struts-1.2.9-src.zip檔案中的web/examples/WEB-INF/web.xml就是樣板檔案。部署應用看struts是否釋出成功。

<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>

</servlet>

<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>


3,寫jsp頁面和業務,實體,和自定義控制器類Action,自定義Action是要繼承於Action類

例:
import org.apache.struts.action.*;
import javax.servlet.http.*;

public class LoginAction extends Action{
public ActionForward execute(ActionMapping mapping, ActionForm form,

         HttpServletRequest request,HttpServletResponse response) throws Exception
        {

       if(request.getParameter("username").equals("admin")&&

                     request.getParameter("passwd").equals("123")){


    return mapping.findForward("success");


    }


    return mapping.findForward("fail");


    }


}


在struts-config.xml檔案中的配置,解析配置檔案中,配置檔案的action標籤就會被對映成ActionMapping物件。


<struts-config>
  <form-beans>
     <form-bean name="xxx" type="ActionForm的類全名">
     <form-bean name="LoginForm" type="basic.LoginForm">
  </form-beans>
  <action-mappings>


     <action path="/basic/login"  type="alan.struts.basic.LoginAction" 
  name="xxx" scope="request|sessio(預設值)">
        <forward name="success" path="/basic/success.jsp"/>
        <forward name="fail" path="/basic/fail.jsp" redirect="false"(重定向,預設false)/>
      </action>

    <action path="action的路徑,在form的action中寫的那個路徑" type="action的類全名">
      <forward name="在自定義的Action中使用的findForward方法的引數" path="跳轉頁面的路徑"/>
      <forward name="xxx" path="xxx/xxx.jsp"/>
    </action>

  </action-mappings>

</struts-config>






ActionForm是可以自動將表單中的資料封裝成物件,當然,一個自定義ActionForm也是要遵守Struts規範的,也就是要繼承於ActionForm,並在以上的struts-config.xml進行配置。

ServletController(ActionServlet和自定義的Action),配置Ctrler需要配置struts-config.xml,通過客戶端form的action來查詢呼叫相應的action,自定義action中的mapping對應的是配置檔案中的forward標籤,通過forward的path屬性來跳轉到相應的路徑。


基於struts的web應用的開發步驟


1,對應用環境進行配置

2,建立web應用的結構,需要將struts應用的jar檔案進行部署。

3,在web伺服器部署struts

4,配置struts-config.xml檔案,配置Actoin

5,寫自定義Action,實體,以及業務類


ActionForm的校驗


<struts-config>
  <form-beans>
     <form-bean name="xxx" type="ActionForm的類全名">
     <form-bean name="LoginForm" type="basic.LoginForm">
     <!--配置ActionForm類-->
  </form-beans>
  <action-mappings>
     <action path="/basic/login"  type="alan.struts.basic.LoginAction" 
                 name="xxx" scope="request|sessio(預設值)Form的儲存空間">
        <forward name="success" path="/basic/success.jsp"/>
        <forward name="fail" path="/basic/fail.jsp" redirect="false"(重定向,預設false)/>
      </action>
   <action-mappings>
</struts-config>


ActionForm的校驗是struts提供的一項類似於Javascri&#112;t的表單校驗的功能。他可以驗證使用者填寫的表單資料的正確性。


ActionForm的校驗,如果表單中的資料符不符合規定格式的要求,ActionForm的validate()方法會返回一個Acti&#111;nError物件,Acti&#111;nError物件中封裝了一個或多個應用發現的校驗錯誤,每一個錯誤有一個ActionMessage物件表達,我們可以通過判斷這個Acti&#111;nError的物件是否為空,如果為空那麼表單的資料符合格式要求,不為空就是表單項中就有不符合格式要求的項。


struts標籤


在使用struts標籤的JSP頁面中要先加上以下的標籤庫的引用
<%@taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>


<bean:message key="errors.username.required">這個標籤可以從指定的資原始檔中根據指定的key值來取得可以對應的值,但是需要在struts-config.xml中進行配置。
配置資源,這些資源可以在ActionMessage中使用,也就是在構造ActionMessage是指定資原始檔中的key這樣,在發現校驗錯誤時,就可以先在資原始檔中指定的key的值了。可以使用struts的<html:errors>
<html:message>、<bean:message>標籤都可以顯示指定錯誤的訊息。
<struts-config>
    .....
    <message-resources parameter="alan.struts.message.MessageResource" />
    <!--使用message標籤時配置資原始檔的位置-->
</struts-config>


struts會自動的判斷返回Acti&#111;nError是否為空,如果是空可以自動的轉向指定頁面,也可以強制不進行校驗,雖然可以在Form中不去覆蓋validate()方法,但是那樣是不可取的。要實現上面提得到功能還需要在struts-config中配置。
<action   path="/basic-validate/login"  type="alan.struts.basic.LoginAction"
         name="loginValidateForm" scope="request"
         validate="true"  input="/basic-validate/login.jsp">
    <!--scope可以指定Form的存放空間,預設為sessoin-->
    <!--action標籤中配置validate="false"可以不進行校驗,input是指定校驗出錯跳轉的頁面-->
    <forward name="success" path="/basic-validate/success.jsp"/>
    <forward name="fail" path="/basic-validate/fail.jsp"/>
</action>


<html:message id="error"><!--id屬性是ActionMessage存放在空間中的key-->
  <h1>${error}</h1>
</html:message>
<html:errors>標籤只會原樣輸出在Acti&#111;nErrors中ActionMessage對應資原始檔中對應的值。
<html:messages>標籤還可以對輸出在Acti&#111;nError中ActionMessage對應資原始檔中對應的值作一些顯示效果的修改。
<bean:message key="xxx.xxx">標籤只會取資原始檔中指定key所對應的值,使用bean:message標籤可以實現國際化。


struts的html標籤


struts的html標籤的使用類似於html標籤,但是少有區別,指定型別的方式變成使用不同的標籤,這樣會繫結struts,所以旨在需要時使用。
<html:form method="post" action="/basic-validate/login">
<!--
   struts的html標籤中的action可以只寫轉到的actionpath,struts會在解析是自動新增需 要的部分  
-->
<html:text property="userName" />
<html:password property="password" redisplay="false"/>
        <!--redisplay="false"不進行回寫,只有html:password標籤可用-->
        <html:radio property="hibbos">
<html:submit value="login" />
</html:form>


Struts預定義的Action類

注意:在使用繼承Struts預定義的Action類,一定不要覆蓋execute方法,否則會導致無法呼叫自定義Action相應方法。

DispatchAction類(org.apache.struts.actions.DispatchAction)
DispatchAction類是Action類的子類,他提供了有實現的execute方法。

我們寫的自定義Action類,可以繼承DispatchAction類,但不要覆蓋execute方法,可以在自定義類中寫反回值和引數表都與execute方法相同的方法,可以通過在struts-congfig.xml中為這個action的配置中新增一個引數,來判斷調哪一個方法,實際上DispatchAction類就是通過反射機制,通過form中引數呼叫了自定義Action中的方法,當然這些方法的定義要符合規範,使用繼承DispatchAction類的自定義的Action類,也就會共享同一的Action路徑。


注意:使用繼承DispatchAction類的自定義的Action,只會匹配一個action路徑,只能共享一個ActionForm,如果加上校驗,會產生form表單的引數不一致的情況,會導致校驗無法通過。


例:
public class MyAction extends DispatchAction{
ActionForward add(ActionForm form,HttpServletRequest request,HttpServletResponse                                         response ,ActionMapping mapping) throws Exception
        {
                    return mapping.findForward("sucess")                     
        }
}


<action path="/add"  type="MyAction" parameter="methodName">
    <!--parameter屬性是和form中隱藏域的名字相對應的-->
    <forward name="sucess" path="/sucess.jsp"/>
</action>


<from action="add.do" method="post">
   <input type="hidden" name="methodName" value="add"/>
   <!--
      使用隱藏域為struts傳遞要呼叫自定義Action中方法的方法名,是通過與struts-config.xml
      中action標籤中的parameter和name屬性相對應來獲取隱藏域的value。
   -->
   <input type="submit" value="submit"/>
</from>


MappingDispatchAction類(org.apache.struts.actions.MappingDispatchAction)


MappingDispatchAction類是DispatchAction的子類,他和DispatchAction不同點就是可以去匹配多個action路徑,這樣也就是結決了共用ActoinForm的校驗問題了,多個Action的路徑使用同一的自定義Action類,這樣就不用共享同一個ActionForm,也就不會有校驗問題了。




例:
public class MyAction extends MappingDispatchAction{
ActionForward add(ActionForm form,HttpServletRequest request,HttpServletResponse                                         response ActionMapping mapping) throws Exception
        {
                    return mapping.findForward("add")                     
        }
        ActionForward del(ActionForm form,HttpServletRequest request,HttpServletResponse                                         response ActionMapping mapping) throws Exception
        {
                    return mapping.findForward("del")                     
        }
}


<action path="/add"  type="MyAction" parameter="add">
   <!--parameter屬性是指定呼叫方法的名字-->
   <forward name="add" path="/add.jsp"/>
</action>        
<action path="/del"  type="MyAction" parameter="del">
   <forward name="del" path="/del.jsp"/>
</action>


在JSP頁面中也不用在使用隱藏域傳遞引數,直接在form中的action中就可以直接使用xxx.do匹配了。
<form action="add.do" method="post">
   <input type="submit" value="submit"/>
</form>
<form action="del.do" method="post">
   <input type="submit" value="submit"/>
</form>


LookupDispatchAction(org.apache.struts.actions.LookupDispatchAction)


LookupDispatchAction類也是DispatchAction類的子類,他所實現的功能是解決一個表單多種提交問題的
,他是通過使用資原始檔,用submit按鈕的value來作為資原始檔中的key所對應的值,通過這個值來找到對用的key,在使用這個key來獲得指定Map中所對應的值,這個值就是要呼叫的方法名。


submit的value---->MessageResource.properties中的key----->Map中key對相應的值---->action


例:
<%@taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>


<form method="post" action="${pageContext.request.contextPath}/lookup/adddel.do">
<input type="submit" value="<bean:message key="button.add" />" name="methodName">
        <!--注意name="methodName"是和strut-config.xml中action標籤中的parameter屬性-->
<input type="submit" value="<bean:message key="button.delete" />" name="methodName">
</form>


MessageResource.properties


button.add=add new user
button.delete=delete user


注意:在繼承LookupDispatchAction時,要覆蓋getKeyMethodMap()方法,並定義Map,向Map中放入指定的鍵值對。


public class AddDelLookupDispatchAction extends LookupDispatchAction
{
public Map getKeyMethodMap(){
Map keyMethodMap= new HashMap();
keyMethodMap.put("button.add", "add");
keyMethodMap.put("button.delete", "delete");
return keyMethodMap;
}
    public ActionForward add(ActionMapping mapping,ActionForm form,
                   HttpServletRequest request,HttpServletResponse response) throws Exception
    {    
        return mapping.findForward("add");
    }
    public ActionForward delete(ActionMapping mapping,ActionForm form,
                   HttpServletRequest request,HttpServletResponse response) throws Exception
    {
    return mapping.findForward("delete");
    }
}


<action   path="/lookup/adddel"  type="alan.struts.actions.AddDelLookupDispatchAction"
         parameter="methodName">
            <forward name="add" path="/add.jsp"/>
            <forward name="delete" path="/delete.jsp" />
</action>
<message-resources parameter="alan.struts.message.MessageResource" />


自定義的Action類的一些規則
1,儘量不要在Action類中使用(靜態)成員變數,如果使用要加上同步。
2,儘量使各模組間的耦合性降低,最大限度的針對介面程式設計。
3,可以將共程式碼方在覆蓋父類的方法中,最後可以用super.xxx(xxx)來呼叫父類的方法,使用父類的實現,並加上了自定義的功能。





Struts的Token(令牌)機制

Struts使用Token機制,來防止惡意的破壞和重複提交問題,也就是點選後退後在再提交,這是Struts無法發現的,在form中生成一個token碼,在session中也報村有一個同樣的token碼,當表單提交後,判斷兩個token碼向等後,就會改變session中的這個token碼,當然在用回退後,form的token碼是不會變的,在提交,還會判斷兩個token碼是否相等,如果不等就會丟擲異常,證明這是過時的垃圾資料。

void saveToken(HttpServletRequest request)方法用於將在客戶端生成的token碼,儲存在session中。

void resetToken(HttpServletRequest request)方法用於重置token碼,生成新的token碼。

boolean isTokenValid(HttpServletRequest request,boolean reset)判斷token碼是否相等,並且是否重置token碼。reset是設定是否重置token碼,一般設為true。


設定token碼


 public ActionForward toadd(ActionMapping mapping, ActionForm form,


            HttpServletRequest request, HttpServletResponse response)throws Exception


    {


        saveToken(request);


        return mapping.findForward("next");


    }


驗證token碼

 public ActionForward add(ActionMapping mapping, ActionForm form,


            HttpServletRequest request, HttpServletResponse response)throws Exception
    {

        if(isTokenValid(request, true)){

            request.setAttribute("message", "contratulation!");


        } else {

            request.setAttribute("message", "sorry");


        }

        return mapping.findForward("next");


    } 


Struts的異常處理

Struts只處理action的異常,

配置struts的異常處理

全域性的異常處理
<global-exceptions>
   <exception key="error" path="xxx/xxx" type="xxx.xxx.Xxxx">
</global-exceptions>


<action path="xxx/xxx" type="xxx.xxx.Xxxx">

  ....

  <exception key="xxx" path="xxx/xxx" type="xxx.xxx.Xxxx">

</action>


在exception標籤中的key,也就是在出現異常時會封裝在Acti&#111;nErrors中,也就是可以在頁面中使用。


Acti&#111;nError(String key, Object value0),可以通過在構造Acti&#111;nError時,指定不同的key值來對異常進行分類,並且在html:error標籤的

自己構造Acti&#111;nErrors並使用下面的方法傳送

void saveErrors(HttpServletRequest request,Acti&#111;nErrors errors)這個方法用以把封裝了異常的Acti&#111;nErrors的key儲存到request中。   

Struts動態Form

DynaActionForm,動態的ActionForm,動態的form不需要去寫特定的ActionForm類,只需要在配置檔案中配置好form中的屬性名和屬性型別。以,Struts會自動的封裝成動態的Form。

<form-bean name="xxx" type="org.apache.struts.action.DynaActionForm">


   <from-property name="xxx" type="xxx.xxx.xxx">


   <from-property name="xxx" type="xxx.xxx.xxx">


     ...


     ...


</form-bean>


動態的ActionForm的使用上和普通的ActionForm相同。


在Struts中的Form要是粗粒度的,不要寫太多的Form,要根據情況確定Form的多少。






Struts的動態校驗

Struts可以通過繼承DynaActionForm,並覆蓋validate()方法來打倒校驗的目的。也可以通過配置校驗規則來進行動態Form的校驗實質上就是翻譯成javasctipt程式碼。


使用校驗規則來進行動態校驗時需要寫validation.xml,validator-rules.xml


還需要對struts-config.xml進行配置


validation.xml

<form-validation>


  <formset>


    <form name="/token/add">


      <field property="name" depends="required,minlength, maxlength">


        <arg0 key="token.name" />


        <arg1 name="minlength" key="${var:minlength}" resource="false"/>


        <arg1 name="maxlength" key="${var:maxlength}" resource="false"/>


        <var>


          <var-name>minlength</var-name>


          <var-value>5</var-value>


        </var>


        <var>


          <var-name>maxlength</var-name>


          <var-value>8</var-value>


        </var>


      </field>


    </form>


  </formset>


</form-validation>






struts-config.xml

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">


    <set-property


        property="pathnames"


        value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>


  </plug-in>



Struts的標籤

bean,html,logic標籤庫,在Struts的標籤也支援JSP2.0的EL表示式。


bean標籤庫


<bean:... >


bean標籤庫,是用來訪為JavaBean的屬性或者是為Bean的屬性賦值,建立JavaBean,類似於JSP中的jsp:useBean動作的功能。


bean標籤庫中的標籤中大部分都有以下的屬性


id="xxx" 指定Bean的名字標識,Bean在被讀出後將引用儲存在以這個id命名的物件中,也就是在JSP中使用的變數的引用。


name="xxxx"指定要讀取Bean的名字


property="xxxx"


scope="page|request|session|application"


資源讀取標籤


<bean:resource>讀取資原始檔


<bean:cookie>使用這個標籤可以對Cookie進行操作


<bean:header>讀取header資訊






例:


<bean:resource id="indexpage" name="index.jsp"/>


<bean:write name="indexpage"/>

<bean:head id="head" name="user-agent"/>


<bean:write name="head"/>

<bean:cookie id="testcookie" name="/taglib/bean-cookie" value="emptyValue"/>

<%


if(testcookie.getValue.equals("emptyValue")){


             javax.servlet.http&#46;cookie cook=new javax.servlet.http&#46;cookie("/taglib/bean-cookie","taglib cookie");


             cook.setComment("test");


             cook.setMaxAge(3600);


             response.addCookie(cook);


        }


%>


可以將資源寫到頁面的標籤


<bean:write>將Bean的屬性加入到輸出流中


<bean:write name="xxx"/>name屬性是要加入的資源,也就是先前在其他資源標籤中的id屬性定義的名字

<bean:define>定義變數


例:<bean:define id="test" value="test in Struts">


    <bean:write name="test"/>

<bean:message>讀取訊息,可以根據key讀取訊息。


例:


<bean:message key="org.test">


html標籤庫

<html:form>


對應html中的<form>,使用<html:form>會將表單中的屬性自動封裝成Form,他的action屬性可以直接寫struts的配置檔案中的path


<html:text>、<html:password>、<html:textarea>、<html:hidden>、<html:submit>


<html:reset>、<html:checkbox>、<html:radio>、<html:select>、<html:option>


以上者寫標籤的使用是和html中的form相對應的。


<html:options>這個標籤用來表示一組選擇項


<%


   java.util.ArrayList list=new java.util.ArrayList();


   list.add(new org.apache.struts.util.LabelValueBean("show value","value"));


   list.add(new org.apache.struts.util.LabelValueBean("show value1","value1"));


   pageContext.setAttribute("vlauelist" list);


%>


<html:form action="xxx.do">


   <html:select property="test">


      <html:options collection="valuelist" property="value" labelProperty="label"/>


   </html:select>


</html:form>


Struts的Tiles框架


Tiles是一個框架,他實現了頁面的複合檢視,頁面程式碼中不僅有資料,也有頁面的佈局格式。


要在基於Struts應用中使用Tiles框架,就要在struts-config.xml中配置


<plugin className="org.apache.struts.tiles.TilesPlugin">


  <set-property property="definintions-config" value="/WEB-INF/tiles-defs.xml">


  <!--定義tiles佈局檔案tiles-defs.xml-->


</plugin>


tiles的佈局配置檔案tiles-defs.xml

<tiles-definitions>


    <!-- 頁面基本佈局-->


    <definition name="pms_base" path="/common/pms_layout.jsp">


    <put name="title" value="pms title" />


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


        <put name="body"   value="some body page" />


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


    </definition>


   <!-- 其他頁面定義-->


   <definition name="add" extends="pms_base">


        <put name="title" value="add" />


        <put name="body" value="/person_add.jsp" />


    </definition>


</tiles-definitions>

在struts-config.xml中要把forward的配置更改一下


<action path="/person/toadd"  type="alan.pms.action.PersonAction"


         name="personForm" scope="request"


         parameter="toAdd">


            <forward name="add" path="add"/>


</action>






這樣就會使頁面加上header.jsp和footer.jsp顯示在配置好的頁面中


在頁面中使用tiles標籤時,要引入標籤庫,<%@taglib uri="/WEB-INF/tiles.tld" prefix="tiles"%>

<tiles:insert page="xxx.jsp">


   <tiles:put name="header" value="header.jsp">


   <tiles:put name="footer" value="footer.jsp">


</tiles:insert>


在struts-config.xml中要把forward的配置更改一下


<action path="/person/toadd"  type="alan.pms.action.PersonAction"


         name="personForm" scope="request"


         parameter="toAdd">


            <forward name="add" path="add"/>


</action>