java框架之Struts2(4)-攔截器&標籤庫

攔截器

概述

Interceptor (攔截器):起到攔截客戶端對 Action 請求的做用。html

  • Filter:過濾器,過濾客戶端向服務器發送的請求。
  • Interceptor:攔截器,攔截的是客戶端對 Action 的訪問,是更細粒度化的攔截。
Struts2 框架的核心功能都是經過攔截器實現。

自定義攔截器

編寫攔截器類

編寫一個類實現 Interceptor 接口或繼承 AbstractInterceptor 類。java

package com.zze.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class Test1Interceptor implements Interceptor {
    @Override
    public void destroy() {
        System.out.println("from Test1Interceptor.destroy");
    }

    @Override
    public void init() {
        System.out.println("from Test1Interceptor.init");
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("from Test1Interceptor.intercept");
        return invocation.invoke();
    }
}
com.zze.interceptor.Test1Interceptor 方式一:實現 Interceptor 接口
package com.zze.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class Test2Interceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("Test2Interceptor.intercept");
        return invocation.invoke();
    }
}
com.zze.interceptor.Test2Interceptor 方式二:繼承 AbstractInterceptor 類

配置攔截器

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.devMode" value="true"/>
    <package name="test" extends="struts-default" namespace="/">
        <!--定義攔截器-->
        <interceptors>
            <interceptor name="interceptor1" class="com.zze.interceptor.Test1Interceptor"/>
            <interceptor name="interceptor2" class="com.zze.interceptor.Test2Interceptor"/>
        </interceptors>
        <action name="*" class="com.zze.action.{1}Action">
            <result>/index.jsp</result>
            <!--引入攔截器-->
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
        </action>
    </package>
</struts>
struts.xml 方式一:引入攔截器
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.devMode" value="true"/>
    <package name="test" extends="struts-default" namespace="/">
        <!--定義攔截器-->
        <interceptors>
            <interceptor name="interceptor1" class="com.zze.interceptor.Test1Interceptor"/>
            <interceptor name="interceptor2" class="com.zze.interceptor.Test2Interceptor"/>
            <!--定義攔截器棧-->
            <interceptor-stack name="myStack">
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="interceptor1"/>
                <interceptor-ref name="interceptor2"/>
            </interceptor-stack>
        </interceptors>
        <action name="*" class="com.zze.action.{1}Action">
            <result>/index.jsp</result>
            <!--引入攔截器棧-->
            <interceptor-ref name="myStack"/>
        </action>
    </package>
</struts>
struts.xml 方式二:引入攔截器棧

補充

Struts2 還爲咱們提供了一些功能加強的過濾器,咱們只須要繼承它簡單配置便可,例如:web

package com.zze.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

/**
 * MethodFilterInterceptor 可讓咱們很簡單的控制要攔截的方法和不需攔截的方法
 */
public class TestInterceptor extends MethodFilterInterceptor {

    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        System.out.println("from TestInterceptor.doIntercept");
        return invocation.invoke();
    }
}
com.zze.interceptor.TestInterceptor
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.devMode" value="true"/>
    <package name="test" extends="struts-default" namespace="/">
        <!--定義攔截器-->
        <interceptors>
            <interceptor name="methodInterceptor" class="com.zze.interceptor.TestInterceptor"/>
        </interceptors>
        <action name="*_*" class="com.zze.action.{1}Action" method="{2}">
            <result>/index.jsp</result>
            <interceptor-ref name="methodInterceptor">
                <!--配置不攔截的方法名-->
                <param name="excludeMethods">login,index</param>
                <!--配置要攔截的方法名-->
                <param name="includeMethods">home,list</param>
            </interceptor-ref>
        </action>
    </package>
</struts>
struts.xml

Struts2執行流程

官方架構圖

源碼分析

