Struts2基础

1、Struts2概述

1.1 理解MVC原理

MVC(Model-View-Controller 模型-视图-控制器),是一种程序设计理念。目前,在Java Web应用方面MVC框架有很多,常用的流行框架有Struts、JSF、Tapestry、Spring MVC等,在这些框架之中,Struts和Spring MVC框架的应用最为广泛。

到目前为止,Struts框架拥有两个主要的版本,分别为Struts1.x版本与Struts2.x版本,它们都是遵循MVC设计理念的开源Web框架。在2001年6月发布了Struts1.0版本,它是基于MVC设计理念而开发的Java Web应用框架,其MVC架构如下图所示:

1.2 Struts2框架的产生

性能高效、松耦合、低侵入是程序开发人员追求的理想状态,针对Struts1框架中存在的缺陷与不足,全新的Struts2框架诞生,它改变了Struts1框架中的缺陷,而且还提供了更加灵活与强大的功能。

相对于Struts1框架而言,Struts2是一个全新的框架,Struts2的结构体系与Struts1的结构体系有很大的区别,因为Struts2框架是在WebWork框架的基础上发展而来的,它是WebWork技术与Struts技术的结合。

1.3 Struts2结构体系

Struts2是基于WebWork技术开发的全新Web框架,它的结构体系如下图。

Struts2通过过滤器拦截要处理的请求,当客户端发送一个HTTP请求时,需要经过一个过滤器链,这个过滤器链包括ActionContextClearUp过滤器、其他Web应用过滤器及StrutsPrepareAndExecuteFilter过滤器,其中StrutsPrepareAndExecuteFilter过滤器是必须要配置的。

当StrutsPrepareAndExecuteFilter过滤器被调用时,Action映射器将查找需要调用的Action对象,并返回Action对象的代理。接下来,Action代理将从配置管理器中读取Struts2的相关配置(struts.xml),读取完成后,Action容器调用指定的Action对象,在调用Action对象之前需要经过Struts2的一系列拦截器。拦截器与过滤器的原理相似,从图中可以看出它的两次执行顺序是相反的。

当Action处理请求后,将返回相应的结果视图(JSP、FreeMarker等),在这些视图中可以使用Struts标签显示数据及对数据逻辑方面的控制,最后HTTP请求回应给浏览器,在回应的过滤器中同样经过过滤器链。

 

2、Struts2入门

2.1 Struts2的获取与放置

Struts的官方网站是“http://struts.apache.org”,在此网站上可以获取Struts的所有版本及帮助文档,本文所使用的Struts2开发包为Struts2.5.20版本。

在项目开发之前,需要添加Struts2的类库支持,也就是将lib目录中的jar包文件添加到项目的classpath下,通常情况下,这些jar包文件不用全部添加,根据项目实际的开发需要进行添加即可。

(1)开发Struts2项目需要添加的类库文件:

(2)如果使用Maven,则pom.xml文件配置如下:

<!-- servlet-api -->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

<!-- Struts2框架 -->
<dependency>
  <groupId>org.apache.struts</groupId>
  <artifactId>struts2-core</artifactId>
  <version>2.5.20</version>
</dependency>

 2.2 第一个Struts2程序

Struts2框架主要通过一个过滤器将Struts集成到Web应用,这个过滤器对象就是org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter,通过这个过滤器对象,Struts2就可以获得Web应用中的HTTP请求,并将这个HTTP请求转发到指定的Action进行处理,Action根据处理的结果返回给客户端相应的页面。因此,在Struts2框架中,过滤器StrutsPrepareAndExecuteFilter是Web应用与Struts2 API之间的入口,它在Struts2应用中占有巨大的作用。

【示例】创建Java Web项目,添加Struts2的支持类库,通过Struts2将请求转发到指定的JSP页面。

(1)创建Java Web项目,添加Struts2框架的支持类型库文件到项目中。

说明:Struts2的支持类库可以在所下载的Struts2开发包中获取,其放置在Struts2开发包解压缩目录的lib文件夹中。

(2)在web.xml文件中声明Struts2提供的过滤器。

<!-- 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>

(3)在Web项目的源码文件夹(src文件夹)中,创建名称为struts.xml的配置文件,在此文件中定义Struts2中的Action对象。

