ModelDriven和Preparable拦截器
- 原理剖析
- Struts2运行机制
[该图片请放大查看]
- 拦截器和拦截器栈
①打个比方:我们去医院体检,需要检查很多个项目,比如:测血压、胸透、做心电图、测身高、测体重、测肺活量等等,经历这一系列的检查后,最终才能拿到体检报告。
这里体检的项目就相当于我们Struts2里面的拦截器,若干个拦截器组织在一起就是一个拦截器栈,最终的体检报告相当于目标Action。
②在Struts2中,默认的拦截器栈是:struts-default.xml中定义的defaultStack,这里只列举了其中一部分
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
……
<interceptor-ref name="params">
……
</interceptor-stack>
- params拦截器
params拦截器有两项功能
①提交表单时将表单域中的值注入到栈顶对象对应的属性中
②目标页面为表单时,将栈顶对象的属性回显到对应的表单域中
- ModelDriven拦截器
getModel()方法是由谁来调用的呢?通过在getModel()方法内设置断点,以Debug模式运行项目发现:
找到ModelDrivenInterceptor.intercept()方法:
总体流程:
- 改进edit()方法
- 问题分析
问题产生的原因是:在getModel()方法中将一个手动创建的空对象提供给ModelDriven拦截器,单调死板。
- 需求:当目标action方法是edit()时,将从数据库中取出的JavaBean压入栈顶,当目标action方法是add()、update()时将一个空的JavaBean压入栈顶
- 解决问题
借助Preparable拦截器,为ModelDriven拦截器“准备”不同action方法所需要的不同JavaBean
- Preparable拦截器使用方法:
①Action类实现com.opensymphony.xwork2.Preparable接口
②为不同的action方法声明专门的prepare方法
③修改StudentAction类代码
[1]prepare方法
[2]getModel()方法
[3]action()方法
- Preparable拦截器工作流程
- 自定义prepare方法的命名格式有什么玄机?
- 深情的呼唤:急需在prepare拦截器之前有一个params拦截器
- paramsPrepareParamsStack 拦截器栈
paramsPrepareParamsStack 从字面上理解来说, 这个stack的拦截器调用的顺序为:首先 params,然后 prepare,接下来 modelDriven,最后再 params
Struts 2.0的设计上要求 modelDriven 在 params 之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在 prepare之前运行params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。
配置方法
在struts.xml文件中,package标签下添加
<default-interceptor-ref name="paramsPrepareParamsStack">
</default-interceptor-ref>
- paramsPrepareParamsStack 拦截器栈工作流程
- 最终的工作流程
- 补充:如何取消prepare()方法的执行
在struts.xml文件中action标签内配置:
<!-- 覆盖prepare 拦截器的alwaysInvokePrepare 参数值为 false -->
<interceptor-ref name="paramsPrepareParamsStack">
<param name="prepare.alwaysInvokePrepare">false</param>
</interceptor-ref>