依舊是從核心過濾器的 doFilter 方法開始:ajax

 1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
 2 
 3         HttpServletRequest request = (HttpServletRequest) req;
 4         HttpServletResponse response = (HttpServletResponse) res;
 5 
 6         try {
 7             // 判斷當前請求 URL 是否在不處理範圍內
 8             if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
 9                 chain.doFilter(request, response);
10             } else {
11                 // 設置編碼,默認 request.setCharacterEncoding("UTF-8")
12                 prepare.setEncodingAndLocale(request, response);
13                 // 建立 Action 及建立 ValueStack 值棧
14                 prepare.createActionContext(request, response);
15                 // 將本次請求相關配置綁定到當前線程 ThreadLocal
16                 prepare.assignDispatcherToThread();
17                 // 包裝原生 request ,對其進行加強
18                 request = prepare.wrapRequest(request);
19                 // 找到這次請求對應配置文件 struts.xml 中的映射相關信息,封裝到 ActionMapping 實例
20                 ActionMapping mapping = prepare.findActionMapping(request, response, true);
21                 if (mapping == null) { // 未找到映射信息
22                     // 查看這次請求目標是不是靜態資源
23                     boolean handled = execute.executeStaticResourceRequest(request, response);
24                     if (!handled) {
25                         chain.doFilter(request, response);
26                     }
27                 } else {// 找到了映射信息
28                     // 執行攔截器及 Action
29                     execute.executeAction(request, response, mapping);
30                 }
31             }
32         } finally {
33             // 清理請求信息
34             prepare.cleanupRequest(request);
35         }
36     }
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter#doFilter

進到 29 行的 execute.executeAction 方法:正則表達式

1 public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
2     dispatcher.serviceAction(request, response, mapping);
3 }
org.apache.struts2.dispatcher.ng.ExecuteOperations#executeAction

繼續進到 dispatcher.serviceAction 方法:express

 1 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
 2         throws ServletException {
 3 
 4     Map<String, Object> extraContext = createContextMap(request, response, mapping);
 5     // 從 request 中獲取值棧
 6     ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
 7     boolean nullStack = stack == null;
 8     if (nullStack) {
 9         // 若是從 request 中未獲取到值棧,則從 ActionContext 中取出值棧賦值給 stack
10         ActionContext ctx = ActionContext.getContext();
11         if (ctx != null) {
12             stack = ctx.getValueStack();
13         }
14     }
15     if (stack != null) {
16         extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
17     }
18 
19     String timerKey = "Handling request from Dispatcher";
20     try {
21         UtilTimerStack.push(timerKey);
22         String namespace = mapping.getNamespace();
23         String name = mapping.getName();
24         String method = mapping.getMethod();
25         // 建立 Action 代理對象
26         ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
27                 namespace, name, method, extraContext, true, false);
28         // 將值棧放入 request
29         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
30         if (mapping.getResult() != null) {
31             Result result = mapping.getResult();
32             result.execute(proxy.getInvocation());
33         } else {
34             // Action 代理開始執行過濾器和 Action
35             proxy.execute();
36         }
37 
38         if (!nullStack) {
39             // 將已存在的值棧放入 Request
40             request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
41         }
42     } catch (ConfigurationException e) {
43         logConfigurationException(request, e);
44         sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
45     } catch (Exception e) {
46         if (handleException || devMode) {
47             sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
48         } else {
49             throw new ServletException(e);
50         }
51     } finally {
52         UtilTimerStack.pop(timerKey);
53     }
54 }
org.apache.struts2.dispatcher.Dispatcher#serviceAction

Action 及過濾器的執行在 34 行,查看 proxy.execute 方法:apache

 1 public String execute() throws Exception {
 2     ActionContext previous = ActionContext.getContext();
 3     ActionContext.setContext(invocation.getInvocationContext());
 4     try {
 5         return invocation.invoke();
 6     } finally {
 7         if (cleanupContext)
 8             ActionContext.setContext(previous);
 9     }
10 }
org.apache.struts2.impl.StrutsActionProxy#execute

