• 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表达式
        *   #
        *   %
        *   $
  • 相关阅读:
    OpenGL播放yuv视频
    windows 播放器(wzplayer)
    Lotus中的保留域
    Domino Attachment and Object Service (DAOS)
    关于MyEclipse
    DB2站点荟萃
    @IsMember用法
    深入浅出SharePoint——解读Sharepoint日志之输出缓存
    UML用例图概要
    表单设计中的网页视觉体验
  • 原文地址:https://www.cnblogs.com/wwwwyc/p/6375430.html
Copyright © 2020-2023  润新知