Struts2之OGNL与ValueStack

 

时间:2017-1-12 12:02

 

——OGNL

1、OGNL表达式是什么
    OGNL的全称是Object-Graph Navigation Language的缩写,中文名是对象图导航语言,它是一种功能强大的表达式语言。
    比EL表达式功能强大。

    Struts2将OGNL表达式语言集成到Struts2框架中,作为它的默认表达式语言。

2、OGNL表达式的功能
    1)支持对象方法调用,如:xxx.doSomeMethod()
    2)支持类静态的方法调用和值访问。
    3)访问OGNL上下文(OGNL Context)和ActionContext:(重点,操作ValueStack)
    4)支持赋值操作和表达式串联。
    5)操作集合对象。

3、OGNL中“根”与“非根”的区别

    root:只能有一个根,用于存储Action相关数据
    contextMap:用于存储Web相关数据

4、示例代码

在Java代码中使用ognl表达式。

根中数据不需要使用#获取。
非根中数据需要使用#获取。
OGNL叫做对象图导航语言。


Person.java

public class Person {
    private String name;
    private Dog dog;
 
    public Dog getDog() {
        return dog;
    }
 
    public void setDog(Dog dog) {
        this.dog = dog;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
 
----------------------------------------------------------------------------------------------------------------------------

Dog.java

public class Dog {
    private String name;
    private Person p;
 
    public Person getP() {
        return p;
    }
 
    public void setP(Person p) {
        this.p = p;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}

----------------------------------------------------------------------------------------------------------------------------

OgnlDemo1.java

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
 
public class OgnlDemo1 {
    public static void main(String[] args) throws OgnlException{
        // ognl可以通过对象调用方法
        System.out.println("aaa".length());
 
        /*
         * 使用ognl来实现上面操作
         * 1、创建一个ognl上下文对象
         * 2、调用getValue()方法
         */
        OgnlContext context = new OgnlContext();
        Object o1 = Ognl.getValue("'aaa'.length()", context.getRoot());
        System.out.println(o1);
 
 
        // 调用Math的静态方法和静态成员
        System.out.println(Math.max(10, 20));
        System.out.println(Math.PI);
 
        /*
         * 在ognl表达式中调用静态方法
         */
        Object o2 = Ognl.getValue("@java.lang.Math@max(10, 20)", context.getRoot());
        System.out.println(o2);
        Object o3 = Ognl.getValue("@java.lang.Math@PI", context.getRoot());
        System.out.println(o3);
    }
}
 
----------------------------------------------------------------------------------------------------------------------------

OgnlDemo2.java

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
 
public class OgnlDemo2 {
    public static void main(String[] args) throws OgnlException {
        /*
         * 创建一个ognl上下文 OgnlContext是一个Map集合 
         * public class ognl.OnglContext implements java.util.Map
         */
        OgnlContext context = new OgnlContext();
 
        Person p = new Person();
        p.setName("张三");
        Dog dog = new Dog();
        dog.setName("王五");
        p.setDog(dog);
 
        // 设置根
        context.setRoot(p);
 
        Dog d = new Dog();
        d.setName("李四");
        Person p2 = new Person();
        p2.setName("赵六");
        d.setP(p2);
 
        // 设置属性(非根)
        context.put("dog", d);
 
        // 使用ognl来获取根中数据
        // 获取根中数据,不需要加#
        Object o1 = Ognl.getValue("name", context, context.getRoot());
 
        System.out.println(o1);
 
        // 使用ognl来获取非根中的数据
        // 获取非根中数据,需要使用#
        Object o2 = Ognl.getValue("#dog.name", context, context.getRoot());
        System.out.println(o2);
 
        // 获取p中的dog对象
        // p表示根,所以可以省略p
        Object o3 = Ognl.getValue("dog.name", context, context.getRoot());
        System.out.println(o3);
 
        // 获取dog中的person
        Object o4 = Ognl.getValue("#dog.p.name", context, context.getRoot());
        System.out.println(o4);
    }
}
 
——在Struts2中使用ognl表达式

需要结合Struts2的标签使用:<s:property value="" />
    *   value:
        书写ognl表达式
    *   default:
        默认值
    *   escapeHtml
        是否解析HTML
    *   escapeJavaScript
        是否解析JS
    *   escapeXml
        是否解析XML

注意:在Struts的JSP页面中访问静态成员时,必须设置一个常量值:
    struts.ognl.allowStaticMethodAccess=false

示例代码:
  <h1>使用ognl通过对象来调用方法</h1>
  <s:property value="'aaa'.length()"/>
  <hr />
  <!-- 在Struts2中使用静态成员,必须设置一个常量 -->
  <s:property value="@java.lang.Math@max(10,20)"/>


 

——ValueStack

1、ValueStack是什么
    从技术角度来讲,ValueStack是一个接口(com.opensymphony.xwork2.util.ValueStack)。
    从实用角度来讲,ValueStack是一个容器,用于将数据携带到action数据页面,然后在页面通过ognl表达式来获取。

    ValueStack是Struts2提供的一个接口,实现类是OgnlValueStack。

    OGNL表达式是从ValueStack中获取数据的。

    每个Action实例都有一个ValueStack对象(一个请求对应一个ValueStack对象)
    ValueStack中保存当前Action对象和其他常用Web对象,例如request, session, application, parameters(值栈中是有Action引用的)
    Struts2框架把ValueStack对象保存在key为“struts.valueStack”的request域中(request中值栈对象是request的一个属性)

    一个request一个Action,一个Action一个ValueStack,request - Action - ValueStack是一一对应的。
    ValueStack生命周期就是一个request的生命周期。

    流程(源码分析):
        从第一个请求开始,被StrutsPrepareAndExecuteFilter拦截后执行doFilter()中的execute.executeAction(request, response, mapping);方法,然后一直调用,进入到Dispatcher中的serviceAction()方法,在该方法中通过request获取ValueStack对象:ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);如果是第一次获取,则ValueStack对象为null,然后创建一个新的ValueStack,因为每次请求都是一个新的请求,所以每次请求都会创建一个新的ValueStack。当请求结束后,ValueStack就被释放了,所以ValueStack的生命周期等同于request的生命周期。

        然后通过Dispatcher类中的serviceAction()方法中的:request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());来获取一个新的ValueStack对象,并保存到request域中,保存的key为:ServletActionContext.STRUTS_VALUESTACK_KEY,在ServletActionContext中可以查看,该常量的值为:struts.valueStack。

2、ValueStack的内部结构
    查看ValueStack接口,可以看到两个方法:
        *   public abstract Map<String, Object> getContext();
        *   public abstract CompoundRoot getRoot();
            >   public class CompoundRoot extends ArrayList
            >   CompoundRoot类继承了ArrayList,提供了peek() pop() push()方法,相当于栈。

