SSH框架之旅-struts2(3)

2018-08-30 09:39:16 浏览数 (1)

struts.jpg

1.OGNL


1.1 OGNL 概述

OGNL,全称是 Object-Graph Navigation Language(对象导航语言),是一种功能强大的开源表达式语言,通过简单的表达式语法就可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。OGNL 是被集成到 struts2中的,并不是 struts2 项目的一部分,struts2 用 OGNL 来取代原始 java web 项目中的 EL 表达式。

1.2 OGNL 结构

  • 表达式(Expression)

表达式是整个 OGNL 的核心,OGNL 解析表达式才知道该做什么,如:从对象中取值的操作。

  • 根对象(Root Object)

根对象可以理解为 OGNL 的操作对象,而表达式只是说明了对这个对象所做的操作。OGNL 称为对象导航语言,也即是把对象放在一张图中,通过任意一个对象作为根,可以找到与这个对象关联的其他对象。

  • 上下文环境(Context)

OGNL 在取值操作的过程中还需要一个上下文的环境,有了根对象和表达式,OGNL就知道改对谁做什么操作,但还需知道这个操作执行的位置,也就是上下文环境。上下文环境 Context 是一个 Map 类型的对象,在表达式中访问 Context 中的对象需要使用 # 号加上对象的名称。

1.3 OGNL 的简单使用

OGNL 在 struts2 中,要结合 struts2 的标签一起使用,首先要 导入 OGNL 的 jar 包,在jsp页面中我们就可以直接使用 OGNL 表达式完成之前需要使用 EL 表达式结合 java 代码才能做到的事情。

牛刀小试:

记得在 web.xml 文件中配置 struts2 的拦截器。

代码语言:javascript复制
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   <!--  引入struts2的标签库 -->
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
 <!--  在struts2 标签中使用 ognl 表达式 -->
  <s:property value="'ognl'.length()"/>
 <!-- 页面的输出结果是 ognl 这个字符串的长度 4 -->
</body>
</html>

2.Struts2 中的值栈


2.1 值栈是什么

在原始的 java web 项目,在 servlet 中操作完后,把数据放到域对象中,然后在 jsp 页面中使用 EL 表达式来获取数据值,域对象在一定的范围内可以进行存值和取值。在 struts2 中也提供了一种存储机制,类似于域对象,就是值栈,同样可以存值和取值。这样在 Action 类中把数据放到值栈中,就可以在页面中获取值栈中的数据。

值栈英文是 ValueStack,它其实是 struts2 的一个接口,而 OgnlValueStack 是 ValueStack 的实现类,浏览器访问 一个 action 请求时,struts2 架构会创建一个 action 的实例同时也会创建一个 OgnlValueStack 的值栈实例,OgnlValueStack 贯穿整个 Action 实例的生命周期,struts2 使用 OGNL 来把请求 action 中的参数封装成对象存储在值栈中,并通过 OGNL 表达式来读取值栈中的对象的属性值。

2.2 值栈对象

之前说到的 ActionContext 和 ServletActionContext 中都有获取 ValueStack的方法,可以去看这两个类的源码,所以通过这两个类就可以获取到 ValueStack对象的引用。

servlet 和 action的区别:

    1. Servlet 默认是在第一次访问是创建的,只创建一次,是单实例的对象。
    1. Action 是在每次访问时创建的,每访问一次 action,就会创建一个 action 对象,对应创建一个值栈对象。

示例代码如下:

证明每个 action 对象中的 valueStack 对象只有一个。

代码语言:javascript复制
package cc.wenshixin.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class ActionDemo1 extends ActionSupport {
    @Override
    public String execute() throws Exception {
        //1.获取ActionContext类的对象
        ActionContext context = ActionContext.getContext();
        //2.调用方法获得值栈对象的引用
        ValueStack stack1 = context.getValueStack();
        ValueStack stack2 = context.getValueStack();
        //3.比较两个值栈引用是否为同一个值栈对象的引用
        System.out.println(stack1==stack2); //结果为true
        return NONE;
    }
}

2.3 值栈的内部结构