<!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">
		<!-- 定义action -->
		<action name="first">
			<!-- 定义处理成功后的映射页面 -->
			<result>/first.jsp</result>
		</action>
	</package>
</struts>

struts.xml配置文件标签说明:

标签说明
<package>标签声明一个包,通过name属性指定包的名称为myPackage,并通过extends属性指定此包继承于struts-default包。
<action>标签用于定义Action对象,它的name属性用于指定访问此Action的URL。
<result>子元素用于定义处理结果和资源之间的映射关系,实例中<result>子元素的配置为处理成功后,请求将其转发到first.jsp页面。

(4)创建程序中的主页面index.jsp,在该页面中编写一个超链接,用于访问上面定义的Action对象,此链接所指向的地址为first.action。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>主页</title>
    <meta name="author" content="pan_junbiao的博客">
  </head>
  <body>
    <a href="first.action">请求 Struts</a>
  </body>
</html>

说明:在Struts2中,Action对象的默认访问后缀为“.action”。此后缀并非绝对,而是可以自由更改的。

(5)创建名称为first.jsp的JSP页面,此页面时Action对象first处理成功后的返回页面。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>第一个 Struts2 程序</title>
        <meta name="author" content="pan_junbiao的博客">
    </head>
    <body>
        <b>您好,欢迎访问 pan_junbiao的博客</b><br>
        <b>博客地址:https://blog.csdn.net/pan_junbiao</b><hr>
        <h3>第一个 Struts2 程序!</h3>
    </body>
</html>

执行结果:

(1)进入到程序主页index.jsp页面。

(2)点击主页中的“请求 Struts”超链接,请求将交给Action对象first进行处理,在处理成功后,返回到first.jsp页面。

 

3、Action对象

3.1 认识Action对象

Action对象是Struts2框架中的重要对象,它主要用于对HTTP请求进行处理,在Struts2 API中,Action对象是一个接口,它位于com.opensymphony.xwork2包中。Struts2项目开发中,创建Action对象都要直接或间接实现此对象,它的方法声明如下:

package com.opensymphony.xwork2;

public interface Action {
    String SUCCESS = "success";
    String NONE = "none";
    String ERROR = "error";
    String INPUT = "input";
    String LOGIN = "login";

    String execute() throws Exception;
}

在Action接口中,包含了5个静态的成员变量,它们是Struts2 API为处理结果定义的静态变量。各变量的含义如下:

静态变量含义
SUCCESS静态变量SUCCESS是Action执行成功时的返回值。在Action执行成功的情况下,需要返回到成功页面,此时就可以将返回值设置为SUCCESS。
NONE静态变量NONE也是Action执行成功时的返回值,但不需要返回到成功页面。主要用于处理不需要返回结果的页面的业务逻辑。
ERROR静态变量ERROR,从词义可以看出,它代表Action执行失败时的返回值。在一些信息校验失败的情况下,可以使用Action返回此值。
INPUT静态变量INPUT代表需要返回到某个输入信息的页面的返回值。例如,在修改某些信息时,加载数据后需要返回到修改页面,此时就可以将Action对象处理的返回值设置为INPUT。
LOGIN静态变量LOGIN代表需要用户登录的返回值。例如,在验证用户是否登录时,Action验证失败,需要用户重新登录,此时就可以将Action对象的返回值设置为LOGIN。

3.2 请求参数的注入原理

在Struts2框架之中,表单提交的数据会自动注入到与Action对象中相对应的属性,它与Spring框架中IOC注入原理相同,通过Action对象为属性提供setter方法进行注入。

【示例】创建UserAction类,提供一个username属性,其代码如下:

public class UserAction extends ActionSupport
{
    // 用户名属性
    private String username;
    // 为username提供setter方法
    public void setUsername(String username) {
        this.username = username;
    }
    // 为username提供getter方法
    public String getUsername() {
        return username;
    }
    public String execute() {
        return SUCCESS;
    }
}

要注入属性值的Action对象,必须对属性提供 setXXX()方法,因为Struts2的内部实现是按照JavaBean规范中提供的setter方法,自动为属性注入值。

由于Struts2中Action对象的属性,是通过对其setter方法进行注入,所以需要为属性提供一个setter方法,但是获取这个属性的值时,又需要通过getter方法进行获取。因此,在编写代码时,最好为Action对象中的属性提供setter与getter方法。

