Struts2框架(一)

现在我们就开始 Struts2 框架的学习了,这是我们整理的第一个框架,掌握了之后我们的技能包中就又多了一个利器了。这篇博客具体的内容就是用 Struts2 框架实现了登录跳转的功能,同时我们会讲解其中各个配置文件的具体作用,以便我们更好地使用该框架。

1.框架介绍

首先我们先看看,在软件领域,框架的概念是什么?框架其实是一组组件的结合,供我们用于解决特定领域中的问题,因为框架本身提供了很多可重用的组件与功能,因此可以大大地提高我们的开发效率,同时也能很好地保证质量。当我们使用框架进行开发时,由于它提供了统一的标准,这样就能大大降低我们后期的维护成本。我们在学习各种框架时,最重要的就是知道这个框架提供了哪些功能,同时为了完成我们想要的功能,我们还需要做些什么。

2.Java常用开发框架

由于每个框架都是解决特定领域内的问题的,因此在实际开发中,往往都是多个框架组合起来进行开发,常用的组合就有 SSHSSM 以及 SSI,它们分别指什么呢?

SSH:Struts2,Spring,Hibernate
SSM:SpringMvc,Spring,Mybatis
SSI:SpringMvc,Spring,ibatis

那它们分别是负责哪一块呢?我们以 SSH 架构举例来进行说明,Struts2 框架主要是负责 web 层,也就是表现层,Hibernate 框架主要是负责 dao 层,也就是负责和数据库进行交互的持久化层,而 Spring 框架比较特殊,它是一个一栈式框架,可以用在 service 层,也就是负责业务逻辑操作,同时也可以在表现层和持久化层进行使用,后续我们都会进行讲解。

3.Struts2框架介绍

Struts2 是一个基于 MVC 设计模式的 Web 应用框架,本质上相当于一个 Servlet,在 MVC 设计模式中,Struts2 框架主要是作为控制器来建立模型与视图之间的数据交互的。Struts2 框架的核心点主要有以下 3 个:

1.拦截器 interceptor
2.action
3.ognl和valueStack

现在开发中和 Struts2 框架比较类似的框架就是 SpringMvc 框架了,平时使用中也是作为和前端交互的控制器来使用的。

4.简单登录案例

为了便于我们学习 Struts2 框架的使用,我们可以从一个简单的登录案例来入手,这里我们先看使用 ServletJSP 如何实现登录案例,然后接着再使用 Struts2 框架来实现,这样我们就能掌握 Struts2 框架的基础使用了。

我们先使用 ServletJSP 来实现,首先需要三个页面,一个登录页面 login.jsp,一个登录成功页面 success.jsp,一个登录失败页面 failer.jsp,还要一个 Servlet 来实现业务逻辑和页面的控制跳转 LoginServlet,首先我们在登录页面中输入用户名和密码,然后点击登录按钮,这时候会向 Servlet 发送请求,如果用户名和密码正确,那就跳转到登录成功页面,如果用户名和密码不正确,那就跳转到失败页面。

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录页面</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/login" method="post">
        username:<input type="text" name="username" /><br>
        password:<input type="password" name="password" /><br>
        <input type="submit" name="login" />
    </form>
</body>
</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录成功页面</title>
</head>
<body>
    登录成功
</body>
</html>

failer.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录失败页面</title>
</head>
<body>
    登录失败
</body>
</html>

LoginServlet