    ValueStack接口中声明了root属性(CompoundRoot)、context属性(OgnlContext):
        *   CompoundRoot就是ArrayList。
        *   OgnlContext就是Map

    值栈由两部分组成:
        ObjcetStack:Struts2把Action和相关对象压入ObjectStack中,用一个List保存
            保存Action相关信息。
 
        ContextMap:Struts2把各种各样的映射关系(一些Map类型的对象)压入ContextMap中。
            比较常见的映射关系就是常见Web对象。

    Struts2会把下面这些映射压入ContextMap中:
        *   parameters:该Map中包含当前请求的请求参数
        *   request:该Map中包含当前request对象的所有属性
        *   session:该Map中包含当前session对象的所有属性
        *   application:该Map中包含当前application对象的所有属性。
        *   attr:该Map按如下顺序来检索某个属性:request、session、application,相当于全域查找
        *   对象引用
    通过断点可以发现:
        图片

    其中root在ContextMap中也有一个映射关系:
        ValueStack中包含ContextMap和Root,而在ContextMap中又持有了Root的引用。
    可以在断点调试中发现:
        图片

    OGNL表达式访问root(List)中数据时,不需要使用#访问。

    访问(Map)request、session、application、attr、parameters、对象引用时,必须写#。

    操作ValueStack时,默认是指操作root元素。

