zoukankan      html  css  js  c++  java
  • struts2第三天——值栈

      大致内容

        ognl概述
        ognl入门
        值栈

    一、OGNL概述

      OGNL,全称为Object-Graph Navigation Language,对象图导航语言
          它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,
          它旨在提供一个更高的更抽象的层次来对Java对象图进行导航 

      struts2自带的表达式语言就是OGNL
        >支持对象方法调用
        >支持类静态方法调用和值访问
        >【主要用法】在struts2中操作值栈
        和struts2标签一起使用来操作值栈

      OGNL不是struts2的一部分,是一个单独的项目,可以独立使用,但常用于struts2中操作值栈
      同样,和JSTL标签库一样先要导入jar包,但struts2里已经带有(myeclispe中JSTL也自带了)
      使用struts2标签库的时候也要引入标签库

    二、OGNL入门案例  

      OGNL入门案例:
        导入标签库
          <%@ taglib uri="/struts-tags" prefix="s" %>
        使用的方式
          <!-- 里面的 value 值即为ognl表达式,此标签主要用于操作值栈 -->
          <s:property value="'hello'.length()"/>

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="/struts-tags" prefix="s" %>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'ognl.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
          <!-- 里面的 value 值即为ognl表达式,例如用法1:对象方法的调用 -->
        <s:property value="'hello'.length()"/>
      </body>
    </html>

    三、值栈  

      1.概述:
        web阶段,都是servlet中进行操作,把数据放域对象,再使用EL表达式
        在页面显示
        在struts2中提供了一种存储的机制,就类似于域对象,就称之为值栈
        可以存取数据
        在action中可以放数据在值栈,再通过页面取到(当然,就用域对象也是可以,但不学值栈不能说学了struts2)

      servlet和action的区别:
        servlet:在第一次访问时创建,只创建一次 ===单实例对象
        action:也是在访问时创建,但每次访问action时都会创建action对象 ===多实例对象
        (验证方法,在构造函数中输出内容,若每次访问都有输出,则证明执行了构造函数,创建了对象)

        每次访问action时都会创建acion的对象,在每个acion对象中都会有一个值栈对象
      而且是有且只有一个值栈对象,由此可知,值栈生命周期是一次请求!

      2.值栈的内部结构  

      值栈的内部结构:
        两部分:
          root 【经常操作的是这个】(本身是list集合 继承了ArrayList) 根对象
          context本身是map集合,实现了Map)存的是对象的引用(request,session,application,parameters,attr五个对象的引用)
            (值栈可以通过查看 variable查看到)

      3.如何获取值栈对象:(两种方式,掌握较常用的方式)

        1.【常用】使用ActionContext类(静态方法获得本类实例)来获取(getValueStack())

    ActionContext context = ActionContext.getContext(); 

      4.向值栈中放数据:
        <s:debug/> (调试用的,直接给用户用用户直接疯掉...)
        配置页面和action (见stack.jsp)
        页面会出现超链接
        用户点开会疯的 ,一大堆的。。。
        例子里值栈里栈顶是action ,是action的引用
      放数据:
        有多种方式,但常用的是一两种
          获取值栈对象,调用它的set()方法 ===使用ActionContext()方法
          获取值栈对象,调用它的push()方法
          【常用】 在acion定义一个成员变量,然后生成变量的get()方法,在方法使用时再设置值也能放到值栈中去
            第三种方式直接放在action里面,而前两种需要单独开辟空间
            (三种方法均在valuestack.java中进行演示)

    package cn.action;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionSupport;
    import com.opensymphony.xwork2.util.ValueStack;
    
    public class StackAction extends ActionSupport {
    
        //定义私有成员变量
        private String username;
        //定义get()方法
        public String getUsername() {
            return username;
        }
    
        @Override
        public String execute() throws Exception {
            //在使用时设置值
            username = "江北01";//===方式3
            ActionContext context = ActionContext.getContext();
            ValueStack stack = context.getValueStack();
            stack.push("10086");//===方式2
            stack.set("name", "value");//===方式1
            return "success";
        }
    }

            更多的是向值栈中放对象,放list集合等:
        1.在成员变量出定义一个对象,并且生成其get()方法,再在方法里对对象赋值
          基本流程都非常相似,见ObjectStackAction

        2.放list集合(作表单回显等操作)

    package cn.action;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    import cn.entity.User;
    
    public class GetStackAction extends ActionSupport {
    
        private String username;
        
        public String getUsername() {
            return username;
        }
    
        //定义成员变量,此处执行new构造操作,不执行下面也得执行
           // private User user = new User();
         //不要new来浪费空间,后面返回的直接赋给它即可!
        private List<User> list
    //生成get方法 public User getUser() { return user; } //定义list集合 private List<User> list = new ArrayList<User>();
    //定义get方法 public List<User> getList() { return list; } @Override public String execute() throws Exception { //值栈中放字符串 username = "江北01"; //值栈中放对象 user.setUsername("jiangbei01"); user.setPassword("123"); User user1 = new User(); user1.setUsername("小王"); user1.setPassword("123"); User user2 = new User(); user2.setUsername("小李"); user2.setPassword("123"); //值栈中放集合  list.add(user1); list.add(user2); return "success"; } }

      5.从值栈中取数据(day02已经有相关的一些使用方法):
        (取的都是方式3放的数据)
      使用struts2的标签和ognl使用来取值栈的值
        <s:propertiry value="ognl表达式"/>
      获取字符串:
        <!-- 根据名称可以得到值栈的值,它会去找get()方法去拿值 -->
        <s:property value="username"/>
      获取对象:
        <!-- 获取值栈中对象的值 -->
      第一步先去找user的get方法,返回user对象,再通过User的get/set()方法找到值
        <s:property value="user.username"/>
        <s:property value="user.password"/>
      获取集合:
        1.【内容少的时候用,较少用】写法太固定,不灵活
          <!-- 获取值栈中list集合的值 -->
          <s:property value="list[0].username"/>
          <s:property value="list[1].password"/>
        2. <s:iterator value="list">
          <!-- 可以直接写list里面的User对象的属性值,会自动迭代查找 -->
          <s:property value="username"/>
          </s:iterator>
          对比之前的EL的 item 和var 会觉得少了点什么,引出第三种
          注意:<!-- -->标签不能注释<>标签,应当使用JSP的注释:<%-- --%>
        3.【常用】
          <s:iterator value="list" var="user">
          <!-- 表示取得是context中的临时值 -->
          <s:property value="#user.username"/>
          <s:property value="#user.password"/>
          </s:iterator>
      使用这种方式后,每次遍历List集合后遍历的元素会放到context中,也就是context中会临时存放,
      context中是map结构
      key存的就是var的值,value存的就是user对象的引用

      获取context中的数据,需要使用# ,它才知道取得是context中的内容
      这样设计是为了提高取值效率

      如果要在上述Iterator之间取值,由于不能使用EL表达式,可以直接将整个标签复制过来
      例如<a href="${pageContext.request.contextPath}/cus_list?psd=<s:property value="#user.password"/>"></a>

    各种取数据的方式演示如下:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="/struts-tags" prefix="s" %>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'stack.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
          <!-- struts2查看值栈标签 -->
        <s:debug></s:debug> <br>
        <!-- 根据名称可以得到值栈的值,它会去找get()方法去拿值 -->
        <s:property value="username"/>
        <!-- 获取值栈中对象的值,先找user的get方法返回user,再通过user的get/set方法找值 -->
        <s:property value="user.username"/>
        <s:property value="user.password"/>
        <!-- 获取值栈中list集合的值 的第一种方式,不灵活-->
        <s:property value="list[0].username"/>
        <s:property value="list[1].password"/>
        <!-- 获取集合第二种标签,类似JSTL的forEach value会去找getList()方法得到list-->
        <s:iterator value="list">
            <!-- 可以直接写list里面的User对象的属性值,会自动迭代查找 -->
            <s:property value="username"/>
        </s:iterator>
        <%--获取List的第三种方式,注意这是JSP注释,也是使用iterator --%>
        <s:iterator value="list" var="user">
            <!-- 表示取得是context中的临时值 -->
            <s:property value="#user.username"/>
            <s:property value="#user.password"/>
        </s:iterator>
        <s:textarea name="username" value="%{#request.req}"></s:textarea>
      </body>
    </html> 

      如何获取set/push()方法放的值栈数据(会用)
        set中是set(name,value)的形式:用前面的用到的标签,value出填set()方法中的name值即可
          <s:property value="itcast"/>
        push中是直接放入object的,不能根据名称取到,利用set或push方法放的元素会放在一个叫 top的数组中
          可以通过 top 数组取到,但写法特别怪:
          [0].top 取到栈顶值

      扩展延伸: 

      *其实上面的通过OGNL表达式取到的值,直接写EL表达式与JSTL也是可以实现的
      这里有必要讲的是里面的简单原理,即为什么能取到呢
        <c:forEach items="${list}" var="user">
          ${user.username}
        </c:forEach>

      EL操作域对象里面的值,都是通过setAttribute() getAttribute()方法存取域对象里的值
      底层是增强了request里的getAttribute()方法
        1.若域对象中有,则从域对象中取
        2.若域对象中没有,则从值栈中取出来,再放入域对象中
      过滤器那个doFilter()方法中,有个wrapRequest()方法 request = wrapRequest(request);
      通过继承HttpServletRequestWrapper类来增强,增强的方法就叫做getAttribute()方法

      所以,EL表达式本身取得还是域对象的值但是不建议使用EL来去值栈的数据,会影响性能

      OGNL中两个符号的使用:
        #
          使用#来获取context中的数据,访问非根元素对象。实际上,#相当于ActionContext.getContext()
          比如context中存放了request ,可以实现向request域中放值
          ServletActionContext 可以获取,相当于servletContext的一顶九
          #context里Key的名称.xx 用的较少,要取域对象,可以使用EL使用
        %
          在struts2的标签中,有一类标签叫表单标签
          在struts2的标签中不能直接识别OGNL,需要在%之后
          例如这里它识别不了
            <s:textarea name="username" value="#request.req"></s:textarea>
          需要使用%{}
            <s:textarea name="username" value="%{#request.req}"></s:textarea>

    更多表单标签会在第四天引入,但实际使用不多,性能等方面不行

  • 相关阅读:
    LeetCode(35):Palindrome Number 分类: leetCode 2015-07-10 09:26 161人阅读 评论(0) 收藏
    在pycharm进行单元测试(unittest python)
    Django 基本操作
    Django中数据库操作相关的错误
    Question&&Answer
    ubuntu下 SVN 服务器搭建及使用
    python 在不同层级目录import 模块的方法
    Ubuntu 16.04安装PyCharm
    修改mysql中数据库存储主路径
    查看mysql的数据库物理存放位置
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6763213.html
Copyright © 2011-2022 走看看