struts2值栈分析与接收封装参数原理

来源:互联网 发布:知乎mac 编辑:程序博客网 时间:2024/05/24 03:59

一.概述

通过之前的博客,我们大致了解了OGNL的语法格式和Struts接收参数的三种方式。

OGNL语法博客地址(点击打开链接),struts2接受参数三种方式的语法(点击打开链接)。

本文将继续介绍OGNL是怎么运用到Struts2中,用于参数接接收的。

二.一般的OGNL对象结构

我们知道OGNL表达式主要包含两部分:root对象context对象,root对象是OGNL表达式的操作对象,而context对象则代表了root对象

所在的上下文环境。而且root中可以保存任何的对象,而context中则以键值对的方式保存了servlet的十一大内置对象。用图表示如下。


三.struts2中的OGNL结构

struts2在设计之初就借鉴了OGNL语法,并实现了一个很好的OGNL结构。从上,我们知道,OGNL语法要想运行,就必须准备

一个OGNLContext,struts2实现了这样一个OGNLContext,并取名为ValueStack(值栈),与OGNLContextl类似,ValueStack也由两

部分构成,一部分是CompoundRoot,本身是一个底层由list实现的栈内存结构,这个栈里面放置了要访问的action实例。另一部分是

ActionContext,是一个map结构,里面放置了一些参数域对象。struts2对OGNL最重要的改进是Root部分用自定义的

CompoundRoot代替,使用OGNLValueStack的findValue方法可以实现在CompoundRoot中从栈顶到栈底 查找对象的属性值。

以上描述用图表示,大致如下。

四. strut2接收参数的原理解析

阅读此内容必定要先明白struts2接受参数的三种方式:属性驱动,对象驱动,模型驱动。可以参见上文链接。

1.方式一,属性驱动原理解析

我们假设从前端表单页面传来的参数为"name=tom",接着,此带着参数的请求会经过strut2框架中的拦截器群,其中params

拦截器会拦截此参数请求,并把此参数交由OGNL处理,OGNL拿到此参数,就开始从Root中搜索是否有name属性,一旦发现

存在此参数,就把其赋值为tom.至此,struts2属性驱动接受参数模式就完成全部工作。这样就可以清楚的解释,

为什么要把表单的项设置成action的属性才可接受对象。可用下图帮助理解。


方式二,对象驱动原理解析

同属性驱动类似,当表单传来user.name=tom(此种表单参数的写法是OGNL表达式要求的,详情可参见上文链接的

参数获得方法详解),OGNL会从栈顶对象中(当前访问的action)查找user对象(同样,要把user作为action的对象),

然后再把user的name属性赋值为tom.可以看下图帮助理解。


方式三,模型驱动原理解析

1.自定义实现

现在我们知道,前面两种方式接受参数的方式都是OGNL先获取栈顶对象,即是要访问的action实例,在把值赋给此action

实例的属性即可。但我们知道,模型驱动方式接受参数并没有在action添加额外的属性。既然如此,那模型驱动方式是如何

获取到表单参数的呢。一种很好的思路就是:在参数赋值之前,把接受参数的对象压入栈顶即可。基于此思路,我们可以

自己简单实现一个吗,模型驱动接受参数,特别强调,必须在参数赋值之前就要把对象参数压入栈顶。

我们查找struts2的默认核心配置文件可知,在params拦截器之前,先经过了prepare拦截器,在prepare拦截器中会检查action

是否实现了Prepareable接口,若实现了此接口,则调用prepare方式对action进行必要初始化。在此拦截器被调用时把对象

压入栈顶即可。依然用name=tom为例。在action中可以做如下调整。

public class DemoAction extend ActionSupport implements Preparable//需要实现preparable接口{private User user;execute方法....@Overridepublic void prepare()throw Exception{//在此接口的prepare方法中把对象压入栈顶,此时请求还没经过params拦截器,经过此操作后,位于ValueStckValueStack vs=ActionContext.getContext.getValueStack;vs.push(user);
}

在action中,实现Preparable接口,并在prepare方法中把接受参数的对象压入栈顶就可实现模型驱动方式接受参数。

2.一般方式

值得注意的是strut2实现模型属性驱动的方式与上述自定义的思路基本一致,即在赋值之前把对象压入栈顶。不过struts2在

modelDriven拦截器中实现这种操作,而modelDriven拦截器仍然在params拦截器之前。modelDriven拦截器相关代码如下。

从此代码中看出,大概流程如下,先判断出action实现了ModelDriven->获取值栈->调用getModel方法获取model->把model

压到栈顶。这就清楚解释了模型驱动为什么要求action实现ModelDriven接口,并在getModel方法中返回获取参数的对象。

五.总结

此博客详细记录了struts2三种接受参数写法的原因。通过了解此原理,可以得记忆struts2获取参数的几种方式的写法。



原创粉丝点击