Struts2会把请求参数给栈顶对象的属性。
文章目录
该流程以Employee的增删改查为例进行整个流程的讲解。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/58f12f04f5ca800101581c90bc0781f8.png)
显示和删除员工信息列表流程
定义两个jsp页面
index.jsp
:用于发送显示员工信息的请求。
删除某个员工的请求:
emp-list.jsp
:用于显示员工信息的页面。
Struts.xml
Employee.java
实体类,用于定义员工的相关信息。
EmployeeAction.java
Dao.java
进行增删改查操作。
运行流程
从发请求到调用action方法的流程:
在到达目标action方法之前,Struts2会经过一系列的拦截器。
Params拦截器
Parameters
拦截器将把表单字段映射到ValueStack栈的栈顶对象的各个属性中,如果某个字段在模型里没有匹配的属性,那么该拦截器将尝试ValueStack栈中的下一个对象,默认情况下,栈顶对象为当前的Action,于是请求参数就是给Action的字段。
ModelDriven拦截器
当删除指定Id的员工或者是向列表中添加一个员工信息时,使用的属性都是在当前EmployeeAction中定义相关属性,以接受请求参数,当属性比较多时就很复杂,然后就可以采用直接将请求参数赋值给一个Employee对象的方式,这个时候就需要ModelDriven拦截器了。
该拦截器实现将Action和Model隔开。
实现方式
在EmployeeAction
中实现ModelDriven
接口并重写getModel()
方法。
Action实现ModelDriven接口后的运行流程:
-
先会执行
ModelDrivenInterceptor
的intercept
方法
-
执行
ParametersInterceptor
的intercept
方法:把请求参数的值赋给栈顶对象对应的属性。若栈顶对象没有对应的属性,则查询值栈中下一个对象对应的属性。 -
注意: getModel 方法不能提供以下实现:
public Employee getModel() {
return new Employee();
}
这样做的确会返回一个 Employee 对象到值栈的栈顶, 但当前 Action 的 employee 成员变量却是 null。
edit修改方法流程总结
该方法将在页面上显示表单,在表单中回显员工的详细信息。
1. 发送请求
2. 核心处理
回显问题:只要在值栈的栈顶有一个对应的对象,对象的属性与表单的属性一一对应的话,就会自动的赋上。
方式一:可行
方式二:不可行
方式三:可行,但有缺陷
方式四:最终版(可行)
此时的edit()函数中只有一行代码:
使用 paramsPrepareParamsStack 拦截器栈后的运行流程
paramsPrepareParamsStack
和defaultStack
一样都是拦截器栈.,而struts-default
包默认使用的是defaultStack
。- 可以在 Struts 配置文件中通过以下方式修改使用的默认的拦截器栈
<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
paramsPrepareParamsStack
拦截器的流程:
params -> modelDriven -> params
先把请求参数赋给 Action 对应的属性, 再根据赋给 Action 的那个属性值决定压到值栈栈顶的对象, 最后再为栈顶对象的属性赋值。
对于 edit 操作而言:
I. 先为 EmployeeAction 的 employeeId 赋值
II. 根据 employeeId 从数据库中加载对应的对象, 并放入到值栈的栈顶
III. 再为栈顶对象的 employeeId 赋值(实际上此时 employeeId 属性值已经存在)
IV. 把栈顶对象的属性回显在表单中.
- 关于回显: Struts2 表单标签会从值栈中获取对应的属性值进行回显
- 存在的问题:
(1)在执行删除的时候, employeeId 不为 null, 但 getModel 方法却从数据库加载了一个对象. 不该加载!
(2)指向查询全部信息时, 也 new Employee() 对象. 浪费! - 解决方案: 使用
PrepareInterceptor
和Preparable
接口
PrepareInterceptor
Preparable
接口中的prepare()
方法主要作用是:为getModel()
方法准备model.
Struts2.0中的modelDriven拦截器负责把Action类以外的一个对象压入到值栈栈顶。
而prepare拦截器负责准备为getModel()方法准备model
源代码解析:
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes)
方法:
PrefixMethodInvocationUtil.getPrefixedMethod
方法:
总结:
-
PrepareInterceptor将调用
prepare()
方法,prepare[ActionMethodName]
方法或prepareDo[ActionMethodName]
方法。 -
PrepareInterceptor根据
firstCallPrepareDo
属性决定获取prepare[ActionMethodName]、prepareDo[ActionMethodName]
的顺序。默认情况下先获取prepare[ActionMethodName]
方法,如果没有该方法,就寻找prepareDo[ActionMethodName]
方法,如果找到对应的方法就调用该方法。若都不存在, 就都不执行。 -
PrepareInterceptor会根据
alwaysInvokePrepare
属性决定是否执行prepare()
方法。 -
可以为每一个 ActionMethod 准备
prepare[ActionMethdName]
方法, 而抛弃掉原来的prepare()
方法。 -
将PrepareInterceptor的
alwaysInvokePrepare
属性置为 false, 以避免 Struts2 框架再调用prepare()
方法。
具体实现:
paramsPrepareParamsStack拦截器栈
这个栈的拦截器调用顺序为:
params->prepare->modelDriven->params
Struts2.0的设计上要求modelDriven在params之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在prepare之前运行params拦截器设置相关参数。
流程如下: