這是一個Struts2.1.8.1應用,代碼如下
首先是web.xml文件
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <welcome-file-list>
- <welcome-file>methodFilter.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
然後用於提交方法過濾測試的methodFilter.jsp頁面
- <%@ page language="java" pageEncoding="UTF-8"%>
- <%@ taglib prefix="s" uri="/struts-tags"%>
- <s:form action="methodFilter" theme="simple">
- 您可以直接點擊Submit提交請求,然後在控制檯查看輸出情況<br/>
- <s:submit value="我要測試方法過濾攔截器"/>
- </s:form>
然後是用於顯示方法過濾結果的methodFilterResult.jsp頁面
- <%@ page pageEncoding="UTF-8"%>
- <h2>請移步控制檯查看輸出情況</h2>
然後是struts.xml文件
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
- "http://struts.apache.org/dtds/struts-2.1.dtd">
- <struts>
- <package name="methodFilter" extends="struts-default">
- <interceptors>
- <interceptor name="myInterceptor11" class="com.jadyer.interceptor.MyInterceptor11">
- <param name="hello">world</param>
- </interceptor>
- <!-- <param name="hello">world</param>表示爲攔截器增加一個名爲hello值爲world的屬性 -->
- <!-- 但是這裏也只是爲hello賦了初值爲world。如若在下面的<action/>中配置使用該攔截器的時候 -->
- <!-- 增加了<param name="hello">welcome</param>,則最後攔截器類中hello屬性值即爲welcome -->
- <interceptor name="myInterceptor22" class="com.jadyer.interceptor.MyInterceptor22"/>
- <interceptor name="myInterceptor33" class="com.jadyer.interceptor.MyInterceptor33">
- <param name="includeMethods">test,abc</param>
- </interceptor>
- </interceptors>
- <action name="methodFilter" class="com.jadyer.action.MethodFilterAction" method="test">
- <result name="success">/methodFilterResult.jsp</result>
- <interceptor-ref name="defaultStack"/>
- <interceptor-ref name="myInterceptor11"/>
- <interceptor-ref name="myInterceptor22"/>
- <interceptor-ref name="myInterceptor33">
- <param name="includeMethods">abc</param>
- </interceptor-ref>
- </action>
- </package>
- </struts>
- <!-- *********************【方法過濾攔截器的使用】********************************************** -->
- <!-- 默認的情況下,攔截器會攔截Action中的所有的方法,這裏不包括setter或getter方法 -->
- <!-- 這時就可以使用方法過濾攔截器來攔截指定的方法,這是一種更加細化的攔截器的配置方式 -->
- <!-- 它可以細化到攔截具體的某個方法。而不是攔截某個Action,因爲攔截Action是一種粗粒度的實現方式 -->
- <!-- 使用includeMethods指明攔截器所要攔截的方法。使用excludeMethods指明攔截器不再攔截的方法 -->
- <!-- 這裏excludeMethods和includeMethods是在MethodFilterInterceptor類中定義的成員變量 -->
- <!-- 而且只要includeMethods進來的方法就一定會被攔截,而不管是否已經把它excludeMethods在外了 -->
- <!-- 也就是說includeMethods的優先級要高於excludeMethods -->
- <!-- 也可以使用<param name="includeMethods"/>在上面定義攔截器的時候指定全局性過濾的方法 -->
- <!-- 區別就是對方法的過濾有全局性和局部性區分。而當發生衝突時,則依照【就近原則】以局部性的配置爲準 -->
- <!-- 所謂的發生衝突,指的是類似於全局中有一個includeMethods配置,而局部中也有一個includeMethods配置 -->
- <!-- 另外,還有一種情況,假設全局性過濾定義爲<param name="includeMethods">test</param> -->
- <!-- 而在局部性過濾中定義爲<param name="excludeMethods">test</param> -->
- <!-- 這種情況下,<param name="includeMethods">test</param>將生效,即攔截Action中的test()方法 -->
- <!-- 這個時候全局中配置的是攔截,局部中配置的是不攔截,二者並沒有發生衝突,所以仍是以includeMethods優先級高 -->
- <!-- 可以認爲在局部的配置中,已經隱含的把<param name="includeMethods">test</param>繼承過來了 -->
- <!-- 補充:這裏衡量的所謂攔截到與否,主要可以通過查看控制檯輸出的語句,以判斷是否執行到該攔截器內部 -->
- <!-- **************************************************************************************** -->
實現了Interceptor接口的自定義攔截器MyInterceptor11.java
- package com.jadyer.interceptor;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.Interceptor;
- /**
- * 實現Interceptor接口的自定義攔截器
- * @see 【這種方式不太常用】
- */
- @SuppressWarnings("serial")
- public class MyInterceptor11 implements Interceptor {
- //這裏的屬性名要與struts.xml配置的<param name=""/>中的name值相同
- //然後Struts2會自動將struts.xml中配置的world值賦值到這裏的hello屬性中
- //當然,前提是要提供setter和getter方法,只要符合JavaBean的要求即可
- private String hello;
- public String getHello() {
- return hello;
- }
- public void setHello(String hello) {
- this.hello = hello;
- }
- /**
- * 初始化時執行的方法
- */
- public void init() {
- System.out.println("------MyInterceptor11 init method invoked------");
- System.out.println(hello);
- }
- /**
- * 銷燬時執行的方法
- */
- public void destroy() {
- System.out.println("------MyInterceptor11 destroy method invoked------");
- }
- //每執行一次action請求,這裏的intercept()方法都會被執行一次
- public String intercept(ActionInvocation invocation) throws Exception {
- System.out.println("------MyInterceptor11 invoked begin------");
- //調用invoke()方法
- //如果還有下一個攔截器的話,就執行下一個攔截器
- //如果沒有下一個攔截器的話,便執行Action中的方法
- String result = invocation.invoke();
- System.out.println("------MyInterceptor11 invoked finish------");
- return result;
- }
- }
- /********************【淺析Struts2的攔截器】***********************************************************/
- //Struts2中的攔截器,實際上就是用來攔截Action的。它就相當於入口和出口一樣,把Action的相關方法包裹在中間了
- //過濾器可以組成過濾器鏈,也就是有多個過濾器來過濾相同的東西。攔截器同樣也有攔截器鏈,在Struts2中稱爲攔截器棧
- //攔截器棧相當於一串攔截器,用來共同的攔截某一個Action。攔截的順序是按照配置的順序執行的
- //假設先配置的是myInterceptor11,後配置的是myInterceptor22
- //所以在執行時,先執行myInterceptor11,後執行myInterceptor22
- //但是在結束時,先執行myInterceptor22,後執行myInterceptor11
- //就好像進入一個有兩道門的房間一樣,進去的順序和出來的順序正好相反
- //也就是說它首先會進入第一個攔截器,出來後再進入第二個攔截器,依此類推,最後進入Action的execute()方法
- //當execute()執行後,再按照相反的順序,先回到第二個攔截器,再回到第一個攔截器,最後纔回到結果視圖
- //因此invoke()就是用來判斷,若還有下一個攔截器,就調用下一個攔截器。否則,直接跳到Action的execute()方法
- /********************【Struts2的默認攔截器】***********************************************************/
- //實際上可以把Struts2看成是一個空的容器。就是因爲裏面配置了大量的攔截器,導致了我們的請求需要一層一層的通過這些攔截器
- //然後它會處理我們的請求,並根據我們的配置,把它所感興趣的東西解析出來。如果出現問題,它會放到錯誤消息裏面去
- /****************************************************************************************************/
繼承了AbstractInterceptor類的自定義攔截器MyInterceptor22.java
- package com.jadyer.interceptor;
- import java.util.Map;
- import org.apache.struts2.ServletActionContext;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
- /**
- * 繼承AbstractInterceptor類的自定義攔截器
- * @see 【這種方式比較常用】
- * @see 繼承AbstractInterceptor之後,就不需要再去實現init()和destroy()方法了
- * @see 所以實際應用中,更多的時候還是繼承AbstractInterceptor,而不是實現Interceptor
- * @see ------------------------------------------------------------------------------------------------------------
- * @see 也可以用下面這種方式來配置
- * @see <package name="scriptHit" extends="struts-default">
- * @see <interceptors>
- * @see <interceptor name="ScriptHitInterceptor" class="com.jadyer.interceptor.ScriptHitInterceptor"/>
- * @see <interceptor-stack name="scriptHitStack">
- * @see <interceptor-ref name="ScriptHitInterceptor"/>
- * @see <interceptor-ref name="defaultStack"/>
- * @see </interceptor-stack>
- * @see </interceptors>
- * @see <default-interceptor-ref name="scriptHitStack"/>
- * @see </package>
- * @see ------------------------------------------------------------------------------------------------------------
- * @editor Mar 6, 2013 2:16:11 PM
- * @author 玄玉<http://blog.csdn/net/jadyer>
- */
- @SuppressWarnings("serial")
- public class MyInterceptor22 extends AbstractInterceptor {
- /**
- * http://127.0.0.1:8088/jfb/web/preLoginCheck?phoneNo=302<script>alert(1)</script>225&fromBanner=yes
- * 控制檯輸出如下
- * @see 獲取請求方法:methodName=preLoginCheck
- * @see 獲取請求參數:phoneNo=302<script>alert(1)</script>225
- * @see 獲取請求參數:fromBanner=yes
- * @see 重新獲取參數:phoneNo=jadyer302<script>alert(1)</script>225
- * @see 重新獲取參數:fromBanner=jadyeryes
- * @see 重新獲取參數:myname=jadyer
- * @see 再次獲取參數:phoneNo=302<script>alert(1)</script>225
- * @see 再次獲取參數:fromBanner=yes
- * @see 再次獲取參數:myname=null
- */
- @Override
- public String intercept(ActionInvocation invocation) throws Exception {
- System.out.println("------------ScriptHitInterceptor invoked begin------------");
- //獲取請求的方法名,得到的方法名不包含括號,例如methodName=preLoginCheck
- System.out.println("獲取請求方法:methodName=" + invocation.getInvocationContext().getName());
- //獲取請求的參數名和參數值
- Map<string object=""> parameters = invocation.getInvocationContext().getParameters();
- for(Map.Entry<string object=""> entry : parameters.entrySet()){
- //藉助parameters根據參數名獲取參數值對象,其實得到的參數值對象是一個字符串數組,該數組第一個元素即真實參數值
- System.out.println("獲取請求參數:" + entry.getKey() + "=" + ((String[])parameters.get(entry.getKey()))[0]);
- //修改下參數值
- parameters.put(entry.getKey(), new String[]{"jadyer" + ((String[])parameters.get(entry.getKey()))[0]});
- }
- //填加一個參數,這裏指定其值爲jadyer
- //Struts2之所以採用字符串數組的方式,或許是爲了應對參數名或參數值相同的情況吧
- parameters.put("myname", new String[]{"jadyer"});
- //再次獲取參數名和參數值
- for(Map.Entry<string object=""> entry : parameters.entrySet()){
- System.out.println("重新獲取參數:" + entry.getKey() + "=" + ((String[])parameters.get(entry.getKey()))[0]);
- }
- //也可以通過HttpServletRequest獲取真實參數值,不過它獲取到的是最原始的請求參數值,而非上面我們改動過的參數值
- //如果在Struts2的Action中通過ServletActionContext.getRequest().getParameter("fromBanner")獲取參數值的話
- //那麼後臺獲取到的也只是原始的請求參數值fromBanner=yes,而非fromBanner=jadyeryes
- for(Map.Entry<string object=""> entry : parameters.entrySet()){
- System.out.println("再次獲取參數:" + entry.getKey() + "=" + ServletActionContext.getRequest().getParameter(entry.getKey()));
- }
- String result = invocation.invoke();
- System.out.println("------------ScriptHitInterceptor invoked finish------------");
- return result;
- }
- }</string></string></string></string></http:>
繼承了MethodFilterInterceptor攔截器類的自定義攔截器MyInterceptor33.java
- package com.jadyer.interceptor;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
- /**
- * 繼承MethodFilterInterceptor的攔截器,即方法過濾的攔截器
- * @see 查看MethodFilterInterceptor的源碼可知,它也是一個攔截器類,它繼承了AbstractInterceptor
- * @see 觀察它的類名,可以發現,它就是一個攔截某一個具體的方法的方法過濾攔截器
- * @see 而MethodFilterInterceptor類已經自動實現好了Intercept()方法
- * @see 實際上MethodFilterInterceptor類中的Intercept()方法真正執行的是它本身的一個doIntercept()抽象方法
- * @see 因此,我們想要攔截某一個方法的時候,只要繼承MethodFilterInterceptor類,然後實現doIntercept()便OK
- */
- @SuppressWarnings("serial")
- public class MyInterceptor33 extends MethodFilterInterceptor {
- @Override
- protected String doIntercept(ActionInvocation invocation) throws Exception {
- System.out.println("------MyInterceptor33 invoked begin------");
- String result = invocation.invoke();
- System.out.println("------MyInterceptor33 invoked finish------");
- return result;
- }
- }
最後是用到的Action類
- package com.jadyer.action;
- import com.opensymphony.xwork2.ActionSupport;
- @SuppressWarnings("serial")
- public class MethodFilterAction extends ActionSupport{
- public String test() throws Exception {
- System.out.println("------test() is invoked------");
- return SUCCESS;
- }
- public String abc() throws Exception {
- System.out.println("------abc() is invoked------");
- return SUCCESS;
- }
- @Override
- public String execute() throws Exception {
- System.out.println("------execute() is invoked------");
- return SUCCESS;
- }
- }