    其实ContextMap就是一个OgnlContext,可以查看ValutStack接口的实现类:OgnlValueStack
        protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticMethodAccess) {
        this.root = compoundRoot;
        this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
        this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);
        context.put(VALUE_STACK, this);
        Ognl.setClassResolver(context, accessor);
        ((OgnlContext) context).setTraceEvaluations(false);
        ((OgnlContext) context).setKeepLastEvaluation(false);
    }

    结论:
        ValueStack有两个部分,一个是List,一个是Map。
        在Struts2中List就是Root,Map就是OgnlContext。
        在Struts2中,默认情况下(不加#)从ValueStack中的Root获取数据。

3、ValueStack对象的创建,ValueStack和ActionContext是什么关系?
    当请求发出时,会被doFilter()拦截然后调用Dispatcher类中的serviceAction()方法,方法中可以创建ValueStack对象:
        // 刚开始会到request域中获取
        ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
        // 如果获取不到ValueStack对象
        boolean nullStack = stack == null;
        if (nullStack) {
            // 会到ActionContext中获取 
            ActionContext ctx = ActionContext.getContext();
            if (ctx != null) {
                stack = ctx.getValueStack();
            }
        }

    ValueStack和ActionContext的关系:
        ActionContext中持有了ValueStack的引用。

4、如何获取ValueStack对象
    有两种方式可以获取ValueStack对象:
        1)通过request获取
        2)通过ActionContext获取
    public class OgnlDemo1Action extends ActionSupport {
 
        @Override
        public String execute() throws Exception {
 
            /*
             * 获取ValueStack
             */
            // 1、通过request获取
            ValueStack stack1 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
 
            System.out.println(stack1);
 
            // 2、通过ActionContext获取(推荐)
            ValueStack stack2 = ActionContext.getContext().getValueStack();
            System.out.println(stack2);
            return null;
        }
}

5、向ValueStack中保存数据(主要针对root)
    在ValueStack接口中有两个方法:
    有两种方式:
        *   push(Object obj)
        *   set(String key, Object obj)

    1)push(Object obj)
        在ValueStack接口的实现类OgnlValueStack中,重写了此方法:
            public void push(Object obj) {
                root.push(obj);
            }
        底层调用的是:root.add(0, obj);
        所以push方法会将对象压入栈顶。
        如果当前位置存在元素,那么当前元素会先后移,然后再在栈顶压入元素。

    2)set(String key, Object obj)
        在ValueStack接口的实现类OgnlValueStack中,重写了此方法:
            public void set(String key, Object o) {
                Map setMap = retrieveSetMap();
                setMap.put(key, o);
            }
 
            private Map retrieveSetMap() {
                Map setMap;
                Object topObj = peek();
                if (shouldUseOldMap(topObj)) {
                    setMap = (Map) topObj;
                } else {
                    setMap = new HashMap();
                    // 将数据封装到一个新的HashMap中 
                    setMap.put(MAP_IDENTIFIER_KEY, "");
                    // 将Map集合压入栈顶
                    push(setMap);
                }
                return setMap;
            }
        底层是将数据封装到HashMap中,再将这个HashMap压入栈顶,保存到List集合中。 

    示例代码:

        public String execute() throws Exception {
 
            ValueStack stack = ActionContext.getContext().getValueStack();
            stack.push("1");
            stack.push("2");
            stack.push("3");

            stack.set("username", "张三"); 
 
            List list = stack.getRoot();
            System.out.println(list);
 
            return null;
        }
    输出结果:
        [3, 2, 1, com.wyc.action.OgnlDemo2Action@320859ec, com.opensymphony.xwork2.DefaultTextProvider@5c1958e7]

6、在JSP页面中使用<s:debug />标签查看ValueStack中的数据
    <body>
        <h1>使用debug标签查看ValueStack数据</h1>
        <!-- 通过debug标签查看ValueStack中存储的数据 -->
        <s:debug />
    </body>
    图片

7、在JSP页面中获取ValueStack数据
    获取Root中数据不需要#
    获取ContextMap中数据需要#

获取Root中的数据:

    1)如果栈顶是一个Map集合,那么获取时可以直接通过Map集合的key来获取value。
        <s:property value="username"/>

        如果只写属性名,那么即使栈顶不是Map集合,也会从栈顶开始依次往下查找。

    2)如果栈顶元素不是Map,不能通过key来获取,可以使用下标来获取元素:
        <s:property value="[0] />
            从0位置开始向下查找所有数据。

        <s:property value="[0].top" />
            只查找0位置上的数据。

    JSP页面示例代码:
        1、获取栈顶的Map
        <br />
        <s:property value="username" />
        <hr />
        2、获取栈顶非Map集合数据
        <br />
        <!-- 如果只写[0],表示从0位置开始检索元素 -->
        <s:property value="[0]" />
        <hr />
        <!-- [0].top表示获取栈的顶部元素 -->
        <s:property value="[0].top" />
        <hr />
        <!-- 如果只写[1],表示从1位置开始检索全部元素 -->
        <s:property value="[1]" />
        <hr />
        <!-- [1].top表示获取栈的第二个位置的元素 -->
        <s:property value="[1].top" />
        <hr />

