一、自定義攔截器
要自定義攔截器需要實現com.opensymphony.xwork2.interceptor.Interceptor介面:
public class PermissionInterceptor implements Interceptor { private static final long serialVersionUID = -5178310397732210602L; public void destroy() { } public void init() { } public String intercept(ActionInvocation invocation) throws Exception { System.out.println("進入攔截器"); if(session裡存在使用者){ String result = invocation.invoke(); }else{ return “logon”; } //System.out.println("返回值:"+ result); //return result; } }
<package name="itcast" namespace="/test" extends="struts-default"> <interceptors> <interceptor name=“permission" class="cn.itcast.aop.PermissionInterceptor" /> <interceptor-stack name="permissionStack"> <interceptor-ref name="defaultStack" /> <interceptor-ref name=" permission " /> </interceptor-stack> </interceptors> <action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}"> <result name="success">/WEB-INF/page/hello.jsp</result> <interceptor-ref name="permissionStack"/> </action> </package>
因為struts2中如檔案上傳,資料驗證,封裝請求引數到action等功能都是由系統預設的defaultStack中的攔截器實現的,所以我們定義的攔截器需要引用系統預設的defaultStack,這樣應用才可以使用struts2框架提供的眾多功能。
如果希望包下的所有action都使用自定義的攔截器,可以通過<default-interceptor-ref name=“permissionStack”/>把攔截器定義為預設攔截器。注意:每個包只能指定一個預設攔截器。另外,一旦我們為該包中的某個action顯式指定了某個攔截器,則預設攔截器不會起作用。
舉例:定義訪問許可權攔截器
package com.dzq.action; public class HelloWorldAction { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String addUI(){ this.message="addUI"; return "success"; } public String execute() { this.message="execute"; return "success"; } }
package com.dzq.interceptor; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class PermissionInterceptor implements Interceptor { @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation invocation) throws Exception { Object user=ActionContext.getContext().getSession().get("user"); if(user!=null){ return invocation.invoke();//如果user不為空,代表使用者已經登入,允許執行action中的方法 } ActionContext.getContext().put("message", "對不起,請先登入"); return "success"; } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- 指定訪問字尾 --> <constant name="struts.action.extension" value="do,action"/> <package name="department" namespace="/test/department" extends="struts-default"> <interceptors> <interceptor name="permission" class="com.dzq.interceptor.PermissionInterceptor"/> <!--攔截器棧 --> <interceptor-stack name="permissionStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="permission"/> </interceptor-stack> </interceptors> <!-- 包內所有action都使用預設攔截器 --> <!-- <default-interceptor-ref name="permissionStack"/> --> <global-results> <result name="success">/WEB-INF/page/message.jsp</result> </global-results> <!--使用萬用字元訪問 --> <action name="list_*" class="com.dzq.action.HelloWorldAction" method="{1}"> <interceptor-ref name="permissionStack"/> <!-- <interceptor-ref name=""></interceptor-ref> --> </action> </package> </struts>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> ${message}<br> </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% request.getSession().setAttribute("user", "dudu"); %> 使用者已登入 </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%request.getSession().removeAttribute("user"); %> 使用者退出登入 </body> </html>
流程:直接訪問localhost:8080.../test/department/list_addUI.do,報使用者尚未登入資訊,訪問user.jsp,設定使用者登入session,再訪問action,則顯示已登入,訪問logout.jsp銷燬session,再訪問action,則顯示未登入,通過攔截器實現,攔截器在struts.xml中註冊後使用,攔截action
二、輸入校驗
在struts2中,我們可以實現對action的所有方法進行校驗或者對action的指定方法進行校驗。
對於輸入校驗struts2提供了兩種實現方法:
1. 採用手工編寫程式碼實現。
2. 基於XML配置方式實現。
1.手工編寫程式碼實現對action中所有方法輸入校驗
通過重寫validate() 方法實現, validate()方法會校驗action中所有與execute方法簽名相同的方法。當某個資料校驗失敗時,我們應該呼叫addFieldError()方法往系統的fieldErrors新增校驗失敗資訊(為了使用addFieldError()方法,action可以繼承ActionSupport ),如果系統的fieldErrors包含失敗資訊,struts2會將請求轉發到名為input的result。在input檢視中可以通過<s:fielderror/>顯示失敗資訊。
validate()使用例子:
public void validate() { if(this.mobile==null || "".equals(this.mobile.trim())){ this.addFieldError("username", "手機號不能為空"); }else{ if(!Pattern.compile("^1[358]\\d{9}").matcher(this.mobile.trim()).matches()){ this.addFieldError(“mobile", "手機號的格式不正確"); } } }
驗證失敗後,請求轉發至input檢視:
<result name="input">/WEB-INF/page/addUser.jsp</result>
在addUser.jsp頁面中使用<s:fielderror/>顯示失敗資訊。
例項程式碼:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>輸入校驗</title> </head> <body> <div align="center"> <h1>struts2輸入校驗</h1><hr> <s:fielderror/> <form action="${pageContext.request.contextPath }/person/manage_update.do" method="post"> 使用者名稱:<input type="text" name="username"/><br> 手機號:<input type="text" name="mobile"/><br> <input type="submit" value="驗證"/> </form> </div> </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>結果</title> </head> <body> ${message } </body> </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- 指定訪問字尾 --> <constant name="struts.action.extension" value="do,action"/> <package name="department" namespace="/person" extends="struts-default"> <action name="manage_*" class="com.dzq.action.PersonAction" method="{1}"> <result name="message">/WEB-INF/page/message.jsp</result> <result name="input">/index.jsp</result> </action> </package> </struts>
package com.dzq.action; import java.util.regex.Pattern; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class PersonAction extends ActionSupport{ private String username; private String mobile; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String update(){ ActionContext.getContext().put("message", "更新成功"); return "message"; } public String save(){ ActionContext.getContext().put("message", "儲存成功"); return "message"; } /** * 輸入校驗,對action中所有方法進行校驗 */ @Override public void validate() { if(this.username==null||"".equals(this.username.trim())){ this.addFieldError("username","使用者名稱不能為空"); } if(this.mobile==null||"".equals(this.mobile.trim())){ this.addFieldError("mobile","手機號不能為空"); }else{ if(!Pattern.compile("^1[358]\\d{9}$").matcher(this.mobile).matches()){ this.addFieldError("mobile","手機號格式不正確"); } } } }
2.手工編寫程式碼實現對action中指定方法輸入校驗
通過validateXxx()方法實現, validateXxx()只會校驗action中方法名為Xxx的方法。其中Xxx的第一個字母要大寫。當某個資料校驗失敗時,我們應該呼叫addFieldError()方法往系統的fieldErrors新增校驗失敗資訊(為了使用addFieldError()方法,action可以繼承ActionSupport ),如果系統的fieldErrors包含失敗資訊,struts2會將請求轉發到名為input的result。在input檢視中可以通過<s:fielderror/>顯示失敗資訊。
validateXxx()方法使用例子:
public String add() throws Exception{ return "success";} public void validateAdd(){ if(username==null && "".equals(username.trim())) this.addFieldError("username", "使用者名稱不能為空"); }
驗證失敗後,請求轉發至input檢視:
<result name="input">/WEB-INF/page/addUser.jsp</result>
在addUser.jsp頁面中使用<s:fielderror/>顯示失敗資訊
例項程式碼:將上述例項的validate方法改為validateUpdate
/* * 只會對update方法輸入校驗 */ public void validateUpdate() { if(this.username==null||"".equals(this.username.trim())){ this.addFieldError("username","使用者名稱不能為空"); } if(this.mobile==null||"".equals(this.mobile.trim())){ this.addFieldError("mobile","手機號不能為空"); }else{ if(!Pattern.compile("^1[358]\\d{9}$").matcher(this.mobile).matches()){ this.addFieldError("mobile","手機號格式不正確"); } } }
輸入校驗的流程:
1.型別轉換器對請求引數執行型別轉換,並把轉換後的值賦給action中的屬性。
2.如果在執行型別轉換的過程中出現異常,系統會將異常資訊儲存到ActionContext,conversionError攔截器將異常資訊新增到fieldErrors裡。不管型別轉換是否出現異常,都會進入第3步。
3.系統通過反射技術先呼叫action中的validateXxx()方法,Xxx為方法名。
4.再呼叫action中的validate()方法。
5.經過上面4步,如果系統中的fieldErrors存在錯誤資訊(即存放錯誤資訊的集合的size大於0),系統自動將請求轉發至名稱為input的檢視。如果系統中的fieldErrors沒有任何錯誤資訊,系統將執行action中的處理方法。
3.基於XML配置方式實現對action的所有方法進行輸入校驗
使用基於XML配置方式實現輸入校驗時,Action也需要繼承ActionSupport,並且提供校驗檔案,校驗檔案和action類放在同一個包下,檔案的取名格式為:ActionClassName-validation.xml,其中ActionClassName為action的簡單類名,-validation為固定寫法。如果Action類為cn.itcast.UserAction,那麼該檔案的取名應為:UserAction-validation.xml。下面是校驗檔案的模版:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>使用者名稱不能為空!</message> </field-validator> </field> </validators>
<field>指定action中要校驗的屬性,<field-validator>指定校驗器,上面指定的校驗器requiredstring是由系統提供的,系統提供了能滿足大部分驗證需求的校驗器,這些校驗器的定義可以在xwork-2.x.jar中的com.opensymphony.xwork2.validator.validators下的default.xml中找到。
<message>為校驗失敗後的提示資訊,如果需要國際化,可以為message指定key屬性,key的值為資原始檔中的key。
在這個校驗檔案中,對action中字串型別的username屬性進行驗證,首先要求呼叫trim()方法去掉空格,然後判斷使用者名稱是否為空。
例項程式碼:
import com.opensymphony.xwork2.ActionSupport; public class PersonAction extends ActionSupport{ private String username; private String mobile; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String update(){ ActionContext.getContext().put("message", "更新成功"); return "message"; } public String save(){ ActionContext.getContext().put("message", "儲存成功"); return "message"; }
}
PersonAction-validation.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"><!-- 指定校驗器 --> <param name="trim">true</param> <message>使用者名稱不能為空!</message> </field-validator> </field> <field name="mobile"> <field-validator type="requiredstring"><!-- 指定校驗器 --> <param name="trim">true</param> <message>手機號不能為空!</message> </field-validator> <field-validator type="regex"> <!-- 指定正則校驗器--> <param name="expression"><![CDATA[^1[358]\d{9}$]]></param> <message>手機號格式不正確!</message> </field-validator> </field> </validators>
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- 指定訪問字尾 --> <constant name="struts.action.extension" value="do,action"/> <package name="department" namespace="/person" extends="struts-default"> <action name="manage_*" class="com.dzq.action.PersonAction" method="{1}"> <result name="message">/WEB-INF/page/message.jsp</result> <result name="input">/index.jsp</result> </action> </package> </struts>
struts2提供的校驗器列表
系統提供的校驗器如下:
required (必填校驗器,要求field的值不能為null)
requiredstring (必填字串校驗器,要求field的值不能為null,並且長度大於0,預設情況下會對字串去前後空格)
stringlength(字串長度校驗器,要求field的值必須在指定的範圍內,否則校驗失敗,minLength引數指定最小長度,maxLength引數指定最大長度,trim引數指定校驗field之前是否去除字串前後的空格)
regex(正規表示式校驗器,檢查被校驗的field是否匹配一個正規表示式.expression引數指定正規表示式,caseSensitive引數指定進行正規表示式匹配時,是否區分大小寫,預設值為true)
int(整數校驗器,要求field的整數值必須在指定範圍內,min指定最小值,max指定最大值)
double(雙精度浮點數校驗器,要求field的雙精度浮點數必須在指定範圍內,min指定最小值,max指定最大值)
fieldexpression(欄位OGNL表示式校驗器,要求field滿足一個ognl表示式,expression引數指定ognl表示式,該邏輯表示式基於ValueStack進行求值,返回true時校驗通過,否則不通過)
email(郵件地址校驗器,要求如果field的值非空,則必須是合法的郵件地址)
url(網址校驗器,要求如果field的值非空,則必須是合法的url地址)
date(日期校驗器,要求field的日期值必須在指定範圍內,min指定最小值,max指定最大值)
conversion(轉換校驗器,指定在型別轉換失敗時,提示的錯誤資訊)
visitor(用於校驗action中的複合屬性,它指定一個校驗檔案用於校驗複合屬性中的屬性)
expression(OGNL表示式校驗器,expression引數指定ognl表示式,該邏輯表示式基於ValueStack進行求值,返回true時校驗通過,否則不通過,該校驗器不可用在欄位校驗器風格的配置中)
校驗器的使用例子
required 必填校驗器
<field-validator type="required"> <message>性別不能為空!</message> </field-validator>
requiredstring 必填字串校驗器
<field-validator type="requiredstring"> <param name="trim">true</param> <message>使用者名稱不能為空!</message> </field-validator>
stringlength:字串長度校驗器
<field-validator type="stringlength"> <param name="maxLength">10</param> <param name="minLength">2</param> <param name="trim">true</param> <message><![CDATA[產品名稱應在2-10個字元之間]]></message> </field-validator>
email:郵件地址校驗器
<field-validator type="email"> <message>電子郵件地址無效</message> </field-validator>
regex:正規表示式校驗器
<field-validator type="regex"> <param name="expression"><![CDATA[^1[358]\d{9}$]]></param> <message>手機號格式不正確!</message> </field-validator>
int:整數校驗器
<field-validator type="int"> <param name="min">1</param> <param name="max">150</param> <message>年齡必須在1-150之間</message> </field-validator>
欄位OGNL表示式校驗器
<field name="imagefile"> <field-validator type="fieldexpression"> <param name="expression"><![CDATA[imagefile.length() <= 0]]></param> <message>檔案不能為空</message> </field-validator> </field>
4、基於XML配置方式對指定action方法實現輸入校驗
當校驗檔案的取名為ActionClassName-validation.xml時,會對 action中的所有處理方法實施輸入驗證。如果你只需要對action中的某個action方法實施校驗,那麼,校驗檔案的取名應為:ActionClassName-ActionName-validation.xml,其中ActionName為struts.xml中action的名稱。例如:在實際應用中,常有以下配置:
<action name="user_*" class="cn.itcast.action.UserAction" method="{1}“ > <result name="success">/WEB-INF/page/message.jsp</result> <result name="input">/WEB-INF/page/addUser.jsp</result> </action>
UserAction中有以下兩個處理方法:
public String add() throws Exception{ .... } public String update() throws Exception{ .... }
要對add()方法實施驗證,校驗檔案的取名為: UserAction-user_add-validation.xml
要對update()方法實施驗證,校驗檔案的取名為: UserAction-user_update-validation.xml
示例程式碼:PersonAction-manage_update-validation.xml 只對update方法進行校驗
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"><!-- 指定校驗器 --> <param name="trim">true</param> <message>使用者名稱不能為空!</message> </field-validator> </field> <field name="mobile"> <field-validator type="requiredstring"><!-- 指定校驗器 --> <param name="trim">true</param> <message>手機號不能為空!</message> </field-validator> <field-validator type="regex"> <param name="expression"><![CDATA[^1[358]\d{9}$]]></param> <message>手機號格式不正確!</message> </field-validator> </field> </validators>
5、基於XML校驗的一些特點
當為某個action提供了ActionClassName-validation.xml和ActionClassName-ActionName-validation.xml兩種規則的校驗檔案時,系統按下面順序尋找校驗檔案:
1.AconClassName-validation.xml
2.ActionClassName-ActionName-validation.xml
系統尋找到第一個校驗檔案時還會繼續搜尋後面的校驗檔案,當搜尋到所有校驗檔案時,會把校驗檔案裡的所有校驗規則彙總,然後全部應用於action方法的校驗。如果兩個校驗檔案中指定的校驗規則衝突,則只使用後面檔案中的校驗規則。
當action繼承了另一個action,父類action的校驗檔案會先被搜尋到。
假設UserAction繼承BaseAction:
<action name="user" class="cn.itcast.action.UserAction" method="{1}"> </action>
訪問上面action,系統先搜尋父類的校驗檔案:BaseAction-validation.xml, BaseAction-user-validation.xml,接著搜尋子類的校驗檔案: UserAction-validation.xml, UserAction-user-validation.xml。應用於上面action的校驗規則為這四個檔案的總和。