public class LoginServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println(username + "   " + password);
        if ("tom".equals(username) && "123".equals(password)) {
            response.sendRedirect(request.getContextPath() + "/success.jsp");
        } else {
            response.sendRedirect(request.getContextPath() + "/failer.jsp");
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

LoginServletweb.xml 文件中的配置:

<servlet>
    <description></description>
    <display-name>LoginServlet</display-name>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>party.laucloud.web.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>

5.Struts2框架入门

学习 Struts2 框架,我们需要先去下载它的 jar 包,最好的方式便是去官网下载了。

https://struts.apache.org/

我这里是使用的 2.3.24 版本的,下载到完整文件为 struts-2.3.24-all.zip,解压之后会看到几个文件夹,名称以及对应的含义为:

apps:示例代码
docs:文档
lib:相关jar包
src:源代码

如果我们要使用 Struts2 框架,是不是需要将 lib 目录下的所有 jar 包导入到工程当中呢?不是的,没有必要导入这么多,我们一般会根据 apps 目录下的 struts2-blank.war 文件来新建我们的 Struts2 工程,这个文件包含了 Struts2 工程可运行的最小单元,因此我们完全可以根据这个工程来编写我们的项目,这个文件我们也可以使用压缩软件打开,其中的 jar 包和配置文件我们都可以使用。

使用 Struts2 框架的基本步骤如下:

1.导入相关的jar文件
2.在web.xml文件当中配置Struts2框架的核心过滤器StrutsPrepareAndExecuteFilter
3.增加struts.xml配置文件
4.创建Action来完成逻辑操作

那我们就照着这个步骤,新建一个 Struts2 项目,第一步是导入 jar 包,我们就可以使用上面 struts2-blank 工程中的 jar 包文件,打开工程下面 WEB-INF 目录下面的 lib 目录,就可以看到其中有 13jar 包文件,导入我们自己的工程中就可以了。

第二步是配置 Struts2 框架的核心过滤器,主要在 web.xml 文件中配置如下:

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

很显然便是拦截对于项目的一切请求,然后转到用框架进行逻辑处理。第三步便是增加 struts.xml 配置文件,我们同样也可以使用 struts2-blank 工程中的,其位置在 WEB-INF 目录下面的 classes 目录下面,需要注意的是这个是工程的部署目录,那开发时这个文件应该放到哪个地方呢?其实只需要放在我们的 src 目录下就可以了,那为什么呢?其实可以用鼠标右键点击 src 目录,然后选择 Build Path 按钮,接着选择其中的最后一个选项 Configure Build Path...,就可以看到弹出的面板中有个 Default output folder,其中显示的正是 classes 目录,因此开发时 struts.xml 文件放在 src 目录就好了。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="default" namespace="/" extends="struts-default">

    </package>
</struts>

第四步便是编写具体的 Action 来完成业务逻辑操作了,我们可以创建一个简单的 Struts2Action,然后在 struts.xml 文件中增加对应配置。

Struts2Action

public class Struts2Action {

    public void show() {
        System.out.println("hello Struts2......");
    }
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="default" namespace="/" extends="struts-default">            
        <action name="struts2" class="party.laucloud.web.action.Struts2Action"
            method="show"></action>
    </package>
</struts>

为了演示效果,我们可以再新建一个 jsp 页面 index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>主页</title>
</head>
<body>
    <a href="${pageContext.request.contextPath}/struts2">Struts2入门</a>
</body>
</html>

当我们访问 index.jsp 并点击其中的超链接按钮时,便会向我们的项目发送 /struts2 的请求,因为我们在 web.xml 文件中配置了 Struts2 框架的核心过滤器,是拦截一切请求的,因此会拦截到该请求,然后再去 struts.xml 文件中匹配对应的 Java 类以及方法,因此我们就能在控制台看到打印的日志了。

6.Struts2框架完成登录操作

上面完成了 Struts2 框架的基本使用,那如果我们想使用 Struts2 框架完成上面的登录案例呢?其实也非常简单,我们可以创建一个 Action,然后在其中接受前端传递的用户名和密码,判断是否正确,最后进行页面跳转的操作。

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录页面</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/login" method="post">
        username:<input type="text" name="username" /><br>
        password:<input type="password" name="password" /><br>
        <input type="submit" name="login" />
    </form>
</body>
</html>

LoginAction

public class LoginAction {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String login() {
        System.out.println("LoginAction login()");
        System.out.println(username + "   " + password);
        if ("tom".equals(username) && "123".equals(password)) {
            return "success";
        } else {
            return "failer";
        }
    }
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="default" namespace="/" extends="struts-default">
        <action name="login" class="party.laucloud.web.action.LoginAction"
            method="login">
            <result name="success">/success.jsp</result>
            <result name="failer">/failer.jsp</result>
        </action>
    </package>
</struts>

主要的代码和配置就是上面这样了,主要注意的两点是接收前端页面传递参数的部分和页面进行跳转的部分,先看接收前端传递参数的部分,这里是创建两个和前端传递参数名称一样的两个成员变量,然后再新建对应的 get/set 方法,这样我们就可以直接在 Action 中拿到前端传递的数据了;还有一部分便是页面跳转的部分,是在对应的方法上面加了一个 String 类型的返回参数,然后会在方法中返回相关的值,那程序是怎么判断应该跳转到哪个页面中的呢?其实这时拿到方法返回的具体值后,会再去 struts.xml 文件中找到对应 action 的配置,然后匹配其中的 result 配置,跳转到这里面设置的页面,这样就完成我们想要的功能了。

7.Struts2框架执行流程

7.1 Struts2源代码导入

我们先看看如何在 Eclipse 中关联 Struts2 框架的源代码,Struts2 框架的源代码一共分为以下三部分:

1.Struts2核心部分源代码
2.Struts2中xwork核心部分源代码
3.Struts2插件的源代码

先看 Struts2 核心部分的源代码,这类代码一般是以 org.apache.struts2 包名开头的,比如我们之前使用的核心过滤器 StrutsPrepareAndExecuteFilter,如果我们之前没有配置过源代码,当我们点击进入该类时,会报源代码找不到的提示,我们可以点击其中的 Attach Source... 按钮,因为我们这里想要关联的是我们下载的 Struts2 包中的源代码,所以需要选择弹出界面中的 External location 选项,然后再点击 External Folder,选择到 /struts-2.3.24/src/core/src/main/java 这一级目录就可以了,这时候 Struts2 框架核心部分源代码就关联成功了。

Struts2xwork 核心部分源代码,通常是以 com.opensymphony.xwork2 包名开头的,关联源代码和上面的类似,只是对应的目录不一样罢了,目录应该为 /struts-2.3.24/src/xwork-core/src/main/java

Struts2 插件的源代码关联和上面的步骤类似,只是对应的目录不一样罢了,目录为 /struts-2.3.24/src/plugins,由于有多个插件,因此需要针对具体插件,选择其中具体的目录进行匹配,不过步骤都是一样的。

7.2 struts.xml文件中的提示问题

当我们使用 Struts2 框架,在 struts.xml 文件中增加配置时,会有自动的内容提示,这是因为当我们联网时,工具会自动帮我们缓存 http://struts.apache.org/dtds/struts-2.3.dtd,因此才会有自动内容提示,那如果没有网络连接时呢?其实也是可以有自动的内容提示的,只是需要我们增加一些配置。

上面的 struts-2.3.dtd 在我们下载的 Struts2 包中同样也是存在的,因此我们只需要增加配置指向它就好了,首先点击 Window 按钮,点击其中出现的 Preferences 按钮,在弹出的面板中,选择 XML 节点下的 XML Catalog 选项,然后点击 add 按钮,Location 通过 File System 选中我们下载的 Struts2 包中的 struts-2.3.dtd 文件,其目录为 /struts-2.3.24/src/core/src/main/resources/struts-2.3.dtdKey type 选择 URI,下面的 Key 填入 http://struts.apache.org/dtds/struts-2.3.dtd,这样的话即使在无网络环境中编辑 struts.xml 文件也会有自动内容提示了。

7.3 Struts2框架执行流程

Struts2 框架的执行流程如下:

1.当通过浏览器发送一个请求
2.会被StrutsPrepareAndExecuteFilter拦截
3.会调用struts2框架默认的拦截器(interceptor)完成部分功能
4.再执行Action中操作
5.根据Action中方法的执行结果来选择跳转页面result视图

其中 Struts2 框架的默认拦截器是在 struts-default.xml 文件中定义的,该文件在 struts2-core-2.3.24.jar 当中,在配置文件当中可以看到,Struts2 框架定义好了很多拦截器,而默认使用的拦截器栈是 defaultStack

8.Struts2框架配置详解

下面我们再来看看 Struts2 框架搭建的项目使用时,需要加载哪些配置文件,以及配置文件当中一些具体的配置。

8.1 Struts2框架配置文件加载顺序

要想知道 Struts2 框架会加载哪些配置文件,我们可以在 StrutsPrepareAndExecuteFilter 类的源码中进行查找,首先可以看到该类中有个 init() 的初始化方法,其中会初始化一个 Dispatcher 对象,我们需要进去看该对象是如何初始化的。

dispatcher = init.initDispatcher(config);

点进去会发现其中又调用了它自身的 init() 方法,接着查看,就会发现在这个 init() 方法当中,就有加载配置文件的逻辑。

init_DefaultProperties(); // [1]
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
init_CustomConfigurationProviders(); // [5]
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]

下面我们便具体地来看看,这 6 个方法到底加载了哪些配置文件。

第一个加载的是 default.properties 文件,该文件是在 struts2-core.jar 文件的 org.apache.struts2 包当中,其中主要是配置的一些 Struts2 框架的常量,比如编码方式,是否允许动态方法调用之类的。

第二个加载的是一批配置文件,主要是以下三个。

struts-default.xml
struts-plugin.xml
struts.xml

struts-default.xml 文件在 struts2-core.jar 文件当中,主要是声明了一些 interceptorresultbean

struts-plugin.xml 文件则是在各个具体的插件包中,主要是用于对插件的声明配置。

struts.xml 文件则是我们工程中自己创建的,主要是我们工程使用 Struts2 框架时的一些配置。

第三个加载的则是 struts.properties 文件,也是我们自己进行创建的,和 struts.xml 文件一样保存在我们的 src 目录下,主要是用于定制常量。

第四个加载的是一些自定义配置提供。

第五个加载的是 web.xml 文件,主要是加载 Struts2 框架在 web.xml 文件中的相关配置。

第六个加载的 bean 相关配置。

主要加载的就是上面这些配置文件了,其中需要重点掌握的是下面这些:

1.default.properties
2.struts-default.xml
3.struts-plugin.xml
4.struts.xml
5.web.xml

8.2 struts.xml配置文件介绍

struts.xml 配置文件中主要设置的是对于 action 访问的配置,而对于一个 action 的访问来说,最主要的就是 packageactionresult 这三种配置了,下面我们具体来看这三种配置。

8.2.1 package配置

package 配置中主要属性以及作用如下:

name属性:定义一个包的名称,必须保持唯一;
namespace属性:主要是与action标签的name属性联合使用来确定一个action的访问路径;
extends属性:主要指定继承自哪个包,一般值是struts-default,这个值是在struts-default.xml文件中声明的;
abstruct属性:代表当前包是抽象的,主要是用于被继承。
8.2.2 action配置

action 配置中主要属性以及作用如下:

name属性:主要是与package的namespace联合使用来确定一个action的访问路径;
class属性:用于指示当前的action类;
method属性:用于指示当前的action类中的哪个方法执行。
8.2.3 result配置

result 配置中主要属性以及作用如下:

name属性:主要是与action类中的method方法的返回值进行匹配,来确定跳转路径;
type属性:作用是用于指定跳转方式,可以指定为请求转发和重定向等方式,默认是请求转发。

type 属性的属性值,其实是在 struts-default.xml 文件中进行配置的,就在 struts-defaultpackage 配置中,其中有个 result-types 的配置:

<result-types>
    <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
    <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
    <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
    <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
    <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
    <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
    <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
    <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
    <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
    <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
    <result-type name="postback" class="org.apache.struts2.dispatcher.PostbackResult" />
</result-types>

这些便都是 type 属性的属性值了,可以看出默认是 dispatcher 方式,也就是请求转发方式,这里我们先介绍几种常用的方式。

dispatcher:代表的是请求转发。针对于jsp页面
redirect:代表的是重定向。针对于jsp页面 
chain:类似于请示转发。针对于action跳转
redirectAction:类似于重定向。针对于action

同时如果多个 action 中的 result 都是一样的,我们还可以设置全局的 result 配置,同样也是在 package 节点中进行配置。

<global-results>
    <result name="success">/success.jsp</result>
    <result name="failer">/failer.jsp</result>
</global-results>

下面我们再来看看 action 配置和 result 配置中各个属性的默认值是怎样的?我们可以先新建下面这样的一个 action 配置:

<action name="test">
    <result>/success.jsp</result>
</action>

然后根据 /test 来访问这个 action,页面中会是什么效果呢?我们会发现页面成功跳转到 success.jsp 页面了,同时浏览器的访问路径没有变化,这是什么原因呢?这就需要先说明下,在声明 action 时没有指定 class 属性和 method 属性,那访问该 action 时会访问哪个类?其实在 struts-default.xml 文件中是有配置的,那就是:

<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

也就是在没有指定 class 属性的情况下,会默认访问这个类,那访问这个类中的哪个方法呢?是 execute() 方法,我们再看下这个方法的定义:

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

也就是直接返回了 success 字符串,这里我们就要接着说 result 配置的默认值了,result 配置中的 name 属性默认值便是 success 了,而 type 属性,由页面跳转了之后浏览器的访问路径不变,就可以看出是请求转发方式了,也就是 dispatcher

8.3 常量配置

前面已经说过,在 default.properties 配置文件当中,默认设置了很多常量,那如果我们想再定义一些常量或者修改常量设置的默认值呢?可以有下面三种方法:

1.可以在src下创建一个struts.properties配置文件
2.可以在web.xml文件中配置
3.可以直接在struts.xml文件中定义常量

一般我们都会使用第 3 中方式来进行设置,通过 constant 的配置便可以设置了,例如:

<constant name="struts.devMode" value="true"></constant>
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

需要注意的一点是,后加载配置文件中的设置会覆盖前面配置文件中的设置。

9.Struts2框架Action详解

关于 Struts2 框架中的 Action,主要是用来完成业务逻辑的操作,相当于是代替了之前的 Servlet,对于 Action,我们最关注的两点就是,如何创建一个 Action,以及如何访问一个 Action

9.1 Action的创建方式

Action 类创建一共有三种方式,分别如下:

1.创建一个普通的Java类
2.创建一个类实现Action接口
3.创建一个类继承ActionSupport类

第一种创建一个普通的 Java 类,这种方式不会实现任何接口,也不会继承任何类,最主要的优点便是无耦合,缺点则是所有的功能都需要自己来实现。

第二种方式是实现 Action 接口,即是 com.opensymphony.xwork2.Action 接口,Action 接口中声明了五个常量和一个 execute() 方法,五个常量其实是便于我们返回五个结果视图。

ERROR:错误视图
INPUT:它是struts2框架中interceptor中发现问题后会访问的一个视图
LOGIN:它是一个登录视图,可以在权限操作中使用
NONE:它代表的是null,什么都不做(也不会做跳转操作)
SUCCESS:成功视图

使用实现 Action 接口的方式,优点是耦合度低,但是还是有很多功能需要自己来实现。

第三种方式是继承 ActionSupport 类,即是 com.opensymphony.xwork2.ActionSupport 类,其实 ActionSupport 类也实现了 Action 接口,我们在开发中也一般是使用这种方式,这种方式的优点是具有丰富的功能,比如表单校验,错误信息设置以及国际化,缺点则是耦合度高。

9.2 Action的访问方式

Action 的访问方式一共有以下两种:

1.直接通过<action>标签来配置,通过method来指定访问的方法,如果method没有,默认访问的是execute方法。
2.简化的action访问方式,可以使用*通配符来访问。

我们可以通过具体的例子来进行说明,比如有下面的 BookAction 类。

public class BookAction {

    public void add() {
        System.out.println("BookAction add()");
    }

    public void del() {
        System.out.println("BookAction del()");
    }

    public void update() {
        System.out.println("BookAction update()");
    }

    public void find() {
        System.out.println("BookAction find()");
    }
}

按照第一种方法,我们需要这样配置:

<action name="book_add" class="party.laucloud.web.action.BookAction"    method="add"></action>
<action name="book_del" class="party.laucloud.web.action.BookAction"    method="del"></action>
<action name="book_update" class="party.laucloud.web.action.BookAction" method="update"></action>
<action name="book_find" class="party.laucloud.web.action.BookAction"    method="find"></action>

很显然,使用第一种方法的话,如果需要访问的方法很多,那么对应的配置也需要增加很多,如果使用第二种方式呢?那就可以像下面这样。

<action name="book_*" class="party.laucloud.web.action.BookAction"        method="{1}"></action>

method 属性中的 {1} 其实是对应着 name 参数中的第 1* 号,当请求为 /book_add 时,就是访问的 add() 方法了,其它的以此类推。

当不止有 BookAction,还有下面的 PersonAction 类时,应该怎么配置呢?

public class PersonAction {

    public void add() {
        System.out.println("PersonAction add()");
    }

    public void del() {
        System.out.println("PersonAction del()");
    }

    public void update() {
        System.out.println("PersonAction update()");
    }

    public void find() {
        System.out.println("PersonAction find()");
    }
}

其实如果想覆盖这两个 Action 类的访问的话,我们可以这样进行配置。

<action name="*_*" class="party.laucloud.web.action.{1}Action"        method="{2}"></action>

同样的,class 属性中的 {1} 其实是对应着 name 参数中的第 1* 号,method 属性中的 {2} 其实是对应着 name 参数中的第 2* 号,当请求为 /Person_add 时,便是访问的 PersonAction 类中的 add() 方法了,其它的同样以此类推。

使用 * 通配符这种方式访问 Action,不建议使用过多的 *,以免造成阅读障碍,难于理解,通常使用 * 号通配符这种方式进行访问时,对应的名称规范应该统一。

9.3 动态方法调用

访问 Action 还有一种方法,那便是通过动态方法进行调用,要想使用动态方法调用,需要先在 struts.xml 文件当中开启动态方法调用的配置。

<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

开启之后我们便可以使用了,具体访问时可以使用 /struts2!show 进行访问,Struts2 框架便会根据 /struts2 的访问路径在 struts.xml 文件中找到对应的 Action 类,然后调用其中的 show() 方法。

其实最好不要使用动态调用方法,因为之前也是暴露出了漏洞。

10.Struts2框架封装数据

这个部分主要想实现的功能是,在 Action 中如何获取前端传过来的数据,比如我们之前登录案例中的用户名和密码信息,一共有下面属性驱动和模型驱动两种方法。

10.1 属性驱动

属性驱动同样可以分为下面两种方式:

a.直接在action类中提供与请求参数匹配属性,提供get/set方法
b.在action类中创建一个javaBean,对其提供get/set方法,在请求页面上要进行修改,例如user.username和user.password,需要使用ognl表达式

为了更好地理解,我们就使用登录案例分别来进行说明。

属性驱动中的第一种方法:

login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录页面</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/login" method="post">
        username:<input type="text" name="username" /><br>
        password:<input type="password" name="password" /><br>
        <input type="submit" name="login" />
    </form>
</body>
</html>

LoginAction.java:

public class LoginAction {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String login() {
        System.out.println("LoginAction login()");
        System.out.println(username + "   " + password);
        if ("tom".equals(username) && "123".equals(password)) {
            return "success";
        } else {
            return "failer";
        }
    }
}

属性驱动中的第二种方法:

login2.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录页面</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/login2" method="post">
        username:<input type="text" name="user.username" /><br>
        password:<input type="password" name="user.password" /><br>
        <input type="submit" name="login" />
    </form>
</body>
</html>

LoginAction2.java:

public class LoginAction2 {

    private User user;

    public User getUser() {
        return user;
    }

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

    public String login() {
        System.out.println(user.getUsername() + "   " + user.getPassword());
        if ("tom".equals(user.getUsername()) && "123".equals(user.getPassword())) {
            return "success";
        } else {
            return "failer";
        }
    }
}

User.java:

public class User {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

对于上面的这两种方法来说,第一种比较简单,在实际操作时我们需要将 action 的属性再赋值给模型 (javaBean) 去操作;第二种不需要再直接将值给 javaBean 模型,因为直接将数据封装到了 javaBean 中,但是它要求在页面上必须使用 ognl 表达式,就存在页面不通用问题。

10.2 模型驱动

使用模型驱动的步骤如下:

1.Action类要实现ModelDriven接口
2.实例化模型对象(就是要new出来javaBean)
3.重写getModel方法将实例化的模型返回。

同样的,我们使用登录案例来进行说明。

login3.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录页面</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/login3" method="post">
        username:<input type="text" name="username" /><br>
        password:<input type="password" name="password" /><br>
        <input type="submit" name="login" />
    </form>
</body>
</html>

LoginAction3.java:

public class LoginAction3 implements ModelDriven<User> {

    private User user = new User();

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

    public String login() {
        System.out.println(user.getUsername() + "   " + user.getPassword());
        if ("tom".equals(user.getUsername()) && "123".equals(user.getPassword())) {
            return "success";
        } else {
            return "failer";
        }
    }
}

这便是模型驱动的使用了,和属性驱动相比的话,模型驱动在开发中是使用更多的,不过它只能对一个模型数据进行封装。

11.总结

关于这篇博客,最主要的内容便是能使用 Struts2 框架实现登录案例,能实现这个案例,便掌握了具体的使用流程,其它的配置细节可以慢慢地再进行填补,大的流程通了,便能建立大局观,学习也就稳固了。

坚持原创技术分享,您的支持将鼓励我继续创作!