在這裏又執行 invocation.invoke 方法:瀏覽器

 1 public String invoke() throws Exception {
 2     String profileKey = "invoke: ";
 3     try {
 4         UtilTimerStack.push(profileKey);
 5 
 6         if (executed) {
 7             throw new IllegalStateException("Action has already executed");
 8         }
 9         // interceptors 是一個 Iterator (迭代器)對象,存放了全部攔截器的引用
10         if (interceptors.hasNext()) { // 若是存在下一個未迭代的攔截器
11             final InterceptorMapping interceptor = interceptors.next(); // 獲取到攔截器
12             String interceptorMsg = "interceptor: " + interceptor.getName();
13             UtilTimerStack.push(interceptorMsg);
14             try {
15                             // 執行攔截器的 intercept 方法
16                             resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
17                         }
18             finally {
19                 UtilTimerStack.pop(interceptorMsg);
20             }
21         } else { // 若是不存在下一個未迭代的攔截器
22             // 開始執行 Action
23             resultCode = invokeActionOnly();
24         }
25 
26         if (!executed) {
27             if (preResultListeners != null) {
28                 LOG.trace("Executing PreResultListeners for result [#0]", result);
29 
30                 for (Object preResultListener : preResultListeners) {
31                     PreResultListener listener = (PreResultListener) preResultListener;
32 
33                     String _profileKey = "preResultListener: ";
34                     try {
35                         UtilTimerStack.push(_profileKey);
36                         listener.beforeResult(this, resultCode);
37                     }
38                     finally {
39                         UtilTimerStack.pop(_profileKey);
40                     }
41                 }
42             }
43 
44             if (proxy.getExecuteResult()) {
45                 executeResult();
46             }
47 
48             executed = true;
49         }
50 
51         return resultCode;
52     }
53     finally {
54         UtilTimerStack.pop(profileKey);
55     }
56 }
com.opensymphony.xwork2.DefaultActionInvocation#invoke

重點就在這個方法的 10-24 行了,這裏在迭代全部攔截器,而且在 16 行把當前 DefaultActionInvocation 實例做爲 invocation 參數傳入執行了當前迭代的攔截器的 intercept 方法。而咱們已經知道,攔截器中放行就是經過調用傳入的 invocation 參數的 invocation.invoke 方法,即當前 invoke 方法。沒錯,這是一個遞歸!!!服務器

Struts2 就是經過遞歸來迭代調用攔截器,這個遞歸能維持下去的條件有兩個:架構

一、迭代器 interceptors 中還存在未迭代的攔截器。

二、在迭代器的 intercept 方法中必須調用 invocation.invoke 方法。

總結上述,Struts2 的執行流程以下:

    客戶端向服務器發送一個 Action 請求,首先執行核心過濾器 (StrutsPrepareAndExecuteFilter) 的 doFilter 方法。

    在這個方法中,調用了 ExecuteOperations 實例 execute 的 executeAction 方法,而 executeAction 方法中又執行了 Dispatcher 實例 dispatcher 的 serviceAction 方法。

    在 serviceAction 中建立了 Action 代理對象 proxy,這個代理對象爲 StrutsActionProxy 的實例,接着執行了 Action 代理對象的 execute 方法。

    在 execute 方法中又執行了 DefaultActionInvocation 的實例 invocation 的 invoke 方法。

    在 invoke 方法中遞歸迭代執行攔截器,當攔截器迭代完畢,就會執行目標 Action 的目標方法,最後 Struts2 處理 Action 返回的邏輯視圖結果,將處理結果交給 response 對象響應給瀏覽器。

    經過上述代碼也能夠看到,Action 的執行時機是在迭代器正常執行完以後,到這裏能夠得出結論:

    若是在迭代器中未調用 invocation.invoke ,則後續的迭代器不會被執行,且 Action 也不會被執行,這就是 invocation.invoke 放行的原理。

標籤庫

通用標籤庫

判斷

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>標籤庫測試</title>
</head>
<body>
<s:set var="i" value="3" scope="request"/>
<s:if test="#request.i>3">
    i>3
</s:if>
<s:elseif test="#request.i<3">
    i<3
