Struts 2 简明教程

Struts 2 - Quick Guide

Basic MVC Architecture

M*odel *V*iew *C*ontroller or *MVC (这是人们通常叫法),是一种用于开发 Web 应用程序的软件设计模式。Model View Controller 模式由以下三部分构成−

M*odel *V*iew *C*ontroller or *MVC as it is popularly called, is a software design pattern for developing web applications. A Model View Controller pattern is made up of the following three parts −

  1. Model − The lowest level of the pattern which is responsible for maintaining data.

  2. View − This is responsible for displaying all or a portion of the data to the user.

  3. Controller − Software Code that controls the interactions between the Model and View.

MVC 很受欢迎,因为它将应用程序逻辑从用户界面层隔离出来,并支持关注点分离。在这里,控制器接收所有应用程序请求,然后与模型协作准备视图所需的所有数据。随后,视图使用控制器准备的数据生成最终的可展示响应。MVC 抽象可图形化表示如下。

MVC is popular as it isolates the application logic from the user interface layer and supports separation of concerns. Here the Controller receives all requests for the application and then works with the Model to prepare any data needed by the View. The View then uses the data prepared by the Controller to generate a final presentable response. The MVC abstraction can be graphically represented as follows.

struts mvc

The Model

模型负责管理应用程序的数据。它响应视图的请求,并且还响应控制器的指令来更新自身。

The model is responsible for managing the data of the application. It responds to the request from the view and it also responds to instructions from the controller to update itself.

The View

这意味着通过控制器的决策来呈现特定格式的数据的展示。它们是基于脚本的模版系统,如 JSP、ASP、PHP,非常容易与 AJAX 技术集成。

It means presentation of data in a particular format, triggered by a controller’s decision to present the data. They are script-based templating systems like JSP, ASP, PHP and very easy to integrate with AJAX technology.

The Controller

控制器负责响应用户输入,并在数据模型对象上执行交互。控制器接收输入,验证输入,然后执行修改数据模型状态的业务操作。

The controller is responsible for responding to the user input and perform interactions on the data model objects. The controller receives the input, it validates the input and then performs the business operation that modifies the state of the data model.

Struts2 是一个基于 MVC 的框架。在接下来的章节中,我们将看到如何在 Struts2 中使用 MVC 方法。

Struts2 is a MVC based framework. In the coming chapters, let us see how we can use the MVC methodology within Struts2.

Struts 2 - Overview

Struts2 是一个基于 MVC 设计模式的流行且成熟的 Web 应用程序框架。Struts2 不仅仅是 Struts 1 的一个新版本,而是一种对 Struts 架构的完全重写。

Struts2 is a popular and mature web application framework based on the MVC design pattern. Struts2 is not just a new version of Struts 1, but it is a complete rewrite of the Struts architecture.

Webwork 框架最初以 Struts 框架为基础,其目标是提供一个建立在 Struts 之上的增强和改进的框架,以便为开发人员简化 Web 开发。

The Webwork framework initially started with Struts framework as the basis and its goal was to offer an enhanced and improved framework built on Struts to make web development easier for the developers.

一段时间后,Webwork 框架和 Struts 社区携手合作创建了著名的 Struts2 框架。

After a while, the Webwork framework and the Struts community joined hands to create the famous Struts2 framework.

Struts 2 Framework Features

以下是一些可能迫使您考虑 Struts2 的强大功能 −

Here are some of the great features that may force you to consider Struts2 −

  1. POJO Forms and POJO Actions − Struts2 has done away with the Action Forms that were an integral part of the Struts framework. With Struts2, you can use any POJO to receive the form input. Similarly, you can now see any POJO as an Action class.

  2. Tag Support − Struts2 has improved the form tags and the new tags which allow the developers to write less code.

  3. AJAX Support − Struts2 has recognized the take over by Web2.0 technologies, and has integrated AJAX support into the product by creating AJAX tags, this function is very similar to the standard Struts2 tags.

  4. Easy Integration − Integration with other frameworks like Spring, Tiles and SiteMesh is now easier with a variety of integration available with Struts2.

  5. Template Support − Support for generating views using templates.

  6. Plugin Support − The core Struts2 behavior can be enhanced and augmented by the use of plugins. A number of plugins are available for Struts2.

  7. Profiling − Struts2 offers integrated profiling to debug and profile the application. In addition to this, Struts also offers integrated debugging with the help of built in debugging tools.

  8. Easy to Modify Tags − Tag markups in Struts2 can be tweaked using Freemarker templates. This does not require JSP or java knowledge. Basic HTML, XML and CSS knowledge is enough to modify the tags.

  9. Promote Less configuration − Struts2 promotes less configuration with the help of using default values for various settings. You don’t have to configure something unless it deviates from the default settings set by Struts2.

  10. View Technologies − Struts2 has a great support for multiple view options (JSP, Freemarker, Velocity and XSLT)

上面列出了 Struts 2 的 10 大特性,因此它成为企业就绪框架。

Listed above are the Top 10 features of Struts 2 which makes it as an Enterprise ready framework.

Struts 2 Disadvantages

虽然 Struts 2 带有一系列出色的特性,但当前版本(Struts 2)有一些限制,需要进一步改进。下面列出了一些要点 −

Though Struts 2 comes with a list of great features, there are some limitations of the current version - Struts 2 which needs further improvement. Listed are some of the main points −

  1. Bigger Learning Curve − To use MVC with Struts, you have to be comfortable with the standard JSP, Servlet APIs and a large & elaborate framework.

  2. Poor Documentation − Compared to the standard servlet and JSP APIs, Struts has fewer online resources, and many first-time users find the online Apache documentation confusing and poorly organized.

  3. Less Transparent − With Struts applications, there is a lot more going on behind the scenes than with normal Java-based Web applications which makes it difficult to understand the framework.

最后需要注意的是,一个好的框架应提供多种不同类型的应用程序可以利用的通用行为。

Final note, a good framework should provide generic behavior that many different types of applications can make use of it.

Struts 2 是最好的 Web 框架之一,被广泛用于开发富互联网应用程序 (RIA)。

Struts 2 is one of the best web frameworks and being highly used for the development of Rich Internet Applications (RIA).

Struts 2 - Environment Setup

我们的第一个任务是运行一个极简的 Struts 2 应用程序。本章将指导你如何准备开发环境,以开始使用 Struts 2。

Our first task is to get a minimal Struts 2 application running. This chapter will guide you on how to prepare a development environment to start your work with Struts 2.

我假设你的计算机上已经安装了 JDK (5+)、Tomcat 和 Eclipse。如果你没有安装这些组件,那么请按照快速通道中的给定步骤操作 −

I assume that you already have JDK (5+), Tomcat and Eclipse installed on your machine. If you do not have these components installed, then follow the given steps on fast track −

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。

You can download the latest version of SDK from Oracle’s Java site − Java SE Downloads. You will find instructions for installing JDK in downloaded files, follow the given instructions to install and configure the setup. Finally, set PATH and JAVA_HOME environment variables to refer to the directory that contains java and javac, typically java_install_dir/bin and java_install_dir respectively.

如果你运行的是 Windows,并且在 C:\jdk1.5.0_20 中安装了 SDK,则应在 C:\autoexec.bat 文件中输入以下行。

If you are running Windows and installed the SDK in C:\jdk1.5.0_20, you should be inputting the following line in your C:\autoexec.bat file.

set PATH = C:\jdk1.5.0_20\bin;%PATH%
set JAVA_HOME = C:\jdk1.5.0_20

或者,在 Windows NT/2000/XP 上 −

Alternatively, on Windows NT/2000/XP −

  1. You can right-click on My Computer, Select Properties, then Advanced, then Environment Variables. Then, you would update the PATH value and press the OK button.

  2. On Unix (Solaris, Linux, etc.), if the SDK is installed in /usr/local/jdk1.5.0_20 and you use the C shell, you would put the following into your .cshrc file.

在 Unix(Solaris、Linux 等)上,如果 SDK 安装在 /usr/local/jdk1.5.0_20 中,而您使用 C shell,您应将以下内容放入 .cshrc 文件中。

On Unix (Solaris, Linux, etc.), if the SDK is installed in /usr/local/jdk1.5.0_20 and you use the C shell, you would put the following into your .cshrc file.

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 提供文档进行适当设置。

Alternatively, if you use an Integrated Development Environment (IDE) like Borland JBuilder, Eclipse, IntelliJ IDEA, or Sun ONE Studio, compile and run a simple program to confirm that the IDE knows where you installed Java, otherwise do proper setup as per the given document of IDE.

Step 2 - Setup Apache Tomcat

您可以从 https://tomcat.apache.org/ 下载最新版本的 Tomcat。下载安装后,将二进制发行版解压缩到一个方便的位置。

You can download the latest version of Tomcat from https://tomcat.apache.org/. Once you downloaded the installation, unpack the binary distribution into a convenient location.

例如,在 Windows 中为 C:\apache-tomcat-6.0.33,在 Linux/Unix 中为 /usr/local/apachetomcat-6.0.33,并创建指向这些位置的 CATALINA_HOME 环境变量。

For example in C:\apache-tomcat-6.0.33 on windows, or /usr/local/apachetomcat-6.0.33 on Linux/Unix and create CATALINA_HOME environment variable pointing to these locations.

您可以在 Windows 计算机上执行以下命令启动 Tomcat,或者您只需双击 startup.bat

You can start Tomcat by executing the following commands on windows machine, or you can simply double click on startup.bat

%CATALINA_HOME%\bin\startup.bat

or

C:\apache-tomcat-6.0.33\bin\startup.bat

可以通过在 Unix(Solaris、Linux 等)计算机上执行以下命令启动 Tomcat:

Tomcat can be started by executing the following commands on Unix (Solaris, Linux, etc.) machine −

$CATALINA_HOME/bin/startup.sh

or

/usr/local/apache-tomcat-6.0.33/bin/startup.sh

成功启动后,通过访问 http://localhost:8080/ 即可使用包含在 Tomcat 中的默认 Web 应用程序。如果一切都很好,则应显示以下结果 -

After a successful startup, the default web applications included with Tomcat will be available by visiting http://localhost:8080/. If everything is fine, then it should display the following result −

tomcathomepage

有关配置和运行 Tomcat 的更多信息可在本文档中找到,也可以在 Tomcat 网站上找到: https://tomcat.apache.org/

Further information about configuring and running Tomcat can be found in the documentation included here, as well as on the Tomcat website: https://tomcat.apache.org/

可以通过在 Windows 计算机上执行以下命令停止 Tomcat:

Tomcat can be stopped by executing the following commands on windows machine −

%CATALINA_HOME%\bin\shutdown

or

C:\apache-tomcat-5.5.29\bin\shutdown

可以通过在 Unix(Solaris、Linux 等)计算机上执行以下命令停止 Tomcat:

Tomcat can be stopped by executing the following commands on Unix (Solaris, Linux, etc.) machine −

$CATALINA_HOME/bin/shutdown.sh

or

/usr/local/apache-tomcat-5.5.29/bin/shutdown.sh

Step 3 - Setup Eclipse (IDE)

本教程中的所有示例都使用 Eclipse IDE 编写。我建议您在计算机中安装最新版本的 Eclipse。

All the examples in this tutorial are written using Eclipse IDE. I suggest that, you have the latest version of Eclipse installed in your machine.

若要安装 Eclipse,请从 https://www.eclipse.org/downloads/ 下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压缩到一个方便的位置。

To install Eclipse Download the latest Eclipse binaries from https://www.eclipse.org/downloads/. Once you download the installation, unpack the binary distribution into a convenient location.

例如,在 Windows 中为 C:\eclipse,在 Linux/Unix 中为 /usr/local/eclipse,最后适当地设置 PATH 变量。可以在 Windows 计算机上执行以下命令启动 Eclipse,或者您只需双击 eclipse.exe

For example in C:\eclipse on windows, or /usr/local/eclipse on Linux/Unix and finally set PATH variable appropriately. Eclipse can be started by executing the following commands on windows machine, or you can simply double click on eclipse.exe

%C:\eclipse\eclipse.exe

可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse −

Eclipse can be started by executing the following commands on Unix (Solaris, Linux, etc.) machine −

$/usr/local/eclipse/eclipse

成功启动后,如果一切都好,则应显示以下结果 -

After a successful startup, if everything is fine, it should display the following result −

eclipsehomepage

Step 4 - Setup Struts2 Libraries

现在,如果一切正常,您可以继续设置 Struts2 框架。以下是下载和在计算机上安装 Struts2 的简单步骤。

Now if everything is fine, then you can proceed to setup your Struts2 framemwork. Following are the simple steps to download and install Struts2 on your machine.

  1. Make a choice whether you want to install Struts2 on Windows, or Unix and then proceed to the next step to download .zip file for windows and .tz file for Unix.

  2. Download the latest version of Struts2 binaries from https://struts.apache.org/download.cgi.

  3. At the time of writing this tutorial, I downloaded struts-2.0.14-all.zip and when you unzip the downloaded file it will give you directory structure inside C:\struts-2.2.3 as follows.

struts directories

第二步是在任何位置提取 zip 文件,我在 Windows 7 计算机上的 c:\ 文件夹中下载并提取了 struts-2.2.3-all.zip ,以便将所有 jar 文件都放入 C:\struts-2.2.3\lib 中。确保正确设置 CLASSPATH 变量,否则在运行应用程序时将遇到问题。

Second step is to extract the zip file in any location, I downloaded & extracted struts-2.2.3-all.zip in c:\ folder on my Windows 7 machine so that I have all the jar files into C:\struts-2.2.3\lib. Make sure you set your CLASSPATH variable properly otherwise you will face problem while running your application.

Struts 2 - Architecture

从高层次来说,Struts2 是一个 pull-MVC(或 MVC2)框架。Struts2 中的模型-视图-控制器模式使用以下五个核心组件实现 -

From a high level, Struts2 is a pull-MVC (or MVC2) framework. The Model-ViewController pattern in Struts2 is implemented with the following five core components −

  1. Actions

  2. Interceptors

  3. Value Stack / OGNL

  4. Results / Result types

  5. View technologies

Struts 2 与传统的 MVC 框架略有不同,其中操作充当模型而不是控制器,尽管有一些重叠。

Struts 2 is slightly different from a traditional MVC framework, where the action takes the role of the model rather than the controller, although there is some overlap.

struts 2 architecture

上图描述了 M*odel, *V*iew and *C*ontroller to the Struts2 high level architecture. The controller is implemented with a *Struts2 调度 servlet 过滤器以及拦截器,此模型使用操作实现,而视图是结果类型和结果的组合。值堆栈和 OGNL 提供公共线程,链接和启用其他组件之间的集成。

The above diagram depicts the M*odel, *V*iew and *C*ontroller to the Struts2 high level architecture. The controller is implemented with a *Struts2 dispatch servlet filter as well as interceptors, this model is implemented with actions, and the view is a combination of result types and results. The value stack and OGNL provides common thread, linking and enabling integration between the other components.

除了上述组件外,还将存在大量与配置相关的信息。Web 应用程序配置,以及动作、拦截器、结果等配置。

Apart from the above components, there will be a lot of information that relates to configuration. Configuration for the web application, as well as configuration for actions, interceptors, results, etc.

这是 Struts 2 MVC 模式的架构概览。我们将在后续章节中更详细地介绍每个组件。

This is the architectural overview of the Struts 2 MVC pattern. We will go through each component in more detail in the subsequent chapters.

Request Life Cycle

根据上图,您可以理解用户请求生命周期中的工作流程 Struts 2 如下 −

Based on the above diagram, you can understand the work flow through user’s request life cycle in Struts 2 as follows −

  1. User sends a request to the server for requesting for some resource (i.e. pages).

  2. The Filter Dispatcher looks at the request and then determines the appropriate Action.

  3. Configured interceptor functionalities applies such as validation, file upload etc.

  4. Selected action is performed based on the requested operation.

  5. Again, configured interceptors are applied to do any post-processing if required.

  6. Finally, the result is prepared by the view and returns the result to the user.

Struts 2 - Hello World Example

您已从 Struts 2 架构中了解到,在 Struts 2 Web 应用程序中单击超链接或提交 HTML 表单时,输入由控制器收集,该控制器将输入发送到名为 Actions 的 Java 类。在执行 Action 后,结果选择资源以呈现响应。该资源通常是 JSP,但它也可以是 PDF 文件、Excel 电子表格或 Java 小程序窗口。

As you have already learnt from the Struts 2 architecture, when you click on a hyperlink or submit an HTML form in a Struts 2 web-application, the input is collected by the Controller which is sent to a Java class called Actions. After the Action is executed, a result selects a resource to render the response. The resource is generally a JSP, but it can also be a PDF file, an Excel spreadsheet, or a Java applet window.

假设您已经构建了开发环境。现在,让我们继续构建我们的第一个 Hello World Struts2 项目。该项目的目标是构建一个收集用户姓名并在用户姓名后显示“Hello World”的 Web 应用程序。

Assuming that you already have built your development environment. Now, let us proceed for building our first Hello World Struts2 project. The aim of this project is to build a web application that collects the user’s name and displays "Hello World" followed by the user name.

对于任何 Struts 2 项目,我们必须创建以下四个组件 −

We would have to create following four components for any Struts 2 project −

Sr.No

Components & Description

1

Action Create an action class which will contain complete business logic and control the interaction between the user, the model, and the view.

2

Interceptors Create interceptors if required, or use existing interceptors. This is part of Controller.

3

View Create a JSPs to interact with the user to take input and to present the final messages.

4

Configuration Files Create configuration files to couple the Action, View and Controllers. These files are struts.xml, web.xml, struts.properties.

我打算使用 Eclipse IDE,这样所有必需的组件都将创建在动态 Web 项目下。让我们现在开始创建动态 Web 项目。

I am going to use Eclipse IDE, so that all the required components will be created under a Dynamic Web Project. Let us now start with creating Dynamic Web Project.

Create a Dynamic Web Project