从名字上就可以看出值栈具有数据结构中栈的结构特性,先进后出(后进先出)。可以查看 OgnlValueStack 类的源码或者 Debug 的方式查看值栈的结构,会发现值栈具有 root 和 context 两个属性,这就是值栈主要的两部分。root 部分基于List集合,root属性继承 ArrayList,实现压栈和出栈的功能,用来存储 action 和实例以及请求的参数,我们一般操作的都是 root 中的数据。context 基于Map集合,也即是 OnglContext(上下文),存储了一些对象的引用,如 parameters、request、response、session、application等。

context 部分的存储结构表

key(固定)

value

request

request对象的引用

session

httpSesion对象的引用

application

servletContext对象的引用

parameter

传递相关的参数

att

三个域对象的值

在 struts2 中提供了一个调试值栈的标签,s:debug,使用这个标签就可以查看到值栈结构以及存储的值。

相关代码如下:

jsp页面

代码语言:javascript复制
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   <!--  引入struts2的标签库 -->
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 使用debug标签查看值栈中的值 -->
  <s:debug></s:debug>
</body>
</html>

Action 类

代码语言:javascript复制
package cc.wenshixin.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

public class ActionDemo2 extends ActionSupport {
    @Override
    public String execute() throws Exception {
        return "success";
    }
}

struts 配置

代码语言:javascript复制
    <package name="demo1" extends="struts-default" namespace="/">
        <action name="action2" class="cc.wenshixin.action.ActionDemo2">
          <result name="success">/debug.jsp</result>
        </action>
    </package>

Debug的结果1

3.值栈的相关操作


3.1 值栈存放数据

向值栈中放数据的方式很多,下面介绍几种常见的方式。

3.1.1 使用值栈对象,调用对象中的 set() 方法

将上面 Action 类中的部分代码改为下面的,重新刷新页面,查看debug标签中的结构,发现值栈中多出一个 map对象,使用 set() 方法,会将对象存储到一个map集合中。

代码语言:javascript复制
public String execute() throws Exception {
        //1.获取ActionContext类的对象
        ActionContext context = ActionContext.getContext();
        //2.调用方法获得值栈对象的引用
        ValueStack stack = context.getValueStack();
        
        //调用set方法   
        stack.set("name", "小明");
        
        return "success";
    }

set方法

3.1.2 使用值栈对象,调用对象中的 push() 方法

将上面 Action 类中的部分代码改为下面的,重新刷新页面,查看debug标签中的结构,发现值栈中多出一个 String 对象,使用 push() 方法,会将对象存储到一个 String 字符串中。

代码语言:javascript复制
public String execute() throws Exception {
        //1.获取ActionContext类的对象
        ActionContext context = ActionContext.getContext();
        //2.调用方法获得值栈对象的引用
        ValueStack stack = context.getValueStack();
        
        //调用push方法
        stack.push("小明");
        
        return "success";
    }

push方法

3.1.3 在 Action 中定义变量,生成变量的 get 方法

将上面 Action 类中的代码改为下面的,重新刷新页面,查看debug标签中的结构,发现值栈的属性中多了一个定义的变量的名称,并且该属性的值就是 Action 中赋予该变量的值。

代码语言:javascript复制
package cc.wenshixin.action;

import com.opensymphony.xwork2.ActionSupport;

public class ActionDemo5 extends ActionSupport {
    
    private String name; //定义变量
    
    //生成变量的get方法
    public String getName() {
        return name;
    }

    @Override
    public String execute() throws Exception {
        name = "小明"; //给变量赋值
        
        return "success";
    }
}

get方法

3.1.4 向值栈中放对象

实现步骤:

    1. 创建实体类对象
    1. 定义实体类对象的变量
    1. 生成变量的get方法

将上面 Action 类中的代码改为下面的,实体类的对象自己创建,重新刷新页面,查看debug标签中的结构,发现值栈的属性中多了一个定义的变量的名称,并且该属性的值就是 Action 中赋予该变量的值。

代码语言:javascript复制
package cc.wenshixin.action;

import com.opensymphony.xwork2.ActionSupport;

import cc.wenshixin.entity.Student;

public class ActionDemo6 extends ActionSupport {
    //1.定义对象变量,这里也可以不创建对象内容,在下面new
    private Student student = new Student();
    //2.生成对象的get方法
    public Student getStudent() {
        return student;
    }

    @Override
    public String execute() throws Exception {
        //给对象赋值
        student.setName("小明");
        student.setSex("女");
        
        return "success";
    }
}

存放对象

3.1.5 向值栈中放 list 集合