3.3 Action的基本流程

Struts2框架的工作,主要是通过Struts2的过滤器对象拦截HTTP请求,然后将请求分配到指定的Action进行处理,它的基本流程如下图所示。

由于在Web项目中配置的是Struts2过滤器,所以当浏览器向Web容器发送一个HTTP请求时,Web容器就要调用Struts2过滤器的doFilter()方法。此时Struts2就接受到了HTTP请求,通过Struts2的内部处理机制,它会判断这个HTTP请求是否与某个Action对象相匹配。如果找到了与这个HTTP请求匹配的Action,就会调用Action对象的execute()方法,并根据处理结果返回相应的值,然后Struts2就会通过Action的返回值查找返回值所映射的页面,最后通过一定的视图回应给浏览器。

3.4 什么是动态Action

前面所讲解的Action对象,都是通过重写execute()方法实现对浏览器请求的处理,这种方式只适合于比较单一的业务逻辑请求。在实际的项目开发中,业务请求的类型是多种多样的,如对一个对象进行数据的增、删、改、查操作。如果通过创建多个Action对象,编写多个execute()方法来应对这些请求,那么不仅处理的方式过于复杂,而且需要编写多个代码。

在Struts2框架中,提供了“Dynamic Action”这样一个概念,称之为“动态Action”。通过动态请求Action对象中的方法,实现某一业务逻辑的处理。应用动态Action和处理方式如下图。


动态Action是通过请求Action对象中一个具体的方法来实现动态操作的。其具体的操作方式是:在请求Action的URL地址后方加上请求字符串(方法名称),与Action对象中的方法进行匹配。需要注意的是,Action地址与请求字符串之间需要以“!”进行分割。

【示例】在配置文件struts.xml中配置了userAction,当请求其中的add()方法时,其请求方式如下:

/userAction!add

3.5 动态Action的应用

下面通过示例来学习动态Action的应用。

【示例】创建一个Java Web项目,应用Struts2提供的动态Action处理添加用户信息请求和更新用户信息请求。

(1)创建Java Web项目,添加Struts2框架的支持类型库文件到项目中,并在web.xml文件中注册Struts2提供的过滤器。

(2)创建名称为UserAction的Action对象。

package com.pjb.action;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 用户Action
 * @author pan_junbiao
 **/