启动 Eclipse,然后使用 File > New > Dynamic Web Project 执行,输入项目名称为 HelloWorldStruts2 ,并设置其选项的其余部分,如下一个界面中所示 −

Start your Eclipse and then go with File > New > Dynamic Web Project and enter project name as HelloWorldStruts2 and set rest of the options as given in the following screen −

helloworldstruts1

在下一个界面中选择所有默认选项,最后选中 Generate Web.xml deployment descriptor 选项。这将在 Eclipse 中为您创建一个动态 Web 项目。现在使用 Windows > Show View > Project Explorer ,您会看到您的项目窗口如下所示 −

Select all the default options in the next screens and finally check Generate Web.xml deployment descriptor option. This will create a dynamic web project for you in Eclipse. Now go with Windows > Show View > Project Explorer, and you will see your project window something as below −

helloworldstruts2

现在,将 struts 2 库文件夹 C:\struts-2.2.3\lib 中的以下文件复制到我们的项目的 WEB-INF\lib 文件夹。为此,您可以简单地将以下所有文件拖放到 WEB-INF\lib 文件夹中。

Now copy following files from struts 2 lib folder C:\struts-2.2.3\lib to our project’s WEB-INF\lib folder. To do this, you can simply drag and drop all the following files into WEB-INF\lib folder.

  1. commons-fileupload-x.y.z.jar

  2. commons-io-x.y.z.jar

  3. commons-lang-x.y.jar

  4. commons-logging-x.y.z.jar

  5. commons-logging-api-x.y.jar

  6. freemarker-x.y.z.jar

  7. javassist-.xy.z.GA

  8. ognl-x.y.z.jar

  9. struts2-core-x.y.z.jar

  10. xwork-core.x.y.z.jar

Create Action Class

Action 类是 Struts 2 应用程序的关键,我们大多数在 action 类中实现业务逻辑。因此,让我们在 Java Resources > src 下创建一个 Java 文件 HelloWorldAction.java,其中含有 com.tutorialspoint.struts2 包的名称,并在其中包含如下内容。

Action class is the key to Struts 2 application and we implement most of the business logic in action class. So let us create a java file HelloWorldAction.java under Java Resources > src with a package name com.tutorialspoint.struts2 with the contents given below.

Action 类在用户单击 URL 时响应用户操作。将执行一个或多个 Action 类的,并将返回一个字符串结果。特定 JSP 页面将基于结果中含有的值进行呈现。

The Action class responds to a user action when user clicks a URL. One or more of the Action class’s methods are executed and a String result is returned. Based on the value of the result, a specific JSP page is rendered.

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 方法。

This is a very simple class with one property called "name". We have standard getters and setter methods for the "name" property and an execute method that returns the string "success".

Struts 2 框架将为此 HelloWorldAction 类创建一个对象,并在响应用户的操作时调用 execute 方法。您将业务逻辑放入该方法,该方法最终返回 String 常量。换句话说,对于每个 URL,您必须实现一个 action 类,并可以使用类名作为您的 action 名称,或者使用 struts.xml 文件进行映射,如下所示。

The Struts 2 framework will create an object of the HelloWorldAction class and call the executed method in response to a user’s action. You put your business logic inside this method which finally returns the String constant. In other words, for each URL, you would have to implement one action class and either you can use that class name directly as your action name or you can map to some other name using struts.xml file as shown below.

Create a View

我们还需要一个 JSP 来显示最终信息,当发生预定义的操作时,此页面将由 Struts 2 框架调用,且此映射将定义在 struts.xml 文件中。因此,让我们在 Eclipse 项目中的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp 。为此,在 Project Explorer 文件夹中右键单击 WebContent 文件夹,并选择 New >JSP File

We need a JSP to present the final message, this page will be called by Struts 2 framework when a predefined action will happen and this mapping will be defined in struts.xml file. So let us create the below jsp file HelloWorld.jsp in the WebContent folder in your eclipse project. To do this, right click on the WebContent folder in the project explorer and select 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

The taglib directive tells the Servlet container that this page will be using the Struts 2 tags and that these tags will be preceded by s.

s:property 将显示 action 类属性“name”的值,后者由 HelloWorldAction 类中的 getName() 方法返回。

The s:property tag displays the value of action class property "name> which is returned by the method getName() of the HelloWorldAction class.

Create Main Page

我们还需要在 WebContent 中创建 index.jsp 。此文件将作为初始 action URL,用户可以单击此 URL 通知 Struts 2 框架调用 HelloWorldAction 类的确定方法并呈现 HelloWorld.jsp 视图。

We also need to create index.jsp in the WebContent folder. This file will serve as the initial action URL where a user can click to tell the Struts 2 framework to call a defined method of the HelloWorldAction class and render the HelloWorld.jsp view.

<%@ 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 方法,且基于该方法返回的一个值,将选择一个合适的视图并将其呈现为响应。

The hello action defined in the above view file will be mapped to the HelloWorldAction class and its execute method using struts.xml file. When a user clicks on the Submit button it will cause the Struts 2 framework to run the execute method defined in the HelloWorldAction class and based on the returned value of the method, an appropriate view will be selected and rendered as a response.

Configuration Files

我们需要一个映射来关联 URL、HelloWorldAction 类(模型)和 HelloWorld.jsp(视图)。该映射将告诉 Struts 2 框架哪些类将响应用户的操作(URL)、将执行该类的哪些方法,以及将基于该方法返回的字符串结果呈现哪些视图。

We need a mapping to tie the URL, the HelloWorldAction class (Model), and the HelloWorld.jsp (the view) together. The mapping tells the Struts 2 framework which class will respond to the user’s action (the URL), which method of that class will be executed, and what view to render based on the String result that method returns.

因此,让我们创建一个名为 struts.xml 的文件。因为 Struts 2 要求将 struts.xml 放在 classes 文件夹中。因此,在 WebContent/WEB-INF/classes 文件夹下创建 struts.xml 文件。Eclipse 默认不会创建“classes”文件夹,因此您需要自己创建。为此,在 Project Explorer 中右键单击 WEB-INF 文件夹,并选择 New > Folder 。您的 struts.xml 应如下所示:

So let us create a file called struts.xml. Since Struts 2 requires struts.xml to be present in the classes folder. Hence, create struts.xml file under the WebContent/WEB-INF/classes folder. Eclipse does not create the "classes" folder by default, so you need to do this yourself. To do this, right click on the WEB-INF folder in the project explorer and select New > Folder. Your struts.xml should look like −

<?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 的包。

Few words which need to be understood regarding the above configuration file. Here, we set the constant struts.devMode to true, because we are working in development environment and we need to see some useful log messages. Then, we define a package called helloworld.

当您想要将 action 放在一起时,创建包非常有用。在我们的示例中,我们将其 action 命名为“hello”,它对应于 URL /hello.action ,并且由 HelloWorldAction.class 支持。当调用 URL /hello.action 时, HelloWorldAction.classexecute 方法就是要运行的方法。如果 execute 方法返回的结果为“success”,那么我们就会将用户带到 HelloWorld.jsp

Creating a package is useful when you want to group your actions together. In our example, we named our action as "hello" which is corresponding to the URL /hello.action and is backed up by the*HelloWorldAction.class*. The execute method of HelloWorldAction.class is the method that is run when the URL /hello.action is invoked. If the outcome of the execute method returns "success", then we take the user to HelloWorld.jsp.

下一步是创建 web.xml 文件,该文件是 Struts 2 任何请求的入口点。Struts2 应用程序的入口点将是部署描述符 (web.xml) 中定义的一个过滤器。因此,我们会在 web.xml 中定义 org.apache.struts2.dispatcher.FilterDispatcher 类的入口。需要在 WebContent 下的 WEB-INF 文件夹下创建 web.xml 文件。当您创建该项目时,Eclipse 已经为您创建了一个空的 web.xml 文件。因此,我们只需按如下所示对其进行修改:

Next step is to create a web.xml file which is an entry point for any request to Struts 2. The entry point of Struts2 application will be a filter defined in deployment descriptor (web.xml). Hence, we will define an entry of org.apache.struts2.dispatcher.FilterDispatcher class in web.xml. The web.xml file needs to be created under the WEB-INF folder under WebContent. Eclipse had already created a skeleton web.xml file for you when you created the project. So, lets just modify it as follows −

<?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)。

