Struts2 的ModelDriven 二——ModelDrive

来源:互联网 发布:天津大悦城it电话 编辑:程序博客网 时间:2024/06/02 05:52

继上篇博客介绍了值传递的几种形式,这篇博客,来说说struts2是如何实现的?
有这么两个概念和modelDriven实现有关:ValueStack,ModelDrivenInterceptor。

一、ModelDrivenInterceptor

首先先介绍以下ModelDrivenInterceptor,该拦截器处于defaultStack第九的位置。ModelDrivenInterceptor拦截器主要做的事就是调用Action的getModel()方法然后把返回的model压入值栈。
下面是该拦截器intercept方法源码:

public class ModelDrivenInterceptor extends AbstractInterceptor {    protected boolean refreshModelBeforeResult = false;    public void setRefreshModelBeforeResult(boolean val) {        this.refreshModelBeforeResult = val;    }     @Override    public String intercept(ActionInvocation invocation) throws Exception {        Object action = invocation.getAction();        if (action instanceof ModelDriven) {            ModelDriven modelDriven = (ModelDriven) action;            ValueStack stack = invocation.getStack();            Object model = modelDriven.getModel();            if (model !=  null) {              stack.push(model);            }            if (refreshModelBeforeResult) {                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));            }        }        return invocation.invoke();    }

此方法就是就是把getModel方法返回的结果压入值栈而已,我们一般实现这个接口是利用压入值栈的model对象接收从页面提交过来的数据,因为Action也是在值栈中,而struts2在赋值参数的时候是在值栈从栈顶往栈底寻找有相应setter方法的对象,而这时model压入了值栈,它是处于栈顶的,所以从页面提交过来的参数也就被model对象接收了。

二、ValueStack

这个ValueStack和 struts的ognl是分不开的。(valueStack是接口,ognl实现了该接口)
ValueStack实际上就是对OGNL的封装,OGNL主要的功能就是赋值与取值,Struts2正是通过ValueStack来进行赋值与取值的!

ValueStack是一个接口,而OgnlValueStack是strtus2中的缺省实现。ValueStack中的数据,分两个部分存放:root和context(这与OGNL中的概念一致),同时ValueStack暴露相关的接口:

void setValue(String expr, Object value);

Object findValue(String expr);

用来通过OGNL表达式对ValueStack中的数据进行操作!

ValueStack中的root对象是CompoundRoot,CompoundRoot继承了ArraryList,提供了额外的方法:push()和pop()方法,用来对root对象中所包含的数据进行存取!

public class CompoundRoot extends ArrayList {     public CompoundRoot() {    }    public CompoundRoot(List list) {        super(list);    }    public CompoundRoot cutStack(int index) {        return new CompoundRoot(subList(index, size()));    }    public Object peek() {        return get(0);    }    public Object pop() {        return remove(0);    }    public void push(Object o) {        add(0, o);    }}

正是通过这两个方法,CompoundRoot变成了一个栈结构!压栈操作,将导致对象被放到CompoundRoot的第0个元素上(第0个元素 是栈顶),其它对象被依次往后移动;出栈操作,将导致CompoundRoot的第0个元素被移除(即栈顶元素被弹出),其它对象被依次往前移动!

OGNL不支持多个root对象,而struts2能够支持多个root对象,它对OGNL做了扩展。

如果某个OGNL表达式被传递给ValueStack(即调用ValueStack的setValue或findValue方法),而表达式中包含 有对root对象的访问操作,ValueStack将依次从栈顶往栈底搜索CompoundRoot对象中所包含的对象,看哪个对象具有相应的属性,找到 之后,立刻返回。

三、存与 取 的实现

这里的存是:客户端请求中的参数如何被 “存” 进 ValueStack,例如:添加操作;而 “取” 是指服务器查询数据,如何回显到前台页面,例如 更新操作。
接下来,我们看 存 的实现,其实就是博客开篇提到的,三种方法,一个原则:前台 控件的name必须是和实体属性名称是一致的。这里不再赘述。
主要是看 “取” 的实现。
服务器端,我们需要手动将model 压入 ValueStack:ActionContext.getContext().getValueStack().push(××);

 public class UserAction     {    //查看用户的详细信息    public String detail()    {       User u = new User();       u.setUsername("wyx");       ActionContext.getContext().getValueStack().push(u);       return "update";        }}

在JSP中: 对应的JSP使用 struts2标签 + ognl 来取。

username:<input type="text" name="username" value="<s:property value="username"/>"> <br/>

或者:

<s:textfield name="username"/>

总结

所以struts2的modelDriven机制:
1、客户端请求:当一个请求过来,首先被modelDriveInterceptor拦截,执行getModel方法,压入valueStack,ValueStack 将请求的值和压入的model进行对比赋值;
2、服务端回发:我们需要把model push进ValueStack。前台使用 struts2标签 + ognl来接受,解析。

0 0
原创粉丝点击