public class UserAction extends ActionSupport {
    private static final long serialVersionUID = 1L;
    // 提示信息
    private String info;
    // 添加用户信息
    public String add() throws Exception{
        info = "添加用户信息";
        return "add";
    }
    // 更新用户信息
    public String update() throws Exception{
        info = "更新用户信息";
        return "update";
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

(3)在Web项目的源码文件夹(src文件夹)中,创建名称为struts.xml的配置文件,配置UserAction的相关配置。

<!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="add">user_add.jsp</result>
            <!-- 更新成功的映射页面 -->
            <result name="update">user_update.jsp</result>
        </action>
    </package>
</struts>

配置说明:

在Struts2.1之后的版本中,动态Action功能是默认关闭的,所以需要添加2段配置信息。

在<struts>节点下添加如下配置信息,用于设置开启动态Action。

<!--设置开启动态Action -->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>

在<package>节点下添加如下配置信息,用于设置允许调用动态Action中的方法。

<!--设置允许调用动态Action中的方法 -->
<global-allowed-methods>regex:.*</global-allowed-methods>

(4)创建程序中的首页index.jsp,在该页面中添加两个超链接,使用Struts2提供的动态Action功能。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主页</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
    <a href="userAction!add">添加用户</a>
    <br>
    <a href="userAction!update">更新用户</a>
    <hr>
    <b>您好,欢迎访问 pan_junbiao的博客</b>
    <br>
    <b>博客地址:https://blog.csdn.net/pan_junbiao</b>
</body>
</html>

(5)创建名称为user_add.jsp的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>
    <div style="color: red">
        <s:property value="info"/>
    </div>
    <hr>
    <b>您好,欢迎访问 pan_junbiao的博客</b>
    <br>
    <b>博客地址:https://blog.csdn.net/pan_junbiao</b>
</body>
</html>

(6)创建名称为user_update.jsp的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>
    <div style="color: red">
        <s:property value="info"/>
    </div>
    <hr>
    <b>您好,欢迎访问 pan_junbiao的博客</b>
    <br>
    <b>博客地址:https://blog.csdn.net/pan_junbiao</b>
</body>
</html>

执行结果:

(1)进入到程序主页index.jsp页面。

(2)点击主页中的“新增用户”超链接,请求将交给动态Action对象UserAction的add()方法进行处理,在处理成功后,返回到user_add.jsp页面。

(3)点击主页中的“更新用户”超链接,请求将交给动态Action对象UserAction的update()方法进行处理,在处理成功后,返回到user_update.jsp页面。

 

4、Struts2的配置文件

4.1 Struts2的配置文件类型

Struts2是一个非常灵活的Web应用框架,在Struts2框架中,配置文件为Struts2的灵活应用做出了巨大的贡献。Struts2中的配置文件主要有4个,其名称与位置如下表所示。

名称说明
struts-default.xml位于struts2-core-2.5.20.jar文件的org.apache.struts2包中。
struts-plugin.xml位于Struts2提供的各个插件的包中。
struts.xmlWeb应用默认的Struts2配置文件。
struts.propertiesSturts2框架中属性配置文件。
web.xml此文件是Web应用中的web.xml文件中,在此文件中也可以设置Struts2框架的一些信息。

配置文件中, struts-default.xml文件、struts-plugin.xml文件是Struts2提供的配置文件,它们都在Struts2提供的包中;而struts.xml文件是Web应用默认的struts.xml配置文件,struts.properties文件是Struts2框架中的属性配置文件,这两个配置文件需要开发人员编写。

4.2 Struts2的包配置

在struts.xml文件中,存在一个包的概念,它类似于Java中的包。配置文件struts.xml中包使用<package>元素声明,主要用于放置一些项目中的相关配置,可以将理解成为配置文件中的一个逻辑单元,已经配置配置好的包可以被其它包所继承,从而提高配置文件的重用性。与Java中的包相类似,在struts.xml文件中使用包,不仅可以提高程序的可读性,而且还可以简化日后的维护工作,其使用方式如下:

<struts>
    <!-- 声明包 -->
    <package name="user" extends="struts-default"  namespace="/user">
     ...
    </package>
</struts>

包使用<package>元素进行声明,它必须拥有一个name属性来指定包的名称。<package>元素所包含的属性及说明。

名称说明
name声明包的名称,以方便在其他处引用此包,此属性是必需的。
extends用于声明继承的包,也就是它的“父”包。
namespace指定名称空间,也就是访问此包下的Action需要访问的路径。
abstract将包声明为抽象类型(包中不定义action)。

4.3 名称空间配置

在Java Web开发中,Web文件目录通常以模块进行划分,如用户模块的首页可以定义成“/user”目录中,其访问地址为“/user/index.jsp”。在Struts2框架之中,Struts2配置文件提供了名称空间的功能,用于指定一个Action对象的访问路径,它的使用方法是通过在配置文件struts.xml的包声明中,使用“namespace”属性进行声明。

【示例】将包book的名称空间指定为/bookmanager。

<struts>
    <!-- 声明包 -->
    <package name="book" extends="struts-default"  namespace="/bookmanager">
     ...
    </package>
</struts>

注意:在<package>元素中指定名称空间属性,名称空间的值需要以“/”开头,否则,找不到Action对象的访问地址。

4.4 Action相关配置

Struts2框架中的Action对象是一个控制器的角色。Struts2框架通过Action对象处理HTTP请求,其请求地址的映射需要配置在struts.xml文件中,它的配置方式使用<action>元素进行配置。

【示例】配置Action。

<!-- 定义action -->
<action name="userAction" class="com.pjb.action.UserAction" method="save">
    <!-- 添加成功的映射页面 -->
    <result>success.jsp</result>
</action>

配置文件中的<action>元素,主要用于建立Action对象的映射,通过<action>元素可以指定Action请求地址及处理后的映射页面。<action>元素中包含的属性及说明如下:

属性说明
name必须,用于配置Action对象被请求的URL映射。
class指定Action对象的类名。
method设置请求Action对象时,调用Action对象的哪一个方法。
converter指定Action对象类型转换器的类。

在实际的项目开发中,对于每个模块来说,其业务逻辑都是比较复杂,一个Action对象包含多个业务逻辑请求的分支。

【示例】在用户管理模块中,需要对用户信息进行添加、删除、修改、查询操作。

package com.pjb.action;
import com.opensymphony.xwork2.ActionSupport;
/**
 * 用户Action
 * @author pan_junbiao
 **/
public class UserAction extends ActionSupport {
    private static final long serialVersionUID = 1L;
    //添加用户信息
    public String save() throws Exception{
        //忽略中间代码
        return SUCCESS;
    }
    //修改用户信息
    public String update() throws Exception{
        //忽略中间代码
        return SUCCESS;
    }
    //删除用户信息
    public String delete() throws Exception{
        //忽略中间代码
        return SUCCESS;
    }
    //查询用户信息
    public String find() throws Exception{
        //忽略中间代码
        return SUCCESS;
    }
}

调用一个Action对象,默认情况下,它执行的是execute()方法。在这种多个业务逻辑分支的Action对象中,如果需要请求指定的方法,就可以通过<action>元素的method属性进行配置,将一个请求交给指定的业务逻辑方法进行处理。

配置文件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 name="userAction" class="com.pjb.action.UserAction" method="save">
            <result>success.jsp</result>
        </action>
        <!-- 修改用户信息 -->
        <action name="userAction" class="com.pjb.action.UserAction" method="update">
            <result>success.jsp</result>
        </action>
        <!-- 删除用户信息 -->
        <action name="userAction" class="com.pjb.action.UserAction" method="delete">
            <result>success.jsp</result>
        </action>
        <!-- 查询用户信息 -->
        <action name="userAction" class="com.pjb.action.UserAction" method="find">
            <result>success.jsp</result>
        </action>
    </package>
</struts>

<action>元素的method属性主要用于为Action请求分发指定业务逻辑方法,例如将<action>元素的method属性值设置为add,那么这个请求就会交个Action对象的add()方法进行处理,这个配置方法可以减少Action对象数目。

4.5 通配符实现简化配置

Struts2框架是一个非常灵活的框架,在它的配置文件struts.xml中,还支持通配符的使用。这种配置方式主要针对,在非常多Action的情况下,通过一定的命名约定,使用通配符来配置Action对象,来达到一种简化配置的效果。

在Struts2框架的配置文件struts.xml中,常用的通配符主要有两个,分别为通配符“*”与通配符“\”。

  1. 通配符“*”:匹配0或多个字符。
  2. 通配符“\”:是一个转义字符,如需要匹配“/”,则可以使用“\/”进行匹配。

【示例】在Struts2框架的配置文件struts.xml中应用通配符的方法如下:

<struts>
    <!-- 声明包 -->
    <package name="myPackage" extends="struts-default" namespace="/">
        <!-- 定义Action -->
        <action name="add*" class="com.pjb.action.{1}AddAction">
            <!-- 结果映射 -->
            <result name="success">/success.jsp</result>
            <result name="input">/input.jsp</result>
            <result name="error">/error.jsp</result>
        </action>
    </package>
</struts>

<action>元素的name属性的值为“add*”,它匹配的是以字符add开头的字符串,如:addUser、addBook都可以匹配。对于通配符所匹配的字符,在Struts2框架的配置文件中可以获取,它使用表达式{1}、{2}、{3}的方式进行获取,如代码中的“com.pjb.action.{1}AddAction”。

4.6 返回结果的配置

在MVC的设计思想中,业务逻辑处理需要返回一个视图View,Struts2框架中通过Action的结果映射配置返回视图。

Action对象是Struts2框架中的请求处理对象,针对不同的业务请求及处理结果,Action将返回一个字符串,这个字符串就是Action处理结果的逻辑视图名,Struts2框架将根据逻辑视图名称,到配置文件struts.xml中查找逻辑视图名称匹配的视图,在找到之后将这个视图返回给浏览器,如下图所示。

在配置文件struts.xml中,结果映射使用<result>元素进行映射,其使用方法如下:

<!-- 定义Action -->
<action name="user" class="com.pjb.action.UserAction">
    <!-- 结果映射 -->
    <result>/user/success.jsp</result>
    <!-- 结果映射 -->
    <result name="error">/user/error.jsp</result>
    <!-- 结果映射 -->
    <result name="input" type="redirect">/user/input.jsp</result>
</action>

<result>元素有两个属性,分别为name和type。其中,name属性用于指定Result的逻辑名称,它与Action对象中的方法的返回值相对应。例如,execute()方法的返回值为input,那么,就应将<result>元素的name属性配置为input,对应Action对象返回值。<result>元素的type属性用于设置返回结果的类型,如请求转发、重定向等。

重定向:type="redirect"

注意:如果不设置<result>元素的name属性,默认情况下,它的值为success。

 

5、Struts2的开发模式

5.1 实现与Servlet API的交互

Struts2中提供了Map类型的request、session与application,可以从ActionContext对象中获得,ActionContext对象位于com.opensymphony.xwork2包中,它是Action执行的上下文,其常用API方法如下。

5.1.1 实例化ActionContext

在Struts2的API中,ActionContext的构造方法需要传递一个Map类的上下文对象,应用这个构造方法创建ActionContext对象非常不方便,所以,通常情况下都是使用ActionContext对象提供的getContext()方法进行创建,其方法声明如下:

public static ActionContext getContext()

getContext()方法是一个静态方法,可以直接调用,它的返回值就是ActionContext。在开发过程中使用该方法创建ActionContext。

5.1.2 获取Map类型的request

获取Struts2封装的Map类型的request,使用ActionContext对象提供的get()方法进行获取,其方法声明如下:

public Object get(String key)

get()方法的入口参数为String类型的值,获取request可以将此值设置为request。

【示例】获取request值。

Map<String, Object> request = (Map<String, Object>)ActionContext.getContext().get("request");

说明:通过ActionContext对象提供的get()方法,不仅可以获取Map类型的request,还可以获取session、local等对象。

5.1.3 获取Map类型的session

除了可以通过ActionContext对象提供的get()方法获取session之外,ActionContext对象还提供了一个直接获取session的方法getSession(),其方法声明如下:

public Map<String, Object> getSession()

ActionContext类的getSession()方法返回的是Map对象,这个Map对象将作用于HttpSession范围中。

5.1.4 获取Map类型的application

与获取session的方法相类似,ActionContext对象同样为获取Map类型的application提供了单独的方法,其方法声明如下:

public Map<String, Object> getApplication()

ActionContext类的getApplication()方法返回的是Map对象,这个Map对象将作用于ServletContext范围中。

5.2 域模型DomainModel

在前面内容的学习之中,无论是用户注册逻辑的实现,还是其它的一些表单信息的提交操作,并不是通过操作真正的领域对象进行实现,原因是因为将所有的实体对象的属性都封装到了Action对象中,而Action对象只是操作一个实体对象中的属性,而不是操作某一个实体对象,这样的操作有些偏离了领域模型设计的思想,比较好的设计是将某一领域的实体直接封装成为一个实体对象,如操作用户信息可以将用户信息封装成为一个领域对象User、将用户所属的组封装成为Group对象。

将属性信息封装成为一个实体对象,优点非常多。例如,当需要将一个用户信息数据保存到数据库中时,只需要传一个User对象即可,而不用将用户信息的N个属性都进行传递。在Struts2框架中,提供了操作领域对象的方法,可以在Action对象中引用某一个实体对象,并且HTTP请求中的参数值可以注入到实体对象的属性上,这种方式就是Struts2提供的使用DomainModel的方式。

【示例】在Action中应用一个User对象。

package com.pjb.action;
import com.pjb.entity.User;
import com.opensymphony.xwork2.ActionSupport;

/**
 * 用户Action
 * @author pan_junbiao
 **/
public class UserAction extends ActionSupport {
    private User user;

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    public User getUser()
    {
        return user;
    }

    public void setUser(User user)
    {
        this.user = user;
    }
}

在页面中提交注册请求的代码如下:

<body>
    <h2>用户注册</h2>
    <s:form action="userAction" method="POST">
        <s:textfield name="user.name" label="用户名"></s:textfield>
        <s:password name="user.password" label="密码"></s:password>
        <s:radio name="user.sex" list="#{1:'男',0:'女'}" label="性别"></s:radio>
        <s:submit value="注册"></s:submit>
    </s:form>
</body>

5.3 驱动模型ModelDriven

在DomainModel模式中,虽然Struts2的Action对象可以通过直接定义实例对象的引用来调用实体对象进行相关的操作,但前提是请求参数必须指定参数对应的实体对象。例如,在表单中需要指定参数名称为user.name。这种做法还是有些不方便。Struts2框架还提供了另外一种方式,不需要指定请求参数所属的对象引用,就可以向实体对象中注入参数值,这种方式就是驱动模型ModelDriven。

在Struts2框架的API中,提供了一个名称为ModelDriven的接口,Action对象可以通过实现此接口,获取指定的实体对象,获取的方式是实现ModelDriven接口提供的getModel()方法进行获取,其语法格式如下:

T getModel();

说明:ModelDriven接口应用了泛型,getModel()的返回值为所要获取的实体对象。

如果Action对象实现了ModelDriven接口,当表单提交到Action对象后,其处理流程:

Struts2首先会实例化Action对象,然后判断此Action对象是否为ModelDriven对象(也就是是否实现了ModelDriven接口),如果此Action对象实现了ModelDriven接口,则会调用getModel()方法来获取实体对象模型。在获取到实体对象之后,会将其返回。在之后的操作中,就已经存在了明确的实体对象,所以不需要在表单中的元素名称上添加指定的实例对象的引用名称。

【示例】表单中可以设置成一下代码:

<body>
    <h2>用户注册</h2>
    <s:form action="userAction" method="POST">
        <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>
</body>

那么,处理表单请求的UserAction对象需要实现ModelDriven接口,同时需要实现ModelDriven接口的getModel()方法,返回明确的实体对象user。

package com.pjb.action;
import com.opensymphony.xwork2.ModelDriven;
import com.pjb.entity.User;
import com.opensymphony.xwork2.ActionSupport;

/**
 * 用户Action
 * @author pan_junbiao
 **/
public class UserAction extends ActionSupport implements ModelDriven<User>
{
    private User user;

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    @Override
    public User getModel()
    {
        return user;
    }
}

由于UserAction实现了ModelDriven接口,getModel()方法返回了明确的实体对象user,所以,表单中的元素名称不需要指定明确的实体对象引用,即可成功地将表单提交的参数注入到user对象中。

注意:UserAction类中的user属性需要进行初始化操作;否则,在getModel()方法获取实体对象时,将出现空指针异常。

 

6、典型应用

6.1 Struts2处理表单数据

【示例】创建Java Web项目,编写一个Action对象,处理表单提交的数据,模拟用于登录。

登录首页:

 登录成功:

(1)创建Java Web项目,添加Struts2框架的支持类型库文件到项目中,并在web.xml文件中注册Struts2提供的过滤器。

<?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)创建User用户信息实体类。

package com.pjb.entity;

/**
 * 用户信息实体类
 * @author pan_junbiao
 **/
public class User
{
    private String userName;      //用户名称
    private String userPassword;  //登录密码

