Struts2

struts2-第一天

框架搭建

    1.jar包的準備

    2.配置web.xml,配置struts2核心控制器,接收所有的請求(可在dispatcher.ng.filter包下拷貝,把.class去掉)。

    3.拷貝struts.xml和log4j到src目錄下。

        3.1寫個package包,給個名字:user,包就相當於一個模塊,再添加extends="struts-default"

        3.2裏面寫action標籤,寫name和實體類

        3.3裏面寫result標籤,寫name和頁面

執行的過程:請求url滿足了/*,就交給了核心控制器,它啓動會把struts.xml文件的配置全部讀到內存中,用一個對象來保存,會在這<action>裏面找有沒有login的配置,接着會找到對應的類,當action配置裏沒有配method屬性,它就執行業務邏輯控制器類裏的execute(),方法完成後會返回字符串,這個字符串會交給核心控制器,再找<result>裏對應的字符串,匹配就會用這個頁面生成響應到客戶端。

struts2-core-2.3.15.1.jar裏org/apaqi/struts有配置文件default.properties,

    1.更改請求後綴<constant name="struts.action.extension" value="do">

    2.開啓開發模式<constant name="struts.devMode" value="true">

ActionSupport類

    struts.xml裏,<package>配置extends="struts-default"的好處是,如果action裏沒有配置class屬性,將使用struts-default.xml(在覈心jar包裏)中配置的默認類com.opensymphony.xwork2.ActionSupport(最後面),如果沒有配置method,就使用execute(),如果result裏沒有配置name,默認是success

請求參數接收

    一、標量值方式接收參數

        struts對於提交到action的參數,會當作這個action有這個屬性,就會調用這個參數set方法來接收(保存)提交的參數。

    二、複合類型方式接收參數(常用)

    三、模型驅動方式獲取參數(少用)

        1.業務邏輯控制器類要實現ModelDriven<?>接口

        2.預先創建user,並提供方法返回user

        3.代碼不需要寫getset方法

    四、servlet API方式獲取參數(需掌握)

        1.業務邏輯控制器類要繼承ActionSupport

        2.通過ServletActionContext.getRequest()得到HttpServletRequest

        3.就可以用以前getParameter()

Servlet APi 獲取

    一、ServletActionContext類(重點)

        ServletActionContext.getRequest().getSession()

    二、Struts2Aware攔截器IOC模式(重點)

        1.實現ServletRequestAware接口,重寫setServletRequest(HttpServletRequest request),把參數賦值給成員變量HttpServletRequest request,後面就可以使用request。

    三、四、ActionContext類的get方法

Action動態方法

    需要開啓動態方法調用支持,<constant name="struts.enable.DynamicMethodInvocation" value="true"/>

    一、login!login.do歎號方式.注意:用感嘆號動態調用時,配置文件的action是不寫!的,在提交地址那裏寫,如不寫!指定調用的方法,默認調用execute方法。

    二、login_*統配

命名空間

    1.命名空間前面加/

        規則是:1.1如果命名空間存在,進入命名空間搜索action,action存在就執行,不存在就報異常

    1.2如果命名空間不存在,自動刪除最後的命名空間,再進行搜索

    2.加命名空間後,提交地址要加前面那段(不能/開頭),設置了後綴加後綴,但配置那裏的action的name屬性不加後綴(這裏必須注意)。

    3.當配置文件struts.xml的<package/>用了命名空間時,響應頁面一般要加/。而提交地址要加命名空間.

六、類型轉換

    2013-1-15默認會轉換?月份有0嗎?

    自定義類型轉換器的實現

        方式1.繼承DefaultTypeConverter類

        1.1如上,UserAction類要繼承ActionSupport類(如不繼承,無法顯示異常等)

        1.2重寫convertValue方法

        1.3在action包下新建一個同名的UserAction-conversion.properties,文件內容:user.loginTime屬性 = org.fkjava.converter.MyConverter轉換器

            全局的跟struts.xml配置文件放在一起

    方式2.繼承StrutsTypeConverter類(抽象類)(推薦使用)

        --有兩個要實現的方法,主要實現前臺到後臺convertFromString(Map context,String[] values,Class toType)方法,第一個參數是上下文,第二個是提交的實際數據,第三個是提交數據的類型

            方法實現邏輯:判斷values不爲空後,如果寫的是轉換時間的轉換器,判斷toType==Date.class,一旦涉及到時間對象,simpleDateFormat,從字符串轉換爲Date類型用sdf.parse(values[0])

    全局:在src下xwork-conversion.properties,java類型=自定義轉換器

    轉換錯誤顯示:

        1.默認:

        1.1<%@taglib prefix="s" uri="/struts-tags"%>,<s:fielderror>

    2.局部類型轉換失敗自定義信息

        2.1在action包下新建一個UserAction.properties文件,內容是invalid.fieldvalue.屬性名(表單提交的name屬性user.loginTime)=提示語句

        2.2throw new TypeConstraintException("日期類型轉換失敗!");

    3.全局類型轉換失敗自定義信息

        3.1 src根目錄下,fkjava.properties國際化資源文件:xwork.default.invalid.fieldvalue={0},提示信息

        3.2 struts.xml下配置常量name="struts.custom.i18n.resources" value="fkjava"/>

七、後臺驗證

      如果希望使用struts2提供的驗證框架,必須extends ActionSupport

      調用步驟:

      1.先類型轉換

      2.驗證

      3.調用目標action方法

      方式一:代碼方式實現輸入驗證

          a.對action所有方法進行驗證

          方式1:重寫ActionSupport中的validate方法

          //針對本action的所有action方法進行驗證

    public void validate(){

        System.out.println("-------validate()--------");

        if(user == null || "".equals(user.getUserName())){

            /**一旦addFieldError()加了東西,就會返回INPUT*/

            this.addFieldError("user.userName","請輸入用戶名");

        }

    }

    --輸出錯誤信息:<s:fielderror/>

      b.對單個方法進行驗證,只需要在這個方法的後面加你要驗證的方法,如login方法要驗證,validateLogin()

      方式二:配置xml方式實現輸入驗證(比較常用)

          xml文件名寫法:NoticeAction-addNotice-validation.xml針對一個action請求做後臺驗證(中間是<action name=""/>裏name的值)

                     NoticeAction-validation.xml針對整個NoticeAction處理類都做後臺驗證

      例子:

      <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" 

    "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">

    <validators>

        <field name="user.userName">

            <field-validator type="requiredstring">

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

                <message>請輸入用戶名3!</message>

            </field-validator>

            <field-validator type="stringlength">

                <param name="minLength">4</param>

                <param name="maxLength">6</param>

                <message>請輸入${minLength}~${maxLength}範圍的用戶名3</message>

            </field-validator>

        </field>

    </validators>

國際化

    表單:

    1.寫fkjava.properties國際化文件,依次再寫其他語言的properties。說明:裏面寫的就是需要替換的字眼

    2.用struts2標籤庫寫表單(先引入),表單裏的每一項多一項key的屬性,寫的就是properties裏面的key

    3.如果想動態改變語言環境,加一個帶request_locale參數的表單,如直接提交到jsp不行,就配置一個最簡單的action把表單提交到action,再<result>到jsp

    頁面:

    1.使用i18n標籤,name=資源文件前綴,<s:text name=資源文件中的key>,再裏層標籤<s:param>${username}</s:param>

    <s:i18n name="fkjava">

        <s:text name="welcome">

            <s:param>${user.userName}</s:param>

        </s:text>

    </s:i18n>

    代碼中:

    1.put之後,利用ActionContext.getContext.put("msgs",this.getText("國際化資源裏的key")),頁面上取出:${msgs}

result的type屬性

    服務器重定向

        1.dispatcher(默認),轉到資源(jsp html 其他視圖技術)

    2.chain,轉到一個action,參數有actionName,nameSpace,method等。

    客戶端重定向(參數不會自動傳遞,如需傳遞,在actionName拼接,或加<param name="user.userPass">123456</param>)

    動態跳轉:定義動態結果頁面(如果登錄名等於tom,跳到tom.html)定義成員變量typePath,並提供getset方法

    全局result

        1.包裏配置<global-results>。當局部沒有找到返回的字符串時,會去找全局,如果全局也找不到就生成默認錯誤響應。

    2.如果局部全局都有,局部起作用。

