文章目录
Struts2五个核心部件
- Actions(动作)
- Interceptors(拦截器)
- Value Stack / OGNL(值栈 / OGNL)
- Results / Result types(返回结果)
- View technologies(视图)
1 ActionContext
1.1 基础知识
- Struts1的Action必须依赖与web容器,他的execute方法会自动获取HttpServletRequest,HttpServletResponse对象,从而可以跟web容器进行交互。
- Struts2的Action不用依赖与web容器,本身就是一个普通的java类。在web开发中我们要用到request,session,application等对象,这时候,就可以通过ActionContext来处理。
- ActionContext是Action执行的上下文,内部有个map属性,存放了Action执行时需要用到的对象。在每次执行的Action之前都会创建ActionContext对象,所以他是线程安全的。新new的ActionContext是保存在一个Threadlocal变量中,即采用
ThreadlocalM模式
。Threadlocal变量为每个线程提供独立的变量值的副本,使每个线程都可以独立的使用自己的副本,而不会和其他线程发生冲突。 - 通过ActionContext获取的request,session,application并不是真正的HttpServletRequest,HttpServletResponse,ServletContext对象,而是将这三个对象里面的值重新包装成了map对象,这样的封装我们获取了所需要的值,同时避免了跟web容器直接打交道,实现完全的解耦。
1.2 理解
1.2.1 什么是ActionContext?
map结构的容器。ActionContext是Action的上下文,存放Action执行过程中数据信息。ActionContext存放Action的数据,ActionInvocation,request的数据,session的数据,application的数据,local的数据等。每次请求时会为当前线程创建一个新的ActionContext。而ActionContext采用了ThreadLocal的方式来存放ActionContext 所以ActionContext是线程安全的。
1.2.2 获取ActionContext
ActionContext.getContext()获取,由于ActionContext是线程安全的,并且是通过静态方法获取的,所以在本线程中的非Action;类中,也可以直接访问。
注意点:ActionContext基于请求创建的,所以在非请求的线程中是不能使用ActionContext对象的。如:filter的init()方法。
1.2.3 ActionContext简图
部分资料图片参考博客:
https://www.cnblogs.com/auldlangsynezh/p/8493830.html
1.2.4 ThreadLocal模式
public static void main(String[] args) {
// ThreadLocal存放线程局部变量的容器
// 存放在TreadLocal中的局部变量 是线程安全的
final ThreadLocal<String> ac = new TreadLocal<String>();
ac.set("lxy");
new Thread(new Runnable() {
public void run() {
System.out.println("thread:" + ac.get());
}
}).start();
System.out.println(ac.get());
}
1.2.5 ActionContext中包含6大对象
- application
- session
- request
- parameters
- attr(page–>request–>session–>application)
- ValueStack(值栈)
2 ValueStack(值栈)
2.1 理解
值栈ValueStack是ActionContext中的一个对象,值栈是栈结构,特征:FIFO(先进先出);
Struts2中值栈存放的数据是Action对象。
3 ognl 表达式
3.1 ognl 简介
OGNL全称Object-Graph Navigation Language,对象图形导航语言。
相对于EL语言,除了保持EL语言的优点外,他的其他优点如下:
1.能够访问对象的普通方法;
2.能够访问类的静态属性和静态方法;
3.强大的操作集合类对象的能力;
4.支持赋值操作和表达式串联;
5.访问OGNL上下文和ActionContext;
表达式——el, re, ognl——用简洁的表达式完成比较复杂的功能:
User{
Teacher t;
}
Teacher {
Address address;
}
user.t.address
所有框架都可以用jstl,不必掌握这些表达式。
3.2 使用ognl
原则:数据分为2类-----常用的和不常用的-----常用的一般是小数据,不常用的一般是大的数据
表达式:常用的数据直接取,不常用的数据加#取
public static void main(String[] args) throws OgnlException{
// 原则:数据分为2类-----常用的和不常用的-----常用的一般是小数据,不常用的一般是大数据
// 表达式:常用的数据直接取,不常用的数据加#取
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "张三");
map.put("age", 25);
User user = new User();
user.setName("lisi");
Object object = Ognl.getValue("#name", map, user); // 输出:张三
// "name"————取出的是lisi
System.out.println(object);
}
struts2中使用ognl表达式是通过struts2的标签来取值的。
在jsp中导入struts2标签库
<%@ taglib prefix="s" uri="/struts-tags" %>
注意:要使用struts2的标签,那么要通过struts2过滤器来启用。如果过滤器的配置为.action结尾时,不能直接访问jsp页面,需要通过action跳转。如果过滤器配置为/时,可以直接访问jsp页面(不安全的操作)。
struts2推荐不直接访问jsp页面,不安全啊,你把地址告诉别人了!推荐使用action来控制跳转。
3.3 ognl 在项目中的运用
<body>
用户名:<s:property value="name" /> action的属性 <br>
用户名:<s:property value="#session.user" />------------
<a href="logout.action">退出</a>
</body>
3.4 结论
使用ognl表达式访问action属性时,可以直接访问actionContext中的数据时需要加#。
4 Struts类型转换
4.1 解释
- 在servlet中,如果表单提交非字符串数据的时候,需要进行类型转换:如提交age
String strAge = req.getParameter("age");
int age = 0;
if(strAge != null) {
age = Integer.parseInt(strAge);
}
- 在struts2中,常见的数据类型struts2已经自动的进行了类型转换,无需程序员进行手动转换。(日期格式)
- 在某些情况下,有自定义的类型时,struts2不能完成自动类型转换,就需要手动转换,如果该自定义类型使用的频率较高时,手动转换重复代码将会增多——使用struts2提供的类型转换器来进行类型转换。
5 补充
5.1 过滤器,拦截器
5.1.1 过滤器
5.1.2 拦截器
5.1.3 拦截器与过滤器的区别
- 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
- 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
- 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
- SpringMVC的机制是由同一个Servlet来分发请求给不同的Controller,其实这一步是在Servlet的service()方法中执行的。
- 拦截器是spring容器的,是spring支持的。
过滤器和拦截器触发时机不一样:
过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
过滤器和拦截器触发时间和地点不一样:
过滤器包裹住servlet,servlet包裹住拦截器,拦截器只能对action请求起作用。
执行顺序:过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。