struts2 知识点总结2
- servlet和action的区别
- servlet在第一次访问时被创建,并创建一次(单例)
- action也是在访问时创建,但会创建多次(每次都是一个新的action实例)
- 在action中保存数据的值栈对象也会随之而产生多个
- OGNL概述(Object-Graph Navigation Language)
- OGNL的特点
- 表达式语言,比EL表达式更为强大
- 是独立的体系,不属于struts2
- 存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能
- 配合struts2的标签操作值栈数据(大有取代el的用意)
- 只能在jsp页面中使用
-
- OGNL的使用
- 导入jar包(struts2中已经存在)
- 引入struts2标签库
- 调用字符串的方法:
- 值栈(valueStack)
- 概念
struts2中本身提供的一种数据操作的机制,类似之前servlet的域对象(域对象依然可以使用),它并不是用来替换域对象的,值栈可以和域操作同时存在互不影响(其实,值栈和域对象是有一定联系的),给我们操作数据提供了一种更适合sturts2的选择而已
-
- 存储方式
值栈在每一个Action中都独立存在一份值栈对象
-
- 获取值栈对象
- 通过ActionContext,调用getValueStack() 方法
- 通过ServletActionContext,调用getValueStack(request)方法
两种方法返回的对象是相同的
每个action中存在多少个值栈对象?如何验证
栈的结构(栈顶、栈底,push)
先入后出(FILO)
栈的典型应用:汉诺塔
拓展阅读: “在java中栈的操作实现”,通过数组方式,列表的实现方式,map的实现方式
-
- 值栈的内部结构
root(list) 和 context(map)
context中的结构:
root的结构(一般都是操作root):
-
- s:debug 标签
通过s:debug标签调试程序(上线的程序不能使用),查看值栈中的数据情况
在struts中添加常量(开启调试模式,老版本不需要):
<constant name="struts.devMode" value="true" />
在jsp页面中添加debug标签
打开页面后:
点击链接:
值栈中存在Action的引用(通过root既能观察到,目的是方便取值)
-
- 向值栈中存放数据
三种方式
- 通过值栈对象调用set方式(以map的方式添加)
- 通过值栈对象调用push方式
- 在action中声明变量,定义变量的get方法(主要)
通过观察上述三种方式,数据存放的形式和位置,分析优劣
- 存放字符串
- 向值栈中存放对象
- 向值栈中存放集合
声明时可以不赋初值,但返回之前一定要赋值
-
- 从值栈中获取数据
思路: 利用s:property标签,value中指定字符串/对象/集合的名称
- 从值栈中获取字符串
- 从值栈中获取对象
- 向从值栈中获取集合
获取集合操作中,使用下标方式
还可以利用s:iterator 执行遍历集合的操作
或者
或者使用#号(原因是,list中的数据在struts2被优化后,存放在了context中,#就是用来标识这种特殊位置的)
- 获取值域对象通过set方法生成的值
思路:set方法生成的是Map,所以直接通过key获取value
- 获取值域对象通过push方法生成的值
思路:值栈中会把存入的数据放在一个叫做top的数组中,再根据入栈的顺序,采用下标的方式来获取,但,此处有一个特殊的语法: [0].top
使用jstl标签结合el表达式,也可以获取值栈传递的数据
原因是struts2在过滤器中,对于request进行了增强操作:判断request域对象中是否有目标值,如果有则获取该值,如果没有,则判断值域中是否有,有则传递给域对象
简单来说就是,request通过增强,获取了值域中的数据,从而让el表达式能够获取
-
- ognl中 # 和 %的使用:
- #用于获取值栈中context里的数据
如果想要访问reqeust作用域中的数据,可以选择采用ognl表达式
格式: #对象
例如:context中就存放了request对象,通过ognl获取request中的数据:
- %用于在ognl标签中使用表单标签时,识别数据的方法(非重点)
格式: %{ name} %{#request.request}
- 关于拦截器:(复刻)
- 概念:动态拦截Action的对象,提供了一种机制,使得开发者在定义的action执行前后加执行的代码;封装大量的功能的组件;也可以在一个action执行前组织其执行,也就是说它提供了一种可以提取action中的重复代码,统一管理和执行的方式
- 大量的拦截器完成不同的功能
- 拦截器链,即拦截器栈(Interceptor chain->Interceptor Stack),将拦截器按一定顺序链接成一条链,当访问到被拦截的方法或字段时,拦截器栈中的拦截器就会按顺序执行其中定义的拦截器
- 和过滤器的区别:
- 过滤器是servlet中你的规范,任何web项目都可以使用
- 拦截器是struts2框架中的模块
- 过滤器可以过滤任何内容,拦截器只能拦截目标action
- 通常情况下,struts2中会执行一组默认的拦截器
- 拦截器的位置:
=>
=>
拦截器的加载机制: 在Action对象创建之后,方法执行之前执行拦截器操作
- 拦截器底层原理
- AOP思想(面向切面编程,约定大于配置,spring的重点)
在不修改源码的基础上对已有的方法进行动态增强
在struts2中,拦截器就是对Action进行增强(将复刻代码提出来,放在拦截器中统一管理和执行)
- 责任链模式(动态代理)
在action方法执行之前执行默认拦截器,执行过程使用AOP思想(action没有直接调用拦截器的方法,而是使用配置文件方式进行操作)
在执行多个默认的拦截器的时候,使用责任链模式(拦截器1执行完毕之后->放行->执行拦截器2->拦截器2执行完毕后放行->执行拦截器3->拦截器3执行完毕放行->action)
- 拦截器时序图
- 自定义拦截器
- 目的:通过自定义拦截器,补充系统默认拦截器中不具备的功能
- 常用方法:
- 实现Interceptor接口,
- 继承AbstractInterceptor
- 继承MethodFilterInterceptor
- 拦截器结构概述,
以MethodFilterInterceptor为例
它不仅继承了AbstractInterceptor,还可以指定不拦截的方法
其中的核心为doIntercept(ActionInvocation actionInvocation)
放行即通过actionInvocation对象执行invoke方法(注意,该方法并不是反射)
当不放行而要拦截并引导到方法的返回值name即可(拦截器最终会回到action,返回name即在通知action执行方法的哪一个)
拦截器放行之后的情况
拦截器返回为null的情况
- 在action中配置拦截器
在被拦截的action所在package标签中声明拦截器(interceptors/interceptor标签)
在action中使用声明的拦截器(interceptor-ref标签)
- 拦截器的返回值
拦截器返回的是action执行的方法的返回值,那么,如果拦截器同时存在放行和return呢?
jsp页面在拦截器执行完毕后才会显示,所以,执行到放行的时候,jsp的内容是暂存在缓冲区的,不管最后return的是什么,都显示的是缓冲区的内容
- 添加其他默认拦截器
注意,package中如果有其它标签,interceptors必须在最前
自定义拦截器会让默认拦截器失效,手动添加一次,引用defaultStack即可),根据实际情况,如果不需要使用默认中的功能,则不需配置
- 设置拦截器栈:
指定interceptor-stack
指定 default-interceptor-ref
action 改为引用拦截器栈
- 不拦截某个action
拦截器会对action中所有方法都进行拦截,需要对指定的方法不进行拦截(在interceptor-ref中进行配置),使用param标签并配置不拦截的方法名称(不是name名称),多个不拦截的方法可以用,隔开
- 多个拦截器执行(拦截器链,“层层保安”的机制,执行顺序由引用顺序决定,与声明顺序无关)
- 多个Action使用相同的拦截器
- 拦截器之间的关系
- 使用注解配置拦截器
- 要想使用注解,就必须使用jar包: struts2-convention-plugin-2.5.18.jar