異常處理

    1.局部<exception-mapping result="result字符串" exception="java異常"/>

    2.全局<global-exception-mappings>

        <exception-mapping result="" exception=""/>

    注意:當局部異常處理找不到纔會找全局

    3.異常信息顯示

        方式一:引用struts標籤庫,<s:property value="exception.message">和<s:property value="exceptionStack">

    方式二:直接EL表達式:${exception.message}和${exceptionStack}

攔截器

   自定義攔截器

    1.寫一個類繼承AbstractInterceptor,重寫intercept方法。

    2.invocation.invoke()把控制權限交給下一個攔截器,沒有的話交給action,返回值String就是提交給action執行的方法執行完以後返回的字符串

    3.配置攔截器在package裏,引用(使用)是在action裏。

    4.一旦自定了攔截器,默認的就不起作用。

    5.攔截器的定義順序決定了調用的順序,最好先配置好默認的攔截器

    6.如果有一堆的攔截器要用,可以配置一個攔截器棧

    7.如果在一個package中不想每一個action都寫引用攔截器,可以在package裏定義默認攔截器<default-interceptor-ref name=""/>(本包有效)

   方法攔截器

        1.寫一個類繼承MethodFilterIntercepter,重寫doIntercept方法。

    2.引用時多一項參數<param name="includeMethods">login,logout</param>,指定哪些會調用攔截器(白名單)

    3.如果白名單和黑名單衝突,白取勝(邪不壓正)。

   內置攔截器

       timer:統計action方法執行耗時的攔截器

       token:防止表單重複提交

           1.在表單提交的action上調用默認攔截器<interceptor-ref name="token"/>

       2.配置當出現重複提交時到什麼頁面<result name="invalid.token">error.html</result>

       3.頁面上用struts標籤庫,在form里加上<s:token/>,其他不變

   登錄檢查

       1.自定義一個攔截器

       String result = "login";

    if(flag){

        HttpSession session = ServletActionContext.getRequest().getSession();

        User u = (User)session.getAttribute("loginUser");

        if(u != null){

            result = invocation.invoke();

        }

    }else{

        result = invocation.invoke();

    }

    return result;

       2.配置(聲明)攔截器

       3.調用攔截器(先調用系統默認),裏面還可以給攔截器參數(攔截器的成員變量要有getset方法)

freemarker

    使用要引入一個jar包和要在web.xml文件中做一個配置。

文件上傳下載(注意這裏:配置跟default.properties有關!)開始是在struts2-core-2.3.15.1.jar這個jar文件裏的

    一、單個文件上傳

        上傳的form表單的method屬性必須是post,enctype必須是multipart/form-data

        1.頁面的表單<form action="upload.do" method="post" enctype="multipart/form-data">

            <input type="file" name="headImg">

            <input type="submit" value="上傳"/>

            </form>

    這時要配置action:

         <package name="user" extends="struts-default" >

              <action name="upload" class="org.fkit.action.UserAction" method="upload">

            <result name="upload">success.jsp</result>

            <result name="input">error.jsp</result>

          </action>

         </package>

    注意這裏action配置沒有命名空間,如果有,表單提交action要加命名空間。??

    2.UserAction裏

         2.1增加屬性

            private File headImg;//接收文件用的屬性(可以跟表單的不一致,因調的是set方法)

            private String headImgFileName;

            private String headImgContentType;

            //三個屬性要增加getset方法

            說明:這樣寫才能獲取到文件名和文件類型

         2.2.upload方法裏

            //獲取服務器的資源(存儲)路徑

        String path = ServletActionContext.getServletContext().getRealPath("images");

        File file = new File(path,headImgFileName);

        if(!file.getParentFile().exists()){

             file.getParentFile().mkdirs();

        }

        FileUtils.copyFile(headImg, file);

         2.3如想方便查看上傳的文件,可設置上傳路徑:雙擊tomcat,在ServerLocations那裏,

               選中間那一欄(使用tomcat安裝路徑)。

    二、多個文件上傳

    屬性改爲數組,循環new File,其他基本不用變。

    上傳約束配置

        1.全局大小限制:struts.xml裏,配置整個工程:<constant name="struts.multipart.maxSize" value="數值">

    2.局部大小限制:局部的大小限制必須小於全局大小限制!在對應的action下配置<interceptor-ref name="fileUpload"/>攔截器,攔截器裏可以設置參數:

         <param name="maximumSize">數值</param>

    注意點:建議把默認的攔截器放在上傳約束攔截器下面。

    3.類型約束:<param name="allowedTypes">image/pjpeg,image/x-png</param>

    4.後綴約束:<param name="allowedExtensions">.jpg,.png,.bmp</param>

    三、下載

        1.struts-user.xml文件配置下載的action:

        <package name="user" namespace="/" extends="struts-default">

            <action name="download" class="org.fkjava.action.UserAction">//沒配method默認執行execute方法

            <result name="success" type="stream">

                <param name="contentType">application/octet-stream</param>

                <param name="inputName">fileStream(要與Action類getset方法對應)</param>

                <param name="contentDisposition">attachment;filename="${fileName}"</param>//對應action類fileName屬性get方法

            </result>

        </action>

        </package>

    2.在UserAction類增加getFileStream方法

    public InputStream getFileStream(){

          return ServletActionContext.getServletContext().getResourceAsStream("/images/"+fileName);

    }

    還要增加fileName屬性,提供getset方法,在頁面上增加這個參數。

    3.中文亂碼:在取流的方法裏,return之前加上這句(getResource裏的變量毫無疑問改成s):

    String s = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");

    4.下載頁面:

    <a href="download.do?fileName=mm.jpg">下載1</a>