实现步骤:

    1. 创建实体类对象
    1. 定义实体类对象的 list 集合变量
    1. 生成变量的get方法

将上面 Action 类中的代码改为下面的,实体类的对象自己创建,重新刷新页面,查看debug标签中的结构,发现值栈的属性中多了一个定义的list集合的名称,并且该属性的值就是 Action 中添加到list集合的对象。

代码语言:javascript复制
package cc.wenshixin.action;

import java.util.ArrayList;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

import cc.wenshixin.entity.Student;

public class ActionDemo7 extends ActionSupport {

    private List<Student> list = new ArrayList<Student>();

    public List<Student> getList() {
        return list;
    }

    @Override
    public String execute() throws Exception {
        Student student1 = new Student();
        student1.setName("小明");
        student1.setSex("男");
        
        Student student2 = new Student();
        student2.setName("小红");
        student2.setSex("女");
        
        list.add(student1);
        list.add(student2);
        
        return "success";
    }
}

list集合

3.2 获取值栈数据

上面实在 Action 中向值栈中放数据,下面在 jsp 页面中使用 Struts2标签 OGNL 表达式把这些数据显示出来。

3.2.1 获取字符串的值

使用上面 3.1.3 中的 Action 类的代码,显示 Action 中字符串里面的值。

代码语言:javascript复制
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   <!--  引入struts2的标签库 -->
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
  <!-- 获取字符串的值 -->
  <s:property value="name"/>
</body>
</html>
3.2.2 获取对象的值

使用上面 3.1.4 中的 Action 类的代码,显示 Action 中对象的值,在上面的jsp代码中追加下面的代码访问。

代码语言:javascript复制
    <!-- 获取对象的值 -->
  <s:property value="student.name"/>
  <s:property value="student.sex"/>
3.2.3 获取 list 集合的值

获取 list 集合中的值,有三种方式。

使用上面 3.1.5 中的 Action 类的代码,显示 Action 中 list 集合的值,在上面的jsp代码中追加下面的代码访问。

  • 第一种方式需要知道 list 集合中的元素的个数。
代码语言:javascript复制
 <!-- 第一种方式获取list集合中的值 -->
  <s:property value="list[0].name"/>
  <s:property value="list[0].sex"/>
  <s:property value="list[1].name"/>
  <s:property value="list[1].sex"/>
  • 第二种方式通过 <s:iterator> 标签遍历 <s:property>标签中的值
代码语言:javascript复制
<!-- 第二种方式获取list集合中的值 -->
  <s:iterator value="list">
    <s:property value="name"/>
    <s:property value="sex"/>
  </s:iterator>
  • 第三种方式使用 # 取出list种的元素

机制:把每次遍历出来的元素对象放到 context 里面,用 OGNL 表达式获取 context 中的数据需要特殊符号 #

代码语言:javascript复制
<!-- 第三种方式获取list集合中的值 -->
  <s:iterator value="list" var="student">
    <s:property value="#student.name"/>
    <s:property value="#student.sex"/>
  </s:iterator>
3.2.4 其他获取方式

使用上面 3.1.1 中的 Action 类的代码,获取用 set() 方法存到值栈中的值,使用 set() 方法中设置的值的名称。

代码语言:javascript复制
  <!-- 其他获取方式 -->
  <s:property value="name"/>

使用上面 3.1.2 中的 Action 类的代码,获取用 push() 方法存到值栈中的值,因为使用 push() 方法设置值没有名称,只有设置的值,使用值栈的数据名 top,根据数据名来获取值,不过写法有点怪,数组名在后面。

代码语言:javascript复制
  <!-- 其他获取方式 -->
  <s:property value="[0].top"/>

1.4 OGNL 中 # 和 % 的使用总结

1.4.1 # 的使用

在前面获取 list 集合中的第三种方式,使用了 # 来获取 context 种的数据。

1.4.2 % 的使用

struts2 中还定义了表单输入标签,如果在 struts2 的表单标签中使用 OGNL 表达式是不能识别的,需要 %{OGNL表达式} 才能识别。

使用上面 3.1.3 中的 Action 类的代码,将字符串中的值放在一个表单输入项中。

代码语言:javascript复制
    <!-- struts2的表单输入项 -->
  <s:textfield name="name" value="%{name}"></s:textfield>

0 人点赞