We have specified index.jsp to be our welcome file. Then we have configured the Struts2 filter to run on all urls (i.e, any url that match the pattern /*)

To Enable Detailed Log

您可以在 WEB-INF/classes 文件夹下创建 logging.properties 文件,从而在使用 Struts 2 时启用完整的日志功能。在您的属性文件中保留以下两行内容:

You can enable complete logging functionality while working with Struts 2 by creating logging.properties file under WEB-INF/classes folder. Keep the following two lines in your property file −

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 设置处理器的日志级别阈值。

The default logging.properties specifies a ConsoleHandler for routing logging to stdout and also a FileHandler. A handler’s log level threshold can be set using SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST or ALL.

这就完成了。我们已经准备好使用 Struts 2 框架运行我们的 Hello World 应用程序。

That’s it. We are ready to run our Hello World application using Struts 2 framework.

Procedure for Executing the Application

右键点击项目名称,然后点击 Export > WAR File 创建一个 War 文件。

Right click on the project name and click Export > WAR File to create a War file.

然后将这个 WAR 部署在 Tomcat 的 webapps 目录中。

Then deploy this WAR in the Tomcat’s webapps directory.

最后,启动 Tomcat 服务器,然后尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将给你提供以下屏幕 −

Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will give you following screen −

helloworldstruts4

输入一个值“Struts2”并提交页面。你应该能看到下一页

Enter a value "Struts2" and submit the page. You should see the next page

helloworldstruts5

注意,你可以在 struts.xml 文件中定义一个 index 为一个动作,而在那种情况下,你就可以像 http://localhost:8080/HelloWorldStruts2/index.action 一样调用 index 页面。检查下面如何定义 index 为一个动作 −

Note that you can define index as an action in struts.xml file and in that case you can call index page as http://localhost:8080/HelloWorldStruts2/index.action. Check below how you can define index as an action −

<?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.xmlstruts.properties ,可以配置哪些内容

This chapter will take you through basic configuration which is required for a Struts 2 application. Here we will see what can be configured with the help of few important configuration files like web.xml, struts.xml, strutsconfig.xml and struts.properties

老实说,你只需要使用 web.xmlstruts.xml 配置文件就可以开始工作(正如你在我们前一章中已经亲眼所见,我们的示例是使用这两个文件进行工作的)。但是,为了你的知识,我们将解释关于其他文件的情况。

Honestly speaking, you can start working by just using web.xml and struts.xml configuration files (as you have already witnessed in our previous chapter where our example worked using these two files). However, for your knowledge we will explain regarding other files also.

The web.xml File

web.xml 配置文件是一个 J2EE 配置文件,它确定 HTTP 请求的元素将如何由 servlet 容器处理。它并不是一个严格意义上的 Struts2 配置文件,但是它是 Struts2 能够工作的需要配置的一个文件。

The web.xml configuration file is a J2EE configuration file that determines how elements of the HTTP request are processed by the servlet container. It is not strictly a Struts2 configuration file, but it is a file that needs to be configured for Struts2 to work.

正如前面讨论的,这个文件提供了一个任何网络应用程序的入口点。Struts2 应用程序的入口点将是一个在部署描述符(web.xml)中定义的过滤器。因此,我们将在 web.xml 中定义一个 FilterDispatcher 类的入口。web.xml 文件需要在文件夹 WebContent/WEB-INF 中被创建。

As discussed earlier, this file provides an entry point for any web application. The entry point of Struts2 application will be a filter defined in deployment descriptor (web.xml). Hence we will define an entry of FilterDispatcher class in web.xml. The web.xml file needs to be created under the folder WebContent/WEB-INF.

如果您在没有模板或生成它的工具(例如 Eclipse 或 Maven2)的帮助下开始,那么这是您需要配置的第一个配置文件。

This is the first configuration file you will need to configure if you are starting without the aid of a template or tool that generates it (such as Eclipse or Maven2).

以下是我们在上一个示例中使用的 web.xml 文件的内容。

Following is the content of web.xml file which we used in our last example.

<?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 过滤器解析。当我们学习注释章节的时候,我们将涉及到这一点。

Note that we map the Struts 2 filter to /*, and not to /.action* which means that all urls will be parsed by the struts filter. We will cover this when we will go through the Annotations chapter.

The Struts.xml File

struts.xml 文件包含您将在动作开发时修改的配置信息。这个文件可以用来覆盖应用程序的默认设置,例如 struts.devMode = false 和在属性文件中定义的其他设置。这个文件可以创建在 WEB-INF/classes 文件夹中。

The struts.xml file contains the configuration information that you will be modifying as actions are developed. This file can be used to override default settings for an application, for example struts.devMode = false and other settings which are defined in property file. This file can be created under the folder WEB-INF/classes.

让我们来看看在上一个章节中解释的 Hello World 示例中创建的 struts.xml 文件。

Let us have a look at the struts.xml file we created in the Hello World example explained in previous chapter.

<?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> 允许配置的分离和模块化。当您有一个大项目且项目被分成不同的模块时,这将非常有用。

The first thing to note is the DOCTYPE. All struts configuration file needs to have the correct doctype as shown in our little example. <struts> is the root tag element, under which we declare different packages using <package> tags. Here <package> allows separation and modularization of the configuration. This is very useful when you have a large project and project is divided into different modules.

例如,如果您的项目有三个域 - business_application、customer_application 和 staff_application,那么您可以创建三个包并将关联的动作存储在适当的包中。

For example, if your project has three domains - business_application, customer_application and staff_application, then you could create three packages and store associated actions in the appropriate package.

package 标签具有以下属性 −

The package tag has the following attributes −

Sr.No

Attribute & Description

1

name (required) The unique identifier for the package

2

extends Which package does this package extend from? By default, we use struts-default as the base package.

3

abstract If marked true, the package is not available for end user consumption.

4

namespace Unique namespace for the actions

constant 标记连同 name 和 value 属性应该用于覆盖 default.properties 中定义的以下任何属性,例如我们刚刚设置的 struts.devMode 属性。设置 struts.devMode 属性使我们能够在日志文件中看到更多调试消息。

The constant tag along with name and value attributes should be used to override any of the following properties defined in default.properties, like we just set struts.devMode property. Setting struts.devMode property allows us to see more debug messages in the log file.

我们定义 action 标记对应于我们想要访问的每个 URL,并且我们定义一个具有 execute() 方法的类,该方法将在我们每次访问相应 URL 时访问。

We define action tags corresponds to every URL we want to access and we define a class with execute() method which will be accessed whenever we will access corresponding URL.

结果确定在执行某个动作后返回到浏览器的内容。从动作返回的字符串应该是结果的名称。结果像上面那样按每个动作配置,或者作为一个“全局”结果,可供包中的每个动作使用。结果具有可选的 nametype 属性。默认名称值为 “success”。

Results determine what gets returned to the browser after an action is executed. The string returned from the action should be the name of a result. Results are configured per-action as above, or as a "global" result, available to every action in a package. Results have optional name and type attributes. The default name value is "success".

随着时间的推移,Struts.xml 文件可能会变大,因此按包对其进行拆分是一种模块化方法,但 Struts 提供了另一种模块化 struts.xml 文件的方法。你可以将文件拆分为多个 xml 文件,并按以下方式导入它们。

Struts.xml file can grow big over time and so breaking it by packages is one way of modularizing it, but Struts offers another way to modularize the struts.xml file. You could split the file into multiple xml files and import them in the following fashion.

<?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 other configuration file that we haven’t covered is the struts-default.xml. This file contains the standard configuration settings for Struts and you would not have to touch these settings for 99.99% of your projects. For this reason, we are not going into too much detail on this file. If you are interested, take a look into the at the default.properties file available in struts2-core-2.2.3.jar file.

The Struts-config.xml File

struts-config.xml 配置文件是 Web Client 中 View 和 Model 组件之间的链接,但你无需在 99.99% 的项目中接触这些设置。

The struts-config.xml configuration file is a link between the View and Model components in the Web Client but you would not have to touch these settings for 99.99% of your projects.

配置文件基本上包含以下主要元素 −

The configuration file basically contains following main elements −

Sr.No

Interceptor & Description

1

struts-config This is the root node of the configuration file.

2

form-beans This is where you map your ActionForm subclass to a name. You use this name as an alias for your ActionForm throughout the rest of the strutsconfig.xml file, and even on your JSP pages.

3

global forwards This section maps a page on your webapp to a name. You can use this name to refer to the actual page. This avoids hardcoding URLs on your web pages.

4

action-mappings This is where you declare form handlers and they are also known as action mappings.

5

controller This section configures Struts internals and rarely used in practical situations.

6

plug-in This section tells Struts where to find your properties files, which contain prompts and error messages

以下是样本 struts-config.xml 文件 −

Following is the sample struts-config.xml file −

<?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 文档。

For more detail on struts-config.xml file, kindly check your struts documentation.

The Struts.properties File

此配置文件提供了一种机制来更改框架的默认行为。实际上, struts.properties 配置文件中包含的所有属性也可以在 web.xml 中使用 init-param 配置,以及使用 struts.xml 配置文件中的常量标记。但是,如果你希望让内容保持分离并且更具体,则可以在 WEB-INF/classes 文件夹下创建此文件。

This configuration file provides a mechanism to change the default behavior of the framework. Actually, all the properties contained within the struts.properties configuration file can also be configured in the web.xml using the init-param, as well using the constant tag in the struts.xml configuration file. But, if you like to keep the things separate and more struts specific, then you can create this file under the folder WEB-INF/classes.

此文件中配置的值将覆盖 default.properties 中配置的默认值,该值包含在 struts2-core-x.y.z.jar 发行版中。有一些属性你可以考虑使用 struts.properties 文件进行更改 −

The values configured in this file will override the default values configured in default.properties which is contained in the struts2-core-x.y.z.jar distribution. There are a couple of properties that you might consider changing using the struts.properties file −

### 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 忽略。

Here any line starting with hash (#) will be assumed as a comment and it will be ignored by Struts 2.

Struts 2 - Actions

Actions 是 Struts2 框架的核心,它们对任何 MVC(模型视图控制器)框架来说都是如此。每个 URL 都会映射到一个特定的操作,该操作提供处理逻辑,这是为用户提供服务请求所必需的。

Actions are the core of the Struts2 framework, as they are for any MVC (Model View Controller) framework. Each URL is mapped to a specific action, which provides the processing logic which is necessary to service the request from the user.

但是,该操作还可以在两个其他重要能力中发挥作用。首先,无论它是一个 JSP 还是其他类型的结果,该操作在从请求传输到视图的数据传输中扮演着重要的角色。其次,该操作必须协助框架确定哪个结果应呈现将在响应中返回给请求的视图。

But the action also serves in two other important capacities. Firstly, the action plays an important role in the transfer of data from the request through to the view, whether its a JSP or other type of result. Secondly, the action must assist the framework in determining which result should render the view that will be returned in the response to the request.

Create Action

Struts2 中操作的唯一要求是必须有一个不带参数的方法,该方法返回一个 String 或 Result 对象,并且必须是一个 POJO。如果未指定不带参数的方法,则默认行为是使用 execute() 方法。

The only requirement for actions in Struts2 is that there must be one noargument method that returns either a String or Result object and must be a POJO. If the no-argument method is not specified, the default behavior is to use the execute() method.

另外,你可以扩展实现六个接口的 ActionSupport 类,包括 Action 接口。Action 接口如下:

Optionally you can extend the ActionSupport class which implements six interfaces including Action interface. The Action interface is as follows −

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 示例中的操作方法:

Let us take a look at the action method in the Hello World example −

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:

To illustrate the point that the action method controls the view, let us make the following change to the execute method and extend the class ActionSupport as follows −

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 文件:

In this example, we have some logic in the execute method to look at the name attribute. If the attribute equals to the string "SECRET", we return SUCCESS as the result otherwise we return ERROR as the result. Because we have extended ActionSupport, so we can use String constants SUCCESS and ERROR. Now, let us modify our struts.xml file as follows −

<?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”),则会调用该文件:

Let us create the below jsp file HelloWorld.jsp in the WebContent folder in your eclipse project. To do this, right click on the WebContent folder in the project explorer and select New >JSP File. This file will be called in case return result is SUCCESS which is a String constant "success" as defined in Action interface −

<%@ 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 的内容:

Following is the file which will be invoked by the framework in case action result is ERROR which is equal to String constant "error". Following is the content of 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 视图。

We also need to create index.jsp in the WebContent folder. This file will serve as the initial action URL where the user can click to tell the Struts 2 framework to call the *execute*method of the HelloWorldAction class and render the HelloWorld.jsp view.

<%@ 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 应用程序了。

That’s it, there is no change required for web.xml file, so let us use the same web.xml which we had created in Examples chapter. Now, we are ready to run our Hello World application using Struts 2 framework.

Execute the Application

右键单击项目名称并单击 Export > WAR 文件来创建一个 War 文件。然后将此 WAR 部署到 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将为您提供以下屏幕:

Right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will give you following screen −

helloworldstruts4

让我们输入一个单词“SECRET”,你将看到以下页面:

Let us enter a word as "SECRET" and you should see the following page −

helloworldstruts51

现在输入除了“SECRET”之外的任何单词,你将看到以下页面:

Now enter any word other than "SECRET" and you should see the following page −

helloworldstruts6

Create Multiple Actions

你将经常定义多个操作来处理不同的请求并向用户提供不同的 URL,你要按如下所示定义不同的类:

You will frequently define more than one actions to handle different requests and to provide different URLs to the users, accordingly you will define different classes as defined below −

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 文件中配置这些操作:

You will configure these actions in struts.xml file as follows −

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

正如你在上面假设的示例中看到的那样,操作结果 SUCCESSERROR’s 是重复的。

As you can see in the above hypothetical example, the action results SUCCESS and ERROR’s are duplicated.

为了解决此问题,建议你创建一个包含结果结果的类。

To get around this issue, it is suggested that you create a class which contains the result outcomes.

Struts 2 - Interceptors

从本质上讲,拦截器与 servlet 过滤器或 JDK 的 Proxy 类相同。拦截器允许跨模块功能与操作和框架分开发挥作用。您可以使用拦截器实现以下内容 −

Interceptors are conceptually the same as servlet filters or the JDKs Proxy class. Interceptors allow for crosscutting functionality to be implemented separately from the action as well as the framework. You can achieve the following using interceptors −

  1. Providing preprocessing logic before the action is called.

  2. Providing postprocessing logic after the action is called.

  3. Catching exceptions so that alternate processing can be performed.

Struts2 框架中提供的许多功能都是使用拦截器实现的;

Many of the features provided in the Struts2 framework are implemented using interceptors;

Examples 包括异常处理、文件上传、生命周期回调等。实际上,由于 Struts2 将其大部分功能强调在拦截器上,因此不太可能为每个操作分配 7 到 8 个拦截器。

Examples include exception handling, file uploading, lifecycle callbacks, etc. In fact, as Struts2 emphasizes much of its functionality on interceptors, it is not likely to have 7 or 8 interceptors assigned per action.

Struts2 Framework Interceptors

Struts2 框架提供了一个即用型开箱拦截器列表,这些拦截器已经过预配置并准备使用。下面列出了一些重要的拦截器 −

Struts 2 framework provides a good list of out-of-the-box interceptors that come preconfigured and ready to use. Few of the important interceptors are listed below −

Sr.No

Interceptor & Description

1

alias Allows parameters to have different name aliases across requests.

2

checkbox Assists in managing check boxes by adding a parameter value of false for check boxes that are not checked.

3

conversionError Places error information from converting strings to parameter types into the action’s field errors.

4

createSession Automatically creates an HTTP session if one does not already exist.

5

debugging Provides several different debugging screens to the developer.

6

execAndWait Sends the user to an intermediary waiting page while the action executes in the background.

7

exception Maps exceptions that are thrown from an action to a result, allowing automatic exception handling via redirection.

8

fileUpload Facilitates easy file uploading.

9

i18n Keeps track of the selected locale during a user’s session.

10

logger Provides simple logging by outputting the name of the action being executed.

11

params Sets the request parameters on the action.

12

prepare This is typically used to do pre-processing work, such as setup database connections.

13

profile Allows simple profiling information to be logged for actions.

14

scope Stores and retrieves the action’s state in the session or application scope.

15

ServletConfig Provides the action with access to various servlet-based information.

16

timer Provides simple profiling information in the form of how long the action takes to execute.

17

token Checks the action for a valid token to prevent duplicate formsubmission.

18

validation Provides validation support for actions

请在 Struts 2 文档中查找以上所述拦截器的完备详细信息。但我会向你展示如何在 Struts 应用程序中通常使用拦截器。

Please look into Struts 2 documentation for complete detail on the abovementioned interceptors. But I will show you how to use an interceptor in general in your Struts application.

How to Use Interceptors?

让我们了解如何在“Hello World”程序中使用已存在的拦截器。我们将使用 timer 拦截器,其目的是衡量执行操作方法所需的时间。同时,我正在使用 params 拦截器,其目的是将请求参数发送到操作。你可以尝试不使用此拦截器来验证你的示例,你会发现 name 属性没有被设置,这是因为参数无法到达操作。

Let us see how to use an already existing interceptor to our "Hello World" program. We will use the timer interceptor whose purpose is to measure how long it took to execute an action method. At the same time, I’m using params interceptor whose purpose is to send the request parameters to the action. You can try your example without using this interceptor and you will find that name property is not being set because parameter is not able to reach to the action.

我们将保留 HelloWorldAction.java、web.xml、HelloWorld.jsp 和 index.jsp 文件,因为它们已在 Examples 章节中创建,但让我们修改 struts.xml 文件以添加一个拦截器,如下所示:

We will keep HelloWorldAction.java, web.xml, HelloWorld.jsp and index.jsp files as they have been created in Examples chapter but let us modify the struts.xml file to add an interceptor as follows −

<?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 。这将产生以下屏幕:

Right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts4

现在在给定的文本框中输入任意单词并单击马上问候按钮来执行已定义的操作。现在,如果你将检查生成的日志,你会发现以下文本:

Now enter any word in the given text box and click Say Hello button to execute the defined action. Now if you will check the log generated, you will find the following text −

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 毫秒才得以执行。

Here bottom line is being generated because of timer interceptor which is telling that action took total 109ms to be executed.

Create Custom Interceptors

在应用程序中使用自定义拦截器是提供跨切割应用程序功能的优雅方式。创建自定义拦截器很容易;需要扩展的接口是以下 Interceptor 接口:

Using custom interceptors in your application is an elegant way to provide crosscutting application features. Creating a custom interceptor is easy; the interface that needs to be extended is the following Interceptor interface −

public interface Interceptor extends Serializable {
   void destroy();
   void init();
   String intercept(ActionInvocation invocation)
   throws Exception;
}

顾名思义,init() 方法提供一种方法来初始化拦截器,而 destroy() 方法则提供一种拦截器清理功能。与操作不同,拦截器将在所有请求中重复使用,且需要线程安全,尤其是 intercept() 方法。

As the names suggest, the init() method provides a way to initialize the interceptor, and the destroy() method provides a facility for interceptor cleanup. Unlike actions, interceptors are reused across requests and need to be threadsafe, especially the intercept() method.

ActionInvocation 对象提供对运行时环境的访问。它允许访问操作本身以及用于调用操作并确定是否已调用操作的方法。

The ActionInvocation object provides access to the runtime environment. It allows access to the action itself and methods to invoke the action and determine whether the action has already been invoked.

如果你不需要初始化或清理代码,则可以扩展 AbstractInterceptor 类。它提供了 init() 和 destroy() 方法的默认无效操作实现。

If you have no need for initialization or cleanup code, the AbstractInterceptor class can be extended. This provides a default nooperation implementation of the init() and destroy() methods.

Create Interceptor Class

让我们在 Java Resources > src 文件夹中创建以下 MyInterceptor.java:

Let us create the following MyInterceptor.java in Java Resources > src folder −

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() 由拦截器执行。因此,你可以根据你的要求进行某些预处理和后处理。

As you notice, actual action will be executed using the interceptor by *invocation.invoke()*call. So you can do some pre-processing and some postprocessing based on your requirement.

框架本身通过对 ActionInvocation 对象的 invoke() 进行首次调用来启动该进程。每次调用 invoke() 时,ActionInvocation 都会咨询其状态并执行随之而来的任何一个拦截器。当调用所有配置的拦截器后,invoke() 方法将导致执行操作本身。

The framework itself starts the process by making the first call to the ActionInvocation object’s invoke(). Each time invoke() is called, ActionInvocation consults its state and executes whichever interceptor comes next. When all of the configured interceptors have been invoked, the invoke() method will cause the action itself to be executed.

下图通过请求流程显示了相同概念 -

The following diagram shows the same concept through a request flow −

actioninvocation

Create Action Class

让我们在 Java Resources > src 中使用包名 com.tutorialspoint.struts2 创建一个 java 文件 HelloWorldAction.java ,内容如下。

Let us create a java file HelloWorldAction.java under Java Resources > src with a package name com.tutorialspoint.struts2 with the contents given below.

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 方法,还有一个返回字符串“成功”的执行方法。

This is a same class which we have seen in previous examples. We have standard getters and setter methods for the "name" property and an execute method that returns the string "success".

Create a View

让我们在 Eclipse 项目的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp

Let us create the below jsp file HelloWorld.jsp in the WebContent folder in your eclipse project.

<%@ 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 视图。

We also need to create index.jsp in the WebContent folder. This file will serve as the initial action URL where a user can click to tell the Struts 2 framework to call the a defined method of the HelloWorldAction class and render the HelloWorld.jsp view.

<%@ 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 类及其执行方法。

The hello action defined in the above view file will be mapped to the HelloWorldAction class and its execute method using struts.xml file.

Configuration Files

现在,我们需要注册我们的拦截器,然后调用它,就像我们在前一个示例中调用缺省拦截器一样。要注册一个新定义的拦截器,需要将 <interceptors>…​</interceptors> 标签直接放在 struts.xml 文件的 <package> 标签下面。你可以跳过为缺省拦截器执行这一步骤,就像我们在前一个示例中所做的那样。但此处让我们注册并使用它,如下所示 -

Now, we need to register our interceptor and then call it as we had called default interceptor in previous example. To register a newly defined interceptor, the <interceptors>…​</interceptors> tags are placed directly under the <package> tag ins*struts.xml* file. You can skip this step for a default interceptors as we did in our previous example. But here let us register and use it as follows −

<?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> 标签内调用多个拦截器。你可以使用不同的操作调用同一个拦截器。

It should be noted that you can register more than one interceptors inside <package> tag and same time you can call more than one interceptors inside the <action> tag. You can call same interceptor with the different actions.

需要在 WebContent 下面的 WEB-INF 文件夹下创建 web.xml 文件,如下所示 -

The web.xml file needs to be created under the WEB-INF folder under WebContent as follows −

<?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 。这将产生以下屏幕:

Right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts4

现在,在给定文本框中输入任意单词,然后单击“Say Hello”按钮以执行定义的操作。现在,如果你检查生成的日志,你将会在底部找到以下文本 -

Now enter any word in the given text box and click Say Hello button to execute the defined action. Now if you will check the log generated, you will find the following text at the bottom −

Pre-Processing
Inside action....
Post-Processing

Stacking Multiple Interceptors

如你所想象的,必须为每个操作配置多个拦截器会很快变得极度难以管理。因此,拦截器使用拦截器栈进行管理。以下就是一个直接来自 strutsdefault.xml 文件的示例 -

As you can imagine, having to configure multiple interceptor for each action would quickly become extremely unmanageable. For this reason, interceptors are managed with interceptor stacks. Here is an example, directly from the strutsdefault.xml file −

<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 …​/> 标签都引用在此当前拦截器栈之前配置的拦截器或拦截器栈。因此,在配置初始拦截器和拦截器栈时,确保所有拦截器和拦截器栈配置中的名称是唯一的非常重要。

The above stake is called basicStack and can be used in your configuration as shown below. This configuration node is placed under the <package …​/> node. Each <interceptor-ref …​/> tag references either an interceptor or an interceptor stack that has been configured before the current interceptor stack. It is therefore very important to ensure that the name is unique across all interceptor and interceptor stack configurations when configuring the initial interceptors and interceptor stacks.

我们已经了解了如何对操作应用拦截器,对拦截器栈应用拦截器与此没有什么不同。事实上,我们使用完全相同的标签 -

We have already seen how to apply interceptor to the action, applying interceptor stacks is no different. In fact, we use exactly the same tag −

<action name = "hello" class = "com.tutorialspoint.struts2.MyAction">
   <interceptor-ref name = "basicStack"/>
   <result>view.jsp</result>
</action

对“basicStack”的上述注册将完全登记在 hello 操作中六个拦截器的全部赌注。需要注意的是,拦截器按照其配置的顺序执行。例如,在上述情况下,exception 将首先执行,其次是 servlet-config,依此类推。

The above registration of "basicStack" will register complete stake of all the six interceptors with hello action. This should be noted that interceptors are executed in the order, in which they have been configured. For example, in the above case, exception will be executed first, second would be servlet-config and so on.

Struts 2 - Results & Result Types

如前所述, <results> 标记在 Struts2 MVC 框架中扮演 view 的角色。此操作负责执行业务逻辑。执行业务逻辑后的下一步是使用 <results> 标记显示视图。

As mentioned previously, the <results> tag plays the role of a view in the Struts2 MVC framework. The action is responsible for executing the business logic. The next step after executing the business logic is to display the view using the <results> tag.

通常有一些导航规则附加到结果。例如,如果操作方法是验证用户,那么有三个可能的结果。

Often there is some navigation rules attached with the results. For example, if the action method is to authenticate a user, there are three possible outcomes.

  1. Successful Login

  2. Unsuccessful Login - Incorrect username or password

  3. Account Locked

在这种情况下,操作方法将配置三个可能的结果字符串和三个不同的视图来呈现结果。我们在前面的示例中已经看到过这一点。

In this scenario, the action method will be configured with three possible outcome strings and three different views to render the outcome. We have already seen this in the previous examples.

但是,Struts2 并没有将您绑定到使用 JSP 作为视图技术。毕竟,MVC 范例的全部目的是保持层分离和高度可配置。例如,对于 Web2.0 客户端,您可能想要返回 XML 或 JSON 作为输出。在这种情况下,您可以创建用于 XML 或 JSON 的新结果类型并实现此目的。

But, Struts2 does not tie you up with using JSP as the view technology. Afterall the whole purpose of the MVC paradigm is to keep the layers separate and highly configurable. For example, for a Web2.0 client, you may want to return XML or JSON as the output. In this case, you could create a new result type for XML or JSON and achieve this.

Struts 带有一些预定义的 result types 和我们已经看到过的 dispatcher 的默认结果类型,用于分发到 JSP 页面。Struts 允许您使用其他标记语言作为视图技术来呈现结果,流行的选择包括 Velocity, Freemaker, XSLTTiles

Struts comes with a number of predefined result types and whatever we’ve already seen that was the default result type dispatcher, which is used to dispatch to JSP pages. Struts allow you to use other markup languages for the view technology to present the results and popular choices include Velocity, Freemaker, XSLT and Tiles.

The Dispatcher Result Type

dispatcher 结果类型是默认类型,如果未指定其他结果类型,将使用此类型。它用于转发到服务器上的 servlet、JSP、HTML 页面等。它使用 RequestDispatcher.forward() 方法。

The dispatcher result type is the default type, and is used if no other result type is specified. It’s used to forward to a servlet, JSP, HTML page, and so on, on the server. It uses the RequestDispatcher.forward() method.

我们在前面的示例中看到了“简写”版本,其中我们提供了一个 JSP 路径作为结果标记的主体。

We saw the "shorthand" version in our earlier examples, where we provided a JSP path as the body of the result tag.

<result name = "success">
   /HelloWorld.jsp
</result>

我们还可以在 <result…​> 元素内使用 <param name = "location"> 标记指定 JSP 文件,如下所示:

We can also specify the JSP file using a <param name = "location"> tag within the <result…​> element as follows −

<result name = "success" type = "dispatcher">
   <param name = "location">
      /HelloWorld.jsp
   </param >
</result>

我们还可以提供一个 parse 参数,默认情况下为 true。parse 参数确定是否为 OGNL 表达式解析 location 参数。

We can also supply a parse parameter, which is true by default. The parse parameter determines whether or not the location parameter will be parsed for OGNL expressions.

The FreeMaker Result Type

在此示例中,我们将看到如何使用 FreeMaker 作为视图技术。Freemaker 是一个流行的模板引擎,用于使用预定义模板生成输出。现在,让我们创建一个名为 hello.fm 的 Freemaker 模板文件,内容如下:

In this example, we are going to see how we can use FreeMaker as the view technology. Freemaker is a popular templating engine that is used to generate output using predefined templates. Let us now create a Freemaker template file called hello.fm with the following contents −

Hello World ${name}

上述文件是一个模板,其中 name 是一个参数,它将从外部使用已定义的动作传递进来。您将把此文件保持在 CLASSPATH 中。

The above file is a template where name is a parameter which will be passed from outside using the defined action. You will keep this file in your CLASSPATH.

接下来,让我们修改 struts.xml 以指定结果,如下所示:

Next, let us modify the struts.xml to specify the result as follows −

<?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 文件。

Let us keep our HelloWorldAction.java, HelloWorldAction.jsp and index.jsp files as we have created them in examples chapter.

现在右键单击项目名称,然后单击 Export > WAR File 以创建 War 文件。

Now Right click on the project name and click Export > WAR File to create a War file.

然后将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕。

Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen .

helloworldstruts4

输入一个值“Struts2”并提交页面。您应该看到下一页。

Enter a value "Struts2" and submit the page. You should see the next page.

helloworldstruts5

如您所见,这与 JSP 视图完全相同,只不过我们不必绑定到使用 JSP 作为视图技术。在此示例中,我们使用了 Freemaker。

As you can see, this is exactly same as the JSP view except that we are not tied to using JSP as the view technology. We have used Freemaker in this example.

The Redirect Result Type

redirect 结果类型调用标准 response.sendRedirect() 方法,导致浏览器对给定位置创建新的请求。

The redirect result type calls the standard response.sendRedirect() method, causing the browser to create a new request to the given location.

我们可以提供 <result…​> 元素 body 中或 <param name = "location"> 元素中的一个位置。Redirect 也支持 parse 参数。以下是一个使用 XML 配置的样例 −

We can provide the location either in the body of the <result…​> element or as a <param name = "location"> element. Redirect also supports the parse parameter. Here’s an example configured using 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 样例以获得更深入的了解。

So just modify your struts.xml file to define redirect type as mentioned above and create a new file NewWorld.jpg where you will be redirected whenever hello action will return success. You can check Struts 2 Redirect Action example for better understanding.

Struts 2 - Value Stack/OGNL

The Value Stack

值堆栈是一组包含以下对象的对象,这些对象按照给定的顺序排列 −

The value stack is a set of several objects which keeps the following objects in the provided order −

Sr.No

Objects & Description

1

Temporary Objects There are various temporary objects which are created during execution of a page. For example the current iteration value for a collection being looped over in a JSP tag.

2

The Model Object If you are using model objects in your struts application, the current model object is placed before the action on the value stack.

3

The Action Object This will be the current action object which is being executed.

4

Named Objects These objects include #application, #session, #request, #attr and #parameters and refer to the corresponding servlet scopes.

可以通过为 JSP、Velocity 或 Freemarker 提供的标记访问值堆栈。我们将使用各种标记,在单独的章节中学习如何使用这些标记来获取和设置 struts 2.0 值堆栈。您可以按如下方式在操作中获取 ValueStack 对象 −

The value stack can be accessed via the tags provided for JSP, Velocity or Freemarker. There are various tags which we will study in separate chapters, are used to get and set struts 2.0 value stack. You can get valueStack object inside your action as follows −

ActionContext.getContext().getValueStack()

一旦您获得 ValueStack 对象,就可以使用以下方法来操作该对象 −

Once you have a ValueStack object, you can use the following methods to manipulate that object −

Sr.No

ValueStack Methods & Description

1

Object findValue(String expr) Find a value by evaluating the given expression against the stack in the default search order.

2

CompoundRoot getRoot() Get the CompoundRoot which holds the objects pushed onto the stack.

3

Object peek() Get the object on the top of the stack without changing the stack.

4

Object pop() Get the object on the top of the stack and remove it from the stack.

5

*void push(Object o)*Put this object onto the top of the stack.

6

void set(String key, Object o) Sets an object on the stack with the given key so it is retrievable by findValue(key,…​)

7

void setDefaultType(Class defaultType) Sets the default type to convert to if no type is provided when getting a value.

8

void setValue(String expr, Object value) Attempts to set a property on a bean in the stack with the given expression using the default search order.

9

int size() Get the number of objects in the stack.

The OGNL

Object-Graph Navigation Language (OGNL)是一种功能强大的表达式语言,用于引用和操作 ValueStack 上的数据。OGNL 还帮助进行数据传输和类型转换。

The Object-Graph Navigation Language (OGNL) is a powerful expression language that is used to reference and manipulate data on the ValueStack. OGNL also helps in data transfer and type conversion.

OGNL 非常类似于 JSP 表达式语言。OGNL 以在上下文中拥有 root 或默认对象的想法为基础。可以使用井号符号(即标记符号)来引用默认对象或 root 对象的属性。

The OGNL is very similar to the JSP Expression Language. OGNL is based on the idea of having a root or default object within the context. The properties of the default or root object can be referenced using the markup notation, which is the pound symbol.

如前所述,OGNL 基于上下文,而 Struts 会构建一个 ActionContext 映射以用于 OGNL。ActionContext 映射包含以下内容:

As mentioned earlier, OGNL is based on a context and Struts builds an ActionContext map for use with OGNL. The ActionContext map consists of the following −

  1. Application − Application scoped variables

  2. Session − Session scoped variables

  3. Root / value stack − All your action variables are stored here

  4. Request − Request scoped variables

  5. Parameters − Request parameters

  6. Atributes − The attributes stored in page, request, session and application scope

了解 Action 对象始终在值栈中可用非常重要。所以,如果您的 Action 对象具有属性 “x”“y” ,您可以随时使用它们。

It is important to understand that the Action object is always available in the value stack. So, therefore if your Action object has properties “x” and “y” there are readily available for you to use.

ActionContext 中的对象使用井号符号进行引用,但是,可以直接引用值栈中的对象。

Objects in the ActionContext are referred using the pound symbol, however, the objects in the value stack can be directly referenced.

例如,如果 employee 是一个操作类的属性,那么它可以按如下方式引用:

For example, if employee is a property of an action class, then it can be referenced as follows −

<s:property value = "name"/>

代替

instead of

<s:property value = "#name"/>

如果您在会话中有一个名为“login”的属性,您可以按如下方式检索它:

If you have an attribute in session called "login" you can retrieve it as follows −

<s:property value = "#session.login"/>

OGNL 还支持处理集合,即 Map、List 和 Set。例如,要显示颜色下拉列表,您可以执行以下操作:

OGNL also supports dealing with collections - namely Map, List and Set. For example to display a dropdown list of colors, you could do −

<s:select name = "color" list = "{'red','yellow','green'}" />

OGNL 表达式巧妙地将“red”、“yellow”、“green”解释为颜色,并基于此构建了一个列表。

The OGNL expression is clever to interpret the "red","yellow","green" as colours and build a list based on that.

在后续章节中研究不同标记时,OGNL 表达式将被广泛使用。因此,与其孤立地查看它们,不如让我们在表单标记/控制标记/数据标记和 Ajax 标记部分中使用一些示例来查看它们。

The OGNL expressions will be used extensively in the next chapters when we will study different tags. So rather than looking at them in isolation, let us look at it using some examples in the Form Tags / Control Tags / Data Tags and Ajax Tags section.

ValueStack/OGNL Example

Create Action

让我们考虑以下操作类,在该类中我们将访问 valueStack,然后设置一些键,我们将在我们的视图中使用 OGNL 来访问这些键,即 JSP 页面。

Let us consider the following action class where we are accessing valueStack and then setting few keys which we will access using OGNL in our view, i.e., JSP page.

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 中如何工作的。

Actually, Struts 2 adds your action to the top of the valueStack when executed. So, the usual way to put stuff on the Value Stack is to add getters/setters for the values to your Action class and then use <s:property> tag to access the values. But I’m showing you how exactly ActionContext and ValueStack work in struts.

Create Views

让我们在 eclipse 项目中的 WebContent 文件夹中创建以下 jsp 文件 HelloWorld.jsp 。如果执行返回成功,则该视图将被显示:

Let us create the below jsp file HelloWorld.jsp in the WebContent folder in your eclipse project. This view will be displayed in case action returns success −

<%@ 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 ,其内容如下:

We also need to create index.jsp in the WebContent folder whose content is as follows −

<%@ 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 文件的内容 −

Following is the content of struts.xml file −

<?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 文件的内容:

Following is the content of web.xml file −

<?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 目录中。

Right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory.

最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/index.jsp 。这将生成以下屏幕

Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen

helloworldstruts4

现在在给定的文本框中输入任何单词并点击“Say Hello”按钮以执行定义的操作。现在,如果你将检查引发的日志,你将会在底部找到以下文本 −

Now enter any word in the given text box and click "Say Hello" button to execute the defined action. Now, if you will check the log generated, you will find the following text at the bottom −

Size of the valueStack: 3

这将显示以下屏幕,该屏幕将显示你输入的任何值以及我们在 ValueStack 上放置的 key1 和 key2 的值。

This will display the following screen, which will display whatever value you will enter and value of key1 and key2 which we had put on ValueStack.

Struts 2 - File Uploads

Struts 2 框架提供内置的支持来使用“HTML 中基于表单的文件上传”处理文件上传。当上传一个文件时,它通常会存储在一个临时目录中,并应该由你的 Action 类处理或移动到一个永久目录中以确保数据不会丢失。

The Struts 2 framework provides built-in support for processing file upload using "Form-based File Upload in HTML". When a file is uploaded, it will typically be stored in a temporary directory and they should be processed or moved by your Action class to a permanent directory to ensure the data is not lost.

Note - 服务器可能会实施禁止写入临时目录和你 Web 应用程序所属目录之外的目录的安全策略。

Note − Servers may have a security policy in place that prohibits you from writing to directories other than the temporary directory and the directories that belong to your web application.

Struts 中的文件上传可以通过一个称为 FileUpload 的预定义拦截器来实现,可以通过类 org.apache.struts2.interceptor.FileUploadInterceptor 获得,并作为 defaultStack 的一部分包括其中。仍然可以在你自己的 struts.xml 中使用它来设置各种参数,如下所示。

File uploading in Struts is possible through a pre-defined interceptor called FileUpload interceptor which is available through the org.apache.struts2.interceptor.FileUploadInterceptor class and included as part of the*defaultStack*. Still you can use that in your struts.xml to set various paramters as we will see below.

Create View Files

让我们从创建我们的视图开始,该视图需要浏览和上传一个选定的文件。所以让我们创建一个 index.jsp ,带一个允许用户上传文件的简单 HTML 上传表单 −

Let us start with creating our view which will be required to browse and upload a selected file. So let us create an index.jsp with plain HTML upload form that allows the user to upload a file −

<%@ 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 配置。

There is couple of points worth noting in the above example. First, the form’s enctype is set to multipart/form-data. This should be set so that file uploads are handled successfully by the file upload interceptor. The next point noting is the form’s action method upload and the name of the file upload field - which is myFile. We need this information to create the action method and the struts configuration.

接下来,让我们创建一个 success.jsp 以显示在文件上传成功后我们的结果。

Next, let us create a simple jsp file success.jsp to display the outcome of our file upload in case it becomes success.

<%@ 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 的结果文件,如果在上传文件时有一些错误 −

Following will be the result file error.jsp in case there is some error in uploading the file −

<%@ 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 类,它将负责上传文件并将该文件存储在一个安全的位置中 −

Next, let us create a Java class called uploadFile.java which will take care of uploading file and storing that file at a secure location −

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 拦截器为我们完成了所有繁重的任务。

The uploadFile.java is a very simple class. The important thing to note is that the FileUpload interceptor along with the Parameters Interceptor does all the heavy lifting for us.

FileUpload 拦截器默认情况下为你提供三个参数。它们按照以下模式命名 −

The FileUpload interceptor makes three parameters available for you by default. They are named in the following pattern −

  1. *[your file name parameter] * − This is the actual file that the user has uploaded. In this example it will be "myFile"

  2. [your file name parameter]ContentType − This is the content type of the file that was uploaded. In this example it will be "myFileContentType"

  3. [your file name parameter]FileName − This is the name of the file that was uploaded. In this example it will be "myFileFileName"

这三个参数可供我们使用,这要归功于 Struts 拦截器。我们必须做的就是用正确的名称在我们的 Action 类中创建三个参数,这些变量将自动为我们自动连接。因此,在上面的示例中,我们有三个参数,一个行动方法,如果一切都好,它会返回“成功”,否则它将返回“错误”。

The three parameters are available for us, thanks to the Struts Interceptors. All we have to do is to create three parameters with the correct names in our Action class and automatically these variables are auto wired for us. So, in the above example, we have three parameters and an action method that simply returns "success" if everything goes fine otherwise it returns "error".

Configuration Files

以下是控制文件上传过程的 Struts2 配置属性:

Following are the Struts2 configuration properties that control file uploading process −

Sr.No

Properties & Description

1

struts.multipart.maxSize The maximum size (in bytes) of a file to be accepted as a file upload. Default is 250M.

2

struts.multipart.parser The library used to upload the multipart form. By default is jakarta

3

struts.multipart.saveDir The location to store the temporary file. By default is javax.servlet.context.tempdir.

为了更改这些设置中的任何一个,您可以在应用程序的 struts.xml 文件中使用 constant 标记,如我所做的那样,将上传的文件的最大大小更改为。

In order to change any of these settings, you can use constant tag in your applications struts.xml file, as I did to change the maximum size of a file to be uploaded.

让我们将我们的 struts.xml 设置为以下内容:

Let us have our struts.xml as follows −

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

Since, FileUpload interceptor is a part of the default Stack of interceptors, we do not need to configure it explicity. But, you can add <interceptor-ref> tag inside <action>. The fileUpload interceptor takes two parameters (a) maximumSize and (b) allowedTypes.

maximumSize 参数设置允许的最大文件大小(默认大小约为 2MB)。allowedTypes 参数是以逗号分隔的已接受内容(MIME)类型的列表,如下所示:

The maximumSize parameter sets the maximum file size allowed (the default is approximately 2MB). The allowedTypes parameter is a comma-separated list of accepted content (MIME) types as shown below −

<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 文件的内容:

Following is the content of web.xml file −

<?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 。这将生成以下屏幕:

Now Right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/upload.jsp. This will produce the following screen −

helloworldstruts7

现在使用“浏览”按钮选择文件“Contacts.txt”,然后单击上传按钮,该按钮将在您的服务上上传文件,您应该会看到下一页。您可以检查上传的文件是否已保存在 C:\apache-tomcat-6.0.33\work 中。

Now select a file "Contacts.txt" using Browse button and click upload button which will upload the file on your serve and you should see the next page. You can check the uploaded file should be saved in C:\apache-tomcat-6.0.33\work.

helloworldstruts8

请注意,FileUpload 拦截器会自动删除上传的文件,因此您必须在文件被删除之前以编程方式将上传的文件保存在某个位置。

Note that the FileUpload Interceptor deletes the uploaded file automatically so you would have to save uploaded file programmatically at some location before it gets deleted.

Error Messages

fileUplaod 拦截器使用几个默认的错误消息键:

The fileUplaod interceptor uses several default error message keys −

Sr.No

Error Message Key & Description

1

struts.messages.error.uploading A general error that occurs when the file could not be uploaded.

2

struts.messages.error.file.too.large Occurs when the uploaded file is too large as specified by maximumSize.

3

struts.messages.error.content.type.not.allowed Occurs when the uploaded file does not match the expected content types specified.

您可以在 WebContent/WEB-INF/classes/messages.properties 资源文件中覆盖这些消息的文本。

You can override the text of these messages in WebContent/WEB-INF/classes/messages.properties resource files.

Struts 2 - Database Access

本节将指导您使用 Struts 2 以简单的步骤访问数据库。Struts 是 MVC 框架,而不是数据库框架,但它为 JPA/Hibernate 集成提供了出色的支持。我们将在后面的章节中了解 Hibernate 集成,但在本节中我们将使用普通的旧 JDBC 访问数据库。

This chapter will teach you how to access a database using Struts 2 in simple steps. Struts is a MVC framework and not a database framework but it provides excellent support for JPA/Hibernate integration. We shall look at the hibernate integration in a later chapter, but in this chapter we shall use plain old JDBC to access the database.

本节的第一步是设置并启动我们的数据库。我使用 MySQL 作为本示例中的数据库。我在计算机上安装了 MySQL,并创建了一个名为 “struts_tutorial” 的新数据库。我创建了一个名为 login 的表,并在其中填充一些值。以下是创建和填充表的脚本。

The first step in this chapter is to setup and prime our database. I am using MySQL as my database for this example. I have MySQL installed on my machine and I have created a new database called "struts_tutorial". I have created a table called login and populated it with some values. Below is the script I used to create and populate the table.

我的 MYSQL 数据库的默认用户名是 “root”,密码是 “root123”

My MYSQL database has the default username "root" and "root123" password

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 类。

Next step is to download the MySQL Connector jar file and placing this file in the WEB-INF\lib folder of your project. After we have done this, we are now ready to create the action class.

Create Action

Action 类具有与数据库表中的列对应的属性。我们有 user, passwordname 作为字符串属性。在 Action 方法中,我们使用用户和密码参数检查用户是否存在,如果是,我们在下一个屏幕中显示用户名。

The action class has the properties corresponding to the columns in the database table. We have user, password and name as String attributes. In the action method, we use the user and password parameters to check if the user exists, if so, we display the user name in the next screen.

如果用户输入了错误信息,我们将他们再次发送到登录屏幕。

If the user has entered wrong information, we send them to the login screen again.

以下是 LoginAction.java 文件的内容:

Following is the content of LoginAction.java file −

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 来收集用户名和密码。此用户名和密码将与数据库进行比对。

Now, let us create a JSP file index.jsp to collect the username and password. This username and password will be checked against the database.

<%@ 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 返回错误,我们将有另一个视图文件。

Now let us create success.jsp file which will be invoked in case action returns SUCCESS, but we will have another view file in case of an ERROR is returned from the 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

Following will be the view file error.jsp in case of an ERROR is returned from the action.

<%@ 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 配置文件将所有内容组合在一起,如下所示:

Finally, let us put everything together using the struts.xml configuration file as follows −

<?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 文件的内容:

Following is the content of web.xml file −

<?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 。这将生成以下屏幕:

Now, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts9

输入错误的用户名和密码。您应该会看到下一页。

Enter a wrong user name and password. You should see the next page.

helloworldstruts10

现在输入 scott 作为用户名,输入 navy 作为密码。您应该会看到下一页。

Now enter scott as user name and navy as password. You should see the next page.

helloworldstruts11

Struts 2 - Sending Email

本章解释了如何使用 Struts2 应用程序发送电子邮件。

This chapter explains how you can send an email using your Struts 2 application.

对于此练习,您需要从 JavaMail API 1.4.4 下载并安装 mail.jar,然后将 mail.jar 文件放到 WEB-INF\lib 文件夹中,然后按照创建动作、视图和配置文件的标准步骤进行操作。

For this exercise, you need to download and install the mail.jar from JavaMail API 1.4.4 and place the mail.jar file in your WEB-INF\lib folder and then proceed to follow the standard steps of creating action, view and configuration files.

Create Action

下一步是创建一个负责发送电子邮件的动作方法。让我们创建一个名为 Emailer.java 的新类,其中包含以下内容。

The next step is to create an Action method that takes care of sending the email. Let us create a new class called Emailer.java with the following contents.

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 页面中的表单属性相对应的属性。这些属性为 −

As seen in the source code above, the Emailer.java has properties that correspond to the form attributes in the email.jsp page given below. These attributes are −

  1. From − The email address of the sender. As we are using Google’s SMTP, we need a valid gtalk id

  2. Password − The password of the above account

  3. To − Who to send the email to?

  4. Subject − subject of the email

  5. Body − The actual email message

我们尚未考虑以上字段的任何验证,验证将在下一章中添加。现在,我们来看看 execute() 方法。execute() 方法使用 javax Mail 库来使用提供的参数发送电子邮件。如果邮件已成功发送,则该动作返回 SUCCESS,否则返回 ERROR。

We have not considered any validations on the above fields, validations will be added in the next chapter. Let us now look at the execute() method. The execute() method uses the javax Mail library to send an email using the supplied parameters. If the mail is sent successfully, action returns SUCCESS, otherwise it returns ERROR.

Create Main Page

让我们编写 JSP 主页面文件 index.jsp ,这将用于收集上面提到的与电子邮件相关的信息 −

Let us write main page JSP file index.jsp, which will be used to collect email related information mentioned above −

<%@ 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,我们将有另一个视图文件。

We will use JSP file success.jsp which will be invoked in case action returns SUCCESS, but we will have another view file in case of an ERROR is returned from the action.

<%@ 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

Following will be the view file error.jsp in case of an ERROR is returned from the action.

<%@ 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 配置文件将所有内容放在一起,如下所示 -

Now let us put everything together using the struts.xml configuration file as follows −

<?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 文件的内容:

Following is the content of web.xml file −

<?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 。这将生成以下屏幕:

Now, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts12

输入所需信息,然后单击 Send Email 按钮。如果一切顺利,您应该会看到以下页面。

Enter the required information and click Send Email button. If everything goes fine, then you should see the following page.

helloworldstruts13

Struts 2 - Validations Framework

在本章中,我们将更深入地了解 Struts 验证框架。在 Struts 核心,我们有验证框架,它帮助应用程序运行规则,以便在执行操作方法之前执行验证。

In this chapter, we shall look deeper into Struts validation framework. At the Struts core, we have the validation framework that assists the application to run the rules to perform validation before the action method is executed.

客户端侧验证通常使用 Javascript 实现。但是,不应该只依赖于客户端验证。最佳实践表明,验证应该在应用程序框架的所有级别引入。现在让我们来看看向 Struts 项目添加验证的两种方法。

Client side validation is usually achieved using Javascript. However, one should not rely upon client side validation alone. The best practices suggest that the validation should be introduced at all levels of your application framework. Now let us look at two ways of adding validation to our Struts project.

在这里,我们取一个 Employee 的示例,它的名称和年龄应该使用一个简单页面捕获,并且我们对这两个验证进行设置,以确保用户始终输入名称和年龄,且该年龄应在 28 到 65 之间。

Here, we will take an example of an Employee whose name and age should be captured using a simple page, and we will put these two validations to make sure that the user always enters a name and age which should be in a range between 28 and 65.

让我们从示例的主要 JSP 页面开始。

Let us start with the main JSP page of the example.

Create Main Page

让我们编写主页面 JSP 文件 index.jsp ,它将用于收集上述与员工相关的信息。

Let us write main page JSP file index.jsp, which will be used to collect Employee related information mentioned above.

<%@ 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 属性,从而为每个标记创建了标签。

The index.jsp makes use of Struts tag, which we have not covered yet, but we will study them in tags related chapters. But for now, just assume that the s:textfield tag prints a input field, and the s:submit prints a submit button. We have used label property for each tag which creates label for each tag.

Create Views

我们将使用 JSP 文件 success.jsp,它将在定义的动作返回 SUCESS 时被调用。

We will use JSP file success.jsp which will be invoked in case defined action returns 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 ,然后添加一个名为 validate() 的方法,如下所示 Employee.java 文件。确保你的操作类扩展 ActionSupport 类,否则你的验证方法将不会被执行。

So let us define a small action class Employee, and then add a method called validate() as shown below in Employee.java file. Make sure that your action class extends the ActionSupport class, otherwise your validate method will not be executed.

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 之间,如果不满足此条件,我们在已验证字段之上添加一个错误。

As shown in the above example, the validation method checks whether the 'Name' field has a value or not. If no value has been supplied, we add a field error for the 'Name' field with a custom error message. Secondly, we check if entered value for 'Age' field is in between 28 and 65 or not, if this condition does not meet we add an error above the validated field.

Configuration Files

最后,让我们将所有内容组合在一起,使用 struts.xml 配置文件,如下所示 -

Finally, let us put everything together using the struts.xml configuration file as follows −

<?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 文件的内容:

Following is the content of web.xml file −

<?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 。这将生成以下屏幕:

Now, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts12

现在不要输入任何必需信息,只需点击 Submit 按钮即可。您将看到以下结果 -

Now do not enter any required information, just click on Submit button. You will see the following result −

helloworldstruts121

输入必需信息,但输入一个错误的 From 域,假设名称为“测试”,年龄为 30,最后点击 Submit 按钮。您将看到以下结果 -

Enter the required information but enter a wrong From field, let us say name as "test" and age as 30, and finally click on Submit button. You will see the following result −

helloworldstruts122

How this Validation Works?

当用户按下提交按钮时,Struts 2 将自动执行验证方法,如果该方法中列出的任何 “if” 语句为真,Struts 2 将调用其 addFieldError 方法。如果添加了任何错误,Struts 2 将不会继续调用执行方法。相反,Struts 2 框架将返回 input 作为调用动作的结果。

When the user presses the submit button, Struts 2 will automatically execute the validate method and if any of the “if” statements listed inside the method are true, Struts 2 will call its addFieldError method. If any errors have been added, then Struts 2 will not proceed to call the execute method. Rather the Struts 2 framework will return input as the result of calling the action.

因此,当验证失败并且 Struts 2 返回 input 时,Struts 2 框架将重新显示 index.jsp 文件。由于我们使用了 Struts 2 表单标记,Struts 2 会自动将错误信息添加到表单域之上。

Hence, when validation fails and Struts 2 returns input, the Struts 2 framework will redisplay the index.jsp file. Since, we used Struts 2 form tags, Struts 2 will automatically add the error messages just above the form filed.

这些错误消息是我们指定的 addFieldError 方法调用中指定的内容。addFieldError 方法有两个参数。第一,是错误适用的 form 域名称,第二,是在该表单域上方显示的错误消息。

These error messages are the ones we specified in the addFieldError method call. The addFieldError method takes two arguments. The first, is the form field name to which the error applies and the second, is the error message to display above that form field.

addFieldError("name","The name is required");

要处理 input 的返回值,我们需要在 struts.xml 中的操作节点中添加以下结果。

To handle the return value of input we need to add the following result to our action node in struts.xml.

<result name = "input">/index.jsp</result>

XML Based Validation

第二种验证方法是将 xml 文件放在动作类的旁边。基于 Struts2 XML 的验证提供更多的验证选项,如电子邮件验证、整数范围验证、表单验证域、表达式验证、regex 验证、必需验证、必需字符串验证、字符串长度验证等等。

The second method of doing validation is by placing an xml file next to the action class. Struts2 XML based validation provides more options of validation like email validation, integer range validation, form validation field, expression validation, regex validation, required validation, requiredstring validation, stringlength validation and etc.

xml 文件需要命名为 '[action-class]'-validation.xml 。因此,在我们的示例中,我们创建了一个名为 Employee-validation.xml 的文件,内容如下 -

The xml file needs to be named '[action-class]'-validation.xml. So, in our case we create a file called Employee-validation.xml with the following contents −

<!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 操作类 -

Above XML file would be kept in your CLASSPATH ideally along with class file. Let us have our Employee action class as follows without having validate() method −

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;
   }
}

其余的设置将与之前的示例保持一致,现在如果你运行应用程序,它将产生与我们之前示例中接收相同的结果。

Rest of the setup will remain as it is i the previous example, now if you will run the application, it will produce same result what we received in previous example.

将 xml 文件用于存储配置的优点是,它允许将验证与应用程序代码分开。你可以让一个开发人员编写代码,让业务分析员创建验证 xml 文件。另一件需要注意的事情是默认可用的验证类型。

The advantage of having an xml file to store the configuration allows the separation of the validation from the application code. You could get a developer to write the code and a business analyst to create the validation xml files. Another thing to note is the validator types that are available by default.

在 Struts 中还附带了更多的验证器。常见的验证器包括日期验证器、正则验证器和字符串长度验证器。请查看以下链接了解更多详细信息 Struts - XML Based Validators

There are plenty more validators that come by default with Struts. Common validators include Date Validator, Regex validator and String Length validator. Check the following link for more detail Struts - XML Based Validators.

Struts2 - Localization, internationalization (i18n)

国际化 (i18n) 是规划和实施产品和服务以便它们可以轻松适应特定当地语言和文化的过程,这一过程称为本地化。国际化流程称为翻译或本地化支持。

Internationalization (i18n) is the process of planning and implementing products and services so that they can easily be adapted to specific local languages and cultures, a process called localization. The internationalization process is called translation or localization enablement.

国际化缩写为 i18n ,因为该单词以字母 “i” 开头,以 “n” 结尾,并且在第一个 i 和最后一个 n 之间有 18 个字符。

Internationalization is abbreviated i18n because the word starts with the letter “i” and ends with “n”, and there are 18 characters between the first i and the last n.

Struts2 提供本地化,即,通过以下位置的资源包、拦截器和标签库来提供国际化 (i18n) 支持 −

Struts2 provides localization, i.e., internationalization (i18n) support through resource bundles, interceptors and tag libraries in the following places −

  1. The UI Tags

  2. Messages and Errors.

  3. Within action classes.

Resource Bundles

Struts2 使用资源包为 Web 应用程序的用户提供多种语言和区域设置选项。您不必担心用不同语言编写页面。您所要做的就是为所需的每种语言创建一个资源包。资源包将包含在其用户语言中的标题、消息和其他文本。资源包是包含应用程序默认语言的关键/值对的文件。

Struts2 uses resource bundles to provide multiple language and locale options to the users of the web application. You don’t need to worry about writing pages in different languages. All you have to do is to create a resource bundle for each language that you want. The resource bundles will contain titles, messages, and other text in the language of your user. Resource bundles are the file that contains the key/value pairs for the default language of your application.

资源文件的命名格式最简单:

The simplest naming format for a resource file is −

bundlename_language_country.properties

在此处, bundlename 可以是 ActionClass、Interface、SuperClass、Model、Package、全局资源属性。下一部分 language_country 代表国家/地区语言环境,例如,西班牙语(西班牙)语言环境由 es_ES 表示,英语(美国)语言环境由 en_US 等表示,其中您可以跳过国家/地区部分(这是可选的)。

Here, bundlename could be ActionClass, Interface, SuperClass, Model, Package, Global resource properties. Next part language_country represents the country locale for example, Spanish (Spain) locale is represented by es_ES, and English (United States) locale is represented by en_US etc. where you can skip country part which is optional.

当您按其键引用一个消息元素时,Struts 框架按以下顺序搜索相应的讯息包 −

When you reference a message element by its key, Struts framework searches for a corresponding message bundle in the following order −

  1. ActionClass.properties

  2. Interface.properties

  3. SuperClass.properties

  4. model.properties

  5. package.properties

  6. struts.properties

  7. global.properties

要使用多种语言进行开发应用程序,您应该维护对应于那些语言/区域设置的多个属性文件,并根据关键/值对定义所有内容。

To develop your application in multiple languages, you should maintain multiple property files corresponding to those languages/locale and define all the content in terms of key/value pairs.

例如,如果你准备为美式英语(默认)、西班牙语和法语开发你的应用程序,那么你将必须创建三个属性文件。这里我仅使用 global.properties 文件,但你也可以利用不同的属性文件来分离不同类型的消息。

For example, if you are going to develop your application for US English (Default), Spanish, and French, then you would have to create three properties files. Here I will use global.properties file only, you can also make use of different property files to segregate different type of messages.

  1. global.properties − By default English (United States) will be applied

  2. global_fr.properties − This will be used for Franch locale.

  3. global_es.properties − This will be used for Spanish locale.

Access the messages

有许多种方法可以访问消息资源,包括 getText、text 标记、UI 标记的 key 属性以及 i18n 标记。我们简要了解下它们−

There are several ways to access the message resources, including getText, the text tag, key attribute of UI tags, and the i18n tag. Let us see them in brief −

如需显示 i18n 文本,请在属性标记或任何其他标记(如 UI 标记)中调用 getText ,如下所示−

To display i18n text, use a call to getText in the property tag, or any other tag, such as the UI tags as follows −

<s:property value = "getText('some.key')" />

text tag 从默认资源包(即 struts.properties)中检索一条消息

The text tag retrieves a message from the default resource bundle, i.e., struts.properties

<s:text name = "some.key" />

i18n tag 将任意资源包推送到值栈。i18n 标记作用域范围内的其他标记可显示该资源包中的消息−

The i18n tag pushes an arbitrary resource bundle on to the value stack. Other tags within the scope of the i18n tag can display messages from that resource bundle−

<s:i18n name = "some.package.bundle">
   <s:text name = "some.key" />
</s:i18n>

大多数 UI 标记的 key 属性可用于从资源包生成消息−

The key attribute of most UI tags can be used to generate a message from a resource bundle −

<s:textfield key = "some.key" name = "textfieldName"/>

Localization Example

让我们把目标设定为从前一章节中用多种语言创建 index.jsp 。相同的文件将按如下方式编写−

Let us target to create index.jsp from the previous chapter in multiple languages. Same file would be written as follows −

<%@ 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 的情况下,将会调用该文件。

We will create success.jsp file which will be invoked in case defined action returns 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,但我们将根据返回的值采取不同的操作,因为两个操作的目的不同

Here we would need to create the following two actions. (a) First action a to take care of Locale and display same index.jsp file with different language (b) Another action is to take care of submitting form itself. Both the actions will return SUCCESS, but we will take different actions based on return values because our purpose is different for both the actions

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 中 −

Now let us create the following three global.properties files and put the in 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 ,如下所示−

We will create our struts.xml with two actions as follows −

<?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 文件的内容:

Following is the content of web.xml file −

<?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 。这将生成以下屏幕:

Now, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts14

现在选择任何一种语言,我们假设选择 Spanish ,它将显示以下结果−

Now select any of the languages, let us say we select Spanish, it would display the following result −

helloworldstruts15

你也可以尝试使用法语。最后,让我们尝试在我们处于西班牙语地区设置时,单击 Submit 按钮,它将显示以下屏幕−

You can try with French language as well. Finally, let us try to click Submit button when we are in Spanish Locale, it would display the following screen −

helloworldstruts16

恭喜你,现在你拥有了一个多语言网页,可以面向全球推出你的网站。

Congratulations, now you have a multi-lingual webpage, you can launch your website globally.

Struts 2 - Type Conversion

根据协议,HTTP 请求中的所有内容都被视为 String 。这包括数字、布尔值、整数、日期、十进制数和所有其他内容。然而,在 Struts 类中,您可拥有任何数据类型的属性。

Everything on a HTTP request is treated as a String by the protocol. This includes numbers, booleans, integers, dates, decimals and everything else. However, in the Struts class, you could have properties of any data types.

Struts 如何自动连接您的属性?

How does Struts autowire the properties for you?

Struts 使用各种类型转换器来完成繁重的工作。

Struts uses a variety of type converters under the covers to do the heavy lifting.

例如,如果您在 Action 类中拥有一个整数属性,那么 Struts 将自动把请求参数转换成整数属性,而您无需进行任何操作。默认情况下,Struts 配有一些类型转换器

For example, if you have an integer attribute in your Action class, Struts automatically converts the request parameter to the integer attribute without you doing anything. By default, Struts comes with a number of type converters

如果您正在使用下面列出的任何转换器,那么您不必担心 -

If you are using any of the below listed converters, then you have nothing to worry about −

  1. Integer, Float, Double, Decimal

  2. Date and Datetime

  3. Arrays and Collections

  4. Enumerations

  5. Boolean

  6. BigDecimal

当您使用自己的数据类型时,必要时可添加自己的转换器,以让 Struts 了解如何在显示前转换那些值。考虑以下 POJO 类 Environment.java

At times when you are using your own data type, it is necessary to add your own converters to make Struts aware how to convert those values before displaying. Consider the following POJO class 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

This is a very simple class that has an attribute called name, so nothing special about this class. Let us create another class that contains information about the system -SystemDetails.java.

为了执行此练习,我已将环境硬编码为“开发”并将操作系统硬编码为“Windows XP SP3”。

For the purpose of this exercise, I have hardcoded the Environment to "Development" and the Operating System to "Windows XP SP3".

在实时项目中,您将从系统配置中获取此信息。

In a real-time project, you would get this information from the system configuration.

让我们看看以下操作类 -

Let us have the following action class −

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 ,以显示环境和操作系统信息。

Next, let us create a simple JSP file System.jsp to display the Environment and the Operating System information.

<%@ 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.jspSystemDetails.java 类。

Let us wire the system.jsp and the SystemDetails.java class together using struts.xml.

SystemDetails 类有一个简单的 execute () 方法,它返回字符串“ SUCCESS ”。

The SystemDetails class has a simple execute () method that returns the string "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>
  1. Right click on the project name and click Export > WAR File to create a War file.

  2. Then deploy this WAR in the Tomcat’s webapps directory.

  3. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/system.action. This will produce the following screen −

helloworldstruts17

上面输出有什么问题?Struts 知道如何显示和转换字符串“Windows XP SP3”和其他内置数据类型,但它不知道如何处理 Environment 类型属性。它只是简单地调用了类中 toString() 方法

What is wrong with the above output? Struts knows how to display and convert the string "Windows XP SP3" and other built-in data types, but it does not know what to do with the property of Environment type. It is simply called toString() method on the class

为了解决这个问题,我们现在创建一个简单的 TypeConverter 然后为 Environment 类进行注册。

To resolve this problem, let us now create and register a simple TypeConverter for the Environment class.

创建一个名为 EnvironmentConverter.java 的类,其中包含以下内容。

Create a class called EnvironmentConverter.java with the following.

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,反之亦然。

The EnvironmentConverter extends the StrutsTypeConverter class and tells Struts how to convert Environment to a String and vice versa by overriding two methods which are convertFromString() and convertToString().

现在让我们在应用程序中使用此转换器之前先注册此转换器。注册转换器有两种方法。

Let us now register this converter before we use it in our application. There are two ways to register a converter.

如果仅在特定操作中使用此转换器,那么您需要创建一个属性文件,该文件的名称需指定为 '[action-class]'converstion.properties

If the converter will be used only in a particular action, then you would have to create a property file which needs to be named as '[action-class]'converstion.properties.

在本例中,我们创建一个名为 SystemDetails-converstion.properties 的文件,其中包含以下注册项:

In our case, we create a file called SystemDetails-converstion.properties with the following registration entry −

environment = com.tutorialspoint.struts2.EnvironmentConverter

在以上示例中,“environment”是 SystemDetails.java 类中属性的名称,并且我们告诉 Struts 使用 EnvironmentConverter 来转换此属性。

In the above example, "environment" is the name of the property in the SystemDetails.java class and we are telling Struts to use the EnvironmentConverter for converting to and from this property.

但是,我们不会执行此操作。相反,我们将全局注册此转换器,以便可以在整个应用程序中使用它。为此,在 WEBINF/classes 文件夹中创建一个名为 xwork-conversion.properties 的属性文件,并包含以下行

However, we are not going to do this, Instead we are going to register this converter globally, so that it can be used throughout the application. To do this, create a property file called xwork-conversion.properties in the WEBINF/classes folder with the following line

com.tutorialspoint.struts2.Environment = \
   com.tutorialspoint.struts2.EnvironmentConverter

这只是全局注册转换器,以便 Struts 在遇到类型为 Environment 的对象时可以自动执行转换。现在,如果重新编译并重新运行该程序,则你会得到更好的输出,如下所示:

This simply registers the converter globally, so that Struts can automatically do the conversion every time when it encounters an object of the type Environment. Now, if you re-compiling and re-running the program, then you will get a better output as follows −

helloworldstruts18

显然,现在的结果会更好,这意味着我们的 Struts 转换器运行良好。

Obviously, now the result will be better which means our Struts convertor is working fine.

这就是你可以创建多个转换器并注册它们以根据你的需求使用的方式。

This is how you can create multiple convertors and register them to use as per your requirements.

Struts 2 - Themes & Templates

在开始针对本章节的实际教程之前,让我们研究 https://struts.apache.org 提供的一些定义−

Before starting actual tutorial for this chapter, let us look into few definition as given by https://struts.apache.org

Sr.No

Term & Description

1

TAG A small piece of code executed from within JSP, FreeMarker, or Velocity.

2

TEMPLATE A bit of code, usually written in FreeMarker, that can be rendered by certain tags (HTML tags).

3

THEME A collection of templates packaged together to provide common functionality.

我还会建议通读 Struts2 Localization 章节,因为我们将再次采用相同的示例来执行练习。

I would also suggest going through the Struts2 Localization chapter because we will take same example once again to perform our excercise.

在网页中使用 Struts 2 标记(例如 <s:submit…​>、<s:textfield…​> 等)时,Struts 2 框架会生成具有预配置样式和布局的 HTML 代码。Struts 2 附带三个内置主题−

When you use a Struts 2 tag such as <s:submit…​>, <s:textfield…​> etc in your web page, the Struts 2 framework generates HTML code with a preconfigured style and layout. Struts 2 comes with three built-in themes −

Sr.No

Theme & Description

1

SIMPLE theme A minimal theme with no "bells and whistles". For example, the textfield tag renders the HTML <input/> tag without a label, validation, error reporting, or any other formatting or functionality.

2

XHTML theme This is the default theme used by Struts 2 and provides all the basics that the simple theme provides and adds several features like standard two-column table layout for the HTML, Labels for each of the HTML, Validation and error reporting etc.

3

CSS_XHTML theme This theme provides all the basics that the simple theme provides and adds several features like standard two-column CSS-based layout, using <div> for the HTML Struts Tags, Labels for each of the HTML Struts Tags, placed according to the CSS stylesheet.

如上所述,如果您未指定主题,则 Struts 2 将默认使用 xhtml 主题。例如,下面的 Struts 2 select 标记−

As mentioned above, if you don’t specify a theme, then Struts 2 will use the xhtml theme by default. For example, this Struts 2 select tag −

<s:textfield name = "name" label = "Name" />

会生成如下 HTML 标记−

generates following HTML markup −

<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 文件中定义的操作名称。

Here empinfo is the action name defined in struts.xml file.

Selecting Themes

您可以根据 Struts 2 标记指定主题,或者可以使用以下方法之一指定 Struts 2 应使用哪个主题−

You can specify the theme on as per Struts 2, tag basis or you can use one of the following methods to specify what theme Struts 2 should use −

  1. The theme attribute on the specific tag

  2. The theme attribute on a tag’s surrounding form tag

  3. The page-scoped attribute named "theme"

  4. The request-scoped attribute named "theme"

  5. The session-scoped attribute named "theme"

  6. The application-scoped attribute named "theme"

  7. The struts.ui.theme property in struts.properties (defaults to xhtml)

如果您希望针对不同标签使用不同主题,则以下方法可在标签级别指定这些主题 −

Following is the syntax to specify them at tag level if you are willing to use different themes for different tags −

<s:textfield name = "name" label = "Name" theme="xhtml"/>

由于按标签使用主题并不是非常实用,因此我们只需使用以下标签在 struts.properties 文件中指定规则 −

Because it is not very much practical to use themes on per tag basis, so simply we can specify the rule in struts.properties file using the following tags −

# 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 文件中。

Following is the result we picked up from localization chapter where we used the default theme with a setting struts.ui.theme = xhtml in struts-default.properties file which comes by default in struts2-core.xy.z.jar file.

helloworldstruts14

How a Theme Works?

对于给定的主题,每个struts标签都有一个关联的模板,例如 s:textfield → text.ftls:password → password.ftl 等。

For a given theme, every struts tag has an associated template like s:textfield → text.ftl and s:password → password.ftl etc.

这些模板文件以压缩包的形式包含在 struts2-core.xy.z.jar 文件中。这些模板文件针对每个标签保留预定义 HTML 布局。

These template files come zipped in struts2-core.xy.z.jar file. These template files keep a pre-defined HTML layout for each tag.

通过这种方式, Struts 2 框架使用 Sturts 标签和关联的模板生成最终 HTML 标记代码。

In this way, Struts 2 framework generates final HTML markup code using Sturts tags and associated templates.

Struts 2 tags + Associated template file = Final HTML markup code.

默认模板以 FreeMarker 编写,它们具有 .ftl 扩展名。

Default templates are written in FreeMarker and they have an extension .ftl.

您还可以使用 Velocity 或 JSP 设计模板,并使用 struts.ui.templateSuffixstruts.ui.templateDir 在 struts.properties 中相应地设置配置。

You can also design your templates using velocity or JSP and accordingly set the configuration in struts.properties using struts.ui.templateSuffix and struts.ui.templateDir.

Creating New Themes

创建新主题最简单的方法是复制任何现有主题/模板文件,并进行所需的修改。

The simplest way to create a new theme is to copy any of the existing theme/template files and do required modifications.

让我们从在 WebContent/WEBINF/classes 中创建一个名为 template 的文件夹,以及一个以新主题命名的子文件夹开始。例如,WebContent/WEB-INF/classes/template/mytheme。

Let us start with creating a folder called template in WebContent/WEBINF/classes and a sub-folder with the name of our new theme. For example, WebContent/WEB-INF/classes/template/mytheme.

从这里,您可以从头开始构建模板,或者也可以从 Struts2 distribution 复制模板。在未来,您可以在那里根据需要修改它们。

From here, you can start building templates from scratch, or you can also copy the templates from the Struts2 distribution where you can modify them as required in future.

我们准备修改现有默认模板 xhtml ,以达到学习的目的。现在,让我们将 struts2-core-x.y.z.jar/template/xhtml 中的内容复制到我们的主题目录,并且仅修改 WebContent/WEBINF/classes/template/mytheme/control.ftl 文件。打开 control.ftl 后,它将包含以下几行 −

We are going to modify existing default template xhtml for learning purpose. Now, let us copy the content from struts2-core-x.y.z.jar/template/xhtml to our theme directory and modify only WebContent/WEBINF/classes/template/mytheme/control.ftl file. When we open control.ftl which will have the following lines −

<table class="${parameters.cssClass?default('wwFormTable')?html}"<#rt/>
<#if parameters.cssStyle??> style="${parameters.cssStyle?html}"<#rt/>
</#if>
>

让我们将以上 control.ftl 文件更改为包含以下内容 −

Let us change above file control.ftl to have the following content −

<table style = "border:1px solid black;">

如果您将检查 form.ftl ,您会发现 control.ftl 在此文件中被使用,但是 form.ftl 从 xhtml 主题引用此文件。因此,让我们按如下方式进行更改 −

If you will check form.ftl then you will find that control.ftl is used in this file, but form.ftl is referring this file from xhtml theme. So let us change it as follows −

<#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 文件,您仍然可以很好地了解要执行的操作。

I assume that, you would not have much understanding of the FreeMarker template language, still you can get a good idea of what is to be done by looking at the .ftl files.

但是,让我们保存上述更改,返回到本地化示例,并使用以下内容创建 WebContent/WEB-INF/classes/struts.properties 文件

However, let us save above changes, and go back to our localization example and create the WebContent/WEB-INF/classes/struts.properties file with the following content

# 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 。这将生成以下屏幕 −

Now after this change, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2. This will produce the following screen −

helloworldstruts19

您可以看到窗体组件周围存在边框,这是我们在从 xhtml 主题中复制主题后对主题进行更改的结果。如果您努力学习 FreeMarker,那么您将能够很容易地创建或修改您的主题。

You can see a border around the form component which is a result of the change we did in out theme after copying it from xhtml theme. If you put little effort in learning FreeMarker, then you will be able to create or modify your themes very easily.

我希望你现在对 Sturts 2 主题和模板有基本的了解了吗?

I hope that now you have a basic understanding on Sturts 2 themes and templates, isn’t it?

Struts 2 - Exception Handling

Struts 提供了一种更简单的方法来处理未捕获的异常并将用户重定向到一个专门的错误页面。你可以轻松配置 Struts,以便为不同的异常提供不同的错误页面。

Struts provides an easier way to handle uncaught exception and redirect users to a dedicated error page. You can easily configure Struts to have different error pages for different exceptions.

Struts 通过使用“exception”拦截器使异常处理变得容易。“exception”拦截器包含在默认堆栈中,因此你不必做任何额外的事情来配置它。它开箱即用,你随时可以使用。

Struts makes the exception handling easy by the use of the "exception" interceptor. The "exception" interceptor is included as part of the default stack, so you don’t have to do anything extra to configure it. It is available out-of-the-box ready for you to use.

我们采用修改后的 HelloWorldAction.java 文件来看看一个简单的 Hello World 示例。在这里,我们在 HelloWorldAction 操作代码中故意引入了一个 NullPointer 异常。

Let us see a simple Hello World example with some modification in HelloWorldAction.java file. Here, we deliberately introduced a NullPointer Exception in our HelloWorldAction action code.

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 的内容如下所示:

Let us keep the content of HelloWorld.jsp as follows −

<%@ 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 的内容:

Following is the content of 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 应如下所示:

Your struts.xml should look like −

<?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 。这将产生以下屏幕:

Now right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts4

输入值“Struts2”并提交该页面。你应该看到以下页面:

Enter a value "Struts2" and submit the page. You should see the following page −

helloworldstruts16

如上例所示,默认异常拦截器在对异常进行处理方面做得非常好。

As shown in the above example, the default exception interceptor does a great job of handling the exception.

我们现在为异常创建一个专门的错误页面。使用以下内容创建一个名为 Error.jsp 的文件 -

Let us now create a dedicated error page for our Exception. Create a file called Error.jsp with the following contents −

<%@ 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 ,如下所示 -

Let us now configure Struts to use this this error page in case of an exception. Let us modify the struts.xml as follows −

<?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。如果您现在重新运行程序,您将看到以下输出 -

As shown in the example above, now we have configured Struts to use the dedicated Error.jsp for the NullPointerException. If you rerun the program now, you shall now see the following output −

helloworldstruts17

除此之外,Struts2 框架还附带一个“日志记录”拦截器用于记录异常。通过启用记录器来记录未捕获的异常,我们可以轻松查看堆栈跟踪并找出出错的原因

In addition to this, Struts2 framework comes with a "logging" interceptor to log the exceptions. By enabling the logger to log the uncaught exceptions, we can easily look at the stack trace and work out what went wrong

Global Exception Mappings

我们已经了解了如何处理特定操作的异常。我们可以将一个全局异常应用于所有操作。例如,要捕获相同的 NullPointerException 异常,我们可以将 <global-exception-mappings…​> 标记添加到 <package…​> 标记内,并且应该在 struts.xml 文件中的 <action…​> 标记内添加其 <result…​> 标记,如下所示 -

We have seen how we can handle action specific exception. We can set an exception globally which will apply to all the actions. For example, to catch the same NullPointerException exceptions, we could add <global-exception-mappings…​> tag inside <package…​> tag and its <result…​> tag should be added inside the <action…​> tag in struts.xml file as follows −

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

As mentioned previously, Struts provides two forms of configuration. The traditional way is to use the struts.xml file for all the configurations. We have seen so many examples of that in the tutorial so far. The other way of configuring Struts is by using the Java 5 Annotations feature. Using the struts annotations, we can achieve Zero Configuration.

要在您的项目中开始使用注释,请确保您已将以下 jar 文件包含在 WebContent/WEB-INF/lib 文件夹中 -

To start using annotations in your project, make sure you have included the following jar files in your WebContent/WEB-INF/lib folder −

  1. struts2-convention-plugin-x.y.z.jar

  2. asm-x.y.jar

  3. antlr-x.y.z.jar

  4. commons-fileupload-x.y.z.jar

  5. commons-io-x.y.z.jar

  6. commons-lang-x.y.jar

  7. commons-logging-x.y.z.jar

  8. commons-logging-api-x.y.jar

  9. freemarker-x.y.z.jar

  10. javassist-.xy.z.GA

  11. ognl-x.y.z.jar

  12. struts2-core-x.y.z.jar

  13. xwork-core.x.y.z.jar

现在,让我们来看看如何清除 struts.xml 文件中可用的配置并用注释替换它。

Now, let us see how you can do away with the configuration available in the struts.xml file and replace it with annotaions.

要解释 Struts2 中注释的概念,我们必须重新考虑 Struts2 Validations 章节中解释的验证示例。

To explain the concept of Annotation in Struts2, we would have to reconsider our validation example explained in Struts2 Validations chapter.

在这里,我们以一个员工为例,他的姓名和年龄将使用一个简单的页面进行捕获,并且我们将放置两个验证以确保“USER”始终输入一个姓名,并且年龄应介于 28 到 65 之间。

Here, we shall take an example of an Employee whose name, age would be captured using a simple page, and we will put two validations to make sure that ÜSER always enters a name and age should be in between 28 and 65.

让我们从示例的主要 JSP 页面开始。

Let us start with the main JSP page of the example.

Create Main Page

让我们编写主页面 JSP 文件 index.jsp ,用于收集上述与员工相关的的信息。

Let us write main page JSP file index.jsp, which is used to collect Employee related information mentioned above.

<%@ 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 属性,为每个标记创建标签。

The index.jsp makes use of Struts tag, which we have not covered yet but we will study them in tags related chapters. But for now, just assume that the s:textfield tag prints a input field, and the s:submit prints a submit button. We have used label property for each tag which creates label for each tag.

Create Views

我们将使用 JSP 文件 success.jsp ,该文件在已定义的操作返回 SUCCESS 的情况下调用。

We will use JSP file success.jsp which will be invoked in case the defined action returns 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 方法将不会执行。

This is the place where annotation is used. Let us re-define action class Employee with annotation, and then add a method called validate () as shown below in Employee.java file. Make sure that your action class extends the ActionSupport class, otherwise your validate method will not be executed.

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;
   }
}

我们在本示例中使用了几个注释。让我逐一解释一下 -

We have used few annotations in this example. Let me go through them one by one −

  1. First, we have included the Results annotation. A Results annotation is a collection of results.

  2. Under the results annotation, we have two result annotations. The result annotations have the name that correspond to the outcome of the execute method. They also contain a location as to which view should be served corresponding to return value from execute()

  3. The next annotation is the Action annotation. This is used to decorate the execute() method. The Action method also takes in a value which is the URL on which the action is invoked.

  4. Finally, I have used two validation annotations. I have configured the required field validator on name field and the integer range validator on the age field. I have also specified a custom message for the validations.

Configuration Files

我们确实不需要 struts.xml 配置文件,所以让我们删除此文件,并查看 web.xml 文件的内容 −

We really do not need struts.xml configuration file, so let us remove this file and let us check the content of web.xml file −

<?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 。这将生成以下屏幕:

Now, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/index.jsp. This will produce the following screen −

helloworldstruts12

现在不要输入任何必需信息,只需点击 Submit 按钮即可。您将看到以下结果 -

Now do not enter any required information, just click on Submit button. You will see the following result −

helloworldstruts121

输入必需信息,但输入一个错误的 From 域,假设名称为“测试”,年龄为 30,最后点击 Submit 按钮。您将看到以下结果 -

Enter the required information but enter a wrong From field, let us say name as "test" and age as 30, and finally click on Submit button. You will see the following result −

helloworldstruts122

Struts 2 Annotations Types

Struts 2 应用程序可以使用 Java 5 注释,作为 XML 和 Java 属性配置的替代方案。您可以查看与不同类别相关的最重要注释的列表 −

Struts 2 applications can use Java 5 annotations as an alternative to XML and Java properties configuration. You can check the list of most important annotations related to different categories −

Struts 2 - Control Tags

Struts 2 标签有一组标签,可以轻松控制页面执行流。

The Struts 2 tags has a set of tags that makes it easy to control the flow of page execution.

以下是 Struts 2 控制标签的重要列表 −

Following is the list of important Struts 2 Control Tags −

The If and Else Tags

这些标签执行每种语言中都 یافت的基本条件流。

These tags perform basic condition flow found in every language.

'If' 标签仅与 'Else If' 标签和/或一个或多个 'Else' 标签一起使用,如下所示 −

'If' tag is used by itself or with 'Else If' Tag and/or single/multiple 'Else' Tag as shown below −

<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 标签获取列表或数组的子集。

This iterator will iterate over a value. An iterable value can be either itherjava.util.Collection or java.util.Iterator file. While iterating over an iterator, you can use Sort tag to sort the result or SubSet tag to get a sub set of the list or array.

以下示例检索值堆栈中当前对象的 getDays() 方法的值,并使用它进行迭代。

The following example retrieves the value of the getDays() method of the current object on the value stack and uses it to iterate over.

<s:property/> 标签将打印出迭代器的当前值。

The <s:property/> tag prints out the current value of the iterator.

<s:iterator value = "days">
   <p>day is: <s:property/></p>
</s:iterator>

The Merge Tag

这些 merge 标签将两个或多个列表作为参数,并将它们全部合并在一起,如下所示 −

These merge tag takes two or more lists as parameters and merge them all together as shown below −

<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 标签将两个或多个列表作为参数,并将它们全部附加在一起,如下所示 −

These append tag take two or more lists as parameters and append them all together as shown below −

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

The Generator Tag

这些 generator 标签将基于提供的 val 属性生成一个迭代器。以下生成器标签将生成一个迭代器,并使用迭代器标签将其打印出来。

These generator tag generates an iterator based on the val attribute supplied. The following generator tag generates an iterator and prints it out using the iterator tag.

<s:generator val = "%{'aaa,bbb,ccc,ddd,eee'}">
   <s:iterator>
      <s:property /><br/>
   </s:iterator>
</s:generator>

Struts 2 - Data Tags

Struts 2 data tags 主要用于处理显示在页面上的数据。下面列出了重要的数据标记:<在此处开始>

The Struts 2 data tags are primarily used to manipulate the data displayed on a page. Listed below are the important data tags: <Start here>

The Action Tag

此标记通过指定操作名称和可选名称空间,使开发人员能够直接从 JSP 页面调用操作。此标记的正文内容用于呈现来自操作的结果。对 struts.xml 中此操作定义的任何结果处理器都将被忽略,除非指定了 executeResult 参数。

This tag enables developers to call actions directly from a JSP page by specifying the action name and an optional namespace. The body content of the tag is used to render the results from the Action. Any result processor defined for this action in struts.xml will be ignored, unless the executeResult parameter is specified.

<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 文件。

These include will be used to include a JSP file in another JSP page.

<-- 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 中。

These bean tag instantiates a class that conforms to the JavaBeans specification. This tag has a body which can contain a number of Param elements to set any mutator methods on that class. If the var attribute is set on the BeanTag, it will place the instantiated bean into the stack’s 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' 回退到预定义的格式。

These date tag will allow you to format a Date in a quick and easy way. You can specify a custom format (eg. "dd/MM/yyyy hh:mm"), you can generate easy readable notations (like "in 2 hours, 14 minutes"), or you can just fall back on a predefined format with key 'struts.date.format' in your properties file.

<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 标记可用于对其他标记进行参数化。此标记具有以下两个参数。

These param tag can be used to parameterize other tags. This tag has the following two parameters.

  1. name (String) − the name of the parameter

  2. value (Object) − the value of the parameter

<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 的顶部。

These property tag is used to get the property of a value, which will default to the top of the stack if none is specified.

<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 以简化使用。

These push tag is used to push value on stack for simplified usage.

<s:push value = "user">
   <s:propery value = "firstName" />
   <s:propery value = "lastName" />
</s:push>

The Set Tag

set 标签在指定范围内为变量分配一个值。当您希望将变量分配给复杂表达式,然后每次简单地引用该变量而不是复杂表达式时,此标签很有用。可用的范围是 application, session, request, pageaction

These set tag assigns a value to a variable in a specified scope. It is useful when you wish to assign a variable to a complex expression and then simply reference that variable each time rather than the complex expression. The scopes available are application, session, request, page and action.

<s:set name = "myenv" value = "environment.name"/>
<s:property value = "myenv"/>

The Text Tag

text 标签用于呈现 I18n 文本消息。

These text tag is used to render a I18n text message.

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

These url tag is used to create a 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 标签 −

The list of form tags is a subset of Struts UI Tags. These tags help in the rendering of the user interface required for the Struts web applications and can be categorised into three categories. This chapter will take you thorugh all the three types of UI tags −

Simple UI Tags

我们在示例中已使用这些标签,本章将对其进行讲解。让我们查看一个带有几个简单 UI 标签的简单视图页面 email.jsp

We have used these tags in our examples already, we will brush them in this chapter. Let us look a simple view page email.jsp with several simple UI tags −

<%@ 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: 和不同的属性。当我们执行上述程序时,会获得以下用户界面,前提是你已为使用的所有键设置了正确的映射。

If you are aware of HTML, then all the tags used are very common HTML tags with an additional prefix s: along with each tag and different attributes. When we execute the above program, we get the following user interface provided you have setup proper mapping for all the keys used.

simpleuitag

如所示, s:head 生成了 Struts2 应用程序所需的 javascript 和样式表元素。

As shown, the s:head generates the javascript and stylesheet elements required for the Struts2 application.

接下来,我们有 s:div 和 s:text 元素。 s:div 用于呈现 HTML Div 元素。这对于不喜欢将 HTML 和 Struts 标签混合在一起的人来说很有用。对于这些人来说,他们可以选择使用 s:div 来呈现一个 div。

Next, we have the s:div and s:text elements. The s:div is used to render a HTML Div element. This is useful for people who do not like to mix HTML and Struts tags together. For those people, they have the choice to use s:div to render a div.

如所示, s:text 用于在屏幕上呈现一个文本。

The s:text as shown is used to render a text on the screen.

接下来,我们有熟悉的 s:form 标签。 s:form 标签有一个 action 属性,用于确定提交表单的位置。由于表单中有一个文件上传元素,因此我们必须将 enctype 设置为 multipart。否则,我们可以将其留空。

Next we have the famiilar s:form tag. The s:form tag has an action attribute that determines where to submit the form. Because we have a file upload element in the form, we have to set the enctype to multipart. Otherwise, we can leave this blank.

在表单标签的末尾,我们有 s:submit 标签。这用于提交表单。提交表单时,所有表单值均提交到 s:form 标签中指定的 action。

At the end of the form tag, we have the s:submit tag. This is used to submit the form. When the form is submitted, all the form values are submitted to the the action specified in the s:form tag.

在 s:form 内,我们有一个称为 secret 的隐藏属性。这将呈现 HTML 中的一个隐藏元素。在我们的示例中,“secret”元素的值为“abracadabra”。最终用户无法看到此元素,它用于将状态从一个视图传输到另一个视图。

Inside the s:form, we have a hidden attribute called secret. This renders a hidden element in the HTML. In our case, the "secret" element has the value "abracadabra". This element is not visible to the end user and is used to carry the state from one view to another.

接下来,我们有 s:label、s:textfield、s:password 和 s:textarea 标签。这些分别用于呈现标签、输入字段、密码和文本区域。我们在“Struts - 发送电子邮件”示例中已经看到了这些标签的作用。

Next we have the s:label, s:textfield, s:password and s:textarea tags. These are used to render the label, input field, password and the text area respectively. We have seen these in action in the "Struts - Sending Email" example.

这里需要注意的重要事项是“key”属性的使用方式。“key”属性用于从属性文件中提取这些控件的标签。我们在 Struts2 本地化、国际化一章中已经介绍了此功能。

The important thing to note here is the use of "key" attribute. The "key" attribute is used to fetch the label for these controls from the property file. We have already covered this feature in the Struts2 Localization, internationalization chapter.

然后,我们有 s:file 标签,它会呈现一个输入文件上传组件。此组件允许用户上传文件。在此示例中,我们使用了 s:file 标签的“accept”参数来指定可以上传的文件类型。

Then, we have the s:file tag which renders a input file upload component. This component allows the user to upload files. In this example, we have used the "accept" parameter of the s:file tag to specify which file types are allowed to be uploaded.

最后,我们有 s:token 标签。令牌标签会生成一个唯一令牌,用于找出是否已双重提交表单

Finally we have the s:token tag. The token tag generates an unique token which is used to find out whether a form has been double submitted

呈现表单时,隐藏变量将放置为令牌值。假设令牌为“ABC”。提交此表单时,Struts Fitler 会将令牌与存储在会话中的令牌进行比较。如果匹配,它将从会话中删除令牌。现在,如果表单被意外重新提交(通过刷新或按浏览器的后退按钮),则该表单将重新提交,令牌将为“ABC”。在这种情况下,过滤器再次将令牌与存储在会话中的令牌进行比较。但由于令牌“ABC”已从会话中删除,因此它将不匹配,Struts 过滤器将拒绝该请求。

When the form is rendered, a hidden variable is placed as the token value. Let us say, for example that the token is "ABC". When this form is submitted, the Struts Fitler checks the token against the token stored in the session. If it matches, it removes the token from the session. Now, if the form is accidentally resubmitted (either by refreshing or by hitting the browser back button), the form will be resubmitted with "ABC" as the token. In this case, the filter checks the token against the token stored in the session again. But because the token "ABC" has been removed from the session, it will not match and the Struts filter will reject the request.

Group UI Tags

组 UI 标签用于创建单选按钮和复选框。让我们查看一个带有复选框和单选按钮标签的简单视图页面 HelloWorld.jsp

The group UI tags are used to create radio button and the checkbox. Let us look a simple view page HelloWorld.jsp with check box and radio button tags −

<%@ 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>

执行上述程序时,我们的输出将类似于以下内容 −

When we execute the above program, our output will look similar to the following −

sturtsgrouptag

现在让我们看看示例。在第一个示例中,我们使用“Gender”标签创建一个简单的单选按钮。单选按钮标签的名称属性是必需的,因此我们指定了一个名称为“gender”。然后我们将列表提供给 gender。列表填充了“male”和“female”值。因此,在输出中,我们得到一个包含两个值的单选按钮。

Let us look at the example now. In the first example, we are creating a simple radio button with the label "Gender". The name attribute is mandatory for the radio button tag, so we specify a name which is "gender". We then supply a list to the gender. The list is populated with the values "male" and "female". Therefore, in the output we get a radio button with two values in it.

在第二个示例中,我们正在创建一个复选框列表。这是为了收集用户的爱好。用户可以有多个爱好,因此我们使用复选框而不是单选按钮。复选框填充了“sports”、“TV”和“Shopping”列表。这将爱好显示为复选框列表。

In the second example, we are creating a checkbox list. This is to gather the user’s hobbies. The user can have more than one hobby and therefore we are using the checkbox instead of the radiobutton. The checkbox is populated with the list "sports", "TV" and "Shopping". This presents the hobbies as a checkbox list.

Select UI Tags

让我们探索 Struts 提供的 Select 标签的不同变体。让我们查看带有选择标签的简单视图页面 HelloWorld.jsp

Let us explore the different variations of the Select Tag offered by Struts. Let us look a simple view page HelloWorld.jsp with select tags −

<%@ 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>

执行上述程序时,我们的输出将类似于以下内容 −

When we execute the above program our output will look similar to the following −

sturtsselecttag

让我们一一过一下各个案例。

Let us now go through the individual cases, one by one.

  1. First, the select tag renders the HTML select box. In the first example, we are creating a simple select box with name "username" and the label "username". The select box will be populated with a list that contains the names Mike, John and Smith.

  2. In the second example, our company has head offices in America. It also has global offices in Asia and Europe. We want to display the offices in a select box but we want to group the global offices by the name of the continent. This is where the optgroup comes in handy. We use the s:optgroup tag to create a new group. We give the group a label and a separate list.

  3. In the third example, the combobox is used. A combo box is a combination of an input field and a select box. The user can either select a value from the select box in which case the input field is automatically filled in with the value the user has selected. Should the user to enter a value directly, no values from the select box will be selected.

  4. In our example we have the combobox listing the sun signs. The selectbox lists only four entries allowing the user to type in his sun sign if it is not in the list. We also add a header entry to the select box. The headerentry is the one that is displayed at the top of the select box. In our case we want to display "Please Select". If the user does not select anything, then we assume -1 as the value. In some cases, we do not want the user to select an empty value. In those conditions, one would set the "emptyOption" property to false. Finally, in our example we supply "capricorn" as the default value for the combobox.

  5. In the fourth example, we have a double select. A double select is used when you want to display two select boxes. The value selected in the first select box determines what appears in the second select box. In our example the first select box displays "Technical" and "Other". If the user selects Technical, we will display IT and Hardware in the second select box. Otherwise we will display Accounting and HR. This is possible using the "list" and "doubleList" atrributes as shown in the example.

在上面的例子中,我们进行了比较以查看顶部选择框是否等于技术。如果是,则我们显示 IT 和硬件。

In the above example, we did a comparison to see if the top select box equals Technical. If it does, then we display IT and Hardware.

我们还需要为顶部框(“name = 'Occupations')和底部框(doubleName = 'occupations2')提供名称

We also need to give a name for the top box ("name = 'Occupations') and the bottom box (doubleName = 'occupations2')

Struts 2 - The Ajax Tags

Struts 使用 DOJO 框架进行 AJAX 标签实现。首先,要继续此示例,您需要将 struts2-dojo-plugin-2.2.3.jar 添加到您的类路径。

Struts uses the DOJO framework for the AJAX tag implementation. First of all, to proceed with this example, you need to add struts2-dojo-plugin-2.2.3.jar to your classpath.

您可以从 struts2 下载的 lib 文件夹获得此文件(C:\struts-2.2.3all\struts-2.2.3\lib\struts2-dojo-plugin-2.2.3.jar)

You can get this file from the lib folder of your struts2 download (C:\struts-2.2.3all\struts-2.2.3\lib\struts2-dojo-plugin-2.2.3.jar)

对于此练习,让我们修改 HelloWorld.jsp 如下所示 −

For this exercies, let us modify HelloWorld.jsp as follows −

<%@ 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>

当我们运行以上示例时,我们得到以下输出 −

When we run the above example, we get the following output −

sturtsajaxtag

让我们一步一步过一下这个示例。

Let us now go through this example one step at a time.

首先要注意的是添加了一个新标签库,前缀为 sx。这(struts-dojo-tags)是专门为 ajax 集成创建的标签库。

First thing to notice is the addition of a new tag library with the prefix sx. This (struts-dojo-tags) is the tag library specifically created for the ajax integration.

然后,在 HTML 头部内部,我们调用 sx:head。这会初始化 dojo 框架,使其准备好页面内的所有 AJAX 调用。这一步很重要——如果没有初始化 sx:head,您的 ajax 调用将不起作用。

Then inside the HTML head we call the sx:head. This initializes the dojo framework and makes it ready for all AJAX invocations within the page. This step is important - your ajax calls will not work without the sx:head being initialized.

首先我们有自动完成标签。自动完成标签看起来很像选择框。其中填充了红色、绿色和蓝色这三个值。但与选择框之间的不同之处在于其自动完成功能。也就是说,如果您开始输入 gr,它将填充“绿色”。除此之外,此标签与我们之前介绍的 s:select 标签非常相似。

First we have the autocompleter tag. The autocompleter tag looks pretty much like a select box. It is populated with the values red, green and blue. But the different between a select box and this one is that it auto completes. That is, if you start typing in gr, it will fill it with "green". Other than that this tag is very much similar to the s:select tag which we covered earlier.

接下来,我们有一个日期时间选择器。此标签创建一个输入字段,其旁边有一个按钮。按下按钮后,将显示一个弹出式日期时间选择器。当用户选择日期时,日期将以标签属性中指定格式填充到输入文本中。在我们的例子中,我们将 dd/MM/yyyy 指定为日期格式。

Next, we have a date time picker. This tag creates an input field with a button next to it. When the button is pressed, a popup date time picker is displayed. When the user selects a date, the date is filled into the input text in the format that is specified in the tag attribute. In our example, we have specified dd/MM/yyyy as the format for the date.

接下来,我们创建一个指向我们之前练习中创建的 system.action 文件的 url 标签。它不必是 system.action——它可以是您之前创建的任何操作文件。然后,我们有一个 div,其中超链接设置为 url,延迟设置为 2 秒。运行此文件时发生的情况是,“初始内容”将显示 2 秒,然后 div 的内容将被 hello.action 执行的内容替换。

Next we create a url tag to the system.action file which we created in the earlier exercises. It doesn’t have to be the system.action - it could be any action file that you created earlier. Then we have a div with the hyperlink set to the url and delay set to 2 seconds. What happens when you run this is, the "Initial Content" will be displayed for 2 seconds, then the div’s content will be replaced with the contents from the hello.action execution.

最后,我们有一个带有两个选项卡的简单选项卡面板。该选项卡本身就是带有“标签 1”和“标签 2”标签的 div。

Finally we have a simple tab panel with two tabs. The tabs are divs themseleves with the labels Tab 1 and Tab2.

值得注意的是,Struts 中的 AJAX 标记集成仍是进行中的工作,而且,此集成的成熟度正随着每次发布而逐渐提高。

It should be worth noting that the AJAX tag integration in Struts is still a work in progress and the maturity of this integration is slowly increasing with every release.

Struts 2 & Spring Integration

Spring 是一个流行的 Web 框架,它提供了与许多常见 Web 任务的简单集成。因此问题是,当我们有了 Struts2 时,我们为什么需要 Spring?好吧,Spring 不仅仅是一个 MVC 框架 - 它提供了 Struts 中没有的许多其他好处。

Spring is a popular web framework that provides easy integration with lots of common web tasks. So the question is, why do we need Spring when we have Struts2? Well, Spring is more than a MVC framework - it offers many other goodies which are not available in Struts.

例如:依赖项注入对于任何框架都很有用。在本章中,我们将通过一个简单的示例了解如何将 Spring 和 Struts2 集成在一起。

For example: dependency injection that can be useful to any framework. In this chapter, we will go through a simple example to see how to integrate Spring and Struts2 together.

首先,你需要从 Spring 安装将以下文件添加到项目的构建路径中。你可以从 https://www.springsource.org/download 下载并安装最新版本的 Spring 框架

First of all, you need to add the following files to the project’s build path from Spring installation. You can download and install latest version of Spring Framework from https://www.springsource.org/download

  1. org.springframework.asm-x.y.z.M(a).jar

  2. org.springframework.beans-x.y.z.M(a).jar

  3. org.springframework.context-x.y.z.M(a).jar

  4. org.springframework.core-x.y.z.M(a).jar

  5. org.springframework.expression-x.y.z.M(a).jar

  6. org.springframework.web-x.y.z.M(a).jar

  7. 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。

Finally add struts2-spring-plugin-x.y.z.jar in your WEB-INF/lib from your struts lib directory. If you are using Eclipse then you may face an exception java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener.

要解决此问题,您应该在 Marker 选项卡中右键单击类依赖项,然后逐一执行快速修复来发布/导出所有依赖项。最后,确保标记选项卡中没有可用的依赖冲突。

To fix this problem, you should have to go in Marker tab and righ click on the class dependencies one by one and do Quick fix to publish/export all the dependences. Finally make sure there is no dependency conflict available under the marker tab.

struts spring1

现在,让我们按照以下步骤为 Struts-Spring 集成设置 web.xml

Now let us setup the web.xml for the Struts-Spring integration as follows −

<?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 文件位于同级

The important thing to note here is the listener that we have configured. The ContextLoaderListener is required to load the spring context file. Spring’s configuration file is called applicationContext.xml file and it must be placed at the same level as the web.xml file

让我们创建一个名为 User.java 的简单动作类,其中包含两个属性 - firstName 和 lastName。

Let us create a simple action class called User.java with two properties - firstName and 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 文件夹下 −

Now let us create the applicationContext.xml spring configuration file and instantiate the User.java class. As mentioned earlier, this file should be under the WEB-INF folder −

<?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,并且我们已经将值 MichaelJackson 注入到了 bean 中。我们还给这个 bean 起了个名字 “userClass”,以便我们可以在其他地方重复使用它。接下来,让我们在 WebContent 文件夹中创建 User.jsp

As seen above, we have configured the user bean and we have injected the values Michael and Jackson into the bean. We have also given this bean a name "userClass", so that we can reuse this elsewhere. Next let us create the User.jsp in the WebContent folder −

<%@ 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 文件将所有实体放在一起。

The User.jsp file is pretty straight forward. It serves only one purpose - to display the values of the firstname and lastname of the user object. Finally, let us put all entities together using the struts.xml file.

<?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 类进行依赖注入。

The important thing to note is that we are using the id userClass to refer to the class. This means that we are using spring to do the dependency injection for the User class.

现在,右键单击项目名称,然后单击 Export > WAR File 来创建一个 War 文件。然后,将该 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/User.jsp 。这将生成以下屏幕 −

Now right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/User.jsp. This will produce the following screen −

struts spring2

我们现在已经了解了如何将两个伟大的框架结合在一起。这就结束了 Struts - Spring 集成章节。

We have now seen how to bring two great frameworks together. This concludes the Struts - Spring integration chapter.

Struts 2 & Tiles Integration

在本章中,让我们逐步了解将 Tiles 框架与 Struts2 集成的步骤。Apache Tiles 是一个模板框架,用于简化 Web 应用程序用户界面的开发。

In this chapter, let us go through the steps involved in integrating the Tiles framework with Struts2. Apache Tiles is a templating framework built to simplify the development of web application user interfaces.

首先,我们需要从 Apache Tiles 网站下载 tiles jar 文件。您需要将以下 jar 文件添加到项目的类路径中。

First of all we need to download the tiles jar files from the Apache Tiles website. You need to add the following jar files to the project’s class path.

  1. tiles-api-x.y.z.jar

  2. tiles-compat-x.y.z.jar

  3. tiles-core-x.y.z.jar

  4. tiles-jsp-x.y.z.jar

  5. tiles-servlet-x.y.z.jar

除了以上内容之外,我们还必须从 Struts2 下载 WEB-INF/lib 中复制以下 jar 文件。

In addition to the above, we have to copy the following jar files from the struts2 download in your WEB-INF/lib.

  1. commons-beanutils-x.y.zjar

  2. commons-digester-x.y.jar

  3. struts2-tiles-plugin-x.y.z.jar

现在,让我们按照以下步骤设置 Struts-Tiles 集成 web.xml 。此处有两个重要需要注意的点。首先,我们需要告诉 tiles 在哪里可以找到 tiles 配置文件 tiles.xml 。在我们的例子中,它将在 /WEB-INF 文件夹中。接下来,我们需要初始化 Struts2 下载附带的 Tiles 监听器。

Now let us setup the web.xml for the Struts-Tiles integration as given below. There are two important point to note here. First, we need to tell tiles, where to find tiles configuration file tiles.xml. In our case, it will be under /WEB-INF folder. Next we need to initiliaze the Tiles listener that comes with Struts2 download.

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

Next let us create tiles.xml under /WEB-INF folder with the following contents −

<?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, bodyfooter 。我们为 baseLayout 提供默认值,然后创建从默认布局扩展的两个自定义。tiger 布局与基本布局相似,除了它使用 tiger.jsp 作为其正文和文本“Tiger”作为标题。同样,lion 布局与基本布局相似,除了它使用 lion.jsp 作为其正文和文本“Lion”作为标题。

Next, we define a basic skeleton layout in the baseLayout.jsp. It has five reusable / overridable areas. Namely title, banner, menu, body and footer. We provide the default values for the baseLayout and then we create two customizations that extend from the default layout. The tiger layout is similar to the basic layout, except it uses the tiger.jsp as its body and the text "Tiger" as the title. Similarly, the lion layout is similar to the basic layout, except it uses the lion.jsp as its body and the text "Lion" as the title.

让我们看一下各个 jsp 文件。以下是 baseLayout.jsp 文件的内容 −

Let us have a look at the individual jsp files. Following is the content of baseLayout.jsp file −

<%@ 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 文件,内容如下 −

Here, we just put together a basic HTML page that has the tiles attributes. We insert the tiles attributes in the places where we need them to be. Next, let us create a banner.jsp file with the following content −

<img src="http://www.tutorialspoint.com/images/tp-logo.gif"/>

menu.jsp 文件有以下几行,它们是链接 - 到 TigerMenu.action 和 LionMenu.action struts 操作。

The menu.jsp file will have the following lines which are the links - to the TigerMenu.action and the LionMenu.action struts actions.

<%@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 文件会有以下内容 −

The lion.jsp file will have following content −

<img src="http://upload.wikimedia.org/wikipedia/commons/d/d2/Lion.jpg"/>
The lion

tiger.jsp 文件会有以下内容 −

The tiger.jsp file will have following content −

<img src="http://www.freewebs.com/tigerofdarts/tiger.jpg"/>
The tiger

接下来,让我们创建操作类文件 MenuAction.java ,其中包含以下内容 −

Next, let us create the action class file MenuAction.java which contains the following −

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 文件中 −

This is a pretty straight forward class. We declared two methods tiger() and lion() that return tiger and lion as outcomes respectively. Let us put it all together in the struts.xml file −

<!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”类。

Let us check what we did in above file. First of all, we declared a new result type called "tiles" as we are now using tiles instead of plain jsp for the view technology. Struts2 has its support for the Tiles View result type, so we create the result type "tiles" to be of the "org.apache.struts2.view.tiles.TilesResult" class.

接下来,我们想说,如果请求是 /tigerMenu.action,则将用户带到 tiger tiles 页面,如果请求是 /lionMenu.action,则将用户带到 lion tiles 页面。

Next, we want to say if the request is for /tigerMenu.action take the user to the tiger tiles page and if the request is for /lionMenu.action take the user to the lion tiles page.

我们使用一点正则表达式来实现这一点。在我们的操作定义中,我们说,匹配模式“*Menu”的任何内容都将由此操作处理。匹配方法将在 MenuAction 类中调用。也就是说,tigerMenu.action 将调用 tiger(),lionMenu.action 将调用 lion()。然后,我们需要将结果的结果映射到适当的 tiles 页面。

We achieve this using a bit of regular expression. In our action definition, we say anything that matches the pattern "*Menu" will be handled by this action. The matching method will be invoked in the MenuAction class. That is, tigerMenu.action will invoke tiger() and lionMenu.action will invoke lion(). We then need to map the outcome of the result to the appropriate tiles pages.

现在,右键单击项目名称并单击 Export > WAR File 以创建 War 文件。然后,将此 WAR 部署在 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp 。这将产生以下屏幕 −

Now right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp. This will produce the following screen −

struts tiles

同样,如果您转到 lionMenu.action 页面,您将看到使用相同 tiles 布局的 lion 页面。

Similarly, if you goto the lionMenu.action page, you will see the lion page which uses the same tiles layout.

Struts 2 and Hibernate Integration

Hibernate 是一项高性能对象/关系持久性与查询服务,该服务通过开放源代码 GNU Lesser General Public License (LGPL) 获得许可,并可免费下载。在本章中,我们将了解如何将 Struts 2 集成到 Hibernate 中。如果您不熟悉 Hibernate,则可以查看我们的 Hibernate tutorial

Hibernate is a high-performance Object/Relational persistence and query service which is licensed under the open source GNU Lesser General Public License (LGPL) and is free to download. In this chapter. we are going to learn how to achieve Struts 2 integration with Hibernate. If you are not familiar with Hibernate, then you can check our Hibernate tutorial.

Database Setup

对于本教程,我将使用“struts2_tutorial”MySQL 数据库。我使用用户名“root”和无密码连接到我的机器上此数据库。首先,您需要运行以下脚本。此脚本将创建一个名为 student 的新表格,并在该表格中创建一些记录−

For this tutorial, I am going to use the "struts2_tutorial" MySQL database. I connect to this database on my machine using the username "root" and no password. First of all, you need to run the following script. This script creates a new table called student and creates few records in this table −

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 的配置文件。

Next let us create the hibernate.cfg.xml which is the hibernate’s configuration file.

<?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 教程以了解这些属性的含义。

Let us go through the hibernate config file. First, we declared that we are using MySQL driver. Then we declared the jdbc url for connecting to the database. Then we declared the connection’s username, password and pool size. We also indicated that we would like to see the SQL in the log file by turning on "show_sql" to true. Please go through the hibernate tutorial to understand what these properties mean.

最后,我们将映射类设置为 com.tutorialspoint.hibernate.Student,我们将在本章中创建此类。

Finally, we set the mapping class to com.tutorialspoint.hibernate.Student which we will create in this chapter.

Envrionment Setup

接下来,您需要为该项目引入许多 jar。附件是所需 JAR 文件的完整列表的屏幕截图−

Next you need a whole lot of jars for this project. Attached is a screenshot of the complete list of JAR files required −

struts hibernate jars

大多数 JAR 文件可以作为 Struts 分发的一部分获得。如果您已安装 Glassfish、WebSphere 或 JBoss 等应用服务器,则可以从应用服务器的 lib 文件夹中获取剩余 jar 文件。如果没有,则可以单独下载这些文件−

Most of the JAR files can be obtained as part of your struts distribution. If you have an application server such as glassfish, websphere or jboss installed, then you can get the majority of the remaining jar files from the appserver’s lib folder. If not you can download the files individually −

  1. Hibernate jar files − Hibernate.org

  2. Struts hibernate plugin − Struts hibernate plugin

  3. JTA files − JTA files

  4. Dom4j files − Dom4j

  5. log4j files − log4j

其余文件,您应该可以从 Struts2 分发中获取。

Rest of the files, you should be able to get from your Struts2 distribution.

Hibernate Classes

现在,让我们为 Hibernate 集成创建必要的 Java 类。以下是 Student.java 的内容 −

Let us now create required java classes for the hibernate integration. Following is the content of 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 文件 −

This is a POJO class that represents the student table as per Hibernate specification. It has properties id, firstName and lastName which correspond to the column names of the student table. Next let us create StudentDAO.java file as follows −

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(数据访问层)。它具有用于列出所有学生以及保存新学生记录的方法。

The StudentDAO class is the data access layer for the Student class. It has methods to list all students and then to save a new student record.

Action Class

以下文件 AddStudentAction.java 定义了我们的操作类。这里有两种操作方法 - execute() 和 listStudents()。execute() 方法用于添加新的学生记录。我们使用 dao 的 save() 方法实现这一功能。

Following file AddStudentAction.java defines our action class. We have two action methods here - execute() and listStudents(). The execute() method is used to add the new student record. We use the dao’s save() method to achieve this.

另一个方法 listStudents() 用于列出学生。我们使用 dao 的 list 方法获取所有学生的列表。

The other method, listStudents() is used to list the students. We use the dao’s list method to get the list of all students.

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”对象。

You will notice that we are implementing the ModelDriven interface. This is used when your action class is dealing with a concrete model class (such as Student) as opposed to individual properties (such as firstName, lastName). The ModelAware interface requires you to implement a method to return the model. In our case we are returning the "student" object.

Create View Files

现在,让我们使用以下内容创建 student.jsp 视图文件 −

Let us now create the student.jsp view file with the following content −

<%@ 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 的值自动填充。

The student.jsp is pretty straightforward. In the top section, we have a form that submits to "addStudent.action". It takes in firstName, lastName and marks. Because the addStudent action is tied to the ModelAware "AddSudentAction", automatically a student bean will be created with the values for firstName, lastName and marks auto populated.

在底部部分,我们浏览学生列表(见 AddStudentAction.java)。我们遍历列表并在表格中显示名字、姓氏和分数的值。

At the bottom section, we go through the students list (see AddStudentAction.java). We iterate through the list and display the values for first name, last name and marks in a table.

Struts Configuration

我们使用 struts.xml 将所有内容放在一起 −

Let us put it all together using 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 操作方法。

The important thing to notice here is that our package "myhibernate" extends the struts2 default package called "hibernate-default". We then declare two actions - addStudent and listStudents. addStudent calls the execute() on the AddStudentAction class and then upon successs, it calls the listStudents action method.

listStudent 操作方法在 AddStudentAction 类上调用 listStudents(),并使用 student.jsp 作为视图。

The listStudent action method calls the listStudents() on the AddStudentAction class and uses the student.jsp as the view.

现在,右键单击项目名称,然后单击 Export > WAR File 以创建 War 文件。然后将此 WAR 部署到 Tomcat 的 webapps 目录中。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/student.jsp 。这将生成以下屏幕 −

Now, right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat’s webapps directory. Finally, start Tomcat server and try to access URL http://localhost:8080/HelloWorldStruts2/student.jsp. This will produce the following screen −

struts hibernate result

在顶部部分,我们获取用于输入新学生记录值的一个表单,底部部分列出了数据库中的学生。继续添加一个新学生记录并按提交。每次您单击“提交”时,屏幕将刷新并向您显示一个更新的列表。

In the top section, we get a form to enter the values for a new student record and the bottom section lists the students in the database. Go ahead and add a new student record and press submit. The screen will refresh and show you an updated list every time you click Submit.