Struts 2注解开发教程:无需struts.xml实现HelloWorld示例
这是 Struts 2 教程系列的第二篇文章。如果您直接阅读本文,建议您也查看之前的文章。之前的教程是关于 Struts 2 初学者指南的,在那篇教程中,我们了解了 Struts 2 的架构及其组件,并使用基于 XML 的配置文件(struts.xml)构建了一个简单的 Struts 2 Web 应用程序。在本教程中,我们将学习如何完全避免使用 Struts 配置文件,而是采用注解或命名约定来实现相同的功能。
Struts 2 约定概念
Struts 2 使用两种方法来确定 Action 类和 Result 类。我们需要使用 struts2-convention-plugin API 来实现这些方法。如果您有一个普通的 Web 应用程序,可以下载其 JAR 文件并将其放置在 Web 应用程序的 lib 目录中。对于 Maven 项目,您可以像下面这样简单地添加其依赖项。
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>2.3.15.1</version>
</dependency>
扫描方法
使用这种方法,我们需要指定需要扫描以查找 Action 类的包。在 web.xml 中对 Struts 2 过滤器进行配置,如下所示。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>actionPackages</param-name>
<param-value>com.Olivia.struts2.actions</param-value>
</init-param>
</filter>
Struts 2 将通过以下方法找到 Action 类:
- 带有 @Action 或 @Actions 注解的任何类。
- 实现 Action 接口或继承 ActionSupport 类的任何类。
- 类名以 Action 结尾且包含 execute() 方法的任何类。对于这些类,使用命名约定来确定操作和结果。
命名约定
Struts 2 将自动为以 Action 结尾的类创建操作。操作名称通过删除 Action 后缀并将第一个字母转换为小写来确定。因此,如果类名是 HomeAction,那么操作名称将是 “home”。如果这些类没有使用 @Result 注解提供结果,那么结果页面将在 WEB-INF/content 目录中查找,并且名称应为 {action}-{return_string}.jsp。因此,如果 HomeAction 操作类返回 “success”,请求将被转发到 WEB-INF/content/home-success.jsp 页面。仅使用命名约定可能会导致混淆,因为我们无法将同一个 JSP 页面用于其他操作类。因此,我们应该尽量避免这种情况,转而使用基于注解的配置。
现在我们可以使用注解来创建我们的 Struts 2 Hello World 应用程序,而且不需要 Struts 2 配置文件。在 Eclipse 中创建一个动态 Web 项目,命名为 Struts2AnnotationHelloWorld,并将其转换为 Maven 项目。最终项目的结构如下图所示。
Maven 配置
我们在 pom.xml 中添加了 struts2-core 和 struts2-convention-plugin 的依赖项,最终的 pom.xml 代码如下:
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Struts2AnnotationHelloWorld</groupId>
<artifactId>Struts2AnnotationHelloWorld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.15.1</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>2.3.15.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>
部署描述符配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns="https://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>Struts2AnnotationHelloWorld</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>actionPackages</param-name>
<param-value>com.Olivia.struts2.actions</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
请注意 init-param 元素,我们在其中指定了将由 Struts 2 扫描的 Action 类所在的包。
结果页面
我们的应用程序有三个结果页面。登录.jsp。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%-- 在JSP中使用Struts2标签 --%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录页面</title>
</head>
<body>
<h3>欢迎用户,请在下方登录</h3>
<s:form action="login">
<s:textfield name="name" label="用户名"></s:textfield>
<s:textfield name="pwd" label="密码" type="password"></s:textfield>
<s:submit value="登录"></s:submit>
</s:form>
</body>
</html>
错误.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>错误页面</title>
</head>
<body>
<h4>用户名或密码错误</h4>
<s:include value="login.jsp"></s:include>
</body>
</html>
欢迎页.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎页面</title>
</head>
<body>
<h3>欢迎 <s:property value="name"></s:property></h3>
</body>
</html>
现在让我们创建我们的动作类,并用注解配置动作和结果页面。
带有注解的动作类
package com.Olivia.struts2.actions;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Namespaces;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionSupport;
/**
* 默认动作实现的空类,用于:
*
* <action name="home">
* <result>/login.jsp</result>
* </action>
* HomeAction类将自动映射到home.action
* 默认页面是login.jsp,它将提供给客户端
* @author scdev
*
*/
@Namespaces(value={@Namespace("/User"),@Namespace("/")})
@Result(location="/login.jsp")
@Actions(value={@Action(""),@Action("home")})
public class HomeAction extends ActionSupport {
}
请注意,HomeAction是一个空类,其唯一目的是将请求转发到login.jsp页面。
package com.Olivia.struts2.actions;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Namespaces;
import org.apache.struts2.convention.annotation.Result;
/**
* 注意@Action注解,其中声明了动作和结果页面
* 另请注意,我们不需要实现Action接口或扩展ActionSupport类,
* 我们只需要一个具有相同签名的execute()方法
* @author scdev
*
*/
@Action(value = "login", results = {
@Result(name = "SUCCESS", location = "/welcome.jsp"),
@Result(name = "ERROR", location = "/error.jsp") })
@Namespaces(value={@Namespace("/User"),@Namespace("/")})
public class LoginAction {
public String execute() throws Exception {
if("scdev".equals(getName()) && "admin".equals(getPwd()))
return "SUCCESS";
else return "ERROR";
}
//用于保存表单参数的Java Bean
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
注意@Action,@Actions,@Result,@Namespace和@Namespaces注解的使用,其用法是不言自明的。现在当我们运行我们的应用程序时,我们会得到以下响应页面。如果你读过上一篇文章,在那篇文章中我们使用struts.xml配置开发了同样的应用程序,你会注意到它几乎相同。唯一的变化是我们连接应用程序的动作类和结果页面的方式。
下载Struts2注解示例项目