获取OgnlContext中的数据:

    1)request数据
        request.setAttribute()
    2)session数据
        session.setAttribute()
    3)application数据
        application.setAttribute()
    4)attr
        依次从request, session, application域中查找。
        相当于pageContext的全域查找。
    5)parameters数据
        获取请求参数。

    JSP页面代码:
        3、获取OgnlContext中的数据
        <%
            request.setAttribute("rname", "rvalue");
            session.setAttribute("sname", "svalue");
            application.setAttribute("aname", "avalue");
        %>
 
        <s:property value="#request.rname"/><br />
        <s:property value="#session.sname"/><br />
        <s:property value="#application.aname"/><br />
        <s:property value="#attr.sname"/><br />
        <!-- 获取到的是参数的Map集合 -->
        <s:property value="#parameters"/><br />
        <!-- 获取指定参数 -->
        <!-- 当存在checkbox这种一键多值的情况时,#parameters.username会打印一个数组 -->
        <s:property value="#parameters.username"/><br />
        <!-- 获取数组中的第一个元素 -->
        <s:property value="#parameters.username[0]" />

8、ValueStack有什么作用
    使用ValueStack最大的作用就是将Action相关的数据以及Web相关的对象,传递到页面上。
    简单来讲,在Struts2中通过ValueStack将Action中的数据携带到页面上进行展示。

    1)Action向JSP携带的数据都是什么类型的数据?

    *   普通文本(字符串)

            >   fieldError:校验数据错误信息提示(常用于表单校验),this.addFieldError("msg", "字段错误信息")
            >   actionError:关于逻辑操作时的错误信息(普通错误信息,例如登录失败),this.addActionError("Action全局错误信息")
            >   message:通用信息,this.addActionMessage("Action普通消息信息")

            在JSP中使用Struts2标签显示错误信息:
                *   <s: fielderror fieldName="msg" />
                *   <s:actionerror />
                *   <s:actionmessage />


    *   复杂数据

            可以使用ValueStack存储:

            Action中存储数据:
                public String execute() throws Exception {
 
                    ValueStack stack = ActionContext.getContext().getValueStack();
 
                    List<User> users = new ArrayList<User>();
 
                    users.add(new User("zhangsan", "111", 20, "男"));
                    users.add(new User("lisi", "222", 30, "女"));
                    users.add(new User("wangwu", "333", 40, "男"));
 
                    // stack.push(users);
 
                    stack.set("users", users);
 
                    return SUCCESS;
                }


            JSP中获取数据:
                <body>
                    <h1>使用ognl表达式来获取ValueStack中复杂数据</h1>
                    1、使用push()存储时获取数据(保存到OgnlContext中,是一个Map集合)
                    <s:property value="[0].top" />
                    <hr />
                    <s:iterator value="[0].top" var="user">
                        username:<s:property value="#user.username" /><br/>
                        password:<s:property value="#user.password" /><br/>
                        sex:<s:property value="#user.sex" /><br/>
                        age:<s:property value="#user.age" /><hr/>
                    </s:iterator>
 
                    <!-- 如果不为当前元素起别名,则默认使用当前元素 -->
                    <!-- 可以不写user,因为ContextMap中是有“user”的 -->
                    <s:iterator value="[0].top">
                        username:<s:property value="username" /><br/>
                        password:<s:property value="password" /><br/>
                        sex:<s:property value="sex" /><br/>
                        age:<s:property value="age" /><hr/>
                    </s:iterator>
 
                    <hr />
                    2、使用set存储数据(保存到List集合中)
                    <s:property value="users"/>
                    <hr />
                    <s:iterator value="users" var="user">
                        username:<s:property value="#user.username" /><br/>
                        password:<s:property value="#user.password" /><br/>
                        sex:<s:property value="#user.sex" /><br/>
                        age:<s:property value="#user.age" /><hr/>
                    </s:iterator>
                </body>

9、关于默认压入到ValueStack中的数据分析
    当前的Action会被默认压入ValueStack

    1)属性驱动
        每次请求访问Action对象,Action对象都会被压入ValueStack,在DefaultActioninvocation的init()方法中:
            stack.push(action);

        DefaultActioninvocation源码:
            public void init(ActionProxy proxy) {
                this.proxy = proxy;
                Map<String, Object> contextMap = createContextMap();
 
                // Setting this so that other classes, like object factories, can use the ActionProxy and other
                // contextual information to operate
                ActionContext actionContext = ActionContext.getContext();
 
                if (actionContext != null) {
                    actionContext.setActionInvocation(this);
                }
 
                createAction(contextMap);
 
                if (pushAction) {
                    stack.push(action);
                    contextMap.put("action", action);
                }
                ......
            } 

        在拦截器被调用之前就压入ValueStack了。

        作用:
            当Action被压入ValueStack之后,Action如果向传递数据给JSP,只要将数据保存为成员变量,并且提供get()方法就可以了。

        当Action中声明了一个getXxx()方法后,ValueStack会将get之后的JavaBean的名称放到ValueStack的key中,然后在页面中可以直接使用JavaBean对象的key值来获取value值。

        图片

        示例代码:
            public class OgnlDemo4Action extends ActionSupport {
                private List<User> users;
 
                public List<User> getUsers() {
                    return users;
                }
                public void setUsers(List<User> users) {
                    this.users = users;
                }
                @Override
                public String execute() throws Exception {
 
                    ValueStack stack = ActionContext.getContext().getValueStack();
 
                    users = new ArrayList<User>();
 
                    users.add(new User("zhangsan", "111", 20, "男"));
                    users.add(new User("lisi", "222", 30, "女"));
                    users.add(new User("wangwu", "333", 40, "男"));
 
                    return SUCCESS;
                }
            }

        JSP代码:
            <s:iterator value="users" var="user">
                <s:property value="#user.username"/>
            </s:iterator>

    2)模型驱动
        ModelDriven接口有一个单独的拦截器
            <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor" />
        在拦截器中,将Model对象压入了ValueStack:stack.push(model);
        如果Action实现了ModelDriven接口,ValueStack默认栈顶对象就是Model对象。
        因为Action对象在拦截器执行前就已经压入,而Model对象在ModelDrivenInterceptor拦截器执行时才会压入。

        ModelDrivenInterceptor源码:
             public String intercept(ActionInvocation invocation) throws Exception {
                Object action = invocation.getAction();

                // 将实现了ModelDriven接口的Action中的getModel()方法的返回值也就是内部封装的JavaBean对象压入到了ValueStack
                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();
            }

    在同一个请求中,Action中声明的private User user = new User();和getModel()方法中返回的User是相同的,也就是说在JSP页面中通过ValueStack获取到的User对象是同一个对象。但是,如果在execute()方法中对user重新赋值,那么push到ValueStack中的Action所包含的User就是后赋值的user对象,因为这个User对象是通过getXxx()方法获得的。而Model依然是private User user = new User();对象,因为Model是在execute()方法执行之前被压入的,所以在获取值时需要注意,这是两个对象。(new了两次,是两个对象。)

    ModelDriven中保存的是初始化时压入的对象。
    Action中保存的是execute()方法中赋值的对象。

图片

    示例代码:
        public class OgnlDemo4Action extends ActionSupport implements ModelDriven {
            private User user = new User();
            @Override
            public String execute() throws Exception {
 
                return SUCCESS;
            }
            public Object getModel() {
                return this.user;
            }
        }

10、为什么EL表达式可以访问ValueStack中的数据

    Action中:
        stack.set("username", "张三");
    JSP中:
        ognl获取:<s:property value="username" /><br />
        EL获取:${username }

    Struts2框架中所使用的request对象,是增强后的request对象,重写了getAttribute()方法。

    StrutsPreparedAndExecuteFilter的doFilter()方法中:
        request = prepare.wrapRequest(request)
        *   对Request对象进行了包装,包装类:StrutsRequestWrapper
        *   重写了request的getAttribute()方法
        Object attribute = super.getAttribute(key)
        if(attribute == null) {
            attribute = stack.findValue(key);
        }

    增强后的request,会首先在request范围查找,如果查找不到,会到ValueStack中查找。

——OGNL表达式的常见使用

