Interceptor (攔截器):起到攔截客戶端對 Action 請求的做用。html
編寫一個類實現 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(); } }
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(); } }
<?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>
<?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>
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(); } }
<?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>
依舊是從核心過濾器的 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 }
進到 29 行的 execute.executeAction 方法:正則表達式
1 public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException { 2 dispatcher.serviceAction(request, response, mapping); 3 }
繼續進到 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 }
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 }
在這裏又執行 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 }
重點就在這個方法的 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>
<%@ 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>
<%@ 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>
<%@ 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","用戶名不能爲空"); } } }
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..."); } }
<?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>
<?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>
<?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>
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); } } } }
<?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>
一、在類路徑下新建 properties 資源文件,文件名爲以下格式:
名稱_en_uS.properties // 英文 名稱_zh_CN.properties // 中文
例如:
name=姓名不能爲空
name=name can't be null
二、在 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(); } }
<%@ 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>
<?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 所在的包下建立 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>
wel=歡迎 {0}
<%@ 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>
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(); } }
<?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.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
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; } }
<%@ 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>