OGNL表達式

     <s:debug/>標籤:用來調試程序

     值棧(valueStack):取值棧裏的值:${user.userName}或者<s:property value="user.userName"/>

     棧(stack)中獲取數據要加#號:<s:property value="#request.r"/>或者${requestScope.r}或者${r}(先找小範圍,再找大範圍,如果小範圍找到,不會再找大範圍)

     訪問對象屬性中還是對象:<s:property value="user.course.name"/>即:對象.對象.屬性

     訪問方法:調用值棧中對象的普通方法:<s:property value="user.sayHello()"/>

     開啓允許靜態方法調用:

         <constant name="struts.ognl.allowStaticMethodAccess" value="true"/>

取值棧的一個例子:

<td><s:radio theme="simple" list="#{'1':'男','2':'女'}" id="sex" name="vo.sex" value="%{#request.vo.sex}"></s:radio></td>

Struts2標籤

     1.控制標籤

          1.1-iterator標籤操作Map:

      方式一:操作簡單的Map:

      value是json數據,var是臨時變量,顯示用<s:property value="#var裏的變量.key">,<s:property value="#var裏的變量.value">

      方式二:後臺準備數據,

      Map<String, Object> request = ac.getContextMap();

      Map<String, String> maps = new HashMap<>();

      maps.put("A","中國");

      maps.put("B","美國");

      maps.put("C","英國");

      request.put("maps",maps);

      頁面:value="#request.maps",其他不變

      1.2—iterator標籤操作List:

           方式一:這時value不用#號{'a','b','c'},顯示就去掉.key和.value,其他一樣。

           方式二:List<User> userList = new ArrayList<>();

           userList.add(new User("admin",12,new Date()));

           userList.add(new User("admin2",13,new Date()));

           request.put("userList",userList);

           頁面:value="#request.userList" var="l",顯示<s:property value="#l.userName"/>

      iterator標籤進行數據過濾操作

           ?獲取滿足條件的所有數據

           value="#request.userList.{?#this.userPass %2 != 0}"//意思是判斷當前迭代對象的userPass與2取餘不爲0就輸出

           ^獲取滿足條件的第一條數據

           value="#request.userList.{^#this.userPass %2 != 0}"

           $獲取滿足條件的最後一條數據

           value="#request.userList.{$#this.userPass %2 != 0}"

     if...else if...else

          <s:if test="attr.number % 7 == 0">

               輸出語句

          </s:if>

          <s:elseif test="attr.number % 5 == 0">

               輸出語句

          </s:elseif>

          <s:else>

               輸出語句

          </s:else>

     append集合合併標籤:把兩個list拼接在一起放在newList裏

          <s:append var="newList">

               <s:param value="{1,2,3}"/>

           <s:param value="#userList"/>

          </s:append>

          <s:iterator value="#newList" var="nl">

               <s:property value="#nl"/><br>

          </s:iterator>

     generator字符串分割標籤:分割完是一個數組g

          <s:generator separator="," val="'a,b,c'" var="g">

          <s:iterator value="#g" var="nl">

               <s:property value="#nl"/><br>

          </s:iterator>

     subset獲取子集合

        方式一:在裏面迭代

          <s:subset source="{1,2,3,4,5}" start="2" count="2">

               <s:iterator var="s">

                    <s:property value="#s"/><br>

           </s:iterator>

          </s:subset>

        方式二:在其他地方迭代

          <s:subset source="{1,2,3,4,5}" start="2" count="2" var="subs"/>

          <s:iterator value="#attr.subs" var="s">

           <s:property value="#s"/><br>

          </s:iterator>

    2.數據標籤

         set標籤:指定把某值用var的變量名字設置到某個範圍

          <s:set value="要存的值" var="myVar" scope="session"/>

          <s:property value="#session.myVar"/>

     push標籤:將某個值置於值棧的頂部,標籤結束後,將從值棧中移除。

          <s:push value="'push中的數據'">

               <s:property/>

          </s:push>

     bean標籤:可以在頁面創建一個對象

          <s:bean name="org.fkit.bean.User" var="u">

               <s:param name="userName">tom</s:param>

               <s:param name="userPass">123456</s:param>

              </s:bean>

          <s:property value="#u.userName"/>--<s:property value="#u.userPass"/>

     date標籤:

          <%

               request.setAttribute("now",new java.util.Date());

          %>

          <s:date name="#request.now" format="yyyy年MM月dd日HH時mm分ss秒"/>

     include標籤