1、#
    1)#相当于ActionContext.getContext()上下文
        <s:property value="#request.name" />
        相当于:ActionContext.getContext().getRequest().get("name");

    2)不写#默认在ValueStack的Root中进行查找

    3)进行投影映射以及过滤操作(结合复杂对象遍历)
        映射:
            <s:property value="ps" /><br />
            1、使用iterator进行遍历<br />
            <s:iterator value="ps" var="p">
                <s:property value="#p.name" /><br />
                <s:property value="#p.price" /><br />
                <s:property value="#p.count" /><br />
                </s:iterator>
            <hr/>
            2、对集合进行投影,只得到指定的属性<br />
            <!-- 只迭代name -->
            <s:iterator value="ps.{name}" var="name">
                <s:property value="#name" />
            </s:iterator>

        过滤: 
            3、对集合进行过滤操作<br />
            <!-- 得到商品价格大于2000的对象 -->
            <s:iterator value="ps.{?#this.price>1999}" var="p">
                名称:<s:property value="#p.name" /><br />
                价格:<s:property value="#p.price" /><br />
                数量:<s:property value="#p.count" /><br />
            </s:iterator>
            <hr />
            4、对集合进行过滤操作<br />
            <!-- 得到商品价格大于2000的商品的名称 -->
            <s:iterator value="ps.{?#this.price>1999}.{name}" var="pname">
                名称:<s:property value="#pname" /><br />
            </s:iterator>

    4)使用#构造Map集合
        经常结合Struts2标签用来生成select、checkbox、radio

        示例代码:
            1、使用#构造一个Map集合<br/>
                <s:iterator value="#{'name':'tom','age':20 }" var="entry">
                    <s:property value="#entry.key" /> --- <s:property value="#entry.value"/><br />
                </s:iterator>
                <hr/>
                2、构造一个List集合<br/>
                <s:iterator value="{'aa', 'bb', 'cc'}" var="list">
                    <s:property value="list" /><br/>
                </s:iterator>
                <hr/>
                3、手动创建一个集合,在Struts2中结合表单标签使用<br/>
                <s:form>
                    <!-- 用List集合创建radio表单标签 -->
                    <s:radio list="{'男', '女'}" name="sex"/><br/>
                    <!-- 用Map集合创建radio表单标签 -->
                    <s:radio list="#{'male':'男', 'female':'女' }" name="sex2"/><br/>
                    <!-- 使用List集合创建select -->
                    <s:select list="{'a', 'b', 'c'}" name="select" />
                </s:form>
 
2、%

    作用是用来设定当前字符串是否要解析为ognl表达式。

    <h1>演示%用法</h1>
    <%
        request.setAttribute("username", "tom");
    %>
    <s:property value="#request.username" default="null"/><br />
 
    <!-- 当前表达式会被作为ognl表达式解析 -->
    <s:property value="%{#request.username}"/><br/>
    <!-- 当前表达式不会被作为ognl表达式解析 -->
    <s:property value="%{'#request.username'}"/><br/>
    <!-- 如果不解析,则默认显示字符串 -->
    <s:textfield name="username" value="#request.username"/><br/>
    <s:textfield name="username" value="%{#request.username}"/><br/>
 

3、$
    作用是在配置文件中写ognl表达式来获取ValueStack中的数据。

    1)struts.xml
        <result type="stream">
            <param name="contentType">${contentType}</param>
        </result>

    2)在校验文件中使用
        <param min="${min}"></param>
        <param min="${max}"></param>
        <param min="${maxLength}"></param>
        校验文件会引入校验器,校验器会被加载,所以数据也会保存到ValueStack中。

    3)在国际化文件中使用
        在properties文件中:
            username=${#request.username}

        在JSP页面:
            <%
                request.setAttribute("username", "李四");
            %>
            <s:i18n name="com.wyc.resources.my">
                <s:text name="username" />
            </s:i18n>

        在properties文件中也可以使用%获取值:
            username=%{request.username} 

——总结

1、ognl介绍
2、ValueStack介绍
3、什么是ValueStack
4、ValueStack内部结构
5、ValueStack创建以及ActionContext关系
6、如何获取ValueStack
7、如何向ValueStack存储数据(Root)
8、JSP页面中如何获取ValueStack数据
9、关于ValueStack携带数据分析
    *   携带数据类型
    *   如何在页面上获取复杂数据
    *   ValueStack默认压入数据
10、如何使用OGNL表达式
    *   #
    *   %
    *   $
posted @ 2017-02-07 18:19  WWWYC  阅读(405)  评论(0编辑  收藏  举报