Struts2与OGNL的联系(结合原理、体现)

1、Struts与OGNL的结合原理

(1)值栈:

 OGNL表达式要想运行就要准备一个OGNLContext对象,Struts2内部含有一个OGNLContext对象,名字叫做值栈。

 值栈也由两部分组成,一部分叫做root,里面放置的是栈,另一部分是context放入的是数据中心。

(2)栈:

 利用了栈先进先出的特点,每次放入元素的时候是放入到索引为零的位置,取出的时候也是取出索引为零的元素,即:从下图的最上方元素取,符合栈的先进先出的特性。

2、<s:debug>标签(查看值栈中的内容)

(1)root(栈)

 默认情况下栈中存放当前访问的Action。

(2)context:

存放以下这些东西:

 即:

 3、Struts2与OGNL结合的体现

(1)Action以属性名的方式获取数据解析:

直接输出属性名,保持和表单的name属性的值相同。

 

 表单将数据提交给拦截器,拦截器获取到“name=zhai”后,交给OGNL处理,OGNL从root中拿到name属性并赋值为“zhai”,由此,Action获取到了表单提交的数据。

(2)对象方式:

表单:

 获取:

  OGNL从栈顶获得user对象后,获得其name属性并将其值设置为“zhai”,由此,Action获取到了表单提交的数据。

(3)模型驱动

 OGNL获取到name=zhai后,在值栈的root中,将user压入栈顶,并给user中的name赋值,也就是说从栈顶取元素并赋值。

 原理演示:

创建一个Action:

public class ActionStack extends ActionSupport implements Preparable {
    User user=new User();
    public String execute(){
        System.out.println(user);
        return "success";
    }

    @Override
    public void prepare() throws Exception {
        ValueStack valueStack=ActionContext.getContext().getValueStack();
        valueStack.push(user);
    }
}

实现Preparable接口的原因:

要在赋值前将user压入栈顶 ,而将获取栈的代码和将user对象压入栈顶的代码写入到prepare()函数中的目的正是获取栈并在赋值前将user对象压入栈顶。

源码分析:

 <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="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
                <interceptor-ref name="deprecation"/>
            </interceptor-stack>

在众多的拦截器中,params拦截器位置相对靠后,因此需要将params拦截器放到prepare拦截器的位置,以实现赋值前将user压入栈顶。

那么如何操作呢?打开prepare拦截器的源码可知要调用prepare拦截器需要实现Preparable接口并调用 prepare()方法。

配置Struts的配置文件、创建表单、User类后将表单数据提交给Action:

<body>
            <form action="${pageContext.request.contextPath}/s/ActionStack">
                       用户名:<input type="text" name="username"/><br>
                       <input type="submit" value="提交"/>
            </form>
 </body>
public class ActionStack extends ActionSupport implements Preparable {
    User user=new User();
    public String execute(){
        System.out.println(user);
        return "success";
    }

    @Override
    public void prepare() throws Exception {
        ValueStack valueStack=ActionContext.getContext().getValueStack();
        valueStack.push(user);
    }
}

 4、在struts.xml配置文件中的使用

(1)创建两个Action:

Action1:

public class Action1 extends ActionSupport {
    private String name;

    public String execute(){
        name="zhang";
        return "success";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Action2:

public class Action2 extends ActionSupport {
    public String execute(){
        return "success";
    }
}

(2)配置Struts.xml配置文件,使得访问Action1的时候能够重定向到Action2,:

<struts>
    <package name="action" namespace="/a" extends="struts-default">
        <action name="Action2" class="pers.zhb.hello.Action2" method="execute">
            <result name="success" type="dispatcher">hello.jsp</result>
        </action>
        <action name="Action1" class="pers.zhb.hello.Action1" method="execute">
            <result name="success" type="redirectAction">
                <param name="actionName">Action2</param>
                <param name="namespace">/a</param>
                <param name="name">${name}</param>
            </result>
        </action>
    </package>
</struts>

(3)访问Action1:

 

 也就是说在配置struts.xml配置文件的时候,在<param>标签内部将name属性的值设置为属性不能识别的值,就可以在重定向的时候将参数加到另外一个Action。

原文地址:https://www.cnblogs.com/zhai1997/p/12274245.html