1.Struts2架构图
2.Struts2 执行过程分析
1.首先,因为使用 struts2 框架,请求被Struts2Filter 拦截
2.Struts2Filter 调用 DisPatcher 的 serviceAction 方法
3.在serviceAction 中,创建 ActionProxy对象,并调用其execute方法
4.在ActionProxy的execute中,调用ActionInvocation的invoke方法,ActionInvocation对象中包含了众多的拦截器(ExceptionInterceptor等)
5.ActionInvocation的invoke方法 会调用这些拦截器的intercept方法,
每一个intercept方法都会回过头调用之前的ActionInvocation对象的invoke方法
6.再次调用这个invkoe,会继续调用下一个拦截器,直到所有的拦截器都被调用一遍后,没有下一个拦截器了,此时就会调用Action的execute方法了
7.调用了Action中的方法后,此时最后一个拦截器的invoke方法完成调用,
最后一个拦截器执行invoke方法之后的代码,然后一直迭代回去,第一个拦截器的invoke方法也调用完毕
8.所有的拦截器的intercept方法 结束后,ActionInvocation的invoke方法也结束,最后形成响应回去
注:类似于 Filter 拦截WEB资源时的这种关系,doFileter方法和chain方法
调用chain方法时,会先看下后面是否还有Filter注册了,如果有,先执行后面Filter的 doFileter方法,等到判断到后面没有Filter了,
最后一个Filter的chain方法才能被执行,最后一个Filter全部都执行完成之后,才会回调之前的Filter
/*这种形式也有点类似AOP的感觉,一个又一个的拦截器,就是一个又一个的切面*/
3.Interceptor 拦截过程模拟
1 public class ActionInvocation { 2 List<Interceptor> interceptors = new ArrayList<Interceptor>(); 3 Action a = new Action(); 4 int index = -1; 5 6 public ActionInvocation() { 7 this.interceptors.add(new FirstInterceptor()); 8 this.interceptors.add(new SecondInterceptor()); 9 } 10 11 public void invoke() { 12 index++; 13 if(index >= this.interceptors.size()) { 14 a.execute(); 15 } 16 else { 17 this.interceptors.get(index).interceptor(this); 18 } 19 } 20 21 }
4.定义自己的拦截器(一般没有必要去定义自己的拦截器,常见的拦截器通常已经做好了)
1.编写拦截器(实现Interceptor接口)
1 public class MyInterceptor implements Interceptor { 2 3 public void destroy() { 4 // TODO Auto-generated method stub 5 6 } 7 8 public void init() { 9 // TODO Auto-generated method stub 10 11 } 12 13 public String intercept(ActionInvocation arg0) throws Exception { 14 long t1 = System.currentTimeMillis(); 15 String r = arg0.invoke(); 16 long t2 = System.currentTimeMillis(); 17 System.out.println("time="+(t2-t1)); 18 return r; 19 } 20 21 }
2.在struts.xml中注册(使用 interceptors标签 声明拦截器)<interceptor-ref>(使用这个拦截器)
1 <package name="test" namespace="/" extends="struts-default"> 2 <interceptors> 3 <interceptor name="my" class="com.bjsxt.interceptor.MyInterceptor"></interceptor> 4 </interceptors> 5 6 7 <action name="test" class="com.bjsxt.action.TestAction"> 8 <result>/test.jsp</result> 9 <!-- 自定义拦截器在默认拦截器的前面,是为了先执行自定义拦截器,不然自定义拦截器 结束的会很快 --> 10 <interceptor-ref name="my"></interceptor-ref> 11 <!-- 这里必须要加上默认拦截器,不然自定义拦截器会把默认拦截器覆盖 --> 12 <interceptor-ref name="defaultStack"></interceptor-ref> 13 </action> 14 </package>
5.使用token拦截器(防止表单重复提交)(很少用 有其他方式)
1.在form 表单中添加<s:token></s:token> (作用,生成一个唯一的识别码,用于验证是否重复提交)
2.在struts.xml中添加 <result name="invalid.token">/error.jsp</result> (至于为什么是 'invalid.token',可以查看struts-default.xml)
<interceptor-ref name="token"></interceptor-ref>
过程:1.使用token拦截器 会在服务器端生成一个 唯一标识码
2.客户端通过 <s:token></s:token> 发送 标识码过来 和服务器端的进行对比,对比完成后,这个唯一标识码会删除,
重复提交时,客户端再发送 标识码 ,服务端已经没有了,返回结果 'invalid.token'
6.认识默认的拦截器(servletConfig)
作用:取得Map类型request,session,application 等
1.在Action中,让Action实现RequestAware,SessionAware,ApplicationAware 这种接口,
2.实现这些接口,需要重写一些方法,如setRequest(Map<String, Object> request)
这个过程的实现,就是通过 ServletConfigInterceptor 这个拦截器 实现的
7.类型转换
1.默认转换
(将前台提交的String 类型的数据 转换成如int,List,Set(interests=math&interests=history),
数组,Map(users['a']=usera&users['b']=userb))
如果想转换成日期类型,需符合输入规范,也可以通过<s:date> 标签用指定的格式显示 日期
http://localhost:8080/struts2_37_type_conversion/test?name=xzk&age=21&d=1996-07-29&interests=math&interests=history&users[%27a%27]=usera&users[%27b%27]=userb
2.写自己的转换器
1 public class MyPointConverter extends StrutsTypeConverter{ 2 3 @Override 4 public Object convertFromString(Map context, String[] values, Class toClass) { 5 6 Point p = new Point(); 7 String[] strs = (String[])values; 8 String[] xy = strs[0].split(","); 9 p.x = Integer.parseInt(xy[0]); 10 p.y = Integer.parseInt(xy[1]); 11 return p; 12 } 13 14 @Override 15 public String convertToString(Map context, Object o) { 16 // TODO Auto-generated method stub 17 return o.toString(); 18 } 19 20 }
3.三种注册方式(写好自己的转换器后,还需要完成注册)
a) 局部(将注册文件(XXXAction-conversion.properties)放到和Action同级下)
b) 全局:xwork-conversion.properties
java.awt.Point=com.bjsxt.converter.MyPointConverter
c) Annotation (注解)
http://localhost:8080/struts2_37_type_conversion/test?p=2,3&ps=2,3&ps=3,4&points[%27a%27]=2,3&points[%27b%27]=3,4