http://struts.apache.org/2.0.11/docs/interceptors.html
AOP通过拦截来实现关注点织入(Weaving),一般拦截一个方法可以采用回调方法或者动态代理。动态代理至少需要实现两个类:一个代理,一个被代理(都要实现共有接口)。代理类是通过java.lang.reflect.Proxy来的到的。
Action的调用都是通过拦截器来实现的。
HelloWorld拦截器
配置
<interceptors>
<interceptor name="Myinterceptor"
class="Myintercepor">
</interceptor>
>
<action name="Reg" class="Reg">
<result name="success/success.jsp</result>
<result name="input">/reg.jsp</result>
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="MyInterceptor"></interceptor-ref>
</action>
拦截器类
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class Myintercepor extends AbstractInterceptor {
public String intercept(ActionInvocation arg0) throws Exception {
// TODO Auto-generated method stub
Reg reg = (Reg) arg0.getAction();
System.out.println("拦截器信息:HelloWorld拦截器!");
// 执行Action或者执行下一个拦截器
String result = arg0.invoke();
// 提示Action执行完毕
System.out.println("拦截器信息:Action执行完毕!");
return result;
}
}
业务控制器Reg
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class Reg extends ActionSupport {
// 定义用户名属性
private String username;
// 定义处理信息:注意同http中的msg不同名称
private String mymsg;
// 定义密码属性
private String password1;
// 定义确认密码
private String password2;
// 定义生日属性
private Date birthday;
public String execute() throws Exception {
if (username != null && getPassword1().equals(getPassword2())
&& !getUsername().trim().equals("")) {
System.out.println("Action信息:正在执行Actiion... ...");
return SUCCESS;
} else {
System.out.println("Action信息:没有用户参数,返回input");
return INPUT;
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMymsg() {
return mymsg;
}
public void setMymsg(String mymsg) {
this.mymsg = mymsg;
}
public String getPassword1() {
return password1;
}
public void setPassword1(String password1) {
this.password1 = password1;
}
public String getPassword2() {
return password2;
}
public void setPassword2(String password2) {
this.password2 = password2;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
reg.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>用户注册</title>
<s:head />
</head>
<body>
<table>
<s:form id="id" action="Reg">
<s:textfield name="username" label="用户名:"/>
<s:password name="password1" label="密码:"/>
<s:password name="password2" label="确认密码:"/>
<s:datetimepicker name="birthday" label="生日:"/>
<s:submit value="注册"/>
</s:form>
</table>
</body>
</html>
自定义拦截器
Struts 2 框架提供import com.opensymphony.xwork2.interceptor.AbstractInterceptor类,继承该类,就可以定义自己的拦截器,该类定义了init(),destory(),intercept(ActionInvocation invocation),如果不需要加在一些特殊的系统资源,可以不用实现init(),destory().
<!--自定义拦截器-->
<interceptors>
<interceptor name="simpleInterceptor"
class="simpleInterceptor">
</interceptor>
</interceptors>
<action name="Reg" class="Reg">
<result name="success">/success.jsp</result>
<result name="input">/reg.jsp</result>
<interceptor-ref name="defaultStack"></interceptor-ref><!--不能少-->
<interceptor-ref name="simpleInterceptor"></interceptor-ref>
</action>
自定义拦截器实现类
import java.util.Date;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class simpleInterceptor extends AbstractInterceptor {
//重写intercept方法
public String intercept(ActionInvocation arg0) throws Exception {
//获得被拦截的Action引用
Reg reg = (Reg) arg0.getAction();
System.out.println("拦截器信息:启动拦截器,拦截Action时间:"+new Date());
// 执行Action或者执行下一个拦截器
String result = arg0.invoke();//如果在控制中不调用invoke()方法,则Action不会被执行,拦截器直接返回一个"success"字符串。
// 提示Action执行完毕
System.out.println("拦截器信息:Action执行完毕时间:!"+new Date());
return result;
}
}
</interceptor>
<interceptors>
拦截器的方法过滤
继承MethodFilterInterceptor雷,就可以使用拦截器的方法过滤功能,来拦截Action中特定的方法。
。excludeMethods:该参数指定拦截器拒绝的方法列表,如:"method1,method2"
。includeMethods:该参数指定拦截器需要拦截的方法列表。
下面给出该类的主要方法:
.protected abstract String doIntercept(ActionInvocation invocation):继承该类的子类必须重写该方法,并实现拦截逻辑。
.String intercept(ActionInvocation invocation):继承自com.opensyphony.xwork2.interceptor.AbstractInterceptor雷,该方法不需要强制重写。
.void setExcludeMethods(String excludeMethods):设置黑名单,该方法参数为一个字符串,即对应的Action方法名称。
。void setIncludeMethods(String includeMethods):设置拦截器的白名单,该方法参数为一个字符串,即对应的Action方法名称。
.set getExcludeMethodsSet():获得该拦截器的黑名单。
.set getIncludeMethodsSet():获得该拦截器的白名单。
如果使用MethodFilterInterceptor类的子类来实现,不需要重写intercept(ActionInvocationinvocation)方法,只要重写doIntercept(ActionInvocation invocation)方法即可。
实现方法过滤的拦截器与普通拦截器并没有大的差别,只是继承了com.opensymphony.xwork2.interceptor.AbstractInterceptor类的子类MethodFilterInterceptor,并重写doIntercept(ActionInvocationinvocation)方法。
实现方法过滤的拦截器实现类FilterInterceptor
import java.util.Date;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class FilterInterceptor extends MethodFilterInterceptor {
//拦截器名称参数,可以在配置文件中指定
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected String doIntercept(ActionInvocation arg0) throws Exception {
// 引用被拦截Action对象
FilterAction fa = (FilterAction) arg0.getAction();
// 打印拦截信息
System.out.println(name+"拦截器在Action执行前拦截:" + new Date());
// 执行Action或者下一个拦截器
String res = arg0.invoke();
// 打印Action执行完毕信息
System.out.println(name+"拦截器在Action执行后拦截:" + new Date());
// 返回逻辑视图
return res;
}
}
动态调用业务控制器FilterAction
import com.opensymphony.xwork2.ActionSupport;
public class FilterAction extends ActionSupport {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
// 模拟方法1
public String method1() throws Exception {
System.out.println("Action执行方法:method1()");
return SUCCESS;
}
// 模拟方法2
public String method2() throws Exception {
System.out.println("Action执行方法:method2()");
return SUCCESS;
}
// 模拟方法3
public String method3() throws Exception {
System.out.println("Action执行方法:method3()");
return SUCCESS;
}
}
配置
<interceptors>
<interceptor name="FilterInterceptor"
class="ch5.FilterInterceptor">
</interceptor>
</interceptors>
<action name="FilterAction" class="FilterAction">
<result name="success">/MethodFilter.jsp</result>
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="FilterInterceptor">
<!--使用方法过滤,设置白名单或者黑名单-->
<param name="includeMethods">method1</param>
<param name="excludeMethods">method2</param>
<param name="name">方法过滤拦截器</param>
</interceptor-ref>
</action>
一些重要的拦截器
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/><!--将异常定位到一个页面-->
<interceptor-ref name="alias"/><!--在不同请求之间将请求参数在不同名字间转换,请求内容不变-->
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/><!--让前一个Action的属性可以被后一个Action访问,和chain类型的result(resulttype="chain"结合使用-->
<interceptor-ref name="debugging"/>
<interceptor-ref name="profiling"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/><!--提供文件上传-->
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params"><!--将请求中的参数设置到Action中去-->
<param name="excludeParams">dojo..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
首先,第一个是exception 用法如下,如果不用这个功能可以去掉
< interceptor-ref name ="exception" />
< interceptor-ref name ="basicStack" />
< exception-mapping exception ="com.acme.CustomException" result ="custom_error" />
< result name ="custom_error" > custom_error.ftl </ result >
</action>
第二个,是取别名的功能,也可以基本不用
<!– The value for the foo parameter will be applied as if it were named bar –>
<param name="aliases">#{ ’foo’ : ’bar’ }</param>
<interceptor-ref name="alias"/>
<interceptor-ref name="basicStack"/>
<result name="success">good_result.ftl</result>
</action>
第三个,看一下代码就明白了,这个有时还是能用到的,暂且保留好了(我们可以用 ServletActionContext代替)
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
((ServletRequestAware) action).setServletRequest(request);
}
if (action instanceof ServletResponseAware) {
HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);
((ServletResponseAware) action).setServletResponse(response);
}
if (action instanceof ParameterAware) {
((ParameterAware) action).setParameters(context.getParameters());
}
if (action instanceof RequestAware) {
((RequestAware) action).setRequest((Map) context.get("request"));
}
if (action instanceof SessionAware) {
((SessionAware) action).setSession(context.getSession());
}
if (action instanceof ApplicationAware) {
((ApplicationAware) action).setApplication(context.getApplication());
}
第四个 prepare 这个拦截器的控制粒度在方法级别,常用在一些方法的执行必须基于某某方法先执行
Object action = invocation.getAction();
if (action instanceof Preparable) {
try {
PrefixMethodInvocationUtil.invokePrefixMethod(invocation,
new String[] { PREPARE_PREFIX, ALT_PREPARE_PREFIX });
}
catch(Exception e) {
// just in case there’s an exception while doing reflection,
// we still want prepare() to be able to get called.
LOG.warn("an exception occured while trying to execute prefixed method", e);
}
if (alwaysInvokePrepare) {
((Preparable) action).prepare(); 先执行
}
}
return invocation.invoke(); 后执行
}
另外这个拦截器要设置
- excludeMethods - methods name to be excluded
- includeMethods - methods name to be included
这2个属性 因为它是继承自 MethodFilterInterceptorfoo.action?request_locale=en_US
如果看不惯request_locale,可以设置掉 提供了
public void setParameterName(String parameterName) {
this.parameterName = parameterName;
}
第五个,就不用说了,非常重要
在项目应用中,尽量减少不需要的拦截器的饮用。拦截器重要的是可以通过拦截器来实现AOP的设计思想。通过对项目的分析,找出“横切关注点“,可以使用拦截器来实现分离。
应用如权限拦截器
原理:在特定的包含范围内,定义一个权限拦截器,该拦截器的作用是验证当前用户的请求种Session中的权限标识。为了使包中所有的Action都应用该拦截器,将该拦截器定义为包默认拦截器。
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class checkInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation arg0) throws Exception {
// 获得Action上下文
ActionContext ctx = arg0.getInvocationContext();
// 获得Session
Map session = ctx.getSession();
// 获得Session中的user标识
String user = (String) session.get("user");
// 如果标识合法,则执行Action非法
if (user != null && user.equals("pla")) {
return arg0.invoke();
} else {
// 如果不合法,则拦截Action执行,跳转到登录界面
return "login";
}
}
}
这样使用的好处是避免了在每个Action或者JSP视图中判断当前用户是否为合法用户。
配置拦截器
如要配置上权限拦截器
.定义拦截器:使用<interceptor.../>
.定义一个全局result:对应拦截器验证不合法的逻辑视图"login"。
.定义一个默认拦截器zai:为了使包内所有的Action都能使用拦截器,最好的方式就是将其定义为默认拦截器。
<!--定义权限拦截器-->
<interceptors>
<interceptor name="checkInterceptor"
class="ch5.checkInterceptor"></interceptor>
<!--定义一个自定义拦截器栈,包含系统默认拦截器和权限拦截器-->
<interceptor-stack name="mydefaultstack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="checkInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!--将自定义拦截器栈设置为包默认拦截器-->
<default-interceptor-ref name="mydefaultstack"></default-interceptor-ref>
<global-results>
<result name="login">/login.jsp</result>
</global-results>
权限拦截器loginAction
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String username;
private String password;
private String msg;
public String execute() throws Exception {
//检查用户名密码是否合法
if (username.equals("pla")&&password.equals("pla")){
//合法,则设置msg消息内容
setMsg("欢迎"+username);
//将用户名存入session中
ActionContext ctx=ActionContext.getContext();
Map session=ctx.getSession();
session.put("user", username);
return SUCCESS;
}else{
//将用户名存入session中
ActionContext ctx=ActionContext.getContext();
Map session=ctx.getSession();
session.put("user", null);
return LOGIN;
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
import com.opensymphony.xwork2.ActionSupport;
public class ViewBankAction extends ActionSupport {
public String execute() throws Exception {
// 没有任何逻辑,直接返回SUCCESS
return SUCCESS;
}
}
JSP:login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>用户登录</title>
<s:head />
</head>
<body>
<table>
<h2><s:property value="msg" /></h2>
<s:form id="id" action="login">
<s:textfield name="username" label="用户名:" />
<s:password name="password" label="密码:" />
<s:submit value="登录" />
</s:form>
<ul>
<s:url id="url" action="ViewBankAction"></s:url>
<s:a href="%{url}">查看银行账户</s:a>
</ul>
</table>
</body>
</html>
viewbank.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>登录成功界面</title>
<s:head />
</head>
<body>
<table>
<h2>你好<s:property value="username" />,登录成功!!</h2>
<h2>欢迎您查看您的银行账户。</h2>
</table>
</body>
</html>