================================

4、struts2的處理流程

a、browser-->struts2控制器-->查找action(在配置文件找)-->(回到)struts2控制器-->攔截器1,2,3...-->動作Action-->(request)struts2控制器-->查找視圖(配置文件找)-->struts2控制器-->視圖-->browser

一個請求在Struts2框架中的處理大概分爲以下幾個步驟 

1 客戶端初始化一個指向Servlet容器(例如Tomcat)的請求 

2 這個請求經過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對於Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)

3 接着FilterDispatcher被調用,FilterDispatcher詢問ActionMapper來決定這個請是否需要調用某個Action 

4 如果ActionMapper決定需要調用某個Action,FilterDispatcher把請求的處理交給ActionProxy 

5 ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調用的Action類 

6 ActionProxy創建一個ActionInvocation的實例。 

7 ActionInvocation實例使用命名模式來調用,在調用Action的過程前後,涉及到相關攔截器(Intercepter)的調用。 

8 一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可 能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2 框架中繼承的標籤。在這個過程中需要涉及到ActionMapper

在上述過程中所有的對象(Action,Results,Interceptors,等)都是通過ObjectFactory來創建的。

5、Struts2配置文件

a、可以給每個模塊定義一個包(Package元素的namesapce屬性)

b、繼承某個package(Package元素的extends屬性)

c、爲了讓大型應用的struts.xml更好管理,可以把它分成幾個較小的文件ps:

<include file="user.xml"></include>

6、攔截器是什麼?struts-default.xml

是將控制器不做的事情封裝在另外一個地方

a標籤路徑最好是通過絕對路徑來:request.getContextPath()

接收參數三種方式:

1.Action屬性來接收

2.用VO來封裝表單屬性

3.利用ModelDriven模型驅動來接收

要實現 implements ModelDriven<T>接口,Action裏面重寫getModel()方法。

==========填充下拉列表==========

第一種:

<s:select list="#{1:'男',2:'女'}" name="employee.sex" headerKey="0" headerValue="--請選擇性別--"></s:select>

第二種:

先定義private List<Map<String,Object>> jobs;

<s:select list="jobs" name="employee.job.id" headerKey="0" headerValue="--請選擇職位--"  listKey="id" listValue="name"></s:select>

第三種:

$.ajax({

    url : "${ctx}/dept/loadDeptAjax.action",

    type:"post",

    dataType:"json",

    async : true,

    success:function(data){

        //獲取選中的

        var deptId = "${employee.dept.id}";

        alert();

        $.each(data,function(){

            $("<option/>").val(this.id).text(this.name).attr("selected",this.id == deptId).appendTo("#deptSelect");

        });

    }

});

List<Map<String,Object>>dept = deptMapper.find(null);

========================Struts2========================

namespace

1、命名空間一般是以“/”開頭

2.當namespace=""時,它會匹配所有的。

request.getScheme()+request.getServletName()+request.getServletPort()+path;

動態方法調用(DMI):

意思就是不配置method屬性,在請求的時候這樣:user!add

<action name="student*" class="xx" method="{1}">

    <result >/student{1}_success.jsp</result>

</action>

<action name="*_*" class="{1}Action" method="{2}">

    <result >/{1}_{2}_success.jsp</result>

</action>

參數接收:

1.普通類型

2.用DTO來接收

public class UserDTO{

    private String name;

    private String pwd;

    private String cpwd;

}

3.模型驅動:

public class UserAction implements ModelDriven<User>{

    private User user = new User();

    public String add(){

        return SUCCESS;

    }

    public User getModel(){

        return user;

    }

}

參數校驗:

addFieldError("name","name is error!");

頁面:

<s:fielderror fieldName="name" theme="simple"/>

(Map)ActionContext.getContext().get("request");

session = ActionContext.getContext().getSession();

在頁面上拿,要用#key這種方式。

Result的配置

<result type="chain">

forward到另外一個action

全局result

<global-results>

    <result name ="mainpage">/main.jsp</result>

</global-results>

動態結果集

<result>${r}</result>

遍歷操作:

<s:iterator value="{1,2,3}">

</s:iterator>

<s:iterator value="{'aaa','bbb','ccc'}" var="x">

  <s:property value="#x.toUpperCase()"> |

</s:iterator>

<s:iterator value="{'aaa','bbb','ccc'}" status="status">

  <s:property /> |

  遍歷過的總數:<s:property value="#status.count" />

  遍歷的元素索引<s:property value="#status.index" />

  當前是偶數:<s:property value="#status.even" />

  當前是奇數:<s:property value="#status.odd" />

  是第一個元素嗎:<s:property value="#status.first" />

  是最後一個元素嗎:<s:property value="#status.last" />

</s:iterator>

遍歷map

<s:iterator value="#{1:'aaa',2:'bbb',3:'ccc'}" >

  <s:property value="key"> | <s:property value="value">

</s:iterator>

<s:iterator value="#{1:'aaa',2:'bbb',3:'ccc'}" var="x">

  <s:property value="#x.key"> | <s:property value="#x.value"/>

</s:iterator>

struts2錯誤標籤自動有樣式:<s:fielderror /> errorMessage

可以.fielderror ul li{ list-style-type:none;  }解決

struts2Filter -> 攔截器 -> xxAction

                                             ↓

struts2Filter <- 攔截器 <- xxAction

默認攔截器都配置在struts-default.xml

攔截器也是配置在struts.xml文件裏,

<package name="webpub" extends="struts-default" namespace="/">

    <interceptors>

        <!-- 配置攔截器與攔截器棧 -->

        <interceptor name="" class=""></interceptor>

        <interceptor-stack name="customStack">

            <interceptor-ref name="exceptionFilter"></interceptor-ref>

            <interceptor-ref name="defaultStack"></interceptor-ref>

            <interceptor-ref name="authority"></interceptor-ref>

        </interceptor-stack>

    </interceptors>

    <!-- 配置默認的攔截器(攔截器棧) -->

    <default-interceptor-ref name="customStack"></default-interceptor-ref>

    <!-- 當我們在配置Action的時候,如果沒有爲某個Action指定具體的class值時,系統將自動引用<default-class-ref>標籤中所指定的類。在Struts2框架中,系統默認的class爲ActionSupport,該配置我們可以在xwork的核心包下的xwork-default.xml文件中找到。有特殊需要時,可以手動指定默認的class -->

    <default-class-ref class=""></default-class-ref>

    <!-- 當配置裏的action都對應不上的時候,最後就會執行這個 -->

    <default-action-ref name=""></default-action-ref>

</package>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章