</s:elseif>
<s:else>
    i=3
</s:else>
</body>
</html>

例:if/elseif/else

循環

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>標籤庫測試</title>
</head>
<body>

<%--當前遍歷對象會被放到值棧的root和context中--%>

<%--遍歷 List--%>
<s:iterator var="letter" value="{'a','b','c'}">
    <s:property value="letter"></s:property>
</s:iterator>
<hr>
<%--遍歷 Map--%>
<s:iterator value="#{'a':'1','b':'2','c':'3'}">
   key: <s:property value="key"/>
   value: <s:property value="value"/>
    <br>
</s:iterator>

<hr>
<%--相似 for 循環--%>
<s:iterator var="i" begin="0" end="10" step="2" status="s">
   <s:property value="#s.count"/> : <s:property value="i"/> <br>
</s:iterator>
</body>
</html>

例:iterator

日期

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>標籤庫測試</title>
</head>
<body>
<%
    Date date = new Date();
    request.setAttribute("date", date);
%>
<s:date name="#request.date" /> <br>
<s:date name="#request.date" format="yyyy年MM月dd日 HH:mm:ss" />
</body>
</html>

例:date

UI標籤庫

<%@ page import="java.util.Date" %>
<%@ page import="java.util.TreeMap" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>標籤庫測試</title>
</head>
<body>
<%--
Struts2 默認會表單中標籤套上 table
若是不想要 Struts2 提供的樣式,可更改默認常量 struts.ui.theme
struts.ui.theme 有三個可選值:
xhtml : 默認值。
simple : 無樣式提供。
ajax : 這個主題裏的模板以 xhtml 主題裏的模板爲基礎,但增長了一些ajax功能。

除了更改配置文件中的常量,還能夠經過修改 s:form 上的 theme 屬性來讓主題只對當前表單生效
--%>

<%
    Map<String, String> gender = new HashMap<String, String>();
    gender.put("1", "");
    gender.put("2", "");
    request.setAttribute("gender", gender);

    Map<String, String> address = new HashMap<String, String>();
    address.put("hk", "香港");
    address.put("jp", "日本");
    request.setAttribute("address", address);

    Map<String, String> hobby = new HashMap<String, String>();
    hobby.put("1", "吃飯");
    hobby.put("2", "睡覺");
    hobby.put("3", "打豆豆");
    request.setAttribute("hobby",hobby);
%>
<s:form namespace="/" action="Test1">
    <%--隱藏域--%>
    <s:hidden name="id"/>
    <%--文本框--%>
    <s:textfield name="username" label="用戶名"/>
    <%--密碼框--%>
    <s:password name="password" label="密碼"/>
    <%--單選框--%>
    <s:radio list="#request.gender" name="gender" label="性別"/>
    <%--下拉框--%>
    <s:select list="#request.address" name="address" label="地點"/>
    <%--多選框--%>
    <s:checkboxlist list="#request.hobby" name="hobby" label="愛好"/>
    <%--文本域--%>
    <s:textarea rows="3" cols="10" value="默認值" label="簡介" />
    <%--提交按鈕--%>
    <s:submit value="提交"/>
</s:form>
</body>
</html>

例:

補充

數據校驗

手動編碼方式

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

public class Test1Action extends ActionSupport {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(".................");
        return super.execute();
    }

    /**
     * 編寫一個類,繼承 ActionSupport,重寫 validate 方法
     * 每次請求此 Action 都會先執行 validate 方法
     * 若是驗證有錯誤,將錯誤經過 this.addFieldError 或 this.addActionError 交給 Struts2
     * 而後 Struts2 會返回 input 邏輯視圖,手動定義好 input 跳轉到的頁面
     * 在頁面能夠經過 <s:actionerror/> <s:fielderror/> 標籤獲取到錯誤信息
     */
    @Override
    public void validate() {
        if(name == null || name.trim().length() == 0){
            this.addFieldError("name","用戶名不能爲空");
        }
    }
}
例 1:對整個 Action 進行校驗
package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

