一、拦截器
- Struts2拦截器是在访问某个Action或Action的某个方法之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现
- AOP:面向切面编程,其实现原理:动态代理模式
- 拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个Action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也提供了一种可以提取Action中可重用的代码方式
- 拦截器栈(Interceptor Stack):Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截器的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用
- 拦截器在设计和程序结构上的优点:
- 拦截器能把很多功能从Action中独立出来,分散到不同的拦截器里面,减少了Action的代码。拦截器和Action本身的功能都更单一了。当通用的功能代码被封装在拦截器里面(代码模块化),就可以对不同的Action,根据功能需要,来配置相应功能的拦截器了。提高了拦截器所实现的功能的重用性,也变相实现了装配式和可插拔式的体系结构,使得整个系统结构变得更灵活。
二、Struts2执行流程
- 1、客户端发送请求
- 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中的配置找到对应的返回结果。返回结果是一个JSP或其他页面(也可以是其他的Action链)。JSP页面展现可使用Struts2框架中的标签(该过程会涉及ActionMapper)。
三、Struts2内置拦截器
input,back,cancel,browse
input,back,cancel,browse
input,back,cancel,browse
input,back,cancel,browse
input,back,cancel
input,back,cancel
1、常见拦截器
1:params拦截器
这个拦截器偷偷的把请求参数设置到相应的Action的属性去的,并自动进行类型转换。
2.modelDriven拦截器
如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中。
3.execption拦截器
顾名思义,在抛出异常的时候,这个拦截器起作用。最好把它放在第一位,让它能捕获所有的异常。
4.validation拦截器
调用验证框架读取 *-validation.xml文件,并且应用在这些文件中声明的校验。
5.token拦截器
核对当前Action请求(request)的有效标识,防止重复提交Action请求。
6.fileUpload拦截器
用来处理文件上传
7.workflow拦截器
调用Action的validate方法,一旦有错误返回,重新定位到INPUT结果视图
8.servletConfig
通过感知接口,获取感应对象
9.store:保证在两次请求之间共享数据的.
2、servletConfig拦截器原理
- 实现ServletRequestAware接口
package com.revanwang.servlet;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//1、通过让Action类去实现感知接口.
public class ActionServlet1 extends ActionSupport implements
ServletRequestAware, //获取 HttpServletRequest 对象
ServletResponseAware
{
private HttpServletRequest request;
private HttpServletResponse response;
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
this.request = httpServletRequest;
}
@Override
public void setServletResponse(HttpServletResponse httpServletResponse) {
this.response = httpServletResponse;
}
@Override
public String execute() throws Exception {
System.out.println(this.request.getParameter("name")+"--"+this.response);
return NONE;
}
}
- 从struts2-core-2.5.20.jar中struts-default.xml中
- ServletConfigInterceptor源码
public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {
private static final long serialVersionUID = 605261777858676638L;
public ServletConfigInterceptor() {
}
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
ActionContext context = invocation.getInvocationContext();
HttpServletRequest request;
if (action instanceof ServletRequestAware) {
request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
((ServletRequestAware)action).setServletRequest(request);
}
if (action instanceof ServletResponseAware) {
HttpServletResponse response = (HttpServletResponse)context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");
((ServletResponseAware)action).setServletResponse(response);
}
if (action instanceof ParameterAware) {
context.getParameters().applyParameters((ParameterAware)action);
}
if (action instanceof HttpParametersAware) {
((HttpParametersAware)action).setParameters(context.getParameters());
}
if (action instanceof ApplicationAware) {
((ApplicationAware)action).setApplication(context.getApplication());
}
if (action instanceof SessionAware) {
((SessionAware)action).setSession(context.getSession());
}
if (action instanceof RequestAware) {
((RequestAware)action).setRequest((Map)context.get("request"));
}
if (action instanceof PrincipalAware) {
request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
if (request != null) {
((PrincipalAware)action).setPrincipalProxy(new ServletPrincipalProxy(request));
}
}
if (action instanceof ServletContextAware) {
ServletContext servletContext = (ServletContext)context.get("com.opensymphony.xwork2.dispatcher.ServletContext");
((ServletContextAware)action).setServletContext(servletContext);
}
return invocation.invoke();
}
}
- 执行过程
Object action = invocation.getAction();
ActionContext context = invocation.getInvocationContext();
HttpServletRequest request;
if (action instanceof ServletRequestAware) {
request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
((ServletRequestAware)action).setServletRequest(request);
}
1:通过invocation.getAction()来获取自定义Action类,然后在判断该Action类是否实现ServletRequestAware接口,如果实现ServletRequestAware接口,就会调用自定义Action类中的setServletRequest方法
四、在Struts2中自定义拦截器
通过(登录检查拦截器,访问某一个页面时必须要先登录,登录之后才能访问)例子来实现自定义拦截器
- login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
注册界面
- welcome.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录成功
欢迎${sessionScope.user.userName}
- User
package com.revanwang.interceptor;
import lombok.Data;
@Data
public class User {
private String userName;
private String passWord;
}
- Action类
package com.revanwang.interceptor;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import lombok.Getter;
import lombok.Setter;
public class LoginAction extends ActionSupport {
@Setter
@Getter
private User user; //获取请求参数
@Override
public String execute() throws Exception {
System.out.println("Login....." + this.user);
//保存user数据到 session 中
ActionContext.getContext().getSession().put("user", this.user);
return SUCCESS;
}
}
- struts.xml
/login/welcome.jsp
-
上面的缺点就是无论是否登陆成功都可以访问到welcome.jsp,这显然不符合需求。为了只能在登录成功后才能访问welcome.jsp.
- 1、直接判断Action中的请求参数,但是这种方法存在硬编码
- 2、自定义拦截器(checkLoginInterceptor)
CheckLoginInterceptor
package com.revanwang.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import java.util.Map;
public class CheckLoginInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Map sessionMap = invocation.getInvocationContext().getSession();
User user = (User) sessionMap.get("user");
System.out.println("CheckLoginInterceptor. . . ." + sessionMap + "\n" + user);
if (user == null || user.getUserName().equals("".trim())) {
System.out.println("CheckLoginInterceptor. . . .empy");
return "login";
}
return invocation.invoke();
}
}
- struts.xml
/login/login.jsp
checkAction
/login/welcome.jsp
3、拦截器设置参数
- CheckLoginInterceptor
package com.revanwang.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import java.util.Arrays;
import java.util.Map;
public class CheckLoginInterceptor extends AbstractInterceptor {
//需要放行的action名称
private String[] unCheckedActionNames = {};
//通过拦截器设置对应参数
public void setActionNames(String actionNames) {
if (actionNames != null) {
this.unCheckedActionNames = actionNames.split(",");
}
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//拦截器放行
String actionName = invocation.getProxy().getActionName();
System.out.println("unCheckedActionNames:===" + actionName);
if (Arrays.asList(this.unCheckedActionNames).contains(actionName)) {
System.out.println("unCheckedActionNames:===" + actionName);
return invocation.invoke();
}
Map sessionMap = invocation.getInvocationContext().getSession();
User user = (User) sessionMap.get("user");
if (user == null || user.getUserName().equals("".trim())) {
System.out.println("CheckLoginInterceptor. . . .empy");
return "login";
}
return invocation.invoke();
}
}
- struts.xml
lt,dl
/login/login.jsp
checkAction
/WEB-INF/JSP/list.jsp
/login/welcome.jsp
/login/welcome.jsp
/login/welcome.jsp