1.为什么在struts.xml文件中进行相应的拦截器配置之后,拦截器就开始工作了,拦截器是怎样实现的呢?
拦截器的原理在于代理,所以先来看看java中关于代理的一些东西.
代理的目的--就是要为已存在的具有相同的接口的目标类的各个方法添加一些附加的功能
代理对象与目标对象具有相同的接口,客户端调用代理对象,代理对象调用目标对象完成功能,实际上,代理对象调用目标对象来完成功能是借助与代理对象相关联的调用处理程序来调用目标对象并且加入了一些附加的功能
下面来看一个实例,进一步加深对代理的原理的理解
新建名为ProxyPrinciple项目,首先新建一个代理类生成器ProxyBean.java
package com.undergrowth;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 创建一个代理类对象
*/
public class ProxyBean {
public static Object getProxyObject(final AddFunctionInterface af,final Object target)
{
//创建代理对象 代理对象是JVM动态创建的 使用目标对象的类加载器和接口进行创建 并且还带一个与之关联的调用处理程序
Object proxyObject=Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
af.beforeTarget(method);
//执行目标对象的方法 返回该方法在目标对象上利用args所返回的值
Object methodReturn=method.invoke(target, args);
af.afterTarget(method);
return methodReturn;
}
});
return proxyObject;
}
}
接着是一个附加功能的接口与实现类
附加类的接口 AddFunctionInterface.java
package com.undergrowth;
import java.lang.reflect.Method;
public interface AddFunctionInterface {
//相当于在目标对象的方法执行之前添加一些功能 这里只是模拟输出方法名
public abstract void beforeTarget(Method method);
//相当于在目标对象的方法执行之后添加一些功能 这里只是模拟输出方法名
public abstract void afterTarget(Method method);
}
附加类的实现 AddFunction.java
package com.undergrowth;
import java.lang.reflect.Method;
public class AddFunction implements AddFunctionInterface {
//相当于在目标对象的方法执行之前添加一些功能 这里只是模拟输出方法名
/* (non-Javadoc)
* @see com.undergrowth.AddFunctionInterface#beforeTarget(java.lang.reflect.Method)
*/
@Override
public void beforeTarget(Method method)
{
System.out.println("在"+method.getName()+"方法之前执行");
}
//相当于在目标对象的方法执行之后添加一些功能 这里只是模拟输出方法名
/* (non-Javadoc)
* @see com.undergrowth.AddFunctionInterface#afterTarget(java.lang.reflect.Method)
*/
@Override
public void afterTarget(Method method)
{
System.out.println("在"+method.getName()+"方法之后执行");
}
}
代理类的测试类 ProxyMainTest.java
package com.undergrowth;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyMainTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建附加功能的类
AddFunctionInterface af=new AddFunction();
//创建目标类
ArrayList alList=new ArrayList<>();
//获取代理对象
Collection collection=(Collection) ProxyBean.getProxyObject(af, alList);
//调用代理对象的方法 实际上是在用代理对象关联的调用执行程序的invoke方法来进行调用目标对象的方法
collection.add("第一个添加的代理");
System.out.println(collection.size());
}
}
在控制台输出:
在add方法之前执行
在add方法之后执行
在size方法之前执行
在size方法之后执行
1
本质: 调用代理对象的方法 实际上是在用代理对象关联的调用执行程序的invoke方法来进行调用目标对象的方法
上面即是简单的代理类的实例,而struts的拦截器与Action的结合,就和上面的原理是差不多的,拦截器就相当于上面的AddFunction类,Action就相当于上面的alList目标对象,而我们在struts.xml文件中进行配置后,是由系统为我们的目标action生成一个代理的action,然后这个代理的action就会调用各种拦截器的方法来完成相应的功能.
下面即是示意图
2.接着看看拦截器Interceptor的实现
首先登陆的login.jsp页面
<%@ 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>
<center><h2>${sessionScope.msgSession }</h2>
<s:form action="login" namespace="/login" method="post">
<s:textfield label="用户名" name="username"></s:textfield>
<s:password label="密 码" name="password"></s:password>
<s:submit value="提交" />
</s:form>
</center>
</body>
</html>
一个简单的表单 包含一个文本域和一个密码域
${sessionScope.msgSession }----是在拦截器验证失败后 用于输出session中的msgSsession属性的值
业务控制器配置struts.xml文件
<?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>
<package name="login" namespace="/login" extends="struts-default">
<interceptors>
<interceptor name="permission" class="com.undergrowth.Permission"></interceptor>
<interceptor-stack name="perall">
<interceptor-ref name="permission"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="login" class="com.undergrowth.Login">
<result>/success.jsp</result>
<result name="login">/login.jsp</result>
<interceptor-ref name="perall"></interceptor-ref>
</action>
</package>
</struts>
struts.xml文件定义了一个permission的拦截器 实现类为com.undergrowth.Permission 用于检查当前session中时候有user这个属性 有---表示用户已经登陆了 无--则没有登录
还定义了一个拦截器栈 包含定义的permission和默认的拦截器栈defaultStack
在action中引用拦截器栈 perall 这里为什么要定义拦截器栈perall 因为当我们一旦为action指定了拦截器后 默认的拦截器就不会起作用了 但是defaultStack拦截器栈是系统默认的拦截器栈 里面包含了一些基本的拦截器 我们可能会用到 比如params---解析请求参数 staticParams---解析struts.xml中的param属性 fileUpload解析文件上传的文件域等等
登陆的action实现类 Login.java
package com.undergrowth;
import com.opensymphony.xwork2.Action;
public class Login {
//用于验证成功登陆
private String msg;
public String getMsg() {
return msg;
}
public String execute()
{
msg="成功登陆";
return Action.SUCCESS;
}
}
permission拦截器的实现类 Permission.java
package com.undergrowth;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
/*
* 自定义拦截器
* 有三种方式
* 实现Interceptor接口
* 继承AbstractInterceptor抽象类 提供了实现了的空的init destroy方法
* 继承MethodFilterInterceptor类 可实现方法过滤
*/
public class Permission implements Interceptor{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init() {
// TODO Auto-generated method stub
System.out.println(Permission.class.getName());
}
@Override
public String intercept(ActionInvocation arg0) throws Exception {
// TODO Auto-generated method stub
Map sessionMap=arg0.getInvocationContext().getSession();
String userString=(String) sessionMap.get("user");
//调用arg0的invoke方法 将执行权限给下一个拦截器 或者action的方法
if(userString!=null && "admin".equals(userString)) return arg0.invoke();
sessionMap.put("msgSession", "您没有登录,请登录");
return Action.LOGIN;
}
}
登陆成功的sussess.jsp页面 输出登陆成功的消息信息
<%@ 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>
${msg}
</body>
</html>
用于向session中添加user属性的 addSession.jsp 页面
<%@ 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", "admin");
out.println("加入user到session中");
%>
</body>
</html>
3.测试
输入 http://localhost:8080/InterceptorImple/login.jsp
输入admin admin 结果页面
表示permission拦截器起作用了
接着输入 http://localhost:8080/InterceptorImple/addSession.jsp
再次输入 http://localhost:8080/InterceptorImple/login.jsp 和admin admin
进入到
以上即是拦截器的原理和一个实例