public class Test2Action extends ActionSupport {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String add() {
        System.out.println("from add....");
        return SUCCESS;
    }

    /**
     * 編寫一個類,繼承 ActionSupport
     * 若是要給指定的方法校驗,須要按規則定義一個方法:
     * 校驗的方法名要遵循:validate+方法名首字母大寫
     * 以下,要給 add 方法校驗,定義的方法名就爲 validateAdd
     * 而後每次請求這個方法就會限制性校驗方法
     * 若是驗證有錯誤,將錯誤經過 this.addFieldError 或 this.addActionError 交給 Struts2
     * 而後 Struts2 會返回 input 邏輯視圖,手動定義好 input 跳轉到的頁面
     * 在頁面能夠經過 <s:actionerror/> <s:fielderror/> 標籤獲取到錯誤信息
     */
    public void validateAdd() {
        System.out.println("from validateAdd...");
    }
}
例 2:對 Action 中指定方法進行校驗

配置文件方式

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<!--
一、在 Action 所在包下建立一個 xml 文件,名稱爲 Action類名-validation.xml
    如 : 此文件是給名爲 Test3Action 的 Action 校驗,文件名則爲 Test3Action-validation.xml
二、引入 DTD 約束,該約束可在 xwork-core-2.3.37.jar!/xwork-validator-1.0.3.dtd 下找到
 -->
<validators>
    <!--
    name : 要校驗的字段名
        注意:須要獲取到值才能對字段進行校驗,因此在 Action 中要給對應字段提供 get 方法。
    -->
    <field name="name">
        <!--
        type : Struts2 已經給咱們提供了不少驗證器
        在 xwork-core-2.3.37.jar!/com/opensymphony/xwork2/validator/validators/default.xml 中能夠看到
        -->
        <field-validator type="requiredstring">
            <!--返回的錯誤信息-->
            <message>用戶名不能爲空</message>
        </field-validator>
    </field>
</validators>
例 1:對整個 Action 進行校驗
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<!--
一、在 Action 所在包下建立一個 xml 文件,名稱爲 Action類名-方法訪問路徑-validation.xml
    如 : 此文件只給名爲 Test4Action 的 Action 下的 add 方法校驗,
        Struts.xml 對應Action 配置爲 <action name="*_*" class="com.zze.action.{1}Action" method="{2}">
        文件名則爲 Test4Action-Test4_add-validation.xml
二、引入 DTD 約束,該約束可在 xwork-core-2.3.37.jar!/xwork-validator-1.0.3.dtd 下找到
 -->
<validators>
    <!--
    name : 要校驗的字段名
        注意:須要獲取到值才能對字段進行校驗,因此在 Action 中要給對應字段提供 get 方法。
    -->
    <field name="name">
        <!--
        type : Struts2 已經給咱們提供了不少驗證器
        在 xwork-core-2.3.37.jar!/com/opensymphony/xwork2/validator/validators/default.xml 中能夠看到
        -->
        <field-validator type="stringlength">
            <param name="minLength">6</param>
            <param name="maxLength">12</param>
            <!--返回的錯誤信息-->
            <message>用戶名必須在6-12位之間</message>
        </field-validator>
    </field>
</validators>
例 2:對 Action 中指定方法進行校驗
Struts2 內置的校驗器:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator Definition 1.0//EN"
        "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">