    public String getUserName()
    {
        return userName;
    }

    public void setUserName(String userName)
    {
        this.userName = userName;
    }

    public String getUserPassword()
    {
        return userPassword;
    }

    public void setUserPassword(String userPassword)
    {
        this.userPassword = userPassword;
    }
}

(3)创建名称为LoginAction类(登录Action类),并实现ModelDriven接口。

package com.pjb.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.pjb.entity.User;

import java.util.Map;

/**
 * 登录Action类
 * @author pan_junbiao
 **/
public class LoginAction extends ActionSupport implements ModelDriven<User>
{
    private User user;

    public LoginAction()
    {
        user = new User();
    }

    @Override
    public String execute() throws Exception
    {
        //验证用户信息
        if(user.getUserName().equals("pan_junbiao的博客") && user.getUserPassword().equals("123456"))
        {
            //登录成功,记录用户登录信息
            Map<String, Object> session = (Map<String, Object>)ActionContext.getContext().getSession();
            session.put("userName", user.getUserName());

            //返回成功
            return SUCCESS;
        }
        else
        {
            //返回失败
            return ERROR;
        }
    }

    @Override
    public User getModel()
    {
        return user;
    }
}

(4)创建名称为LogoutAction类(注销Action类)。

package com.pjb.action;

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

import java.util.Map;

/**
 * 注销Action类
 * @author pan_junbiao
 **/
public class LogoutAction extends ActionSupport
{
    /**
     * 注销
     */
    public String execute() throws Exception
    {
        //销毁session保存的登录信息
        Map<String, Object> session = (Map<String, Object>) ActionContext.getContext().getSession();
        session.remove("username");
        return LOGIN;
    }
}

(5)配置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 name="userLoginAction" class="com.pjb.action.LoginAction">
            <result name="success">/success.jsp</result>
            <result name="error">/error.jsp</result>
        </action>

