Struts 2 简明教程
Basic MVC Architecture
M*odel *V*iew *C*ontroller or *MVC (这是人们通常叫法),是一种用于开发 Web 应用程序的软件设计模式。Model View Controller 模式由以下三部分构成−
-
Model − 这是模式的最低级,负责维护数据。
-
View − 负责向用户显示全部或部分数据。
-
Controller − 控制模型和视图之间交互的软件代码。
MVC 很受欢迎,因为它将应用程序逻辑从用户界面层隔离出来,并支持关注点分离。在这里,控制器接收所有应用程序请求,然后与模型协作准备视图所需的所有数据。随后,视图使用控制器准备的数据生成最终的可展示响应。MVC 抽象可图形化表示如下。
Struts 2 - Overview
Struts2 是一个基于 MVC 设计模式的流行且成熟的 Web 应用程序框架。Struts2 不仅仅是 Struts 1 的一个新版本,而是一种对 Struts 架构的完全重写。
Webwork 框架最初以 Struts 框架为基础,其目标是提供一个建立在 Struts 之上的增强和改进的框架,以便为开发人员简化 Web 开发。
一段时间后,Webwork 框架和 Struts 社区携手合作创建了著名的 Struts2 框架。
Struts 2 Framework Features
以下是一些可能迫使您考虑 Struts2 的强大功能 −
-
POJO Forms and POJO Actions − Struts2 取消了作为 Struts 框架组成部分的作用表单。使用 Struts2,您可以使用任何 POJO 来接收表单输入。类似地,您现在可以将任何 POJO 视为操作类。
-
Tag Support − Struts2 改进了表单标签和新标签,使开发人员可以编写更少的代码。
-
AJAX Support − Struts2 认识到 Web2.0 技术的接管,并且通过创建 AJAX 标签将 AJAX 支持集成到产品中,此功能与标准 Struts2 标签非常相似。
-
Easy Integration − 借助 Struts2 可用的各种集成,现在可以更轻松地与 Spring、Tiles 和 SiteMesh 等其他框架集成。
-
Template Support − 支持使用模板生成视图。
-
Plugin Support − 可以通过使用插件来增强和扩充核心 Struts2 行为。Struts2 提供大量插件。
-
Profiling − Struts2 提供集成分析工具来调试和分析应用程序。除此之外,Struts 还与内置的调试工具配合提供集成调试功能。
-
Easy to Modify Tags − 可以使用 Freemarker 模板调整 Struts2 中的标签标记。这不需要 JSP 或 Java 知识。修改标签只需具备基本的 HTML、XML 和 CSS 知识即可。
-
Promote Less configuration − Struts2 通过对各种设置使用默认值来促进更少的配置。除非与 Struts2 设置的默认设置有偏差,否则您无需配置某些内容。
-
View Technologies − Struts2 非常支持多种视图选项(JSP、Freemarker、Velocity 和 XSLT)
上面列出了 Struts 2 的 10 大特性,因此它成为企业就绪框架。
Struts 2 Disadvantages
虽然 Struts 2 带有一系列出色的特性,但当前版本(Struts 2)有一些限制,需要进一步改进。下面列出了一些要点 −
-
Bigger Learning Curve − 要将 MVC 与 Struts 一起使用,你必须熟悉标准 JSP、Servlet API 和一个大型且精细的框架。
-
Poor Documentation − 与标准 servlet 和 JSP API 相比,Struts 的在线资源较少,许多初学者发现 Apache 在线文档混乱且组织不善。
-
Less Transparent − 使用 Struts 应用程序,后台发生的事情比基于 Java 的正常 Web 应用程序多得多,这使得理解框架变得困难。
最后需要注意的是,一个好的框架应提供多种不同类型的应用程序可以利用的通用行为。
Struts 2 是最好的 Web 框架之一,被广泛用于开发富互联网应用程序 (RIA)。
Struts 2 - Environment Setup
我们的第一个任务是运行一个极简的 Struts 2 应用程序。本章将指导你如何准备开发环境,以开始使用 Struts 2。
我假设你的计算机上已经安装了 JDK (5+)、Tomcat 和 Eclipse。如果你没有安装这些组件,那么请按照快速通道中的给定步骤操作 −
Step 1 - Setup Java Development Kit (JDK)
你可以从 Oracle 的 Java 网站下载 SDK 的最新版本 − Java SE Downloads 。你会在下载的文件中找到有关安装 JDK 的说明,请按照给出的说明安装并配置该设置。最后,设置 PATH 和 JAVA_HOME 环境变量以引用包含 java 和 javac 的目录,通常分别为 java_install_dir/bin 和 java_install_dir。
如果你运行的是 Windows,并且在 C:\jdk1.5.0_20 中安装了 SDK,则应在 C:\autoexec.bat 文件中输入以下行。
set PATH = C:\jdk1.5.0_20\bin;%PATH%
set JAVA_HOME = C:\jdk1.5.0_20
或者,在 Windows NT/2000/XP 上 −
-
你可以右键单击“我的电脑”,选择“属性”,然后选择“高级”,再选择“环境变量”。然后,你可以更新 PATH 值并按“确定”按钮。
-
在 Unix(Solaris、Linux 等)上,如果 SDK 安装在 /usr/local/jdk1.5.0_20 中,而您使用 C shell,您应将以下内容放入 .cshrc 文件中。
在 Unix(Solaris、Linux 等)上,如果 SDK 安装在 /usr/local/jdk1.5.0_20 中,而您使用 C shell,您应将以下内容放入 .cshrc 文件中。
setenv PATH /usr/local/jdk1.5.0_20/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.5.0_20
或者,如果您使用 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio 等集成开发环境 (IDE),请编译并运行一个简单程序以确认 IDE 知道您在哪里安装 Java,否则按照 IDE 提供文档进行适当设置。
Step 2 - Setup Apache Tomcat
您可以从 https://tomcat.apache.org/ 下载最新版本的 Tomcat。下载安装后,将二进制发行版解压缩到一个方便的位置。
例如,在 Windows 中为 C:\apache-tomcat-6.0.33,在 Linux/Unix 中为 /usr/local/apachetomcat-6.0.33,并创建指向这些位置的 CATALINA_HOME 环境变量。
您可以在 Windows 计算机上执行以下命令启动 Tomcat,或者您只需双击 startup.bat
%CATALINA_HOME%\bin\startup.bat
or
C:\apache-tomcat-6.0.33\bin\startup.bat
可以通过在 Unix(Solaris、Linux 等)计算机上执行以下命令启动 Tomcat:
$CATALINA_HOME/bin/startup.sh
or
/usr/local/apache-tomcat-6.0.33/bin/startup.sh
成功启动后,通过访问 http://localhost:8080/ 即可使用包含在 Tomcat 中的默认 Web 应用程序。如果一切都很好,则应显示以下结果 -
有关配置和运行 Tomcat 的更多信息可在本文档中找到,也可以在 Tomcat 网站上找到: https://tomcat.apache.org/
可以通过在 Windows 计算机上执行以下命令停止 Tomcat:
%CATALINA_HOME%\bin\shutdown
or
C:\apache-tomcat-5.5.29\bin\shutdown
可以通过在 Unix(Solaris、Linux 等)计算机上执行以下命令停止 Tomcat:
$CATALINA_HOME/bin/shutdown.sh
or
/usr/local/apache-tomcat-5.5.29/bin/shutdown.sh
Step 3 - Setup Eclipse (IDE)
本教程中的所有示例都使用 Eclipse IDE 编写。我建议您在计算机中安装最新版本的 Eclipse。
若要安装 Eclipse,请从 https://www.eclipse.org/downloads/ 下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压缩到一个方便的位置。
例如,在 Windows 中为 C:\eclipse,在 Linux/Unix 中为 /usr/local/eclipse,最后适当地设置 PATH 变量。可以在 Windows 计算机上执行以下命令启动 Eclipse,或者您只需双击 eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse −
$/usr/local/eclipse/eclipse
成功启动后,如果一切都好,则应显示以下结果 -
Step 4 - Setup Struts2 Libraries
现在,如果一切正常,您可以继续设置 Struts2 框架。以下是下载和在计算机上安装 Struts2 的简单步骤。
-
选择是否要在 Windows 或 Unix 上安装 Struts2,然后转到下一步,下载 Windows 用的 .zip 文件和 Unix 用的 .tz 文件。
-
从 https://struts.apache.org/download.cgi 下载最新版本的 Struts2 二进制文件。
-
在编写本教程时,我下载了 struts-2.0.14-all.zip ,当您解压缩下载的文件时,它将在 C:\struts-2.2.3 中为您提供以下目录结构。
第二步是在任何位置提取 zip 文件,我在 Windows 7 计算机上的 c:\ 文件夹中下载并提取了 struts-2.2.3-all.zip ,以便将所有 jar 文件都放入 C:\struts-2.2.3\lib 中。确保正确设置 CLASSPATH 变量,否则在运行应用程序时将遇到问题。
Struts 2 - Architecture
从高层次来说,Struts2 是一个 pull-MVC(或 MVC2)框架。Struts2 中的模型-视图-控制器模式使用以下五个核心组件实现 -
-
Actions
-
Interceptors
-
Value Stack / OGNL
-
Results / Result types
-
View technologies
Struts 2 与传统的 MVC 框架略有不同,其中操作充当模型而不是控制器,尽管有一些重叠。
上图描述了 M*odel, *V*iew and *C*ontroller to the Struts2 high level architecture. The controller is implemented with a *Struts2 调度 servlet 过滤器以及拦截器,此模型使用操作实现,而视图是结果类型和结果的组合。值堆栈和 OGNL 提供公共线程,链接和启用其他组件之间的集成。
除了上述组件外,还将存在大量与配置相关的信息。Web 应用程序配置,以及动作、拦截器、结果等配置。
这是 Struts 2 MVC 模式的架构概览。我们将在后续章节中更详细地介绍每个组件。
Struts 2 - Hello World Example
您已从 Struts 2 架构中了解到,在 Struts 2 Web 应用程序中单击超链接或提交 HTML 表单时,输入由控制器收集,该控制器将输入发送到名为 Actions 的 Java 类。在执行 Action 后,结果选择资源以呈现响应。该资源通常是 JSP,但它也可以是 PDF 文件、Excel 电子表格或 Java 小程序窗口。
假设您已经构建了开发环境。现在,让我们继续构建我们的第一个 Hello World Struts2 项目。该项目的目标是构建一个收集用户姓名并在用户姓名后显示“Hello World”的 Web 应用程序。
对于任何 Struts 2 项目,我们必须创建以下四个组件 −
Sr.No |
Components & Description |
1 |
Action 创建一个动作类,它将包含完整的业务逻辑,并控制用户、模型和视图之间的交互。 |
2 |
Interceptors 根据需要创建拦截器或使用现有拦截器。这是控制器的一部分。 |
3 |
View 创建一个 JSP 以与用户进行交互,以获取输入并展示最终消息。 |
4 |
Configuration Files 创建配置文件以连接动作、视图和控制器。这些文件为 struts.xml、web.xml、struts.properties。 |
我打算使用 Eclipse IDE,这样所有必需的组件都将创建在动态 Web 项目下。让我们现在开始创建动态 Web 项目。
Create a Dynamic Web Project
启动 Eclipse,然后使用 File > New > Dynamic Web Project 执行,输入项目名称为 HelloWorldStruts2 ,并设置其选项的其余部分,如下一个界面中所示 −
在下一个界面中选择所有默认选项,最后选中 Generate Web.xml deployment descriptor 选项。这将在 Eclipse 中为您创建一个动态 Web 项目。现在使用 Windows > Show View > Project Explorer ,您会看到您的项目窗口如下所示 −
现在,将 struts 2 库文件夹 C:\struts-2.2.3\lib 中的以下文件复制到我们的项目的 WEB-INF\lib 文件夹。为此,您可以简单地将以下所有文件拖放到 WEB-INF\lib 文件夹中。
-
commons-fileupload-x.y.z.jar
-
commons-io-x.y.z.jar
-
commons-lang-x.y.jar
-
commons-logging-x.y.z.jar
-
commons-logging-api-x.y.jar
-
freemarker-x.y.z.jar
-
javassist-.xy.z.GA
-
ognl-x.y.z.jar
-
struts2-core-x.y.z.jar
-
xwork-core.x.y.z.jar
Create Action Class
Action 类是 Struts 2 应用程序的关键,我们大多数在 action 类中实现业务逻辑。因此,让我们在 Java Resources > src 下创建一个 Java 文件 HelloWorldAction.java,其中含有 com.tutorialspoint.struts2 包的名称,并在其中包含如下内容。
Action 类在用户单击 URL 时响应用户操作。将执行一个或多个 Action 类的,并将返回一个字符串结果。特定 JSP 页面将基于结果中含有的值进行呈现。
package com.tutorialspoint.struts2;
public class HelloWorldAction {
private String name;
public String execute() throws Exception {
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这是一个非常简单的类,其中一个属性称为“name”。我们为“name”属性有标准的 getter 和 setter 方法,并有一个返回字符串“success”的 execute 方法。
Struts 2 框架将为此 HelloWorldAction 类创建一个对象,并在响应用户的操作时调用 execute 方法。您将业务逻辑放入该方法,该方法最终返回 String 常量。换句话说,对于每个 URL,您必须实现一个 action 类,并可以使用类名作为您的 action 名称,或者使用 struts.xml 文件进行映射,如下所示。
Create a View
我们还需要一个 JSP 来显示最终信息,当发生预定义的操作时,此页面将由 Struts 2 框架调用,且此映射将定义在 struts.xml 文件中。因此,让我们在 Eclipse 项目中的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp 。为此,在 Project Explorer 文件夹中右键单击 WebContent 文件夹,并选择 New >JSP File 。
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World, <s:property value = "name"/>
</body>
</html>
taglib 指令告诉 Servlet 容器本页面将使用 Struts 2 标记,且这些标记将 s 。
s:property 将显示 action 类属性“name”的值,后者由 HelloWorldAction 类中的 getName() 方法返回。
Create Main Page
我们还需要在 WebContent 中创建 index.jsp 。此文件将作为初始 action URL,用户可以单击此 URL 通知 Struts 2 框架调用 HelloWorldAction 类的确定方法并呈现 HelloWorld.jsp 视图。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World From Struts2</h1>
<form action = "hello">
<label for = "name">Please enter your name</label><br/>
<input type = "text" name = "name"/>
<input type = "submit" value = "Say Hello"/>
</form>
</body>
</html>
上面视图文件中定义的 hello action 将使用 struts.xml 文件映射到 HelloWorldAction 类及其 execute 方法。当用户点击“提交”按钮时,这将导致 Struts 2 框架运行 HelloWorldAction 类中定义的 execute 方法,且基于该方法返回的一个值,将选择一个合适的视图并将其呈现为响应。
Configuration Files
我们需要一个映射来关联 URL、HelloWorldAction 类(模型)和 HelloWorld.jsp(视图)。该映射将告诉 Struts 2 框架哪些类将响应用户的操作(URL)、将执行该类的哪些方法,以及将基于该方法返回的字符串结果呈现哪些视图。
因此,让我们创建一个名为 struts.xml 的文件。因为 Struts 2 要求将 struts.xml 放在 classes 文件夹中。因此,在 WebContent/WEB-INF/classes 文件夹下创建 struts.xml 文件。Eclipse 默认不会创建“classes”文件夹,因此您需要自己创建。为此,在 Project Explorer 中右键单击 WEB-INF 文件夹,并选择 New > Folder 。您的 struts.xml 应如下所示:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
</action>
</package>
</struts>
需要对上述配置文件作一点说明。在此,我们将 constants struts.devMode 设为 true ,因为我们正在开发环境中工作并且我们需要看到一些有用的日志消息。然后,我们定义了一个名为 helloworld 的包。
当您想要将 action 放在一起时,创建包非常有用。在我们的示例中,我们将其 action 命名为“hello”,它对应于 URL /hello.action ,并且由 HelloWorldAction.class 支持。当调用 URL /hello.action 时, HelloWorldAction.class 的 execute 方法就是要运行的方法。如果 execute 方法返回的结果为“success”,那么我们就会将用户带到 HelloWorld.jsp 。
下一步是创建 web.xml 文件,该文件是 Struts 2 任何请求的入口点。Struts2 应用程序的入口点将是部署描述符 (web.xml) 中定义的一个过滤器。因此,我们会在 web.xml 中定义 org.apache.struts2.dispatcher.FilterDispatcher 类的入口。需要在 WebContent 下的 WEB-INF 文件夹下创建 web.xml 文件。当您创建该项目时,Eclipse 已经为您创建了一个空的 web.xml 文件。因此,我们只需按如下所示对其进行修改:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
我们已经将 index.jsp 指定为我们的欢迎文件。然后,我们已经将 Struts2 过滤器配置为在所有 url 上运行(即与 /* 模式匹配的任何 url)。
To Enable Detailed Log
您可以在 WEB-INF/classes 文件夹下创建 logging.properties 文件,从而在使用 Struts 2 时启用完整的日志功能。在您的属性文件中保留以下两行内容:
org.apache.catalina.core.ContainerBase.[Catalina].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].handlers = \
java.util.logging.ConsoleHandler
默认的 logging.properties 指定了一个 ConsoleHandler,用于将日志转到 stdout 以及一个 FileHandler。可以使用 SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST 或 ALL 设置处理器的日志级别阈值。
这就完成了。我们已经准备好使用 Struts 2 框架运行我们的 Hello World 应用程序。
Procedure for Executing the Application
右键点击项目名称,然后点击 Export > WAR File 创建一个 War 文件。
然后将这个 WAR 部署在 Tomcat 的 webapps 目录中。
最后,启动 Tomcat 服务器,然后尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将给你提供以下屏幕 −
输入一个值“Struts2”并提交页面。你应该能看到下一页
注意,你可以在 struts.xml 文件中定义一个 index 为一个动作,而在那种情况下,你就可以像 http://localhost:8080/HelloWorldStruts2/index.action 一样调用 index 页面。检查下面如何定义 index 为一个动作 −
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "index">
<result >/index.jsp</result>
</action>
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
</action>
</package>
</struts>
Struts 2 - Configuration Files
这一章将指导你完成 Struts 2 应用程序的基础配置。我们将在这里看到使用几个重要的配置文件,例如 web.xml, struts.xml, strutsconfig.xml 和 struts.properties ,可以配置哪些内容
老实说,你只需要使用 web.xml 和 struts.xml 配置文件就可以开始工作(正如你在我们前一章中已经亲眼所见,我们的示例是使用这两个文件进行工作的)。但是,为了你的知识,我们将解释关于其他文件的情况。
The web.xml File
web.xml 配置文件是一个 J2EE 配置文件,它确定 HTTP 请求的元素将如何由 servlet 容器处理。它并不是一个严格意义上的 Struts2 配置文件,但是它是 Struts2 能够工作的需要配置的一个文件。
正如前面讨论的,这个文件提供了一个任何网络应用程序的入口点。Struts2 应用程序的入口点将是一个在部署描述符(web.xml)中定义的过滤器。因此,我们将在 web.xml 中定义一个 FilterDispatcher 类的入口。web.xml 文件需要在文件夹 WebContent/WEB-INF 中被创建。
如果您在没有模板或生成它的工具(例如 Eclipse 或 Maven2)的帮助下开始,那么这是您需要配置的第一个配置文件。
以下是我们在上一个示例中使用的 web.xml 文件的内容。
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
请注意,我们把 Struts 2 过滤器映射到 / ,而不是映射到 */ .action*,这意味着所有的 url 都将由 struts 过滤器解析。当我们学习注释章节的时候,我们将涉及到这一点。
The Struts.xml File
struts.xml 文件包含您将在动作开发时修改的配置信息。这个文件可以用来覆盖应用程序的默认设置,例如 struts.devMode = false 和在属性文件中定义的其他设置。这个文件可以创建在 WEB-INF/classes 文件夹中。
让我们来看看在上一个章节中解释的 Hello World 示例中创建的 struts.xml 文件。
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
</action>
<-- more actions can be listed here -->
</package>
<-- more packages can be listed here -->
</struts>
首先要注意的是 DOCTYPE 。所有 struts 配置文件都需要有正确的 doctype,正如我们的小示例中所示。 <struts> 是根标签元素,我们在它的下面使用 <package> 标签来声明不同的包。这里 <package> 允许配置的分离和模块化。当您有一个大项目且项目被分成不同的模块时,这将非常有用。
例如,如果您的项目有三个域 - business_application、customer_application 和 staff_application,那么您可以创建三个包并将关联的动作存储在适当的包中。
package 标签具有以下属性 −
Sr.No |
Attribute & Description |
1 |
name (required) 包的唯一标识符 |
2 |
extends 这个包从哪个包扩展?默认情况下,我们使用 struts-default 作为基本包。 |
3 |
abstract 如果标记为 true,则包裹不可供最终用户使用。 |
4 |
namespace 动作的唯一名称空间 |
constant 标记连同 name 和 value 属性应该用于覆盖 default.properties 中定义的以下任何属性,例如我们刚刚设置的 struts.devMode 属性。设置 struts.devMode 属性使我们能够在日志文件中看到更多调试消息。
我们定义 action 标记对应于我们想要访问的每个 URL,并且我们定义一个具有 execute() 方法的类,该方法将在我们每次访问相应 URL 时访问。
结果确定在执行某个动作后返回到浏览器的内容。从动作返回的字符串应该是结果的名称。结果像上面那样按每个动作配置,或者作为一个“全局”结果,可供包中的每个动作使用。结果具有可选的 name 和 type 属性。默认名称值为 “success”。
随着时间的推移,Struts.xml 文件可能会变大,因此按包对其进行拆分是一种模块化方法,但 Struts 提供了另一种模块化 struts.xml 文件的方法。你可以将文件拆分为多个 xml 文件,并按以下方式导入它们。
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="my-struts1.xml"/>
<include file="my-struts2.xml"/>
</struts>
我们尚未涉及的另一个配置文件是 struts-default.xml。此文件包含 Struts 的标准配置设置,你无需在 99.99% 的项目中接触这些设置。因此,我们不会对这个文件进行太多详细介绍。如果你有兴趣,可以查看 struts2-core-2.2.3.jar 文件中提供的 default.properties 文件。
The Struts-config.xml File
struts-config.xml 配置文件是 Web Client 中 View 和 Model 组件之间的链接,但你无需在 99.99% 的项目中接触这些设置。
配置文件基本上包含以下主要元素 −
Sr.No |
Interceptor & Description |
1 |
struts-config 这是配置文件的根节点。 |
2 |
form-beans 这是将 ActionForm 子类映射到名称的位置。你将此名称作为 ActionForm 在整个 strutsconfig.xml 文件以及 JSP 页面中的别名使用。 |
3 |
global forwards 此部分将 Web 应用程序上的页面映射到名称。你可以使用此名称来引用实际页面。这避免了在网页上写死 URL。 |
4 |
action-mappings 这是声明窗体处理程序的位置,它们也称为动作映射。 |
5 |
controller 此部分配置 Struts 内部并很少在实际情况下使用。 |
6 |
plug-in 此部分告诉 Struts 在哪里找到你的属性文件,其中包含提示和错误消息 |
以下是样本 struts-config.xml 文件 −
<?xml version = "1.0" Encoding = "ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<struts-config>
<!-- ========== Form Bean Definitions ============ -->
<form-beans>
<form-bean name = "login" type = "test.struts.LoginForm" />
</form-beans>
<!-- ========== Global Forward Definitions ========= -->
<global-forwards>
</global-forwards>
<!-- ========== Action Mapping Definitions ======== -->
<action-mappings>
<action
path = "/login"
type = "test.struts.LoginAction" >
<forward name = "valid" path = "/jsp/MainMenu.jsp" />
<forward name = "invalid" path = "/jsp/LoginView.jsp" />
</action>
</action-mappings>
<!-- ========== Controller Definitions ======== -->
<controller contentType = "text/html;charset = UTF-8"
debug = "3" maxFileSize = "1.618M" locale = "true" nocache = "true"/>
</struts-config>
有关 struts-config.xml 文件的更多详细信息,请查看你的 Struts 文档。
The Struts.properties File
此配置文件提供了一种机制来更改框架的默认行为。实际上, struts.properties 配置文件中包含的所有属性也可以在 web.xml 中使用 init-param 配置,以及使用 struts.xml 配置文件中的常量标记。但是,如果你希望让内容保持分离并且更具体,则可以在 WEB-INF/classes 文件夹下创建此文件。
此文件中配置的值将覆盖 default.properties 中配置的默认值,该值包含在 struts2-core-x.y.z.jar 发行版中。有一些属性你可以考虑使用 struts.properties 文件进行更改 −
### When set to true, Struts will act much more friendly for developers
struts.devMode = true
### Enables reloading of internationalization files
struts.i18n.reload = true
### Enables reloading of XML configuration files
struts.configuration.xml.reload = true
### Sets the port that the server is run on
struts.url.http.port = 8080
在 hash (#) 开头的任何行都会被认为是一个命令,并会被 Struts 2 忽略。
Struts 2 - Actions
Actions 是 Struts2 框架的核心,它们对任何 MVC(模型视图控制器)框架来说都是如此。每个 URL 都会映射到一个特定的操作,该操作提供处理逻辑,这是为用户提供服务请求所必需的。
但是,该操作还可以在两个其他重要能力中发挥作用。首先,无论它是一个 JSP 还是其他类型的结果,该操作在从请求传输到视图的数据传输中扮演着重要的角色。其次,该操作必须协助框架确定哪个结果应呈现将在响应中返回给请求的视图。
Create Action
Struts2 中操作的唯一要求是必须有一个不带参数的方法,该方法返回一个 String 或 Result 对象,并且必须是一个 POJO。如果未指定不带参数的方法,则默认行为是使用 execute() 方法。
另外,你可以扩展实现六个接口的 ActionSupport 类,包括 Action 接口。Action 接口如下:
public interface Action {
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
public String execute() throws Exception;
}
让我们看看 Hello World 示例中的操作方法:
package com.tutorialspoint.struts2;
public class HelloWorldAction {
private String name;
public String execute() throws Exception {
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
为了说明操作方法控制视图的观点,让我们对 execute 方法进行以下更改并按如下方式扩展类 ActionSupport:
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String name;
public String execute() throws Exception {
if ("SECRET".equals(name)) {
return SUCCESS;
} else {
return ERROR;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在此示例中,我们在 execute 方法中有一些逻辑来查看 name 属性。如果该属性等于字符串 "SECRET" ,我们返回 SUCCESS 作为结果,否则返回 ERROR 作为结果。因为我们扩展了 ActionSupport,所以我们可以使用 String 常量 SUCCESS 和 ERROR。现在,让我们按如下方式修改我们的 struts.xml 文件:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
<result name = "error">/AccessDenied.jsp</result>
</action>
</package>
</struts>
Create a View
让我们在 Eclipse 项目的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp 。为此,右键单击项目资源管理器中的 WebContent 文件夹,然后选择 New >JSP File 。如果返回结果是 SUCCESS(这是在 Action 接口中定义的一个 String 常量“success”),则会调用该文件:
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World, <s:property value = "name"/>
</body>
</html>
以下是如果操作结果是 ERROR(等于 String 常量“error”)的情况下框架调用的文件。以下是 AccessDenied.jsp 的内容:
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Access Denied</title>
</head>
<body>
You are not authorized to view this page.
</body>
</html>
我们还需要在 WebContent 文件夹中创建一个 index.jsp 。该文件将作为初始操作 URL,用户可以单击此 URL 告知 Struts 2 框架调用 HelloWorldAction 类的 execute 方法并呈现 HelloWorld.jsp 视图。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World From Struts2</h1>
<form action = "hello">
<label for = "name">Please enter your name</label><br/>
<input type = "text" name = "name"/>
<input type = "submit" value = "Say Hello"/>
</form>
</body>
</html>
就是这样,不需要更改 web.xml 文件,因此让我们使用我们在 Examples 章节中创建的相同的 web.xml。现在,我们可以使用 Struts 2 框架运行我们的 Hello World 应用程序了。
Execute the Application
右键单击项目名称并单击 Export > WAR 文件来创建一个 War 文件。然后将此 WAR 部署到 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将为您提供以下屏幕:
让我们输入一个单词“SECRET”,你将看到以下页面:
现在输入除了“SECRET”之外的任何单词,你将看到以下页面:
Create Multiple Actions
你将经常定义多个操作来处理不同的请求并向用户提供不同的 URL,你要按如下所示定义不同的类:
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
class MyAction extends ActionSupport {
public static String GOOD = SUCCESS;
public static String BAD = ERROR;
}
public class HelloWorld extends ActionSupport {
...
public String execute() {
if ("SECRET".equals(name)) return MyAction.GOOD;
return MyAction.BAD;
}
...
}
public class SomeOtherClass extends ActionSupport {
...
public String execute() {
return MyAction.GOOD;
}
...
}
你将按如下方式在 struts.xml 文件中配置这些操作:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorld"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
<result name = "error">/AccessDenied.jsp</result>
</action>
<action name = "something"
class = "com.tutorialspoint.struts2.SomeOtherClass"
method = "execute">
<result name = "success">/Something.jsp</result>
<result name = "error">/AccessDenied.jsp</result>
</action>
</package>
</struts>
正如你在上面假设的示例中看到的那样,操作结果 SUCCESS 和 ERROR’s 是重复的。
为了解决此问题,建议你创建一个包含结果结果的类。
Struts 2 - Interceptors
从本质上讲,拦截器与 servlet 过滤器或 JDK 的 Proxy 类相同。拦截器允许跨模块功能与操作和框架分开发挥作用。您可以使用拦截器实现以下内容 −
-
在调用操作之前提供预处理逻辑。
-
在调用操作之后提供后处理逻辑。
-
捕获异常,以便执行备用处理。
Struts2 框架中提供的许多功能都是使用拦截器实现的;
Examples 包括异常处理、文件上传、生命周期回调等。实际上,由于 Struts2 将其大部分功能强调在拦截器上,因此不太可能为每个操作分配 7 到 8 个拦截器。
Struts2 Framework Interceptors
Struts2 框架提供了一个即用型开箱拦截器列表,这些拦截器已经过预配置并准备使用。下面列出了一些重要的拦截器 −
Sr.No |
Interceptor & Description |
1 |
alias 允许参数在不同请求之间有不同的名称别名。 |
2 |
checkbox 通过为未选中的复选框添加 false 参数值,帮助管理复选框。 |
3 |
conversionError 将字符串转换为参数类型时的错误信息放置在操作的字段错误中。 |
4 |
createSession 如果尚未存在,则自动创建一个 HTTP 会话。 |
5 |
debugging 向开发者提供几个不同的调试屏幕。 |
6 |
execAndWait 在操作在后台执行时,将用户发送到中间等待页面。 |
7 |
exception 将操作中引发的异常映射到结果,允许通过重定向自动处理异常。 |
8 |
fileUpload Facilitates easy file uploading. |
9 |
i18n 在用户的会话期间跟踪所选的区域设置。 |
10 |
logger 提供简单的日志记录,输出正在执行的操作的名称。 |
11 |
params 在操作中设置请求参数。 |
12 |
prepare 这通常用于执行预处理工作,例如设置数据库连接。 |
13 |
profile 可以将简单的状况信息记录到操作。 |
14 |
scope 在会话或应用程序范围内存储和检索操作的状态。 |
15 |
ServletConfig 为操作提供访问基于 Servlet 的各种信息的权限。 |
16 |
timer 提供操作执行所需时间的形式的简单状况信息。 |
17 |
token 检查操作是否具有有效令牌来防止重复提交表单。 |
18 |
validation 为操作提供验证支持。 |
请在 Struts 2 文档中查找以上所述拦截器的完备详细信息。但我会向你展示如何在 Struts 应用程序中通常使用拦截器。
How to Use Interceptors?
让我们了解如何在“Hello World”程序中使用已存在的拦截器。我们将使用 timer 拦截器,其目的是衡量执行操作方法所需的时间。同时,我正在使用 params 拦截器,其目的是将请求参数发送到操作。你可以尝试不使用此拦截器来验证你的示例,你会发现 name 属性没有被设置,这是因为参数无法到达操作。
我们将保留 HelloWorldAction.java、web.xml、HelloWorld.jsp 和 index.jsp 文件,因为它们已在 Examples 章节中创建,但让我们修改 struts.xml 文件以添加一个拦截器,如下所示:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<interceptor-ref name = "params"/>
<interceptor-ref name = "timer" />
<result name = "success">/HelloWorld.jsp</result>
</action>
</package>
</struts>
右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后再将此 WAR 部署到 Tomcat 的 Web 应用目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将产生以下屏幕:
现在在给定的文本框中输入任意单词并单击马上问候按钮来执行已定义的操作。现在,如果你将检查生成的日志,你会发现以下文本:
INFO: Server startup in 3539 ms
27/08/2011 8:40:53 PM
com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
INFO: Executed action [//hello!execute] took 109 ms.
此处底行是由 timer 拦截器生成的,其表明操作总共花费了 109 毫秒才得以执行。
Create Custom Interceptors
在应用程序中使用自定义拦截器是提供跨切割应用程序功能的优雅方式。创建自定义拦截器很容易;需要扩展的接口是以下 Interceptor 接口:
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation)
throws Exception;
}
顾名思义,init() 方法提供一种方法来初始化拦截器,而 destroy() 方法则提供一种拦截器清理功能。与操作不同,拦截器将在所有请求中重复使用,且需要线程安全,尤其是 intercept() 方法。
ActionInvocation 对象提供对运行时环境的访问。它允许访问操作本身以及用于调用操作并确定是否已调用操作的方法。
如果你不需要初始化或清理代码,则可以扩展 AbstractInterceptor 类。它提供了 init() 和 destroy() 方法的默认无效操作实现。
Create Interceptor Class
让我们在 Java Resources > src 文件夹中创建以下 MyInterceptor.java:
package com.tutorialspoint.struts2;
import java.util.*;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation invocation)throws Exception {
/* let us do some pre-processing */
String output = "Pre-Processing";
System.out.println(output);
/* let us call action or next interceptor */
String result = invocation.invoke();
/* let us do some post-processing */
output = "Post-Processing";
System.out.println(output);
return result;
}
}
如你所见,实际操作将通过调用 invocation.invoke() 由拦截器执行。因此,你可以根据你的要求进行某些预处理和后处理。
框架本身通过对 ActionInvocation 对象的 invoke() 进行首次调用来启动该进程。每次调用 invoke() 时,ActionInvocation 都会咨询其状态并执行随之而来的任何一个拦截器。当调用所有配置的拦截器后,invoke() 方法将导致执行操作本身。
下图通过请求流程显示了相同概念 -
Create Action Class
让我们在 Java Resources > src 中使用包名 com.tutorialspoint.struts2 创建一个 java 文件 HelloWorldAction.java ,内容如下。
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String name;
public String execute() throws Exception {
System.out.println("Inside action....");
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这是一个我们在之前的示例中见过的类。我们为“名称”属性有标准的 getter 和 setter 方法,还有一个返回字符串“成功”的执行方法。
Create a View
让我们在 Eclipse 项目的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp 。
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World, <s:property value = "name"/>
</body>
</html>
Create Main Page
我们还需要在 WebContent 文件夹中创建 index.jsp 。这个文件将作为初始操作 URL,用户可以单击它来告诉 Struts 2 框架调用 HelloWorldAction 类的定义方法,并呈现 HelloWorld.jsp 视图。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World From Struts2</h1>
<form action = "hello">
<label for = "name">Please enter your name</label><br/>
<input type = "text" name = "name"/>
<input type = "submit" value = "Say Hello"/>
</form>
</body>
</html>
在以上视图文件中定义的操作 hello 将使用 struts.xml 文件映射到 HelloWorldAction 类及其执行方法。
Configuration Files
现在,我们需要注册我们的拦截器,然后调用它,就像我们在前一个示例中调用缺省拦截器一样。要注册一个新定义的拦截器,需要将 <interceptors>…</interceptors> 标签直接放在 struts.xml 文件的 <package> 标签下面。你可以跳过为缺省拦截器执行这一步骤,就像我们在前一个示例中所做的那样。但此处让我们注册并使用它,如下所示 -
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<interceptors>
<interceptor name = "myinterceptor"
class = "com.tutorialspoint.struts2.MyInterceptor" />
</interceptors>
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<interceptor-ref name = "params"/>
<interceptor-ref name = "myinterceptor" />
<result name = "success">/HelloWorld.jsp</result>
</action>
</package>
</struts>
需要注意的是,你可以在 <package> 标签内注册多个拦截器,同时你可以在 <action> 标签内调用多个拦截器。你可以使用不同的操作调用同一个拦截器。
需要在 WebContent 下面的 WEB-INF 文件夹下创建 web.xml 文件,如下所示 -
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后再将此 WAR 部署到 Tomcat 的 Web 应用目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将产生以下屏幕:
现在,在给定文本框中输入任意单词,然后单击“Say Hello”按钮以执行定义的操作。现在,如果你检查生成的日志,你将会在底部找到以下文本 -
Pre-Processing
Inside action....
Post-Processing
Stacking Multiple Interceptors
如你所想象的,必须为每个操作配置多个拦截器会很快变得极度难以管理。因此,拦截器使用拦截器栈进行管理。以下就是一个直接来自 strutsdefault.xml 文件的示例 -
<interceptor-stack name = "basicStack">
<interceptor-ref name = "exception"/>
<interceptor-ref name = "servlet-config"/>
<interceptor-ref name = "prepare"/>
<interceptor-ref name = "checkbox"/>
<interceptor-ref name = "params"/>
<interceptor-ref name = "conversionError"/>
</interceptor-stack>
上述栈称为 basicStack ,且你可以在配置中使用它,如下所示。此配置节点放在 <package …/> 节点下面。每个 <interceptor-ref …/> 标签都引用在此当前拦截器栈之前配置的拦截器或拦截器栈。因此,在配置初始拦截器和拦截器栈时,确保所有拦截器和拦截器栈配置中的名称是唯一的非常重要。
我们已经了解了如何对操作应用拦截器,对拦截器栈应用拦截器与此没有什么不同。事实上,我们使用完全相同的标签 -
<action name = "hello" class = "com.tutorialspoint.struts2.MyAction">
<interceptor-ref name = "basicStack"/>
<result>view.jsp</result>
</action
对“basicStack”的上述注册将完全登记在 hello 操作中六个拦截器的全部赌注。需要注意的是,拦截器按照其配置的顺序执行。例如,在上述情况下,exception 将首先执行,其次是 servlet-config,依此类推。
Struts 2 - Results & Result Types
如前所述, <results> 标记在 Struts2 MVC 框架中扮演 view 的角色。此操作负责执行业务逻辑。执行业务逻辑后的下一步是使用 <results> 标记显示视图。
通常有一些导航规则附加到结果。例如,如果操作方法是验证用户,那么有三个可能的结果。
-
Successful Login
-
登录失败 - 用户名或密码不正确
-
Account Locked
在这种情况下,操作方法将配置三个可能的结果字符串和三个不同的视图来呈现结果。我们在前面的示例中已经看到过这一点。
但是,Struts2 并没有将您绑定到使用 JSP 作为视图技术。毕竟,MVC 范例的全部目的是保持层分离和高度可配置。例如,对于 Web2.0 客户端,您可能想要返回 XML 或 JSON 作为输出。在这种情况下,您可以创建用于 XML 或 JSON 的新结果类型并实现此目的。
Struts 带有一些预定义的 result types 和我们已经看到过的 dispatcher 的默认结果类型,用于分发到 JSP 页面。Struts 允许您使用其他标记语言作为视图技术来呈现结果,流行的选择包括 Velocity, Freemaker, XSLT 和 Tiles 。
The Dispatcher Result Type
dispatcher 结果类型是默认类型,如果未指定其他结果类型,将使用此类型。它用于转发到服务器上的 servlet、JSP、HTML 页面等。它使用 RequestDispatcher.forward() 方法。
我们在前面的示例中看到了“简写”版本,其中我们提供了一个 JSP 路径作为结果标记的主体。
<result name = "success">
/HelloWorld.jsp
</result>
我们还可以在 <result…> 元素内使用 <param name = "location"> 标记指定 JSP 文件,如下所示:
<result name = "success" type = "dispatcher">
<param name = "location">
/HelloWorld.jsp
</param >
</result>
我们还可以提供一个 parse 参数,默认情况下为 true。parse 参数确定是否为 OGNL 表达式解析 location 参数。
The FreeMaker Result Type
在此示例中,我们将看到如何使用 FreeMaker 作为视图技术。Freemaker 是一个流行的模板引擎,用于使用预定义模板生成输出。现在,让我们创建一个名为 hello.fm 的 Freemaker 模板文件,内容如下:
Hello World ${name}
上述文件是一个模板,其中 name 是一个参数,它将从外部使用已定义的动作传递进来。您将把此文件保持在 CLASSPATH 中。
接下来,让我们修改 struts.xml 以指定结果,如下所示:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success" type = "freemarker">
<param name = "location">/hello.fm</param>
</result>
</action>
</package>
</struts>
让我们保留我们在示例章节中创建的 HelloWorldAction.java、HelloWorldAction.jsp 和 index.jsp 文件。
现在右键单击项目名称,然后单击 Export > WAR File 以创建 War 文件。
然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕。
输入一个值“Struts2”并提交页面。您应该看到下一页。
如您所见,这与 JSP 视图完全相同,只不过我们不必绑定到使用 JSP 作为视图技术。在此示例中,我们使用了 Freemaker。
The Redirect Result Type
redirect 结果类型调用标准 response.sendRedirect() 方法,导致浏览器对给定位置创建新的请求。
我们可以提供 <result…> 元素 body 中或 <param name = "location"> 元素中的一个位置。Redirect 也支持 parse 参数。以下是一个使用 XML 配置的样例 −
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success" type = "redirect">
<param name = "location">
/NewWorld.jsp
</param >
</result>
</action>
因此,只需修改您的 struts.xml 文件,以按上述方式定义重定向类型,并创建一个新的文件 NewWorld.jpg,当 hello 操作返回成功时您将被重定向到该文件。您可以检查 Struts 2 Redirect Action 样例以获得更深入的了解。
Struts 2 - Value Stack/OGNL
The Value Stack
值堆栈是一组包含以下对象的对象,这些对象按照给定的顺序排列 −
Sr.No |
Objects & Description |
1 |
Temporary Objects 在页面执行期间创建了各种临时对象。例如,JSP 标记中反复循环集合的当前迭代值。 |
2 |
The Model Object 如果您在 struts 应用程序中使用模型对象,则当前模型对象将被放置在值堆栈上的操作之前。 |
3 |
The Action Object 这将是当前正在执行的操作对象。 |
4 |
Named Objects 这些对象包括 #application、#session、#request、#attr 和 #parameters,并且它们对应于相应的 Servlet 作用域。 |
可以通过为 JSP、Velocity 或 Freemarker 提供的标记访问值堆栈。我们将使用各种标记,在单独的章节中学习如何使用这些标记来获取和设置 struts 2.0 值堆栈。您可以按如下方式在操作中获取 ValueStack 对象 −
ActionContext.getContext().getValueStack()
一旦您获得 ValueStack 对象,就可以使用以下方法来操作该对象 −
Sr.No |
ValueStack Methods & Description |
1 |
Object findValue(String expr) 通过针对堆栈中的给定表达式进行求值以查找一个值(采用默认搜索顺序)。 |
2 |
CompoundRoot getRoot() 获取容纳在堆栈上推送的对象的 CompoundRoot。 |
3 |
Object peek() 获取堆栈顶部的对象,而不更改堆栈。 |
4 |
Object pop() 获取堆栈顶部的对象并将其从堆栈中移除。 |
5 |
void push(Object o) 将该对象放置到堆栈的顶部。 |
6 |
void set(String key, Object o) 使用给定的键在堆栈上设置一个对象,以便可通过 findValue(key,…) 检索到该对象。 |
7 |
void setDefaultType(Class defaultType) 设置获取值时未提供类型的默认类型。 |
8 |
void setValue(String expr, Object value) 尝试使用默认搜索顺序,利用给定的表达式设置堆栈中某个 bean 的一个属性。 |
9 |
int size() 获取堆栈中的对象数。 |
The OGNL
Object-Graph Navigation Language (OGNL)是一种功能强大的表达式语言,用于引用和操作 ValueStack 上的数据。OGNL 还帮助进行数据传输和类型转换。
OGNL 非常类似于 JSP 表达式语言。OGNL 以在上下文中拥有 root 或默认对象的想法为基础。可以使用井号符号(即标记符号)来引用默认对象或 root 对象的属性。
如前所述,OGNL 基于上下文,而 Struts 会构建一个 ActionContext 映射以用于 OGNL。ActionContext 映射包含以下内容:
-
Application − 应用范围变量
-
Session − 会话范围变量
-
Root / value stack − 此处存储所有操作变量
-
Request − 请求范围变量
-
Parameters − Request parameters
-
Atributes − 存储在页面、请求、会话和应用范围中的属性
了解 Action 对象始终在值栈中可用非常重要。所以,如果您的 Action 对象具有属性 “x” 和 “y” ,您可以随时使用它们。
ActionContext 中的对象使用井号符号进行引用,但是,可以直接引用值栈中的对象。
例如,如果 employee 是一个操作类的属性,那么它可以按如下方式引用:
<s:property value = "name"/>
代替
<s:property value = "#name"/>
如果您在会话中有一个名为“login”的属性,您可以按如下方式检索它:
<s:property value = "#session.login"/>
OGNL 还支持处理集合,即 Map、List 和 Set。例如,要显示颜色下拉列表,您可以执行以下操作:
<s:select name = "color" list = "{'red','yellow','green'}" />
OGNL 表达式巧妙地将“red”、“yellow”、“green”解释为颜色,并基于此构建了一个列表。
在后续章节中研究不同标记时,OGNL 表达式将被广泛使用。因此,与其孤立地查看它们,不如让我们在表单标记/控制标记/数据标记和 Ajax 标记部分中使用一些示例来查看它们。
ValueStack/OGNL Example
Create Action
让我们考虑以下操作类,在该类中我们将访问 valueStack,然后设置一些键,我们将在我们的视图中使用 OGNL 来访问这些键,即 JSP 页面。
package com.tutorialspoint.struts2;
import java.util.*;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String name;
public String execute() throws Exception {
ValueStack stack = ActionContext.getContext().getValueStack();
Map<String, Object> context = new HashMap<String, Object>();
context.put("key1", new String("This is key1"));
context.put("key2", new String("This is key2"));
stack.push(context);
System.out.println("Size of the valueStack: " + stack.size());
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
实际上,执行 Struts 2 时会将操作添加到 valueStack 的顶部。所以,将内容放入值栈的通常方式是为值添加到您的操作类添加 getter/setter,然后使用 <s:property> 标记来访问值。但是,我将向您展示 ActionContext 和 ValueStack 在 struts 中如何工作的。
Create Views
让我们在 eclipse 项目中的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp 。如果执行返回成功,则该视图将被显示:
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
Entered value : <s:property value = "name"/><br/>
Value of key 1 : <s:property value = "key1" /><br/>
Value of key 2 : <s:property value = "key2" /> <br/>
</body>
</html>
我们还需要在 WebContent 文件夹中创建 index.jsp ,其内容如下:
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World From Struts2</h1>
<form action = "hello">
<label for = "name">Please enter your name</label><br/>
<input type = "text" name = "name"/>
<input type = "submit" value = "Say Hello"/>
</form>
</body>
</html>
Configuration Files
以下为 struts.xml 文件的内容 −
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
</action>
</package>
</struts>
以下是 web.xml 文件的内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
右键点击项目名称并点击 Export > WAR File 以创建一个 War 文件。然后将此 WAR 部署到 Tomcat 的 webapps 目录中。
最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕
现在在给定的文本框中输入任何单词并点击“Say Hello”按钮以执行定义的操作。现在,如果你将检查引发的日志,你将会在底部找到以下文本 −
Size of the valueStack: 3
这将显示以下屏幕,该屏幕将显示你输入的任何值以及我们在 ValueStack 上放置的 key1 和 key2 的值。
Struts 2 - File Uploads
Struts 2 框架提供内置的支持来使用“HTML 中基于表单的文件上传”处理文件上传。当上传一个文件时,它通常会存储在一个临时目录中,并应该由你的 Action 类处理或移动到一个永久目录中以确保数据不会丢失。
Note - 服务器可能会实施禁止写入临时目录和你 Web 应用程序所属目录之外的目录的安全策略。
Struts 中的文件上传可以通过一个称为 FileUpload 的预定义拦截器来实现,可以通过类 org.apache.struts2.interceptor.FileUploadInterceptor 获得,并作为 defaultStack 的一部分包括其中。仍然可以在你自己的 struts.xml 中使用它来设置各种参数,如下所示。
Create View Files
让我们从创建我们的视图开始,该视图需要浏览和上传一个选定的文件。所以让我们创建一个 index.jsp ,带一个允许用户上传文件的简单 HTML 上传表单 −
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form action = "upload" method = "post" enctype = "multipart/form-data">
<label for = "myFile">Upload your file</label>
<input type = "file" name = "myFile" />
<input type = "submit" value = "Upload"/>
</form>
</body>
</html>
在上面的示例中有几点值得注意。首先,表单的 enctype 设置为 multipart/form-data 。应该设置它以使文件上传拦截器成功处理文件上传。另一值得注意的是表单的 action 方法 upload 和文件上传字段的名称 - myFile 。我们需要这些信息来创建 action 方法和 struts 配置。
接下来,让我们创建一个 success.jsp 以显示在文件上传成功后我们的结果。
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>File Upload Success</title>
</head>
<body>
You have successfully uploaded <s:property value = "myFileFileName"/>
</body>
</html>
以下将是 error.jsp 的结果文件,如果在上传文件时有一些错误 −
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>File Upload Error</title>
</head>
<body>
There has been an error in uploading the file.
</body>
</html>
Create Action Class
接下来,让我们创建称为 uploadFile.java 的 Java 类,它将负责上传文件并将该文件存储在一个安全的位置中 −
package com.tutorialspoint.struts2;
import java.io.File;
import org.apache.commons.io.FileUtils;
import java.io.IOException;
import com.opensymphony.xwork2.ActionSupport;
public class uploadFile extends ActionSupport {
private File myFile;
private String myFileContentType;
private String myFileFileName;
private String destPath;
public String execute() {
/* Copy file to a safe location */
destPath = "C:/apache-tomcat-6.0.33/work/";
try {
System.out.println("Src File name: " + myFile);
System.out.println("Dst File name: " + myFileFileName);
File destFile = new File(destPath, myFileFileName);
FileUtils.copyFile(myFile, destFile);
} catch(IOException e) {
e.printStackTrace();
return ERROR;
}
return SUCCESS;
}
public File getMyFile() {
return myFile;
}
public void setMyFile(File myFile) {
this.myFile = myFile;
}
public String getMyFileContentType() {
return myFileContentType;
}
public void setMyFileContentType(String myFileContentType) {
this.myFileContentType = myFileContentType;
}
public String getMyFileFileName() {
return myFileFileName;
}
public void setMyFileFileName(String myFileFileName) {
this.myFileFileName = myFileFileName;
}
}
uploadFile.java 是一个非常简单的类。需要注意的重要事情是 FileUpload 拦截器和 Parameters 拦截器为我们完成了所有繁重的任务。
FileUpload 拦截器默认情况下为你提供三个参数。它们按照以下模式命名 −
-
*[你的文件名参数] * - 这是用户上传的实际文件。在这个示例中它将是 “myFile”
-
[your file name parameter]ContentType - 这是上传文件的类型。在这个示例中它将是 “myFileContentType”
-
[your file name parameter]FileName - 这是上传文件的名称。在这个示例中它将是 “myFIleFileName”
这三个参数可供我们使用,这要归功于 Struts 拦截器。我们必须做的就是用正确的名称在我们的 Action 类中创建三个参数,这些变量将自动为我们自动连接。因此,在上面的示例中,我们有三个参数,一个行动方法,如果一切都好,它会返回“成功”,否则它将返回“错误”。
Configuration Files
以下是控制文件上传过程的 Struts2 配置属性:
Sr.No |
Properties & Description |
1 |
struts.multipart.maxSize 作为文件上传接受的文件的最大大小(以字节为单位)。默认值为 250M。 |
2 |
struts.multipart.parser 用于上传多部件表单的库。默认值为 jakarta |
3 |
struts.multipart.saveDir 存储临时文件的位置。默认值为 javax.servlet.context.tempdir。 |
为了更改这些设置中的任何一个,您可以在应用程序的 struts.xml 文件中使用 constant 标记,如我所做的那样,将上传的文件的最大大小更改为。
让我们将我们的 struts.xml 设置为以下内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<constant name = "struts.multipart.maxSize" value = "1000000" />
<package name = "helloworld" extends = "struts-default">
<action name = "upload" class = "com.tutorialspoint.struts2.uploadFile">
<result name = "success">/success.jsp</result>
<result name = "error">/error.jsp</result>
</action>
</package>
</struts>
由于 FileUpload 拦截器是默认的拦截器堆栈的一部分,因此我们不需要明确配置它。但是,您可以在 <action> 中添加 <interceptor-ref> 标记。FileUpload 拦截器采用两个参数 (a) maximumSize 和 (b) allowedTypes 。
maximumSize 参数设置允许的最大文件大小(默认大小约为 2MB)。allowedTypes 参数是以逗号分隔的已接受内容(MIME)类型的列表,如下所示:
<action name = "upload" class = "com.tutorialspoint.struts2.uploadFile">
<interceptor-ref name = "basicStack">
<interceptor-ref name = "fileUpload">
<param name = "allowedTypes">image/jpeg,image/gif</param>
</interceptor-ref>
<result name = "success">/success.jsp</result>
<result name = "error">/error.jsp</result>
</action>
以下是 web.xml 文件的内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
现在右键单击项目名称,然后单击 Export > WAR File 以下创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/upload.jsp 。这将生成以下屏幕:
现在使用“浏览”按钮选择文件“Contacts.txt”,然后单击上传按钮,该按钮将在您的服务上上传文件,您应该会看到下一页。您可以检查上传的文件是否已保存在 C:\apache-tomcat-6.0.33\work 中。
请注意,FileUpload 拦截器会自动删除上传的文件,因此您必须在文件被删除之前以编程方式将上传的文件保存在某个位置。
Error Messages
fileUplaod 拦截器使用几个默认的错误消息键:
Sr.No |
错误消息键和描述 |
1 |
struts.messages.error.uploading 文件无法上传时发生的常规错误。 |
2 |
struts.messages.error.file.too.large 当上传的文件太大(由 maximumSize 指定)时发生。 |
3 |
struts.messages.error.content.type.not.allowed 当上传的文件与指定的预期内容类型不符时发生。 |
您可以在 WebContent/WEB-INF/classes/messages.properties 资源文件中覆盖这些消息的文本。
Struts 2 - Database Access
本节将指导您使用 Struts 2 以简单的步骤访问数据库。Struts 是 MVC 框架,而不是数据库框架,但它为 JPA/Hibernate 集成提供了出色的支持。我们将在后面的章节中了解 Hibernate 集成,但在本节中我们将使用普通的旧 JDBC 访问数据库。
本节的第一步是设置并启动我们的数据库。我使用 MySQL 作为本示例中的数据库。我在计算机上安装了 MySQL,并创建了一个名为 “struts_tutorial” 的新数据库。我创建了一个名为 login 的表,并在其中填充一些值。以下是创建和填充表的脚本。
我的 MYSQL 数据库的默认用户名是 “root”,密码是 “root123”
CREATE TABLE `struts_tutorial`.`login` (
`user` VARCHAR( 10 ) NOT NULL ,
`password` VARCHAR( 10 ) NOT NULL ,
`name` VARCHAR( 20 ) NOT NULL ,
PRIMARY KEY ( `user` )
) ENGINE = InnoDB;
INSERT INTO `struts_tutorial`.`login` (`user`, `password`, `name`)
VALUES ('scott', 'navy', 'Scott Burgemott');
下一步是下载 MySQL Connector JAR 文件,并将此文件放置在项目的 WEB-INF\lib 文件夹中。完成此操作后,我们现在可以创建 Action 类。
Create Action
Action 类具有与数据库表中的列对应的属性。我们有 user, password 和 name 作为字符串属性。在 Action 方法中,我们使用用户和密码参数检查用户是否存在,如果是,我们在下一个屏幕中显示用户名。
如果用户输入了错误信息,我们将他们再次发送到登录屏幕。
以下是 LoginAction.java 文件的内容:
package com.tutorialspoint.struts2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String user;
private String password;
private String name;
public String execute() {
String ret = ERROR;
Connection conn = null;
try {
String URL = "jdbc:mysql://localhost/struts_tutorial";
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(URL, "root", "root123");
String sql = "SELECT name FROM login WHERE";
sql+=" user = ? AND password = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, user);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
name = rs.getString(1);
ret = SUCCESS;
}
} catch (Exception e) {
ret = ERROR;
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
}
}
}
return ret;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Create Main Page
现在,让我们创建一个 JSP 文件 index.jsp 来收集用户名和密码。此用户名和密码将与数据库进行比对。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Login</title>
</head>
<body>
<form action = "loginaction" method = "post">
User:<br/><input type = "text" name = "user"/><br/>
Password:<br/><input type = "password" name = "password"/><br/>
<input type = "submit" value = "Login"/>
</form>
</body>
</html>
Create Views
现在让我们创建 success.jsp 文件,该文件将在 Action 返回成功时调用,但如果 Action 返回错误,我们将有另一个视图文件。
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Successful Login</title>
</head>
<body>
Hello World, <s:property value = "name"/>
</body>
</html>
在 Action 返回错误时,以下是视图文件 error.jsp 。
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Invalid User Name or Password</title>
</head>
<body>
Wrong user name or password provided.
</body>
</html>
Configuration Files
最后,让我们使用 struts.xml 配置文件将所有内容组合在一起,如下所示:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "loginaction"
class = "com.tutorialspoint.struts2.LoginAction"
method = "execute">
<result name = "success">/success.jsp</result>
<result name = "error">/error.jsp</result>
</action>
</package>
</struts>
以下是 web.xml 文件的内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕:
输入错误的用户名和密码。您应该会看到下一页。
现在输入 scott 作为用户名,输入 navy 作为密码。您应该会看到下一页。
Struts 2 - Sending Email
本章解释了如何使用 Struts2 应用程序发送电子邮件。
对于此练习,您需要从 JavaMail API 1.4.4 下载并安装 mail.jar,然后将 mail.jar 文件放到 WEB-INF\lib 文件夹中,然后按照创建动作、视图和配置文件的标准步骤进行操作。
Create Action
下一步是创建一个负责发送电子邮件的动作方法。让我们创建一个名为 Emailer.java 的新类,其中包含以下内容。
package com.tutorialspoint.struts2;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.opensymphony.xwork2.ActionSupport;
public class Emailer extends ActionSupport {
private String from;
private String password;
private String to;
private String subject;
private String body;
static Properties properties = new Properties();
static {
properties.put("mail.smtp.host", "smtp.gmail.com");
properties.put("mail.smtp.socketFactory.port", "465");
properties.put("mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.port", "465");
}
public String execute() {
String ret = SUCCESS;
try {
Session session = Session.getDefaultInstance(properties,
new javax.mail.Authenticator() {
protected PasswordAuthentication
getPasswordAuthentication() {
return new
PasswordAuthentication(from, password);
}
}
);
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to));
message.setSubject(subject);
message.setText(body);
Transport.send(message);
} catch(Exception e) {
ret = ERROR;
e.printStackTrace();
}
return ret;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public static Properties getProperties() {
return properties;
}
public static void setProperties(Properties properties) {
Emailer.properties = properties;
}
}
如上方的源代码所示, Emailer.java 具有与下面所提供的 email.jsp 页面中的表单属性相对应的属性。这些属性为 −
-
From − 发件人的电子邮件地址。由于我们正在使用 Google 的 SMTP,因此我们需要一个有效的 gtalk ID
-
Password − 以上帐号的密码
-
To − 电子邮件发送给谁?
-
Subject − 电子邮件主题
-
Body − 实际电子邮件正文
我们尚未考虑以上字段的任何验证,验证将在下一章中添加。现在,我们来看看 execute() 方法。execute() 方法使用 javax Mail 库来使用提供的参数发送电子邮件。如果邮件已成功发送,则该动作返回 SUCCESS,否则返回 ERROR。
Create Main Page
让我们编写 JSP 主页面文件 index.jsp ,这将用于收集上面提到的与电子邮件相关的信息 −
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Email Form</title>
</head>
<body>
<em>The form below uses Google's SMTP server.
So you need to enter a gmail username and password
</em>
<form action = "emailer" method = "post">
<label for = "from">From</label><br/>
<input type = "text" name = "from"/><br/>
<label for = "password">Password</label><br/>
<input type = "password" name = "password"/><br/>
<label for = "to">To</label><br/>
<input type = "text" name = "to"/><br/>
<label for = "subject">Subject</label><br/>
<input type = "text" name = "subject"/><br/>
<label for = "body">Body</label><br/>
<input type = "text" name = "body"/><br/>
<input type = "submit" value = "Send Email"/>
</form>
</body>
</html>
Create Views
我们将使用 JSP 文件 success.jsp ,在该动作返回 SUCCESS 时调用,但如果动作返回 ERROR,我们将有另一个视图文件。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Email Success</title>
</head>
<body>
Your email to <s:property value = "to"/> was sent successfully.
</body>
</html>
在 Action 返回错误时,以下是视图文件 error.jsp 。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Email Error</title>
</head>
<body>
There is a problem sending your email to <s:property value = "to"/>.
</body>
</html>
Configuration Files
现在来使用 Struts.xml 配置文件将所有内容放在一起,如下所示 -
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "emailer"
class = "com.tutorialspoint.struts2.Emailer"
method = "execute">
<result name = "success">/success.jsp</result>
<result name = "error">/error.jsp</result>
</action>
</package>
</struts>
以下是 web.xml 文件的内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕:
输入所需信息,然后单击 Send Email 按钮。如果一切顺利,您应该会看到以下页面。
Struts 2 - Validations Framework
在本章中,我们将更深入地了解 Struts 验证框架。在 Struts 核心,我们有验证框架,它帮助应用程序运行规则,以便在执行操作方法之前执行验证。
客户端侧验证通常使用 Javascript 实现。但是,不应该只依赖于客户端验证。最佳实践表明,验证应该在应用程序框架的所有级别引入。现在让我们来看看向 Struts 项目添加验证的两种方法。
在这里,我们取一个 Employee 的示例,它的名称和年龄应该使用一个简单页面捕获,并且我们对这两个验证进行设置,以确保用户始终输入名称和年龄,且该年龄应在 28 到 65 之间。
让我们从示例的主要 JSP 页面开始。
Create Main Page
让我们编写主页面 JSP 文件 index.jsp ,它将用于收集上述与员工相关的信息。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Employee Form</title>
</head>
<body>
<s:form action = "empinfo" method = "post">
<s:textfield name = "name" label = "Name" size = "20" />
<s:textfield name = "age" label = "Age" size = "20" />
<s:submit name = "submit" label = "Submit" align="center" />
</s:form>
</body>
</html>
index.jsp 利用 Struts 标记,我们尚未介绍,但我们在与标记相关的章节中将会学习。但就目前而言,我们假设 s:textfield 标记打印了一个输入域,并且 s:submit 打印了一个提交按钮。我们对每个标记都使用了 label 属性,从而为每个标记创建了标签。
Create Views
我们将使用 JSP 文件 success.jsp,它将在定义的动作返回 SUCESS 时被调用。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Success</title>
</head>
<body>
Employee Information is captured successfully.
</body>
</html>
Create Action
因此,让我们定义一个小型动作类 Employee ,然后添加一个名为 validate() 的方法,如下所示 Employee.java 文件。确保你的操作类扩展 ActionSupport 类,否则你的验证方法将不会被执行。
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class Employee extends ActionSupport {
private String name;
private int age;
public String execute() {
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void validate() {
if (name == null || name.trim().equals("")) {
addFieldError("name","The name is required");
}
if (age < 28 || age > 65) {
addFieldError("age","Age must be in between 28 and 65");
}
}
}
如上面的示例所示,验证方法检查“名称”字段是否具有值。如果没有提供值,我们添加一个带有自定义错误消息的“名称”字段的错误域。其次,我们检查为“年龄”字段输入的值是否介于 28 和 65 之间,如果不满足此条件,我们在已验证字段之上添加一个错误。
Configuration Files
最后,让我们将所有内容组合在一起,使用 struts.xml 配置文件,如下所示 -
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "empinfo"
class = "com.tutorialspoint.struts2.Employee"
method = "execute">
<result name = "input">/index.jsp</result>
<result name = "success">/success.jsp</result>
</action>
</package>
</struts>
以下是 web.xml 文件的内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕:
现在不要输入任何必需信息,只需点击 Submit 按钮即可。您将看到以下结果 -
输入必需信息,但输入一个错误的 From 域,假设名称为“测试”,年龄为 30,最后点击 Submit 按钮。您将看到以下结果 -
How this Validation Works?
当用户按下提交按钮时,Struts 2 将自动执行验证方法,如果该方法中列出的任何 “if” 语句为真,Struts 2 将调用其 addFieldError 方法。如果添加了任何错误,Struts 2 将不会继续调用执行方法。相反,Struts 2 框架将返回 input 作为调用动作的结果。
因此,当验证失败并且 Struts 2 返回 input 时,Struts 2 框架将重新显示 index.jsp 文件。由于我们使用了 Struts 2 表单标记,Struts 2 会自动将错误信息添加到表单域之上。
这些错误消息是我们指定的 addFieldError 方法调用中指定的内容。addFieldError 方法有两个参数。第一,是错误适用的 form 域名称,第二,是在该表单域上方显示的错误消息。
addFieldError("name","The name is required");
要处理 input 的返回值,我们需要在 struts.xml 中的操作节点中添加以下结果。
<result name = "input">/index.jsp</result>
XML Based Validation
第二种验证方法是将 xml 文件放在动作类的旁边。基于 Struts2 XML 的验证提供更多的验证选项,如电子邮件验证、整数范围验证、表单验证域、表达式验证、regex 验证、必需验证、必需字符串验证、字符串长度验证等等。
xml 文件需要命名为 '[action-class]'-validation.xml 。因此,在我们的示例中,我们创建了一个名为 Employee-validation.xml 的文件,内容如下 -
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name = "name">
<field-validator type = "required">
<message>
The name is required.
</message>
</field-validator>
</field>
<field name = "age">
<field-validator type = "int">
<param name = "min">29</param>
<param name = "max">64</param>
<message>
Age must be in between 28 and 65
</message>
</field-validator>
</field>
</validators>
上述 XML 文件理想情况下将保存在你的 CLASSPATH 中,同时还有类文件。让我们使用以下 validate() 方法定义我们的 Employee 操作类 -
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class Employee extends ActionSupport{
private String name;
private int age;
public String execute() {
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
其余的设置将与之前的示例保持一致,现在如果你运行应用程序,它将产生与我们之前示例中接收相同的结果。
将 xml 文件用于存储配置的优点是,它允许将验证与应用程序代码分开。你可以让一个开发人员编写代码,让业务分析员创建验证 xml 文件。另一件需要注意的事情是默认可用的验证类型。
在 Struts 中还附带了更多的验证器。常见的验证器包括日期验证器、正则验证器和字符串长度验证器。请查看以下链接了解更多详细信息 Struts - XML Based Validators 。
Struts2 - Localization, internationalization (i18n)
国际化 (i18n) 是规划和实施产品和服务以便它们可以轻松适应特定当地语言和文化的过程,这一过程称为本地化。国际化流程称为翻译或本地化支持。
国际化缩写为 i18n ,因为该单词以字母 “i” 开头,以 “n” 结尾,并且在第一个 i 和最后一个 n 之间有 18 个字符。
Struts2 提供本地化,即,通过以下位置的资源包、拦截器和标签库来提供国际化 (i18n) 支持 −
-
The UI Tags
-
Messages and Errors.
-
Within action classes.
Resource Bundles
Struts2 使用资源包为 Web 应用程序的用户提供多种语言和区域设置选项。您不必担心用不同语言编写页面。您所要做的就是为所需的每种语言创建一个资源包。资源包将包含在其用户语言中的标题、消息和其他文本。资源包是包含应用程序默认语言的关键/值对的文件。
资源文件的命名格式最简单:
bundlename_language_country.properties
在此处, bundlename 可以是 ActionClass、Interface、SuperClass、Model、Package、全局资源属性。下一部分 language_country 代表国家/地区语言环境,例如,西班牙语(西班牙)语言环境由 es_ES 表示,英语(美国)语言环境由 en_US 等表示,其中您可以跳过国家/地区部分(这是可选的)。
当您按其键引用一个消息元素时,Struts 框架按以下顺序搜索相应的讯息包 −
-
ActionClass.properties
-
Interface.properties
-
SuperClass.properties
-
model.properties
-
package.properties
-
struts.properties
-
global.properties
要使用多种语言进行开发应用程序,您应该维护对应于那些语言/区域设置的多个属性文件,并根据关键/值对定义所有内容。
例如,如果你准备为美式英语(默认)、西班牙语和法语开发你的应用程序,那么你将必须创建三个属性文件。这里我仅使用 global.properties 文件,但你也可以利用不同的属性文件来分离不同类型的消息。
-
global.properties − 默认情况下将应用英语(美国)。
-
global_fr.properties − 这将用于 Fran ch 地区设置。
-
global_es.properties − 这将用于西班牙语地区设置。
Access the messages
有许多种方法可以访问消息资源,包括 getText、text 标记、UI 标记的 key 属性以及 i18n 标记。我们简要了解下它们−
如需显示 i18n 文本,请在属性标记或任何其他标记(如 UI 标记)中调用 getText ,如下所示−
<s:property value = "getText('some.key')" />
text tag 从默认资源包(即 struts.properties)中检索一条消息
<s:text name = "some.key" />
i18n tag 将任意资源包推送到值栈。i18n 标记作用域范围内的其他标记可显示该资源包中的消息−
<s:i18n name = "some.package.bundle">
<s:text name = "some.key" />
</s:i18n>
大多数 UI 标记的 key 属性可用于从资源包生成消息−
<s:textfield key = "some.key" name = "textfieldName"/>
Localization Example
让我们把目标设定为从前一章节中用多种语言创建 index.jsp 。相同的文件将按如下方式编写−
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Employee Form with Multilingual Support</title>
</head>
<body>
<h1><s:text name = "global.heading"/></h1>
<s:url id = "indexEN" namespace="/" action = "locale" >
<s:param name = "request_locale" >en</s:param>
</s:url>
<s:url id = "indexES" namespace="/" action = "locale" >
<s:param name = "request_locale" >es</s:param>
</s:url>
<s:url id = "indexFR" namespace="/" action = "locale" >
<s:param name = "request_locale" >fr</s:param>
</s:url>
<s:a href="%{indexEN}" >English</s:a>
<s:a href="%{indexES}" >Spanish</s:a>
<s:a href="%{indexFR}" >France</s:a>
<s:form action = "empinfo" method = "post" namespace = "/">
<s:textfield name = "name" key = "global.name" size = "20" />
<s:textfield name = "age" key = "global.age" size = "20" />
<s:submit name = "submit" key = "global.submit" />
</s:form>
</body>
</html>
我们将创建 success.jsp 文件,在已定义的操作返回 SUCCESS 的情况下,将会调用该文件。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Success</title>
</head>
<body>
<s:property value = "getText('global.success')" />
</body>
</html>
在这里,我们需要创建以下两个操作。(a) 第一个操作 (a) 负责处理地区设置并显示具有不同语言的相同 index.jsp 文件 (b) 另一个操作负责处理提交表单本身。两个操作都将返回 SUCCESS,但我们将根据返回的值采取不同的操作,因为两个操作的目的不同
Action to take care of Locale
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class Locale extends ActionSupport {
public String execute() {
return SUCCESS;
}
}
Action To Submit The Form
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class Employee extends ActionSupport{
private String name;
private int age;
public String execute() {
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
现在让我们创建以下三个 global.properties 文件,并将其放入 CLASSPATH 中 −
global.properties
global.name = Name
global.age = Age
global.submit = Submit
global.heading = Select Locale
global.success = Successfully authenticated
global_fr.properties
global.name = Nom d'utilisateur
global.age = l'âge
global.submit = Soumettre des
global.heading = Sé lectionnez Local
global.success = Authentifi é avec succès
global_es.properties
global.name = Nombre de usuario
global.age = Edad
global.submit = Presentar
global.heading = seleccionar la configuracion regional
global.success = Autenticado correctamente
我们将使用两个操作创建 struts.xml ,如下所示−
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<constant name = "struts.custom.i18n.resources" value = "global" />
<package name = "helloworld" extends = "struts-default" namespace="/">
<action name = "empinfo"
class = "com.tutorialspoint.struts2.Employee"
method = "execute">
<result name = "input">/index.jsp</result>
<result name = "success">/success.jsp</result>
</action>
<action name = "locale"
class = "com.tutorialspoint.struts2.Locale"
method = "execute">
<result name = "success">/index.jsp</result>
</action>
</package>
</struts>
以下是 web.xml 文件的内容:
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕:
现在选择任何一种语言,我们假设选择 Spanish ,它将显示以下结果−
你也可以尝试使用法语。最后,让我们尝试在我们处于西班牙语地区设置时,单击 Submit 按钮,它将显示以下屏幕−
恭喜你,现在你拥有了一个多语言网页,可以面向全球推出你的网站。
Struts 2 - Type Conversion
根据协议,HTTP 请求中的所有内容都被视为 String 。这包括数字、布尔值、整数、日期、十进制数和所有其他内容。然而,在 Struts 类中,您可拥有任何数据类型的属性。
Struts 如何自动连接您的属性?
Struts 使用各种类型转换器来完成繁重的工作。
例如,如果您在 Action 类中拥有一个整数属性,那么 Struts 将自动把请求参数转换成整数属性,而您无需进行任何操作。默认情况下,Struts 配有一些类型转换器
如果您正在使用下面列出的任何转换器,那么您不必担心 -
-
Integer, Float, Double, Decimal
-
Date and Datetime
-
Arrays and Collections
-
Enumerations
-
Boolean
-
BigDecimal
当您使用自己的数据类型时,必要时可添加自己的转换器,以让 Struts 了解如何在显示前转换那些值。考虑以下 POJO 类 Environment.java 。
package com.tutorialspoint.struts2;
public class Environment {
private String name;
public Environment(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这是一个非常简单的类,它有一个名为 name 的属性,因此此类并没有什么特别之处。让我们创建一个包含系统信息的另一个类 SystemDetails.java 。
为了执行此练习,我已将环境硬编码为“开发”并将操作系统硬编码为“Windows XP SP3”。
在实时项目中,您将从系统配置中获取此信息。
让我们看看以下操作类 -
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class SystemDetails extends ActionSupport {
private Environment environment = new Environment("Development");
private String operatingSystem = "Windows XP SP3";
public String execute() {
return SUCCESS;
}
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public String getOperatingSystem() {
return operatingSystem;
}
public void setOperatingSystem(String operatingSystem) {
this.operatingSystem = operatingSystem;
}
}
接下来,我们创建一个简单的 JSP 文件 System.jsp ,以显示环境和操作系统信息。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>System Details</title>
</head>
<body>
Environment: <s:property value = "environment"/><br/>
Operating System:<s:property value = "operatingSystem"/>
</body>
</html>
让我们通过 struts.xml 连接 system.jsp 和 SystemDetails.java 类。
SystemDetails 类有一个简单的 execute () 方法,它返回字符串“ SUCCESS ”。
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "system"
class = "com.tutorialspoint.struts2.SystemDetails"
method = "execute">
<result name = "success">/System.jsp</result>
</action>
</package>
</struts>
-
右击项目名称并单击 Export > WAR File 以创建一个 WAR 文件。
-
然后将此 WAR 部署到 Tomcat 的 webapps 目录中。
-
最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/system.action 。这将生成以下屏幕 -
上面输出有什么问题?Struts 知道如何显示和转换字符串“Windows XP SP3”和其他内置数据类型,但它不知道如何处理 Environment 类型属性。它只是简单地调用了类中 toString() 方法
为了解决这个问题,我们现在创建一个简单的 TypeConverter 然后为 Environment 类进行注册。
创建一个名为 EnvironmentConverter.java 的类,其中包含以下内容。
package com.tutorialspoint.struts2;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
public class EnvironmentConverter extends StrutsTypeConverter {
@Override
public Object convertFromString(Map context, String[] values, Class clazz) {
Environment env = new Environment(values[0]);
return env;
}
@Override
public String convertToString(Map context, Object value) {
Environment env = (Environment) value;
return env == null ? null : env.getName();
}
}
EnvironmentConverter 扩展了 StrutsTypeConverter 类,并通过覆写 convertFromString() 和 convertToString() 这两个方法,告诉 Struts 如何将 Environment 转换为 String,反之亦然。
现在让我们在应用程序中使用此转换器之前先注册此转换器。注册转换器有两种方法。
如果仅在特定操作中使用此转换器,那么您需要创建一个属性文件,该文件的名称需指定为 '[action-class]'converstion.properties 。
在本例中,我们创建一个名为 SystemDetails-converstion.properties 的文件,其中包含以下注册项:
environment = com.tutorialspoint.struts2.EnvironmentConverter
在以上示例中,“environment”是 SystemDetails.java 类中属性的名称,并且我们告诉 Struts 使用 EnvironmentConverter 来转换此属性。
但是,我们不会执行此操作。相反,我们将全局注册此转换器,以便可以在整个应用程序中使用它。为此,在 WEBINF/classes 文件夹中创建一个名为 xwork-conversion.properties 的属性文件,并包含以下行
com.tutorialspoint.struts2.Environment = \
com.tutorialspoint.struts2.EnvironmentConverter
这只是全局注册转换器,以便 Struts 在遇到类型为 Environment 的对象时可以自动执行转换。现在,如果重新编译并重新运行该程序,则你会得到更好的输出,如下所示:
显然,现在的结果会更好,这意味着我们的 Struts 转换器运行良好。
这就是你可以创建多个转换器并注册它们以根据你的需求使用的方式。
Struts 2 - Themes & Templates
在开始针对本章节的实际教程之前,让我们研究 https://struts.apache.org 提供的一些定义−
Sr.No |
Term & Description |
1 |
TAG 从 JSP、FreeMarker 或 Velocity 内部执行的一小段代码。 |
2 |
TEMPLATE 一小段代码,通常以 FreeMarker 编写,可以通过某些标记(HTML 标记)呈现。 |
3 |
THEME 一组打包在一起的模板,共同提供常用功能。 |
我还会建议通读 Struts2 Localization 章节,因为我们将再次采用相同的示例来执行练习。
在网页中使用 Struts 2 标记(例如 <s:submit…>、<s:textfield…> 等)时,Struts 2 框架会生成具有预配置样式和布局的 HTML 代码。Struts 2 附带三个内置主题−
Sr.No |
Theme & Description |
1 |
SIMPLE theme 最小主题,没有“花里胡哨”。例如,textfield 标记会呈现 HTML <input/> 标记,没有标签、验证、错误报告或任何其他格式化或功能。 |
2 |
XHTML theme 这是 Struts 2 使用的默认主题,它提供simple主题提供的所有基本功能,并添加了多项特性,例如 HTML 的标准双列表格布局、每个 HTML 的标签、验证和错误报告等。 |
3 |
CSS_XHTML theme 该主题提供simple主题提供的所有基本功能,并添加了多项特性,例如标准双列基于 CSS 的布局、对 HTML Struts 标记使用 <div>、与 CSS 样式表对应的每个 HTML Struts 标记的标签。 |
如上所述,如果您未指定主题,则 Struts 2 将默认使用 xhtml 主题。例如,下面的 Struts 2 select 标记−
<s:textfield name = "name" label = "Name" />
会生成如下 HTML 标记−
<tr>
<td class="tdLabel">
<label for = "empinfo_name" class="label">Name:</label>
</td>
<td>
<input type = "text" name = "name" value = "" id = "empinfo_name"/>
</td>
</tr>
此处 empinfo 是 struts.xml 文件中定义的操作名称。
Selecting Themes
您可以根据 Struts 2 标记指定主题,或者可以使用以下方法之一指定 Struts 2 应使用哪个主题−
-
具体标记上的 theme 属性
-
标记周围的 form 标记上的 theme 属性
-
名为“theme”的页面作用域属性
-
名为“theme”的请求作用域属性
-
名为“主题”的会话范围属性
-
名为“主题”的应用程序范围属性
-
配置文件“struts.properties”中的 struts.ui.theme 属性(默认为 xhtml)
如果您希望针对不同标签使用不同主题,则以下方法可在标签级别指定这些主题 −
<s:textfield name = "name" label = "Name" theme="xhtml"/>
由于按标签使用主题并不是非常实用,因此我们只需使用以下标签在 struts.properties 文件中指定规则 −
# Standard UI theme
struts.ui.theme = xhtml
# Directory where theme template resides
struts.ui.templateDir = template
# Sets the default template type. Either ftl, vm, or jsp
struts.ui.templateSuffix = ftl
我们从本地化一章摘取的结果,其中使用了默认主题 struts.ui.theme = xhtml ,它在 struts-default.properties 文件中设置,并且默认包含在 struts2-core.xy.z.jar 文件中。
How a Theme Works?
对于给定的主题,每个struts标签都有一个关联的模板,例如 s:textfield → text.ftl 、 s:password → password.ftl 等。
这些模板文件以压缩包的形式包含在 struts2-core.xy.z.jar 文件中。这些模板文件针对每个标签保留预定义 HTML 布局。
通过这种方式, Struts 2 框架使用 Sturts 标签和关联的模板生成最终 HTML 标记代码。
Struts 2 tags + Associated template file = Final HTML markup code.
默认模板以 FreeMarker 编写,它们具有 .ftl 扩展名。
您还可以使用 Velocity 或 JSP 设计模板,并使用 struts.ui.templateSuffix 和 struts.ui.templateDir 在 struts.properties 中相应地设置配置。
Creating New Themes
创建新主题最简单的方法是复制任何现有主题/模板文件,并进行所需的修改。
让我们从在 WebContent/WEBINF/classes 中创建一个名为 template 的文件夹,以及一个以新主题命名的子文件夹开始。例如,WebContent/WEB-INF/classes/template/mytheme。
从这里,您可以从头开始构建模板,或者也可以从 Struts2 distribution 复制模板。在未来,您可以在那里根据需要修改它们。
我们准备修改现有默认模板 xhtml ,以达到学习的目的。现在,让我们将 struts2-core-x.y.z.jar/template/xhtml 中的内容复制到我们的主题目录,并且仅修改 WebContent/WEBINF/classes/template/mytheme/control.ftl 文件。打开 control.ftl 后,它将包含以下几行 −
<table class="${parameters.cssClass?default('wwFormTable')?html}"<#rt/>
<#if parameters.cssStyle??> style="${parameters.cssStyle?html}"<#rt/>
</#if>
>
让我们将以上 control.ftl 文件更改为包含以下内容 −
<table style = "border:1px solid black;">
如果您将检查 form.ftl ,您会发现 control.ftl 在此文件中被使用,但是 form.ftl 从 xhtml 主题引用此文件。因此,让我们按如下方式进行更改 −
<#include "/${parameters.templateDir}/xhtml/form-validate.ftl" />
<#include "/${parameters.templateDir}/simple/form-common.ftl" />
<#if (parameters.validate?default(false))>
onreset = "${parameters.onreset?default('clearErrorMessages(this);\
clearErrorLabels(this);')}"
<#else>
<#if parameters.onreset??>
onreset="${parameters.onreset?html}"
</#if>
</#if>
#include "/${parameters.templateDir}/mytheme/control.ftl" />
我假设您对 FreeMarker 模板语言不是很了解,不过通过查看 .ftl 文件,您仍然可以很好地了解要执行的操作。
但是,让我们保存上述更改,返回到本地化示例,并使用以下内容创建 WebContent/WEB-INF/classes/struts.properties 文件
# Customized them
struts.ui.theme = mytheme
# Directory where theme template resides
struts.ui.templateDir = template
# Sets the template type to ftl.
struts.ui.templateSuffix = ftl
现在,在进行此更改后,右键单击项目名称,然后单击 Export > WAR File 以创建一个 War 文件。然后将此 WAR 部署到 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2 。这将生成以下屏幕 −
您可以看到窗体组件周围存在边框,这是我们在从 xhtml 主题中复制主题后对主题进行更改的结果。如果您努力学习 FreeMarker,那么您将能够很容易地创建或修改您的主题。
我希望你现在对 Sturts 2 主题和模板有基本的了解了吗?
Struts 2 - Exception Handling
Struts 提供了一种更简单的方法来处理未捕获的异常并将用户重定向到一个专门的错误页面。你可以轻松配置 Struts,以便为不同的异常提供不同的错误页面。
Struts 通过使用“exception”拦截器使异常处理变得容易。“exception”拦截器包含在默认堆栈中,因此你不必做任何额外的事情来配置它。它开箱即用,你随时可以使用。
我们采用修改后的 HelloWorldAction.java 文件来看看一个简单的 Hello World 示例。在这里,我们在 HelloWorldAction 操作代码中故意引入了一个 NullPointer 异常。
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport{
private String name;
public String execute(){
String x = null;
x = x.substring(0);
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
让我们保持 HelloWorld.jsp 的内容如下所示:
<%@ page contentType = "text/html; charset = UTF-8" %>
<%@ taglib prefix = "s" uri = "/struts-tags" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World, <s:property value = "name"/>
</body>
</html>
以下是 index.jsp 的内容:
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World From Struts2</h1>
<form action = "hello">
<label for = "name">Please enter your name</label><br/>
<input type = "text" name = "name"/>
<input type = "submit" value = "Say Hello"/>
</form>
</body>
</html>
你的 struts.xml 应如下所示:
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
</action>
</package>
</struts>
现在右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将产生以下屏幕:
输入值“Struts2”并提交该页面。你应该看到以下页面:
如上例所示,默认异常拦截器在对异常进行处理方面做得非常好。
我们现在为异常创建一个专门的错误页面。使用以下内容创建一个名为 Error.jsp 的文件 -
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
This is my custom error page
</body>
</html>
我们现在将配置 Struts 在异常情况下使用此错误页面。我们修改 struts.xml ,如下所示 -
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<exception-mapping exception = "java.lang.NullPointerException"
result = "error" />
<result name = "success">/HelloWorld.jsp</result>
<result name = "error">/Error.jsp</result>
</action>
</package>
</struts>
如上面的示例中所示,现在我们已经配置 Struts 使用专门的 Error.jsp 来处理 NullPointerException。如果您现在重新运行程序,您将看到以下输出 -
除此之外,Struts2 框架还附带一个“日志记录”拦截器用于记录异常。通过启用记录器来记录未捕获的异常,我们可以轻松查看堆栈跟踪并找出出错的原因
Global Exception Mappings
我们已经了解了如何处理特定操作的异常。我们可以将一个全局异常应用于所有操作。例如,要捕获相同的 NullPointerException 异常,我们可以将 <global-exception-mappings…> 标记添加到 <package…> 标记内,并且应该在 struts.xml 文件中的 <action…> 标记内添加其 <result…> 标记,如下所示 -
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<global-exception-mappings>
<exception-mapping exception = "java.lang.NullPointerException"
result = "error" />
</global-exception-mappings>
<action name = "hello"
class = "com.tutorialspoint.struts2.HelloWorldAction"
method = "execute">
<result name = "success">/HelloWorld.jsp</result>
<result name = "error">/Error.jsp</result>
</action>
</package>
</struts>
Struts 2 - Annotations
如前所述,Struts 提供两种形式的配置。传统方法是为所有配置使用 struts.xml 文件。到目前为止,我们在教程中已经看到了很多这样的例子。配置 Struts 的另一种方法是使用 Java 5 注释特性。使用 Struts 注释,我们可以实现 Zero Configuration 。
要在您的项目中开始使用注释,请确保您已将以下 jar 文件包含在 WebContent/WEB-INF/lib 文件夹中 -
-
struts2-convention-plugin-x.y.z.jar
-
asm-x.y.jar
-
antlr-x.y.z.jar
-
commons-fileupload-x.y.z.jar
-
commons-io-x.y.z.jar
-
commons-lang-x.y.jar
-
commons-logging-x.y.z.jar
-
commons-logging-api-x.y.jar
-
freemarker-x.y.z.jar
-
javassist-.xy.z.GA
-
ognl-x.y.z.jar
-
struts2-core-x.y.z.jar
-
xwork-core.x.y.z.jar
现在,让我们来看看如何清除 struts.xml 文件中可用的配置并用注释替换它。
要解释 Struts2 中注释的概念,我们必须重新考虑 Struts2 Validations 章节中解释的验证示例。
在这里,我们以一个员工为例,他的姓名和年龄将使用一个简单的页面进行捕获,并且我们将放置两个验证以确保“USER”始终输入一个姓名,并且年龄应介于 28 到 65 之间。
让我们从示例的主要 JSP 页面开始。
Create Main Page
让我们编写主页面 JSP 文件 index.jsp ,用于收集上述与员工相关的的信息。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Employee Form</title>
</head>
<body>
<s:form action = "empinfo" method = "post">
<s:textfield name = "name" label = "Name" size = "20" />
<s:textfield name = "age" label = "Age" size = "20" />
<s:submit name = "submit" label = "Submit" align="center" />
</s:form>
</body>
</html>
index.jsp 利用了 Struts 标记,我们尚未介绍它,但我们将在与标记相关的章节中研究它。但就目前而言,假设 s:textfield 标记打印一个输入字段,而 s:submit 打印一个提交按钮。我们在每个标记中使用了 label 属性,为每个标记创建标签。
Create Views
我们将使用 JSP 文件 success.jsp ,该文件在已定义的操作返回 SUCCESS 的情况下调用。
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Success</title>
</head>
<body>
Employee Information is captured successfully.
</body>
</html>
Create Action
这是使用注释的地方。让我们在 Employee.java 文件中使用注释重新定义操作类 Employee ,然后添加一个名为 validate () 的方法,如下所示。确保您的操作类扩展 ActionSupport 类,否则您的 validate 方法将不会执行。
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.validator.annotations.*;
@Results({
@Result(name = "success", Location = "/success.jsp"),
@Result(name = "input", Location = "/index.jsp")
})
public class Employee extends ActionSupport {
private String name;
private int age;
@Action(value = "/empinfo")
public String execute() {
return SUCCESS;
}
@RequiredFieldValidator( message = "The name is required" )
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@IntRangeFieldValidator(message = "Age must be in between 28 and 65", min = "29", max = "65")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
我们在本示例中使用了几个注释。让我逐一解释一下 -
-
首先,我们包含了 Results 注释。Result 注释是结果的集合。
-
在 Results 注释下,有两个 result 注释。Result 注释具有与 execute 方法的执行结果相对应的 name 。它们还包含一个位置,指出应针对 execute() 返回值显示哪个视图
-
下一个注释是 Action 注解。这用于修饰 execute() 方法。Action 方法还采用一个值,该值是在其上调用操作的 URL。
-
最后,我使用了两个 validation 注释。我已在 name 字段上配置所需字段验证器,在 age 字段上配置整数范围验证器。我还为验证指定了一个自定义信息。
Configuration Files
我们确实不需要 struts.xml 配置文件,所以让我们删除此文件,并查看 web.xml 文件的内容 −
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
<init-param>
<param-name>struts.devMode</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕:
现在不要输入任何必需信息,只需点击 Submit 按钮即可。您将看到以下结果 -
输入必需信息,但输入一个错误的 From 域,假设名称为“测试”,年龄为 30,最后点击 Submit 按钮。您将看到以下结果 -
Struts 2 - Control Tags
Struts 2 标签有一组标签,可以轻松控制页面执行流。
以下是 Struts 2 控制标签的重要列表 −
The If and Else Tags
这些标签执行每种语言中都 یافت的基本条件流。
'If' 标签仅与 'Else If' 标签和/或一个或多个 'Else' 标签一起使用,如下所示 −
<s:if test = "%{false}">
<div>Will Not Be Executed</div>
</s:if>
<s:elseif test = "%{true}">
<div>Will Be Executed</div>
</s:elseif>
<s:else>
<div>Will Not Be Executed</div>
</s:else>
The Iterator Tags
此 iterator 将迭代一个值。可迭代值可以是 itherjava.util.Collection 或 java.util.Iterator 文件。在迭代迭代器时,您可以使用 Sort 标签对结果进行排序,或使用 SubSet 标签获取列表或数组的子集。
以下示例检索值堆栈中当前对象的 getDays() 方法的值,并使用它进行迭代。
<s:property/> 标签将打印出迭代器的当前值。
<s:iterator value = "days">
<p>day is: <s:property/></p>
</s:iterator>
The Merge Tag
这些 merge 标签将两个或多个列表作为参数,并将它们全部合并在一起,如下所示 −
<s:merge var = "myMergedIterator">
<s:param value = "%{myList1}" />
<s:param value = "%{myList2}" />
<s:param value = "%{myList3}" />
</s:merge>
<s:iterator value = "%{#myMergedIterator}">
<s:property />
</s:iterator>
The Append Tag
这些 append 标签将两个或多个列表作为参数,并将它们全部附加在一起,如下所示 −
<s:append var = "myAppendIterator">
<s:param value = "%{myList1}" />
<s:param value = "%{myList2}" />
<s:param value = "%{myList3}" />
</s:append>
<s:iterator value = "%{#myAppendIterator}">
<s:property />
</s:iterator>
Struts 2 - Data Tags
Struts 2 data tags 主要用于处理显示在页面上的数据。下面列出了重要的数据标记:<在此处开始>
The Action Tag
此标记通过指定操作名称和可选名称空间,使开发人员能够直接从 JSP 页面调用操作。此标记的正文内容用于呈现来自操作的结果。对 struts.xml 中此操作定义的任何结果处理器都将被忽略,除非指定了 executeResult 参数。
<div>Tag to execute the action</div>
<br />
<s:action name = "actionTagAction" executeresult = "true" />
<br />
<div>To invokes special method in action class</div>
<br />
<s:action name = "actionTagAction!specialMethod" executeresult = "true" />
The Include Tag
这些 include 将用于在另一个 JSP 页面中包含 JSP 文件。
<-- First Syntax -->
<s:include value = "myJsp.jsp" />
<-- Second Syntax -->
<s:include value = "myJsp.jsp">
<s:param name = "param1" value = "value2" />
<s:param name = "param2" value = "value2" />
</s:include>
<-- Third Syntax -->
<s:include value = "myJsp.jsp">
<s:param name = "param1">value1</s:param>
<s:param name = "param2">value2</s:param>
</s:include>
The Bean Tag
这些 bean 标记实例化一个类,该类符合 JavaBean 规范。此标记有一个主体,其中可以包含许多 Param 元素,以设置该类上的任何 mutator 方法。如果在 BeanTag 上设置 var 属性,它将把实例化的 bean 放入 Stack 的 Context 中。
<s:bean name = "org.apache.struts2.util.Counter" var = "counter">
<s:param name = "first" value = "20"/>
<s:param name = "last" value = "25" />
</s:bean>
The Date Tag
这些 date 标记将允许您快速轻松地格式化 Date。您可以指定自定义格式(例如,"dd/MM/yyyy hh:mm"),可以生成易于阅读的标记(例如,“2 小时 14 分钟后”),或者您只需使用属性文件中的键 'struts.date.format' 回退到预定义的格式。
<s:date name = "person.birthday" format = "dd/MM/yyyy" />
<s:date name = "person.birthday" format = "%{getText('some.i18n.key')}" />
<s:date name = "person.birthday" nice="true" />
<s:date name = "person.birthday" />
The Param Tag
这些 param 标记可用于对其他标记进行参数化。此标记具有以下两个参数。
-
name (String) - 参数名称
-
value (Object) - 参数值
<pre>
<ui:component>
<ui:param name = "key" value = "[0]"/>
<ui:param name = "value" value = "[1]"/>
<ui:param name = "context" value = "[2]"/>
</ui:component>
</pre>
The Property Tag
这些 property 标记用于获取值的属性,如果未指定,则默认值为 Stack 的顶部。
<s:push value = "myBean">
<!-- Example 1: -->
<s:property value = "myBeanProperty" />
<!-- Example 2: -->TextUtils
<s:property value = "myBeanProperty" default = "a default value" />
</s:push>
The Push Tag
这些 push 标记用于将值压入 Stack 以简化使用。
<s:push value = "user">
<s:propery value = "firstName" />
<s:propery value = "lastName" />
</s:push>
The Set Tag
set 标签在指定范围内为变量分配一个值。当您希望将变量分配给复杂表达式,然后每次简单地引用该变量而不是复杂表达式时,此标签很有用。可用的范围是 application, session, request, page 和 action 。
<s:set name = "myenv" value = "environment.name"/>
<s:property value = "myenv"/>
The Text Tag
text 标签用于呈现 I18n 文本消息。
<!-- First Example -->
<s:i18n name = "struts.action.test.i18n.Shop">
<s:text name = "main.title"/>
</s:i18n>
<!-- Second Example -->
<s:text name = "main.title" />
<!-- Third Examlpe -->
<s:text name = "i18n.label.greetings">
<s:param >Mr Smith</s:param>
</s:text>
The URL Tag
url 标签用于创建 URL。
<-- Example 1 -->
<s:url value = "editGadget.action">
<s:param name = "id" value = "%{selected}" />
</s:url>
<-- Example 2 -->
<s:url action = "editGadget">
<s:param name = "id" value = "%{selected}" />
</s:url>
<-- Example 3-->
<s:url includeParams="get">
<s:param name = "id" value = "%{'22'}" />
</s:url>
Struts 2 - The Form Tags
form 标签的列表是 Struts UI 标签的子集。这些标签有助于渲染 Struts Web 应用程序所需的用户界面,并可分为三类。本章将带您了解所有三种类型的 UI 标签 −
Simple UI Tags
我们在示例中已使用这些标签,本章将对其进行讲解。让我们查看一个带有几个简单 UI 标签的简单视图页面 email.jsp −
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<s:head/>
<title>Hello World</title>
</head>
<body>
<s:div>Email Form</s:div>
<s:text name = "Please fill in the form below:" />
<s:form action = "hello" method = "post" enctype = "multipart/form-data">
<s:hidden name = "secret" value = "abracadabra"/>
<s:textfield key = "email.from" name = "from" />
<s:password key = "email.password" name = "password" />
<s:textfield key = "email.to" name = "to" />
<s:textfield key = "email.subject" name = "subject" />
<s:textarea key = "email.body" name = "email.body" />
<s:label for = "attachment" value = "Attachment"/>
<s:file name = "attachment" accept = "text/html,text/plain" />
<s:token />
<s:submit key = "submit" />
</s:form>
</body>
</html>
如果你了解 HTML,则所有使用的标签都是非常常见的 HTML 标签,每个标签都带有额外前缀 s: 和不同的属性。当我们执行上述程序时,会获得以下用户界面,前提是你已为使用的所有键设置了正确的映射。
如所示, s:head 生成了 Struts2 应用程序所需的 javascript 和样式表元素。
接下来,我们有 s:div 和 s:text 元素。 s:div 用于呈现 HTML Div 元素。这对于不喜欢将 HTML 和 Struts 标签混合在一起的人来说很有用。对于这些人来说,他们可以选择使用 s:div 来呈现一个 div。
如所示, s:text 用于在屏幕上呈现一个文本。
接下来,我们有熟悉的 s:form 标签。 s:form 标签有一个 action 属性,用于确定提交表单的位置。由于表单中有一个文件上传元素,因此我们必须将 enctype 设置为 multipart。否则,我们可以将其留空。
在表单标签的末尾,我们有 s:submit 标签。这用于提交表单。提交表单时,所有表单值均提交到 s:form 标签中指定的 action。
在 s:form 内,我们有一个称为 secret 的隐藏属性。这将呈现 HTML 中的一个隐藏元素。在我们的示例中,“secret”元素的值为“abracadabra”。最终用户无法看到此元素,它用于将状态从一个视图传输到另一个视图。
接下来,我们有 s:label、s:textfield、s:password 和 s:textarea 标签。这些分别用于呈现标签、输入字段、密码和文本区域。我们在“Struts - 发送电子邮件”示例中已经看到了这些标签的作用。
这里需要注意的重要事项是“key”属性的使用方式。“key”属性用于从属性文件中提取这些控件的标签。我们在 Struts2 本地化、国际化一章中已经介绍了此功能。
然后,我们有 s:file 标签,它会呈现一个输入文件上传组件。此组件允许用户上传文件。在此示例中,我们使用了 s:file 标签的“accept”参数来指定可以上传的文件类型。
最后,我们有 s:token 标签。令牌标签会生成一个唯一令牌,用于找出是否已双重提交表单
呈现表单时,隐藏变量将放置为令牌值。假设令牌为“ABC”。提交此表单时,Struts Fitler 会将令牌与存储在会话中的令牌进行比较。如果匹配,它将从会话中删除令牌。现在,如果表单被意外重新提交(通过刷新或按浏览器的后退按钮),则该表单将重新提交,令牌将为“ABC”。在这种情况下,过滤器再次将令牌与存储在会话中的令牌进行比较。但由于令牌“ABC”已从会话中删除,因此它将不匹配,Struts 过滤器将拒绝该请求。
Group UI Tags
组 UI 标签用于创建单选按钮和复选框。让我们查看一个带有复选框和单选按钮标签的简单视图页面 HelloWorld.jsp −
<%@ page contentType = "text/html; charset = UTF-8"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<html>
<head>
<title>Hello World</title>
<s:head />
</head>
<body>
<s:form action = "hello.action">
<s:radio label = "Gender" name = "gender" list="{'male','female'}" />
<s:checkboxlist label = "Hobbies" name = "hobbies"
list = "{'sports','tv','shopping'}" />
</s:form>
</body>
</html>
执行上述程序时,我们的输出将类似于以下内容 −
现在让我们看看示例。在第一个示例中,我们使用“Gender”标签创建一个简单的单选按钮。单选按钮标签的名称属性是必需的,因此我们指定了一个名称为“gender”。然后我们将列表提供给 gender。列表填充了“male”和“female”值。因此,在输出中,我们得到一个包含两个值的单选按钮。
在第二个示例中,我们正在创建一个复选框列表。这是为了收集用户的爱好。用户可以有多个爱好,因此我们使用复选框而不是单选按钮。复选框填充了“sports”、“TV”和“Shopping”列表。这将爱好显示为复选框列表。
Select UI Tags
让我们探索 Struts 提供的 Select 标签的不同变体。让我们查看带有选择标签的简单视图页面 HelloWorld.jsp −
<%@ page contentType = "text/html; charset = UTF-8"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<html>
<head>
<title>Hello World</title>
<s:head />
</head>
<body>
<s:form action = "login.action">
<s:select name = "username" label = "Username"
list = "{'Mike','John','Smith'}" />
<s:select label = "Company Office" name = "mySelection"
value = "%{'America'}" list="%{#{'America':'America'}}">
<s:optgroup label = "Asia"
list = "%{#{'India':'India','China':'China'}}" />
<s:optgroup label = "Europe"
list="%{#{'UK':'UK','Sweden':'Sweden','Italy':'Italy'}}" />
</s:select>
<s:combobox label = "My Sign" name = "mySign"
list = "#{'aries':'aries','capricorn':'capricorn'}" headerkey = "-1"
headervalue = "--- Please Select ---" emptyOption = "true" value = "capricorn" />
<s:doubleselect label = "Occupation" name = "occupation"
list = "{'Technical','Other'}" doublename = "occupations2"
doubleList="top == 'Technical' ?
{'I.T', 'Hardware'} : {'Accounting', 'H.R'}" />
</s:form>
</body>
</html>
执行上述程序时,我们的输出将类似于以下内容 −
让我们一一过一下各个案例。
-
首先,select 标签呈现 HTML 选择框。在第一个例子中,我们正在创建一个名为“username”且标签为“username”的简单选择框。该选择框将使用包含名称 Mike、John 和 Smith 的列表填充。
-
在第二个例子中,我们公司的总部设在美国。其在亚洲和欧洲也有全球办公室。我们希望在选择框中显示办公室,但我们要按大洲名称对全球办公室进行分组。这时,optgroup 派上了用场。我们使用 s:optgroup 标签新建一个组。我们为组提供一个标签和一个单独的列表。
-
在第三个例子中,使用了组合框。组合框是输入字段和选择框的组合。用户可以选择选择框中的值,在这种情况下,输入字段将自动填充用户选择的值。如果用户直接输入值,则不会从选择框中选择任何值。
-
在我们的例子中,组合框列出了太阳星座。选择框仅列出四个条目,允许用户输入太阳星座(如果不在列表中)。我们还向选择框添加了一个头条目。头条目显示在选择框顶部。在我们的例子中,我们希望显示“请选择”。如果用户未选择任何内容,则我们假设 -1 为该值。在某些情况下,我们不希望用户选择空值。在这些情况下,应将“emptyOption”属性设为 false。最后,在我们的例子中,我们将“capricorn”提供为组合框的默认值。
-
在第四个例子中,我们有一个双重选择。当您想要显示两个选择框时,可以使用双重选择。在第一个选择框中选择的值将确定在第二个选择框中显示的内容。在我们的例子中,第一个选择框显示“技术”和“其他”。如果用户选择“技术”,我们将在第二个选择框中显示“IT”和“硬件”。否则,我们将显示“会计”和“人力资源”。这可以通过使用例子中所示的“list”和“doubleList”属性实现。
在上面的例子中,我们进行了比较以查看顶部选择框是否等于技术。如果是,则我们显示 IT 和硬件。
我们还需要为顶部框(“name = 'Occupations')和底部框(doubleName = 'occupations2')提供名称
Struts 2 - The Ajax Tags
Struts 使用 DOJO 框架进行 AJAX 标签实现。首先,要继续此示例,您需要将 struts2-dojo-plugin-2.2.3.jar 添加到您的类路径。
您可以从 struts2 下载的 lib 文件夹获得此文件(C:\struts-2.2.3all\struts-2.2.3\lib\struts2-dojo-plugin-2.2.3.jar)
对于此练习,让我们修改 HelloWorld.jsp 如下所示 −
<%@ page contentType = "text/html; charset = UTF-8"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<%@ taglib prefix = "sx" uri = "/struts-dojo-tags"%>
<html>
<head>
<title>Hello World</title>
<s:head />
<sx:head />
</head>
<body>
<s:form>
<sx:autocompleter label = "Favourite Colour"
list = "{'red','green','blue'}" />
<br />
<sx:datetimepicker name = "deliverydate" label = "Delivery Date"
displayformat = "dd/MM/yyyy" />
<br />
<s:url id = "url" value = "/hello.action" />
<sx:div href="%{#url}" delay="2000">
Initial Content
</sx:div>
<br/>
<sx:tabbedpanel id = "tabContainer">
<sx:div label = "Tab 1">Tab 1</sx:div>
<sx:div label = "Tab 2">Tab 2</sx:div>
</sx:tabbedpanel>
</s:form>
</body>
</html>
当我们运行以上示例时,我们得到以下输出 −
让我们一步一步过一下这个示例。
首先要注意的是添加了一个新标签库,前缀为 sx。这(struts-dojo-tags)是专门为 ajax 集成创建的标签库。
然后,在 HTML 头部内部,我们调用 sx:head。这会初始化 dojo 框架,使其准备好页面内的所有 AJAX 调用。这一步很重要——如果没有初始化 sx:head,您的 ajax 调用将不起作用。
首先我们有自动完成标签。自动完成标签看起来很像选择框。其中填充了红色、绿色和蓝色这三个值。但与选择框之间的不同之处在于其自动完成功能。也就是说,如果您开始输入 gr,它将填充“绿色”。除此之外,此标签与我们之前介绍的 s:select 标签非常相似。
接下来,我们有一个日期时间选择器。此标签创建一个输入字段,其旁边有一个按钮。按下按钮后,将显示一个弹出式日期时间选择器。当用户选择日期时,日期将以标签属性中指定格式填充到输入文本中。在我们的例子中,我们将 dd/MM/yyyy 指定为日期格式。
接下来,我们创建一个指向我们之前练习中创建的 system.action 文件的 url 标签。它不必是 system.action——它可以是您之前创建的任何操作文件。然后,我们有一个 div,其中超链接设置为 url,延迟设置为 2 秒。运行此文件时发生的情况是,“初始内容”将显示 2 秒,然后 div 的内容将被 hello.action 执行的内容替换。
最后,我们有一个带有两个选项卡的简单选项卡面板。该选项卡本身就是带有“标签 1”和“标签 2”标签的 div。
值得注意的是,Struts 中的 AJAX 标记集成仍是进行中的工作,而且,此集成的成熟度正随着每次发布而逐渐提高。
Struts 2 & Spring Integration
Spring 是一个流行的 Web 框架,它提供了与许多常见 Web 任务的简单集成。因此问题是,当我们有了 Struts2 时,我们为什么需要 Spring?好吧,Spring 不仅仅是一个 MVC 框架 - 它提供了 Struts 中没有的许多其他好处。
例如:依赖项注入对于任何框架都很有用。在本章中,我们将通过一个简单的示例了解如何将 Spring 和 Struts2 集成在一起。
首先,你需要从 Spring 安装将以下文件添加到项目的构建路径中。你可以从 https://www.springsource.org/download 下载并安装最新版本的 Spring 框架
-
org.springframework.asm-x.y.z.M(a).jar
-
org.springframework.beans-x.y.z.M(a).jar
-
org.springframework.context-x.y.z.M(a).jar
-
org.springframework.core-x.y.z.M(a).jar
-
org.springframework.expression-x.y.z.M(a).jar
-
org.springframework.web-x.y.z.M(a).jar
-
org.springframework.web.servlet-x.y.z.M(a).jar
最后在 struts lib 目录中,在 struts2-spring-plugin-x.y.z.jar 中添加 WEB-INF/lib 。如果您正在使用 Eclipse,您可能会遇到一个异常 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener。
要解决此问题,您应该在 Marker 选项卡中右键单击类依赖项,然后逐一执行快速修复来发布/导出所有依赖项。最后,确保标记选项卡中没有可用的依赖冲突。
现在,让我们按照以下步骤为 Struts-Spring 集成设置 web.xml −
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
这里需要注意的重要一点是我们配置的侦听器。需要 ContextLoaderListener 来加载 Spring 上下文文件。Spring 的配置文件被称为 applicationContext.xml 文件,它必须与 web.xml 文件位于同级
让我们创建一个名为 User.java 的简单动作类,其中包含两个属性 - firstName 和 lastName。
package com.tutorialspoint.struts2;
public class User {
private String firstName;
private String lastName;
public String execute() {
return "success";
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
现在,让我们创建 applicationContext.xml spring 配置文件并实例化 User.java 类。如前所述,此文件应位于 WEB-INF 文件夹下 −
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id = "userClass" class = "com.tutorialspoint.struts2.User">
<property name = "firstName" value = "Michael" />
<property name = "lastName" value = "Jackson" />
</bean>
</beans>
如上所示,我们已经配置了 user bean,并且我们已经将值 Michael 和 Jackson 注入到了 bean 中。我们还给这个 bean 起了个名字 “userClass”,以便我们可以在其他地方重复使用它。接下来,让我们在 WebContent 文件夹中创建 User.jsp −
<%@ page language = "java" contentType = "text/html; charset = ISO-8859-1"
pageEncoding = "ISO-8859-1"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World From Struts2 - Spring integration</h1>
<s:form>
<s:textfield name = "firstName" label = "First Name"/><br/>
<s:textfield name = "lastName" label = "Last Name"/><br/>
</s:form>
</body>
</html>
User.jsp 文件非常简单。它只起到一个作用 - 显示用户对象的 firstname 和 lastname 的值。最后,让我们使用 struts.xml 文件将所有实体放在一起。
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "helloworld" extends = "struts-default">
<action name = "user" class="userClass"
method = "execute">
<result name = "success">/User.jsp</result>
</action>
</package>
</struts>
需要注意的重要一点是,我们正在使用 id userClass 来引用类。这意味着我们正在使用 Spring 来对 User 类进行依赖注入。
现在,右键单击项目名称,然后单击 Export > WAR File 来创建一个 War 文件。然后,将该 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/User.jsp 。这将生成以下屏幕 −
我们现在已经了解了如何将两个伟大的框架结合在一起。这就结束了 Struts - Spring 集成章节。
Struts 2 & Tiles Integration
在本章中,让我们逐步了解将 Tiles 框架与 Struts2 集成的步骤。Apache Tiles 是一个模板框架,用于简化 Web 应用程序用户界面的开发。
首先,我们需要从 Apache Tiles 网站下载 tiles jar 文件。您需要将以下 jar 文件添加到项目的类路径中。
-
tiles-api-x.y.z.jar
-
tiles-compat-x.y.z.jar
-
tiles-core-x.y.z.jar
-
tiles-jsp-x.y.z.jar
-
tiles-servlet-x.y.z.jar
除了以上内容之外,我们还必须从 Struts2 下载 WEB-INF/lib 中复制以下 jar 文件。
-
commons-beanutils-x.y.zjar
-
commons-digester-x.y.jar
-
struts2-tiles-plugin-x.y.z.jar
现在,让我们按照以下步骤设置 Struts-Tiles 集成 web.xml 。此处有两个重要需要注意的点。首先,我们需要告诉 tiles 在哪里可以找到 tiles 配置文件 tiles.xml 。在我们的例子中,它将在 /WEB-INF 文件夹中。接下来,我们需要初始化 Struts2 下载附带的 Tiles 监听器。
<?xml version = "1.0" Encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id = "WebApp_ID" version = "2.5">
<display-name>Struts2Example15</display-name>
<context-param>
<param-name>
org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
</param-name>
<param-value>
/WEB-INF/tiles.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.apache.struts2.tiles.StrutsTilesListener
</listener-class>
</listener>
<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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
接下来,让我们在 /WEB-INF 文件夹中用以下内容创建 tiles.xml −
<?xml version = "1.0" Encoding = "UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name = "baseLayout" template="/baseLayout.jsp">
<put-attribute name = "title" value = "Template"/>
<put-attribute name = "banner" value = "/banner.jsp"/>
<put-attribute name = "menu" value = "/menu.jsp"/>
<put-attribute name = "body" value = "/body.jsp"/>
<put-attribute name = "footer" value = "/footer.jsp"/>
</definition>
<definition name = "tiger" extends = "baseLayout">
<put-attribute name = "title" value = "Tiger"/>
<put-attribute name = "body" value = "/tiger.jsp"/>
</definition>
<definition name = "lion" extends = "baseLayout">
<put-attribute name = "title" value = "Lion"/>
<put-attribute name = "body" value = "/lion.jsp"/>
</definition>
</tiles-definitions>
然后,我们在 baseLayout.jsp 中定义一个基本的骨架布局。它有五个可重用/可覆盖区域。即 title, banner, menu, body 和 footer 。我们为 baseLayout 提供默认值,然后创建从默认布局扩展的两个自定义。tiger 布局与基本布局相似,除了它使用 tiger.jsp 作为其正文和文本“Tiger”作为标题。同样,lion 布局与基本布局相似,除了它使用 lion.jsp 作为其正文和文本“Lion”作为标题。
让我们看一下各个 jsp 文件。以下是 baseLayout.jsp 文件的内容 −
<%@ taglib uri = "http://tiles.apache.org/tags-tiles" prefix = "tiles"%>
<!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>
<tiles:insertAttribute name = "title" ignore="true" />
</title>
</head>
<body>
<tiles:insertAttribute name = "banner" /><br/>
<hr/>
<tiles:insertAttribute name = "menu" /><br/>
<hr/>
<tiles:insertAttribute name = "body" /><br/>
<hr/>
<tiles:insertAttribute name = "footer" /><br/>
</body>
</html>
在这里,我们只是将具有 tiles 特性的基本 HTML 页面放在一起。我们在需要的地方插入 tiles 特性。接下来,让我们创建 banner.jsp 文件,内容如下 −
<img src="http://www.tutorialspoint.com/images/tp-logo.gif"/>
menu.jsp 文件有以下几行,它们是链接 - 到 TigerMenu.action 和 LionMenu.action struts 操作。
<%@taglib uri = "/struts-tags" prefix = "s"%>
<a href = "<s:url action = "tigerMenu"/>" Tiger</a><br>
<a href = "<s:url action = "lionMenu"/>" Lion</a><br>
lion.jsp 文件会有以下内容 −
<img src="http://upload.wikimedia.org/wikipedia/commons/d/d2/Lion.jpg"/>
The lion
tiger.jsp 文件会有以下内容 −
<img src="http://www.freewebs.com/tigerofdarts/tiger.jpg"/>
The tiger
接下来,让我们创建操作类文件 MenuAction.java ,其中包含以下内容 −
package com.tutorialspoint.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class MenuAction extends ActionSupport {
public String tiger() { return "tiger"; }
public String lion() { return "lion"; }
}
这是一个非常简单的类。我们声明了两个分别返回 tiger 和 lion 作为结果的方法 tiger() 和 lion()。让我们将所有内容放在 struts.xml 文件中 −
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name = "default" extends = "struts-default">
<result-types>
<result-type name = "tiles"
class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
<action name = "*Menu" method = "{1}"
class = "com.tutorialspoint.struts2.MenuAction">
<result name = "tiger" type = "tiles">tiger</result>
<result name = "lion" type = "tiles">lion</result>
</action>
</package>
</struts>
让我们检查我们在上面文件中做了什么。首先,我们声明了一种称为“tiles”的新结果类型,因为我们现在使用 tiles 而不是普通 jsp 作为视图技术。Struts2 已经支持 Tiles 视图结果类型,因此,我们创建结果类型“tiles”,使其成为“org.apache.struts2.view.tiles.TilesResult”类。
接下来,我们想说,如果请求是 /tigerMenu.action,则将用户带到 tiger tiles 页面,如果请求是 /lionMenu.action,则将用户带到 lion tiles 页面。
我们使用一点正则表达式来实现这一点。在我们的操作定义中,我们说,匹配模式“*Menu”的任何内容都将由此操作处理。匹配方法将在 MenuAction 类中调用。也就是说,tigerMenu.action 将调用 tiger(),lionMenu.action 将调用 lion()。然后,我们需要将结果的结果映射到适当的 tiles 页面。
现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后,将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp 。这将产生以下屏幕 −
同样,如果您转到 lionMenu.action 页面,您将看到使用相同 tiles 布局的 lion 页面。
Struts 2 and Hibernate Integration
Hibernate 是一项高性能对象/关系持久性与查询服务,该服务通过开放源代码 GNU Lesser General Public License (LGPL) 获得许可,并可免费下载。在本章中,我们将了解如何将 Struts 2 集成到 Hibernate 中。如果您不熟悉 Hibernate,则可以查看我们的 Hibernate tutorial 。
Database Setup
对于本教程,我将使用“struts2_tutorial”MySQL 数据库。我使用用户名“root”和无密码连接到我的机器上此数据库。首先,您需要运行以下脚本。此脚本将创建一个名为 student 的新表格,并在该表格中创建一些记录−
CREATE TABLE IF NOT EXISTS `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(40) NOT NULL,
`last_name` varchar(40) NOT NULL,
`marks` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
--
-- Dumping data for table `student`
--
INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)
VALUES(1, 'George', 'Kane', 20);
INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)
VALUES(2, 'Melissa', 'Michael', 91);
INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)
VALUES(3, 'Jessica', 'Drake', 21);
Hibernate Configuration
接下来让我们创建 hibernate.cfg.xml,这是 Hibernate 的配置文件。
<?xml version = '1.0' encoding = 'utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name = "hibernate.connection.driver_class">c
om.mysql.jdbc.Driver
</property>
<property name = "hibernate.connection.url">
jdbc:mysql://www.tutorialspoint.com/struts_tutorial
</property>
<property name = "hibernate.connection.username">root</property>
<property name = "hibernate.connection.password"></property>
<property name = "hibernate.connection.pool_size">10</property>
<property name = "show_sql">true</property>
<property name = "dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name = "hibernate.hbm2ddl.auto">update</property>
<mapping class = "com.tutorialspoint.hibernate.Student" />
</session-factory>
</hibernate-configuration>
让我们仔细阅读 Hibernate 配置文件。首先,我们声明了我们使用的是 MySQL 驱动程序。然后我们声明了用于连接到数据库的 jdbc url。然后我们声明了连接的用户名、密码和池大小。我们还表明,通过将“show_sql”切换为 true,我们希望看到日志文件中的 SQL。请仔细阅读 Hibernate 教程以了解这些属性的含义。
最后,我们将映射类设置为 com.tutorialspoint.hibernate.Student,我们将在本章中创建此类。
Envrionment Setup
接下来,您需要为该项目引入许多 jar。附件是所需 JAR 文件的完整列表的屏幕截图−
大多数 JAR 文件可以作为 Struts 分发的一部分获得。如果您已安装 Glassfish、WebSphere 或 JBoss 等应用服务器,则可以从应用服务器的 lib 文件夹中获取剩余 jar 文件。如果没有,则可以单独下载这些文件−
-
Hibernate jar 文件 − Hibernate.org
-
Struts Hibernate 插件 − Struts hibernate plugin
-
JTA 文件 − JTA files
-
Dom4j files − Dom4j
-
log4j files − log4j
其余文件,您应该可以从 Struts2 分发中获取。
Hibernate Classes
现在,让我们为 Hibernate 集成创建必要的 Java 类。以下是 Student.java 的内容 −
package com.tutorialspoint.hibernate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue
private int id;
@Column(name = "last_name")
private String lastName;
@Column(name = "first_name")
private String firstName;
private int marks;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public int getMarks() {
return marks;
}
public void setMarks(int marks) {
this.marks = marks;
}
}
这是一个 POJO 类,它根据 Hibernate 规范表示 student 表。它具有与学生表中列名称相对应的 id、firstName 和 lastName 三个属性。接下来,让我们按照如下方式创建 StudentDAO.java 文件 −
package com.tutorialspoint.hibernate;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.googlecode.s2hibernate.struts2.plugin.\
annotations.SessionTarget;
import com.googlecode.s2hibernate.struts2.plugin.\
annotations.TransactionTarget;
public class StudentDAO {
@SessionTarget
Session session;
@TransactionTarget
Transaction transaction;
@SuppressWarnings("unchecked")
public List<Student> getStudents() {
List<Student> students = new ArrayList<Student>();
try {
students = session.createQuery("from Student").list();
} catch(Exception e) {
e.printStackTrace();
}
return students;
}
public void addStudent(Student student) {
session.save(student);
}
}
StudentDAO 类是 Student 类的 data access layer(数据访问层)。它具有用于列出所有学生以及保存新学生记录的方法。
Action Class
以下文件 AddStudentAction.java 定义了我们的操作类。这里有两种操作方法 - execute() 和 listStudents()。execute() 方法用于添加新的学生记录。我们使用 dao 的 save() 方法实现这一功能。
另一个方法 listStudents() 用于列出学生。我们使用 dao 的 list 方法获取所有学生的列表。
package com.tutorialspoint.struts2;
import java.util.ArrayList;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.tutorialspoint.hibernate.Student;
import com.tutorialspoint.hibernate.StudentDAO;
public class AddStudentAction extends ActionSupport implements ModelDriven<Student> {
Student student = new Student();
List<Student> students = new ArrayList<Student>();
StudentDAO dao = new StudentDAO();
@Override
public Student getModel() {
return student;
}
public String execute() {
dao.addStudent(student);
return "success";
}
public String listStudents() {
students = dao.getStudents();
return "success";
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
您会注意到我们正在实现 ModelDriven 接口。当您的操作类用于处理具体模型类(例如 Student),而不是各个属性(例如 firstName、lastName)时,就会使用它。ModelAware 接口要求您实现一种方法来返回模型。在我们的案例中,我们返回“student”对象。
Create View Files
现在,让我们使用以下内容创建 student.jsp 视图文件 −
<%@ page contentType = "text/html; charset = UTF-8"%>
<%@ taglib prefix = "s" uri = "/struts-tags"%>
<html>
<head>
<title>Hello World</title>
<s:head />
</head>
<body>
<s:form action = "addStudent">
<s:textfield name = "firstName" label = "First Name"/>
<s:textfield name = "lastName" label = "Last Name"/>
<s:textfield name = "marks" label = "Marks"/>
<s:submit/>
<hr/>
<table>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Marks</td>
</tr>
<s:iterator value = "students">
<tr>
<td><s:property value = "firstName"/></td>
<td><s:property value = "lastName"/></td>
<td><s:property value = "marks"/></td>
</tr>
</s:iterator>
</table>
</s:form>
</body>
</html>
student.jsp 非常简单明了。在顶部部分,我们有一个提交给“addStudent.action”的表单。它接收 firstName、lastName 和 marks。因为 addStudent 操作绑定到 ModelAware “AddSudentAction”,所以会自动创建一个 student bean,其中包含 firstName、lastName 和 marks 的值自动填充。
在底部部分,我们浏览学生列表(见 AddStudentAction.java)。我们遍历列表并在表格中显示名字、姓氏和分数的值。
Struts Configuration
我们使用 struts.xml 将所有内容放在一起 −
<?xml version = "1.0" Encoding = "UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name = "struts.devMode" value = "true" />
<package name = "myhibernate" extends = "hibernate-default">
<action name = "addStudent" method = "execute"
class = "com.tutorialspoint.struts2.AddStudentAction">
<result name = "success" type = "redirect">
listStudents
</result>
</action>
<action name = "listStudents" method = "listStudents"
class = "com.tutorialspoint.struts2.AddStudentAction">
<result name = "success">/students.jsp</result>
</action>
</package>
</struts>
此处需要关注的一点是,我们的软件包“myhibernate”扩展了名为“hibernate-default”的 Struts2 默认软件包。然后我们声明两个操作:addStudent 和 listStudents。addStudent 在 AddStudentAction 类上调用 execute(),然后在成功后,调用 listStudents 操作方法。
listStudent 操作方法在 AddStudentAction 类上调用 listStudents(),并使用 student.jsp 作为视图。
现在,右键单击项目名称,然后单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署到 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/student.jsp 。这将生成以下屏幕 −
在顶部部分,我们获取用于输入新学生记录值的一个表单,底部部分列出了数据库中的学生。继续添加一个新学生记录并按提交。每次您单击“提交”时,屏幕将刷新并向您显示一个更新的列表。