1、OGNL表达式语言
1.1 认识OGNL
OGNL(Object Graph Navigation Language)是一种强大的表达式语言,它能够自动导航对象的结构并访问和设置对象数据。在OGNL表达式中,它的核心对象为OGNL上下文。OGNL上下文相当于一个Map容器,在Map容器的Value中可以保存任何类型的数据(对象、数组等),通过OGNL上下文可以对容器中的对象进行导航。
OGNL上下文是OGNL的核心,在OGNL上下文中可以存放多个对象。通常情况下,标准的OGNL为设定一个根。
例如,OGNL上下文中包含两个对象,分别为User对象与Book对象,其中User对象为OGNL上下文的根。如果获取User对象与Book对象中的name属性,可以使用以下表达式:
#user.name
#book.name
上述代码就相当于调用了User对象与Book对象的getName()方法,由于User对象为OGNL上下文的根,所以可以将表达式中的“#”去除。
user.name
OGNL表达式语言是非常强大的表达式语言,它要比JSP中的EL表达更加强大,OGNL表达式语言特点如下:
- 支持对象方法的调用。
- 支持静态方法的调用。
- 支持变量的赋值。
- 可以操作集合数据。
1.2 Struts2框架中的OGNL
Struts2框架在OGNL的基础上增强,提高了Struts2对数据的访问能力,在Struts2框架之中,OGNL上下文作用于Struts2中的ActionContext对象,ActionContext对象是Struts2框架中的一个核心对象,它的结构如下图所示。

值栈符合与栈的基本特征,对象在栈中的存放是后进先出,它由于Struts2 API中的com.opensymphony.xwork2.ognl.OgnlValueStack类进行实现。在ActionContext中包含了多个对象,值栈是OGNL上下文的根,值栈中的对象可以直接调用。
在Struts2框架中,当接收一个Action请求时,Struts2框架会创建ActionContext对象并实例化值栈等对象。由于OGNL上下文用于ActionContext对象,所以,通过OGNL表达式可以获取ActionContext中的所有对象。
(1)获取值栈中的对象
由于OGNL上下文中的根可以直接获取,所以,值栈中的对象可以直接进行获取,原因是Struts2框架中的值栈就是OGNL上下文的根。其取值方法如下:
${user.name}
(2)获取application中的对象
在ActionContext对象中包含application,由于它并不是OGNL上下文的根,其取值方法如下:
#application.name
或
#application['name']
上述代码相当于调用:application.getAttribute("name")方法。
(3)获取request中的对象
与application相同,request也不是OGNL上下文的根,其取值方法如下:
#request.name
或
#request['name']
上述代码相当于调用:request.getAttribute("name")方法。
(4)获取session中的对象
session也不是OGNL上下文的根,其取值方法如下:
#session.name
或
#session['name']
上述代码相当于调用:session.getAttribute("name")方法。
(5)获取parameters中的值
在Struts2框架中,通过OGNL获取请求参数,其取值方法如下:
#parameters.name
或
#parameters['name']
上述代码相当于调用:request.getParameter("name")方法。
(6)获取attr中的值
如果不指定范围,可以使用attr来获取属性值,其搜索范围为按page、request、session、application的次序进行搜索,其取值方法如下:
#attr.name
或
#attr['name']
1.3 操作普通的属性与方法
Struts2框架在OGNL的基础上增强,在Struts2框架中使用OGNL表达式语言需要借助于Struts2标签进行输出。
获取User对象中的name属性,在JSP页面中可以使用以下代码进行获取。
<s:property value="user.id"/>
在OGNL表达式中,获取属性的方法主要有两种方法,除了上面介绍的方法外,也可以通过下面的代码进行获取。
<s:property value="user['id']"/>
OGNL不仅支持属性的调用,同样也支持方法的调用,在JSP页面中,可以使用如下代码,调用User类中的方法。
<s:property value="user.say()"/>
【示例】通过OGNL操作普通的属性与方法。
(1)创建Java Web项目,将Struts2的相关包引用到项目中,并在web.xml文件中注册Struts2提供的StrutsPrepareAndExecuteFilter过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- Struts2过滤器 -->
<filter>
<!-- 过滤器名称 -->
<filter-name>struts2</filter-name>
<!-- 过滤器类 -->
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<!-- Struts2过滤器映射 -->
<filter-mapping>
<!-- 过滤器名称 -->
<filter-name>struts2</filter-name>
<!-- 过滤器映射 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
(2)创建名称为UserInfo的用户信息类。
package com.pjb.entity;
/**
* 用户信息实体类
* @author pan_junbiao
**/
public class UserInfo
{
private String userName; //用户名称
private String blogUrl; //博客地址
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getBlogUrl()
{
return blogUrl;
}
public void setBlogUrl(String blogUrl)
{
this.blogUrl = blogUrl;
}
public String say()
{
String msg = "您好,欢迎访问 pan_junbiao的博客!";
return msg;
}
}
(3)创建名称为OGNLAction的类,该类继承ActionSupport类,是一个Action对象。
package com.pjb.action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.pjb.entity.UserInfo;
import java.util.Map;
/**
* OGNL测试Action类
* @author pan_junbiao
**/
public class OGNLAction extends ActionSupport
{
private static final long serialVersionUID = 1L;
private String name; //普通属性name
private UserInfo userInfo; //用户信息对象
Map<String,Object> request; //Map类型的request
//构造方法
@SuppressWarnings("unchecked")
public OGNLAction()
{
userInfo = new UserInfo();
userInfo.setUserName("pan_junbiao的博客");
userInfo.setBlogUrl("https://blog.youkuaiyun.com/pan_junbiao");
name = "KevinPan";
request = (Map<String,Object>)ActionContext.getContext().get("request");
}
//请求处理方法
@Override
public String execute() throws Exception
{
request.put("info","request测试");
return SUCCESS;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public UserInfo getUserInfo()
{
return userInfo;
}
public void setUserInfo(UserInfo userInfo)
{
this.userInfo = userInfo;
}
public Map<String, Object> getRequest()
{
return request;
}
public void setRequest(Map<String, Object> request)
{
this.request = request;
}
}
(4)在Web项目的源码文件夹(src目录)中,创建名称为struts.xml的配置文件,在该文件中配置OGNLAction对象。
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="myPackage" extends="struts-default" namespace="/">
<!-- 定义action -->
<action name="ognlAction" class="com.pjb.action.OGNLAction">
<!-- 结果映射 -->
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
(5)创建程序主页index.jsp。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
<meta name="author" content="pan_junbiao的博客">
</head>
<body>
<a href="ognlAction.action">OGNL测试</a>
<hr>
<b>您好,欢迎访问 pan_junbiao的博客</b>
<br>
<b>博客地址:https://blog.youkuaiyun.com/pan_junbiao</b>
<br>
</body>
</html>
(6)创建OGNLAction处理请求后返回页面success.jsp,在该页面中使用OGNL表达式输出OGNLAction对象中设置的属性值。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>成功页面</title>
<meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h1>操作普通属性</h1>
属性name值:<s:property value="name"/><br>
<hr>
用户名称:<s:property value="userInfo.userName"/><br>
博客地址:<s:property value="userInfo['blogUrl']"/><br>
say()方法:<s:property value="userInfo.say()"/><br>
<hr>
request中的info值:<s:property value="#request['info']"/>
</body>
</html>
执行结果:
(1)程序主页index.jsp

(2)OGNLAction处理请求后返回页面success.jsp

1.4 访问静态方法与属性
Struts2框架中的OGNL表达式支持对象的静态方法与静态属性的调用,它类似于Java语言之中的静态引入,需要使用字符“@”进行标注,其调用静态属性的方法如下:
@com.lyq.bean.Bean@NAME
上述代码就相当于调用了Bean.NAME静态属性,与调用静态属性的方法相同,调用静态方法方式如:
@com.lyq.bean.Bean@greeting()
在Struts2框架中,提供了一个是否允许OGNL调用静态方法的常量,它的名称为struts.ognl.allowStaticMethodAccess,其默认属性为false。也就是说,在默认情况下,Struts2不允许OGNL调用静态方法,所以,如果开发中需要使用OGNL调用静态方法,必须将此常量的值设置为true。更改这个常量的值,可以在struts.xml配置文件中加入如下配置信息:
<!-- 允许OGNL表达式调用静态方法 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
说明:关于Struts2的常量,可以通过查看Struts2核心jar包中的org.apache.struts2目录中的default.properties属性文件,得知其配置的默认值。
1.5 访问数组
数组是一组元素的集合,每一个元素都有一个下标(索引)值,访问其中的一个元素通过其下标进行访问。在OGNL表达式中,访问数组中的数据与在Java之中的访问方法相似,也是通过下标对其进行访问,如定义了一个名称为arr的数组,使用OGNL表达式的访问方法如下:
arr[0]
OGNL不仅可以访问到数组中的每一个元素,还可以获取数组的长度,其获取方法如下:
arr.length
1.6 访问List、Set、Map集合
集合是Java开发之中经常用到的对象,OGNL对集合数据的访问也同样提供了方法,由于不同的集合对象,其数据存储结构不同,所以,它的访问方式也存在差异。
(1)List集合是JDK API封装的一个有序集合,使用OGNL访问List集合,可以通过下标值对其进行访问,其访问方式如下:
list[0]
(2)Set集合是JDK API封装的一个无序集合对象,由于对象在Set集合中的存储方式是无序的,所以,不能通过下标值的方式访问Set集合中的数据。
(3)Map集合也是JDK API是封装一个集合对象,它的数组存储结构以Key、Value的方式进行存储,使用OGNL访问Map集合,可以通过获取Key值来访问Value,其访问方式如下:
map.key
或
map[‘key’]
Map对象是包含一组Key与Value的集合,针对Map集合对象OGNL提供了获取Map对象所有Key与Value的方法,它返回Key或Value的数组。其获取方式如下:
map.keys //获取所有Key
map.values //获取所有Value
在OGNL表达式中,针对集合对象还提供了两个通用的方法,用于判断集合中的元素是否为空和获取集合的长度。
collection.isEmpty //判断集合元素是否为空
collection.size() //获取集合的长度
1.7 投影与选择
OGNL表达式对数据以及对象的操作功能是十分强大的,对于集合类型的对象,OGNL还支持投影操作与选择操作,可以轻松的获取集合中的某一列数据的集合,也可以通过条件轻松的过滤掉集合中的某些行。
(1)投影是对集合中列的操作,所谓投影,就是指将集合中的某一列数据都抽取出来形成一个集合,这一列数据就是原集合中的投影。如在一个集合中包含多个学生对象,获取这个集合中的所有学生的姓名,就是投影操作,在OGNL表达式中通过如下代码进行实现:
list.{name}
(2)选择是对集合中行的操作,所谓选择,就是通过一定的条件获取集合中满足这一条件的数据,所获取的行就是对集合中数据的选择操作。如在一个集合中包含多个学生对象,获取这个集合中学生年龄大于10的所有学生,就是选择操作,在OGNL表达式中通过如下代码进行实现:
list.{?#this.age > 10}
注意:上述代码针对的是值栈中的对象,如果是非值栈中的对象,还需要加上“#”,如:
#list.{?#this.age > 10}
在Java语言中包含this关键字,OGNL中同样包含了此关键字,与Java语言相同,它代表当前对象。上述代码中“?”代表获取满足这一条件的所有对象。
对于选择操作,在OGNL表达式中主要提供了3个操作符号:
| 符号 | 说明 |
|---|---|
| ? | 获取满足指定条件的所有元素。 |
| ^ | 获取满足指定条件的所有元素中的第一个元素。 |
| $ | 获取满足指定条件的所有元素中的最后一个元素。 |
2、Struts2标签库
在使用Struts2标签库之前,必须在JSP页面的顶部使用<%@ taglib%>指令定义引用的标签库和访问前缀。
使用Struts2标签库的taglib指令格式如下:
<%@ taglib prefix="s" uri="/struts-tags" %>
2.1 数据标签的应用
2.1.1 property标签
property标签是一个非常常用的标签,它的作用是获取数据值,并将数据值直接输出到页面之中。
property标签的属性及说明:
| 名称 | 是否必须 | 名称 | 是否必须 |
|---|---|---|---|
| default | 可选 | escapeJavaScript | 可选 |
| escape | 可选 | value | 可选 |
2.1.2 set标签
set标签用于定义一个变量,通过此标签可以为所定义的变量赋值,及设置变量的作用域(application、request、session)。在默认情况下,通过set标签所定义的变量被放置到值栈中。
set标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| scope | 可选 | String | 设置变量的作用域,它的值可以是application、request、session、page或action,默认值为action。 |
| value | 可选 | String | 设置变量的值。 |
| var | 可选 | String | 定义变量的名称。 |
set标签的使用方法非常简单,其使用方式如下:
<s:set var="userName" value="pan_junbiao的博客" scope="request"></s:set>
<s:property default="没有数据" value="#request.userName" />
2.1.3 a标签
a标签用于构建一个超链接,其最终的构建效果将形成一个HTML中的超链接。
a标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| action | 可选 | String | 将超链接的地址指向action。 |
| href | 可选 | String | 超链接地址。 |
| id | 可选 | String | 设置HTML中的属性名称。 |
| method | 可选 | String | 如果超链接的地址指向action,method同时可以为action声明所调用的方法。 |
| namespace | 可选 | String | 如果超链接的地址指向action,namespace可以为action声明名称空间。 |
2.1.4 param标签
param标签主要用于对参数赋值,它可以当做其它标签的子标签。
param标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| name | 可选 | String | 设置参数名称。 |
| value | 可选 | Object | 设置参数值。 |
2.1.5 action标签
action标签是一个非常常用的标签,它用于执行一个Action请求。当在一个JSP页面中通过action标签执行Action请求时,可以将Action的返回结果输出到当前页面中,也可以不输出。
action标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| executeResult | 可选 | Boolean | 是否使Action返回到执行结果,默认值为false。 |
| flush | 可选 | Boolean | 输出结果是否刷新,默认值为false。 |
| ignoreContextParams | 可选 | Boolean | 是否将页面请求参数传入被调用的Action,默认值为false。 |
| name | 必须 | String | Action对象所映射的名称,也就是struts.xml中配置的名称。 |
| namespace | 可选 | String | 指定名称空间的名称。 |
| var | 可选 | String | 引用此action的名称。 |
2.1.6 push标签
push标签用于将对象或值压入到值栈之中并放置到顶部。因为值栈中的对象是可以直接调用的,所以,push标签主要起到一种简化操作的作用。它的属性只有一个,名称为value,用于声明压入值栈中的对象,其使用方法如下:
<s:push value="#request.student"></s:push>
2.1.7 date标签
date标签用于格式化日期时间,可以通过指定的格式化样式对日期时间值进行格式化。
date标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| format | 可选 | String | 设置格式化日期的样式。 |
| name | 必须 | String | 日期值。 |
| nice | 可选 | Boolean | 是否输出给定日期与当前日期之间的时差,默认值为false,不输出时差。 |
| var | 可选 | String | 格式化时间的名称变量,通过该变量可以对其进行引用。 |
2.1.8 include标签
Struts2框架中的include标签的作用类似于JSP中的<include>动作标签,也用于包含一个页面,但Struts2框架中的include标签的功能更加强大,它可以向目标页面中通过param标签传递请求参数。
include标签只有一个value属性,该属性是必选的属性,用于包含一个JSP页面或Servlet,其使用方法如下:
<s:include value="index.jsp"/>
2.1.9 url标签
在Struts2框架之中,一个Action对象的URL映射地址包含名称空间、调用方法等多个参数,这样的URL可以直接进行编写,也可以使用Struts2框架提供的url标签自动生成URL地址。
url标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| action | 可选 | String | Action对象映射URL,也就是Action对象的访问地址。 |
| anchor | 可选 | String | 此URL的锚点。 |
| encode | 可选 | Boolean | 是否对参数进行编码,默认值为true。 |
| escapeAmp | 可选 | String | 是否将“&”转义成为“&”。 |
| forceAddSchemeHostAndPort | 可选 | Boolean | 是否添加URL的主机地址及端口,默认值为false。 |
| includeContext | 可选 | Boolean | 生成的URL是否包含上下文路径,默认值为true。 |
| includeParams | 可选 | String | 是否包含可选参数,它的可选值为none、get、all,默认值为none。 |
| method | 可选 | String | 指定请求Action对象所调用的方法。 |
| namespace | 可选 | String | 指定请求Action对象映射地址的名称空间。 |
| scheme | 可选 | String | 指定生成URL所使用的协议。 |
| value | 可选 | String | 指定生成URL的地址值。 |
| var | 可选 | String | 定义生成URL变量名称,可以通过此名称引用URL。 |
2.2 控制标签的应用
2.2.1 if标签
if标签是Struts2框架提供的一个流程控制标签,针对某一逻辑的多种条件进行处理,通常表现为“如果满足某种条件,就进行某种处理,否则就进行另一种处理”,与Java语言相同,Struts2框架的标签同样支持if、else if、else的语句判断,其使用方法如下:
<s:if test="表达式(布尔值)">
输出结果...
</s:if>
<s:elseif test="表达式(布尔值)">
输出结果...
</s:elseif>
<s:else>
输出结果...
</s:else>
<s:if>标签与<s:elseif>标签都有一个名称为test的属性,该属性用于设置标签的判断条件,它的值是一个布尔类型的条件表达式。
2.2.2 iterator标签
iterator标签是Struts2提供的一个迭代数据的标签,它可以根据循环条件,遍历数组和集合类中的所有或部分数据,也可以指定迭代数据的起始位置、步长以及终止位置来迭代集合或数组中的部分数据。
iterator标签的属性及说明:
| 名称 | 是否必须 | 类型 | 说明 |
|---|---|---|---|
| begin | 可选 | Integer | 指定迭代数组或集合的起始位置,默认值为0。 |
| end | 可选 | Integer | 指定迭代数组或集合的结束位置,默认值为数组或集合的长度。 |
| status | 可选 | String | 迭代过程中的状态。 |
| step | 可选 | Integer | 设置迭代的步长,如果指定此值,那么,每一次迭代后,索引值将在原索引值的基础上增加step值,默认值为1。 |
| value | 可选 | String | 指定迭代的集合或数组对象。 |
| var | 可选 | String | 设置迭代元素的变量,如果指定此属性,那么所迭代的变量将压入到值栈中。 |
iterator标签的属性中,status属性用于获取迭代过程中的状态信息。在Struts2框架的内部结构中,status属性实质上是获取了Struts2封装的一个迭代状态的对象,该对象为org.apache.struts2.views.jsp.IteratorStatus,通过该对象可以获取迭代过程中的如下信息:
| 信息 | 说明 |
|---|---|
| 元素数 | IteratorStatus对象提供了getCount()方法来获取迭代集合或数组的元素数,如果status属性设置为st,那么就可以通过 st.count 获取元素数。 |
| 是否为第一个元素 | IteratorStatus对象提供了isFirst()方法来判断当前元素是否为第一个元素,如果status属性设置为st,那么就可以通过 st.first 判断当前元素是否为第一个元素。 |
| 是否为最后一个元素 | IteratorStatus对象提供了isLast()方法来判断当前元素是否为最后一个元素,如果status属性设置为st,那么就可以通过 st.lase 判断当前元素是否为最后一个元素。 |
| 当前索引值 | IteratorStatus对象提供了getIndex()方法来获取迭代集合或数组的当前索引值,如果status属性设置为st,那么就可以通过 st.index 获取当前索引值。 |
| 索引值是否为偶数 | IteratorStatus对象提供了isEven()方法来判断当前索引值是否为偶数,如果status属性设置为st,那么就可以通过 st.even 判断当前索引值是否为偶数。 |
| 索引值是否为奇数 | IteratorStatus对象提供了isOdd()方法来判断当前索引值是否为奇数,如果status属性设置为st,那么就可以通过 st.odd 判断当前索引值是否为奇数。 |
2.3 表单标签的应用
2.3.1 常用的表单标签与通用属性
在Struts2框架中,Struts2提供了一套表单标签,这些标签用于生成表单以及表单中的元素,如文本框、密码框、选择框等。由于这些标签由Struts2提供,它们能够与Struts2 API进行很好的交互。
常用的表单标签及说明如下:
| 名称 | 说明 |
|---|---|
| form标签 | 用于生成一个form表单 |
| hidden标签 | 用于生成一个HTML中的隐藏表单元素,相当于使用了HTML代码:<input type="hidden"> |
| textfield标签 | 用于生成一个HTML中的文本框元素,相当于使用了HTML代码:<input type="text"> |
| password标签 | 用于生成一个HTML中的密码框元素,相当于使用了HTML代码:<input type="password"> |
| radio标签 | 用于生成一个HTML中的单选按钮元素,相当于使用了HTML代码:<input type="radio"> |
| select标签 | 用于生成一个HTML中的下拉列表元素,相当于使用了HTML代码:<select><option></option></select> |
| textarea标签 | 用于生成一个HTML中的文本域元素,相当于使用了HTML代码:<textarea></textarea> |
| checkbox标签 | 用于生成一个HTML中的选择框元素,相当于使用了HTML代码:<input type="checkbox"> |
| checkboxlist标签 | 用于生成一个或多个HTML中的选择框元素,相当于使用了HTML代码:<input type="text"> |
| submit标签 | 用于生成一个HTML中的提交按钮元素,相当于使用了HTML代码:<input type="submit"> |
| reset标签 | 用于生成一个HTML中的重置按钮元素,相当于使用了HTML代码:<input type="reset"> |
在HTML语言中,表单中的元素拥有一些通用的属性,例如id属性、name属性以及JavaScript中的事件,这些元素在HTML表单元素中几乎都会存在。与HTML中相同,Struts2提供的表单标签也存在通用的属性,而且这些属性比较多。
通用的属性及说明:
| 名称 | 说明 |
|---|---|
| name | 指定表单元素的name属性。 |
| title | 指定表单元素的title属性。 |
| cssStyle | 指定表单元素的style属性。 |
| cssClass | 指定表单元素的class属性。 |
| required | 用于在lable上添加“*”,它的值为布尔类型,如果为true,则添加“*”。 |
| disabled | 指定表单元素的disable属性。 |
| value | 指定表单元素的value属性。 |
| labelposition | 用于指定表单元素lable的位置,它的默认值为left |
| requiredPosition | 用于指定表单元素lable上添加“*”的位置,默认值为right。 |
2.3.2 更改默认的主题样式
Struts2框架提供的表单标签应用了内置的主题样式,主题是Struts2框架提供一项功能,主题样式的设置可以应用于Struts2框架中的表单标签与UI标签上。默认情况下,Struts2提供了以下4中主题样式。
| 主题 | 说明 |
|---|---|
| simple | simple主题的功能较弱,它只提供了简单的HTML输出。 |
| xhtml | xhtml主题是在simple上的扩展,它提供了简单的布局样式,可以将元素应用到表格布局中,同时,也提供了lable的支持。Struts2应用的默认主题。 |
| css_xhtml | css_xhtml主题是在xhtml主题基础上进行扩展,它在功能上强化了xhtml主题在CSS上的样式控制。 |
| ajax | ajax主题是在css_xhtml主题上扩展,它在功能上强化了css_xhtml主题在Ajax方面的应用。 |
说明:Struts2框架的主题样式是基于模板语言进行设计,它要求程序员了解模板语言,目前,它的应用并不是很广泛。
修改主题样式的方法,可以通过表单元素上的theme属性进行修改。
【示例】使用Struts2框架的表单标签,并修改表单主题样式为css_xhtml。
<h2>用户注册</h2>
<s:form action="userAction" method="POST" theme="css_xhtml">
<s:textfield name="name" label="用户名"></s:textfield>
<s:password name="password" label="密码"></s:password>
<s:radio name="sex" list="#{1:'男',0:'女'}" label="性别"></s:radio>
<s:submit value="注册"></s:submit>
</s:form>
3、拦截器的使用
3.1 了解拦截器
拦截器(Interceptor)是Struts2框架中一个非常重要的核心对象,它可以动态增强Action对象的功能,在Struts2框架中,很多重要的功能都是通过拦截器进行实现的。比如:在使用Struts2框架中,我们发现了Struts2与Servlet API进行解耦,Action对请求的处理不依赖于Servlet API,但Struts2的Action却具有着更加强大的请求处理功能,那么,这个功能的实现就是拦截器对Action的增强,可见拦截器的重要性。此外,Struts2框架中的表单重负提交、对象类型转换、文件上传、还有ModelDriven的操作,都离不开拦截器幕后的操作,Struts2的拦截器的处理机制是Struts2框架的核心。
3.2 拦截器API
在Struts2 API中,存在一个名称为“com.opensymphony.xwork2.interceptor”的包,此包中的对象是Struts2内置的一些拦截器对象,它们都具有不同的功能。在这些对象中,Interceptor接口是Struts2框架中定义的拦截器对象,其它的拦截器都直接或间接的实现于此接口。
在拦截器Interceptor中,包含了三个方法,其代码如下:
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation var1) throws Exception;
}
Interceptor接口中的方法说明:
| 方法 | 说明 |
|---|---|
| destroy()方法 | 指示拦截器的生命周期结束,它在拦截器被销毁前调用,用于释放拦截器在初始化时所占用的资源。 |
| init()方法 | 用于对拦截器进行初始化操作,该方法在拦截器被实例化后、intercept()方法执行前调用。 |
| intercept()方法 | 拦截器的主要方法,用于执行Action对象中的请求处理方法以及在Action的前后进行操作,动态地增强Action的功能。 |
说明:只有调用了intercept()方法的invocation参数的invoke()方法,才可以执行Action对象中的请求处理方法。
Struts2提供了拦截器对象Interceptor是一个接口,如果要通过该接口创建拦截器对象,就需要实现Interceptor接口提供的3个方法。但实际开发中用到的方法主要是intercept()方法,如果用不到init()与destroy()方法也必须对其进行空实现,这种创建拦截器的方法似乎有些不太方便。
为了简化程序开发,创建拦截器对象也可以通过Struts2 API中的AbstractInterceptor对象进行创建,它对Interceptor接口进行了实现。在创建拦截器时可以通过继承AbstractInterceptor对象进行创建,在继承AbstractInterceptor对象后,创建拦截器的方法就更加简单。除了重写必需的intercept()方法外,如果没有用到init()与destroy()方法,就不需要对着两个方法进行实现了。
在Struts2 API中还提供了MethodFilterInterceptor对象,它继承了AbstractInterceptor对象。在实际开发中推荐使用MethodFilterInterceptor对象,当拦截器继承MethodFilterInterceptor对象后,需要重写doIntercept()方法。
3.3 使用拦截器
在Struts2框架中,如果创建了一个拦截器对象,需要对拦截器进行配置才可以应用到Action对象上,其中拦截器的创建比较简单,可以通过继承AbstractInterceptor对象进行创建,而它的配置使用<interceptor-ref>标签进行配置,下面就通过一个实例来学习一下。
【示例】使用拦截器,判断用户是否登录。
(1)创建类名为AuthorizationInterceptor的授权验证拦截器,该类继承MethodFilterInterceptor对象。
package com.pjb.interceptor;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import java.util.Map;
/**
* 授权验证拦截器
* @author pan_junbiao
**/
public class AuthorizationInterceptor extends MethodFilterInterceptor
{
@Override
public String doIntercept(ActionInvocation var1) throws Exception
{
//获取ActionContext上下文对象
ActionContext context = var1.getInvocationContext();
//获取Session对象
Map<String, Object> session = context.getSession();
//从Session对象中获取用户信息
String user = (String) session.get("user");
//判断是否登录
if(user!=null && user.length()>0)
{
//已登录,程序继续执行
return var1.invoke();
}
else
{
//未登录,转至登录页面
return Action.LOGIN;
}
}
}
(2)在struts.xml配置文件中,添加拦截器的相关配置信息。
<!-- 声明包 -->
<package name="myPackage" extends="struts-default" >
<!-- 拦截器的配置 包括拦截器+拦截器栈 -->
<interceptors>
<interceptor name="authorizationInterceptor" class="com.pjb.interceptor.AuthorizationInterceptor"></interceptor>
<!-- 如果想让自定义的拦截器起作用,就必须从新配置拦截器栈,并加上原先默认的拦截器栈 -->
<interceptor-stack name="MyInterceptorStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="authorizationInterceptor">
<!-- 拦截器排除的方法 -->
<param name="excludeMethods">login</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 使用拦截器:将自定义的拦截器栈应用到项目上,项目上所有的请求都会经过该拦截器栈 -->
<default-interceptor-ref name="MyInterceptorStack"></default-interceptor-ref>
<!-- 全局结果视图 -->
<global-results>
<!-- 当返回login视图名时,转入/login.jsp页面 -->
<result name="login" type="redirect">/login.jsp</result>
</global-results>
</package>
注意:拦截器的配置信息必须放置在<action>节点的上面。
配置说明:
excludeMethods属性:表示排除指定的方法,即不对标记为excludeMethods的方法进行拦截,
includeMethods属性:表示包含指定的方法,即对标记为includeMethods的方法进行拦截,
Struts2拦截器属性excludeMethods、includeMethods配置无效的原因:
拦截器如果通过实现Interceptor接口或继承AbstractInterceptor对象,属性excludeMethods、includeMethods配置无效。拦截器如果通过继承MethodFilterInterceptor类的话,属性excludeMethods、includeMethods配置有效。
说明:Struts2提供了拦截器对象与Servlet过滤器(Filter)区别是挺大的。拦截器只值针对Action对象,而无法拦截JSP页面等文件;Servlet过滤器(Filter)可以过滤JSP、Javasctipt、CSS等请求文件。所以上述的示例是无法很好的满足Java Web项目的授权判断功能的。
4、Struts2的配置文件
4.1 手动验证的实现
在Struts2的API中,ActionSupport类对Validateable接口进行了实现,但对validate()方法的实现却是一个空实现,通常情况下,我们所创建的Action对象,都是通过继承ActionSupport类进行创建,所以,在继承ActionSupport类的情况下,如果通过validate()方法验证数据的有效性,直接重写validate()方法就可以了。
使用validate()方法可以对用户请求的多个Action方法的进行验证,但其验证的逻辑是相同的,如果在一个Action类中编写了多个请求处理方法,而此Action重写了validate()方法,那么,默认情况下,在执行每一个请求方法的过程中,都会经过validate()方法的验证处理。
4.2 验证文件的命名规则
使用Struts2验证框架,验证文件的名称需要遵循一定的命名规则,其验证文件的名称必须为“ActionName-validation.xml”或“ActionName-AliasName-validation.xml”的形式,其中ActionName是Action对象的名称,AliasName为Action配置中的名称,也就是struts.xml配置文件中Action元素对应name属性的名称。
(1)以“ActionName-validation.xml”方式命名
在这种命名方式中,数据的验证会作用于整个Action对象中,并验证Action对象的请求业务处理方法,如果Action对象中只存在单一的处理方法或在多个请求处理方法中,验证处理的规则都相同,可以应用此种命名方式。
(2)以“ActionName-AliasName-validation.xml”方式命名
与上一种命名方式相比较,以“ActionName-AliasName-validation.xml”方式命名更加的灵活,如果一个Action对象中包含多个请求处理方法,而又没有必要对每一个方法进行验证处理,只需要对Action对象中的特定方法进行处理,就可以使用此种命名方式。
4.3 验证文件的编写风格
(1)字段验证器编写风格
<validators>
<!-- 验证用户名 -->
<field name="username">
<field-validator type="requiredstring">
<message>请输入用户名</message>
</field-validator>
</field>
<!-- 验证密码 -->
<field name="password">
<field-validator type="requiredstring">
<message>请输入密码</message>
</field-validator>
</field>
</validators>
(2)非字段验证器编写风格
<validators>
<validator type="requiredstring">
<param name="fieldName">password</param> <!-- 验证密码字段 -->
<param name="fieldName">username</param> <!-- 验证用户名字段 -->
<message>请输入内容</message>
</validator>
</validators>
5、典型案例
5.1 Struts2标签下的用户注册
【示例】通过Struts2框架提供的表单标签编写用户注册表单,将用户的注册信息输出到JSP页面中。


(1)创建Java Web项目,将Struts2的相关包引用到项目中,并在web.xml文件中注册Struts2提供的StrutsPrepareAndExecuteFilter过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- Struts2过滤器 -->
<filter>
<!-- 过滤器名称 -->
<filter-name>struts2</filter-name>
<!-- 过滤器类 -->
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<!-- Struts2过滤器映射 -->
<filter-mapping>
<!-- 过滤器名称 -->
<filter-name>struts2</filter-name>
<!-- 过滤器映射 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
(2)创建名称为UserInfo的用户信息实体类。
package com.pjb.entity;
/**
* 用户信息实体类
* @author pan_junbiao
**/
public class UserInfo
{
private String userName; //用户名称
private String blogUrl; //博客地址
private String password; //密码
private String sex; //性别
private String province; //省份
private String[] bobby; //爱好
private String descript; //描述
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getBlogUrl()
{
return blogUrl;
}
public void setBlogUrl(String blogUrl)
{
this.blogUrl = blogUrl;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
public String getProvince()
{
return province;
}
public void setProvince(String province)
{
this.province = province;
}
public String[] getBobby()
{
return bobby;
}
public void setBobby(String[] bobby)
{
this.bobby = bobby;
}
public String getDescript()
{
return descript;
}
public void setDescript(String descript)
{
this.descript = descript;
}
}
(3)创建名称为UserAction类(用户Action类),该类继承ActionSupport对象,并实现ModelDriven接口。
package com.pjb.action;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.ActionSupport;
import com.pjb.entity.UserInfo;
/**
* 用户Action
* @author pan_junbiao
**/
public class UserAction extends ActionSupport implements ModelDriven<UserInfo>
{
private static final long serialVersionUID = 1L;
private UserInfo userInfo;
public UserAction()
{
//初始化UserInfo对象
userInfo = new UserInfo();
}
//用户注册
public String register() throws Exception
{
return SUCCESS;
}
@Override
public UserInfo getModel()
{
return userInfo;
}
}
(4)创建名称register.jsp的用户注册页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>用户注册</title>
<meta name="author" content="pan_junbiao的博客">
<style>
.txtBox{
padding: 3px;
width: 300px;
font-size: 16px;
}
</style>
</head>
<body>
<h2>用户注册</h2>
<s:form action="userAction!register" method="POST">
<s:textfield name="userName" label="用户名称" cssClass="txtBox" required="true" requiredPosition="left" value="pan_junbiao的博客"></s:textfield>
<s:textfield name="blogUrl" label="博客地址" cssClass="txtBox" required="true" requiredPosition="left" value="https://blog.youkuaiyun.com/pan_junbiao"></s:textfield>
<s:password name="password" label="密码" cssClass="txtBox" required="true" requiredPosition="left"></s:password>
<s:radio name="sex" list="#{1:'男',0:'女'}" label="性别" required="true" requiredPosition="left"></s:radio>
<s:select name="province" list="{'请选择省份','广东省','广西省','山东省','河南省' }" label="省份"></s:select>
<s:checkboxlist name="bobby" list="{'篮球','足球','羽毛球','乒乓球','游泳'}" label="爱好"></s:checkboxlist>
<s:textarea name="descript" cols="40" rows="5" cssStyle="font-size: 16px" label="描述"></s:textarea>
<s:submit value="注册"></s:submit>
<s:reset value="重置"></s:reset>
</s:form>
</body>
</html>
(5)创建名称为regsuccess.jsp的注册成功页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>注册成功</title>
<meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h2 style="color: red">注册成功</h2>
<ul>
<li>用户名称:<s:property value="userName"/></li>
<li>博客地址:<s:property value="blogUrl"/></li>
<li>密码:<s:property value="password"/></li>
<li>性别:<s:if test="sex==1">男</s:if><s:else>女</s:else></li>
<li>省份:<s:property value="province"/></li>
<li>爱好:<s:property value="bobby"/></li>
<li>描述:<s:property value="descript"/></li>
</ul>
</body>
</html>
(6)配置struts.xml文件。
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置开启动态Action -->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<!-- 声明包 -->
<package name="myPackage" extends="struts-default" >
<!--设置允许调用动态Action中的方法 -->
<global-allowed-methods>regex:.*</global-allowed-methods>
<!-- 定义action -->
<action name="userAction" class="com.pjb.action.UserAction">
<result name="success">/regsuccess.jsp</result>
</action>
</package>
</struts>

本文深入解析Struts2框架的核心组件OGNL表达式语言,详细介绍其在数据访问、静态方法调用、集合操作等方面的功能。同时,覆盖Struts2标签库的使用,包括数据标签、控制标签和表单标签的应用技巧。此外,探讨了拦截器的原理和配置方法,以及Struts2配置文件的编写规范。
722

被折叠的 条评论
为什么被折叠?