        <!-- 注销 -->
        <action name="userLogoutAction" class="com.pjb.action.LogoutAction">
            <result name="login" type="redirect">/login.jsp</result>
        </action>
    </package>
</struts>

(6)创建Login.jsp登录页面。

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<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="userLoginAction" method="POST">
    <s:textfield name="blogUrl" label="博客地址" class="txtBox" value="https://blog.csdn.net/pan_junbiao"></s:textfield>
    <s:textfield name="userName" label="登录用户" class="txtBox" value="pan_junbiao的博客"></s:textfield>
    <s:password name="userPassword" label="登录密码" class="txtBox"></s:password>
    <s:submit value="登录"></s:submit>
</s:form>
</body>
</html>

(7)创建success.jsp登录成功页面。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h2 style="color: red">登录成功!</h2>
当前登录用户:<%=session.getAttribute("userName")%><br>
<a href="userLogoutAction">注销</a>
<hr>
<b>您好,欢迎访问 pan_junbiao的博客</b>
<br>
<b>博客地址:https://blog.csdn.net/pan_junbiao</b>
</body>
</html>

(8)创建error.jsp登录失败页面。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录失败</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h2 style="color: red">登录失败!</h2>
<hr>
<b>您好,欢迎访问 pan_junbiao的博客</b>
<br>
<b>博客地址:https://blog.csdn.net/pan_junbiao</b>
</body>
</html>

6.2 使用Map类型的request、session、application

【示例】通过ActionContext对象获取Map类型的request、session和application,分别为这3个对象设置一个info属性并赋值,然后在JSP页面获取3个作用域下的info属性信息。

(1)创建Java Web项目,添加Struts2框架的支持类型库文件到项目中,并在web.xml文件中注册Struts2提供的过滤器。

(2)创建名称为TestAction的类,该类继承ActionSupport类,是一个Action对象。在这个类中分别创建Map类型的request、session和application,并在execute()方法中对其进行操作。

package com.pjb.action;

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

import java.util.Map;

/**
 * 使用Map类型的request、session、application
 * @author pan_junbiao
 **/
public class TestAction extends ActionSupport
{
    private static final long serialVersionUID = 1L;
    // Map类型的request
    private Map<String, Object> request;
    // Map类型的session
    private Map<String, Object> session;
    // Map类型的application
    private Map<String, Object> application;
    // 构造方法
    @SuppressWarnings("unchecked")
    public TestAction(){
        // 获取ActionContext对象
        ActionContext context = ActionContext.getContext();
        // 获取Map类型的request
        request = (Map<String, Object>) context.get("request");
        // 获取Map类型的session
        session = context.getSession();
        // 获取Map类型的application
        application = context.getApplication();
    }
    /**
     * 请求处理方法
     * @return String
     */
    public String execute() throws Exception{
        // 字符串信息
        String info = "pan_junbiao的博客";
        // 向request添加信息
        request.put("info", info);
        // 向session添加信息
        session.put("info", info);
        // 向application添加信息
        application.put("info", info);
        // 成功返回
        return SUCCESS;
    }
}

(3)配置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="testAction" class="com.pjb.action.TestAction">
            <!-- 处理成功的映射页面 -->
            <result>success.jsp</result>
        </action>
    </package>
</struts>

(4)创建TestAction处理成功后的返回页面success.jsp,在该页面总分别从JSP内置对象request、session、application中获取info属性的值,并将这些输出到JSP页面中。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
request范围内的info值: <%=request.getAttribute("info")%>
<br>
session范围内的info值:<%=session.getAttribute("info")%>
<br>
application范围内的info值:<%=application.getAttribute("info")%>
<br>
<b>您好,欢迎访问 pan_junbiao的博客</b>
<br>
<b>博客地址:https://blog.csdn.net/pan_junbiao</b>
</body>
</html>

(5)创建程序的首页index.jsp,在该页面中编写一个超链接,将这个超链接指向testAction。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主页</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
<a href="testAction.action">Map类型的request、session、application</a>
<br>
</body>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pan_junbiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值