<validators>
    <!--必填校驗器,要求被校驗的屬性值不能爲 null-->
    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
    <!--必填字符串校驗器,要求被校驗的屬性值不能爲 null,而且長度大於 0 ,默認狀況下不會對字符串去先後空格-->
    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
    <!--數值校驗器,要求被校驗的屬性值可轉 int ,且可指定範圍,min 指定最小值,max 指定最大值-->
    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
    <!--數值校驗器,要求被校驗的屬性值可轉 long,且可指定範圍,min 指定最小值,max 指定最大值-->
    <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
    <!--數值校驗器,要求被校驗的屬性值可轉 short,且可指定範圍,min 指定最小值,max 指定最大值-->
    <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
    <!--數值校驗器,要求被校驗的屬性值可轉 double,且可指定範圍,min 指定最小值,max 指定最大值-->
    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
    <!--日期校驗器,要求被校驗的屬性值可轉 Date,且可指定範圍,min 指定最小值,max 指定最大值-->
    <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
    <!--OGNL表達式校驗器,它是一個非屬性校驗器,expression 指定 ognl 表達式,該邏輯表達式基於 ValueStack進行求值,返回 true 時校驗經過,不然不經過,該校驗器不可用在字段校驗器風格的配置中-->
    <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
    <!--字段OGNL表達式校驗器,要求被校驗的屬性值知足一個 OGNL 表達式,expression 參數指定 OGNL 表達式,該邏輯表達式基於 ValueStack進行求值,返回 true 時校驗經過,不然不經過-->
    <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
    <!--郵件地址校驗器,要求若是被校驗的屬性值非空,則必須是合法的郵件地址-->
    <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
    <!--網址校驗器,要求若是被校驗的屬性值非空,則必須是合法的 url 地址-->
    <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
    <!--用於校驗 Action 中符合類型的屬性,它指定一個校驗文件用於校驗複合類型屬性中的屬性-->
    <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
    <!--轉換校驗器,指定在類型轉換失敗時,提示的錯誤消息-->
    <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
    <!--字符串長度校驗器,要求被校驗的屬性值必須在指定的範圍內,不然校驗失敗,minLength 指定最小長度,maxLength 指定最大長度,trim 指定交驗以前是否去除字符串先後空格-->
    <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
    <!--正則表達式校驗器,檢查被校驗的屬性值是否匹配一個正則表達式,expression 指定正則表達式,caseSensitive 指定進行正則表達式匹配時,是否區分大小寫,默認爲 true-->
    <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
    
    <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
xwork-core-2.3.37.jar!/com/opensymphony/xwork2/validator/validators/default.xml

自定義校驗器

package com.zze.validator;

import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;

/**
 * 對指定字段進行過濾
 *
 * 除了繼承 FieldValidatorSupport
 * 還能夠繼承 ValidatorSupport
 */
public class AgeValidator extends FieldValidatorSupport {
    @Override
    public void validate(Object object) throws ValidationException {
        // 得到字段名稱
        String fieldName = this.getFieldName();

        Object fieldValue = this.getFieldValue(fieldName, object);

        if(fieldValue instanceof Integer){
            int age = (Integer)fieldValue;
            if(age<0){
                this.addFieldError(fieldName,object);
            }
        }
    }
}
com.zze.validator.AgeValidator:自定義的校驗器
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator Definition 1.0//EN"
        "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">
<!--在 src 下新建 validators.xml -->
<validators>
    <!--註冊驗證器-->
    <validator name="ageValidator" class="com.zze.validator.AgeValidator"/>
</validators>
validators.xml:註冊驗證器

國際化

全局國際化

一、在類路徑下新建 properties 資源文件,文件名爲以下格式:

名稱_en_uS.properties  // 英文
名稱_zh_CN.properties  // 中文

例如:

name=姓名不能爲空
message_zh_CN.properties
name=name can't be null
message_en_US.properties

二、在 struts.xml 中配置常量:

<constant name="struts.custom.i18n.resources" value="message"/>

三、接下來就能夠獲取資源文件中國際化後的內容了:

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

public class I18NAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        String name = getText("name");
        System.out.println(name); // 姓名不能爲空
        return super.execute();
    }
}
在 Action 中獲取
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>國際化測試</title>
</head>
<body>
<s:text name="name"/>
</body>
</html>
在 JSP 中獲取
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>
    <field name="name">
        <field-validator type="requiredstring">
            <!--經過 key 取出國際化文本-->
            <message key="name"></message>
        </field-validator>
    </field>
</validators>
配置文件中獲取

Action範圍國際化

一、在 Action 所在的包下建立 properties 資源文件,文件名爲以下格式:

Action名_zh_CN.properties // 中文
Action名_en_US.properties // 英文

二、直接在 Action 中使用便可,使用方式同全局一致。

包範圍國際化

一、在需國際化的包下新建 properties 資源文件,文件名格式以下:

package_zh_CN.properties // 中文
package_en_US.properties // 英文

二、接下來在當前包及子包中都能使用該國際化資源文件。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>國際化測試</title>
</head>
<body>
<s:i18n name="com/zze/action/package">
    <s:text name="msg"/>
</s:i18n>
</body>
</html>
JSP 中獲取

使用佔位符

wel=歡迎 {0}
com/zze/action/package_zh_CN.properties
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>國際化測試</title>
</head>
<body>
<s:i18n name="com/zze/action/package">
    <s:text name="wel">
        <s:param>張三</s:param>
    </s:text>
</s:i18n>
</body>
</html>
JSP 中傳參並獲取
package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

public class I18NAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        String wel = getText("wel", new String[]{"張三"});
        System.out.println(wel); // 歡迎 張三
        return super.execute();
    }
}
Action 中傳參並獲取

文件上傳

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <!--限制單次文件上傳總大小不可大於 5m-->
    <constant name="struts.multipart.maxSize" value="5242880"/>
    <!--配置國際化資源文件名-->
    <constant name="struts.custom.i18n.resources" value="message"/>
    <package name="test" extends="struts-default" namespace="/">
        <action name="upload" class="com.zze.web.action.FileUploadAction">
            <result name="input">/index.jsp</result>
            <interceptor-ref name="defaultStack">
                <!--限制單個文件大小不超過 2m-->
                <param name="fileUpload.maximumSize">2097152</param>
                <!--限制文件後綴-->
                <param name="fileUpload.allowedExtensions">.jpg,.png</param>
                <!--限制文件的 MIME 類型-->
                <param name="fileUpload.allowedTypes">image/jpg,image/png</param>
            </interceptor-ref>
        </action>
    </package>
</struts>
struts.xml
struts.messages.error.uploading=\u4e0a\u4f20\u9519\u8bef
struts.messages.error.file.too.large=\u6587\u4ef6\u592a\u5927
struts.messages.error.content.type.not.allowed=\u8bf7\u9009\u62e9\u56fe\u7247\u6587\u4ef6
struts.messages.error.file.extension.not.allowed=\u8bf7\u9009\u62e9\u002e\u006a\u0070\u0067\u6216\u002e\u0070\u006e\u0067\u7ed3\u5c3e\u7684\u6587\u4ef6
message_zh_CN.properties
package com.zze.web.action;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.interceptor.ServletResponseAware;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.File;

public class FileUploadAction extends ActionSupport implements ServletResponseAware {
    /*
     爲文件上傳提供三個屬性 :
        String 表單項 name + FileName : 接收文件名稱
        File 表單項 name : 接收文件內容
        String 表單項 name + ContentType : 上傳文件的 ContentType
      */
    private String fileFileName;

    private File file;

    private String fileContentType;

    public void setFileFileName(String fileFileName) {
        this.fileFileName = fileFileName;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public void setFileContentType(String fileContentType) {
        this.fileContentType = fileContentType;
    }

    private ServletResponse response;

    @Override
    public String execute() throws Exception {
        response.setContentType("text/plain;charset=utf8");
        String msg = "上傳成功";
        System.out.println(fileFileName);
        System.out.println(file);
        System.out.println(fileContentType);
        // 存儲路徑
        String fullPath = "D://upload/"+fileFileName;
        File destFile = new File(fullPath);
        FileUtils.copyFile(file,destFile);
        response.getWriter().write(msg);
        return NONE;
    }

    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }
}
com.zze.web.action.FileUploadAction
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Struts2 文件上傳測試</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit" value="上傳">
    <s:actionerror/>
    <s:fielderror/>
</form>
</body>
</html>

index.jsp
相關文章
相關標籤/搜索