Java Struts 教程:从入门到实践
目录
- 什么是 Struts 2?
- 为什么学习 Struts 2?(虽然过时,但仍有价值)
- 核心概念:MVC 设计模式
- 环境搭建
- 安装 JDK
- 安装 IDE (IntelliJ IDEA / Eclipse)
- 安装 Maven
- 创建第一个 Struts 2 应用程序:Hello World
- 第 1 步:创建 Maven Web 项目
- 第 2 步:添加 Struts 2 依赖
- 第 3 步:配置
web.xml - 第 4 步:创建 Action 类
- 第 5 步:创建视图(JSP)
- 第 6 步:配置
struts.xml - 第 7 步:部署和运行
- Struts 2 核心组件详解
- Action:业务逻辑控制器
- Interceptor (拦截器):AOP 思想的体现
- Result (结果):视图的映射
- OGNL (Object-Graph Navigation Language):表达式语言
- ValueStack (值栈):数据存储的核心
- 常用标签库
- 数据标签 (
s:property,s:iterator) - UI 标签 (
s:form,s:textfield,s:submit) - 控制标签 (
s:if,s:else,s:iterator)
- 数据标签 (
- 数据接收与验证
- 属性驱动接收
- 模型驱动接收
- 手动验证
- 基于验证框架的验证 (
validation.xml)
- 文件上传
- 总结与展望
什么是 Struts 2?
Struts 2 是一个用于开发 Java EE Web 应用程序的开源框架,它遵循经典的 MVC (Model-View-Controller) 设计模式,旨在帮助开发者创建可维护、可扩展和结构清晰的 Web 应用。

重要提示:Struts 1 和 Struts 2 是两个完全不同的框架,Struts 2 虽然名字上延续了 Struts 1,但其核心代码源自另一个名为 WebWork 的框架,Struts 2 的架构、API 和使用方式与 Struts 1 有很大不同,更加现代化和灵活。
为什么学习 Struts 2?(虽然过时,但仍有价值)
Struts 2 在 2010 年左右非常流行,是 Java Web 开发领域的主流框架之一,随着 Spring MVC 和后来 Spring Boot 的崛起,Struts 2 的使用率已大幅下降,并且历史上曝出过严重的安全漏洞(如 CVE-2025-5638)。
为什么我们还要学习它?
- 学习历史:了解 Struts 2 有助于理解 Java Web 开发框架的演进史,很多老项目仍在使用 Struts 2,维护这些项目需要相关知识。
- 理解 MVC:Struts 2 对 MVC 模式的实现非常经典和清晰,是学习 MVC 设计模式的一个绝佳范例。
- 概念相通:Struts 2 中的许多核心概念(如拦截器、值栈、OGNL)在其他现代框架(如 Spring MVC)中也有类似的实现,学习 Struts 2 可以帮助你更好地理解这些通用思想。
Struts 2 已不是现代 Web 开发的首选,但它是一个优秀的学习工具和重要的技术遗产。

核心概念:MVC 设计模式
Struts 2 完美地实现了 MVC 模式,将应用分为三个部分:
-
Model (模型):
- 职责:代表应用程序的数据和业务逻辑。
- 实现:通常是普通的 Java 对象(POJO),包含属性和对应的
getter/setter方法,它不依赖于任何 Struts 2 的 API。
-
View (视图):
- 职责:负责显示数据,为用户提供交互界面。
- 实现:通常是 JSP 页面,但也可以是 Velocity、Freemarker 等模板技术,Struts 2 提供了强大的标签库来简化视图层的开发。
-
Controller (控制器):
(图片来源网络,侵删)- 职责:接收用户请求,调用 Model 处理业务逻辑,然后选择合适的 View 进行响应。
- 实现:在 Struts 2 中,控制器由框架本身和开发者编写的 Action 类共同构成。
- 用户请求首先到达 Struts 2 的核心过滤器
FilterDispatcher(或StrutsPrepareAndExecuteFilter)。 - 过滤器根据配置 (
struts.xml) 找到对应的 Action 类。 - Action 类执行业务逻辑,并返回一个字符串(称为 "result code")。
- 框架根据这个 result code 在
struts.xml中找到对应的视图(JSP)并渲染。
- 用户请求首先到达 Struts 2 的核心过滤器
环境搭建
在开始之前,确保你的电脑上安装了以下软件:
- JDK:版本 8 或更高。
- IDE:IntelliJ IDEA (推荐) 或 Eclipse。
- Maven:用于项目管理和依赖管理。
创建第一个 Struts 2 应用程序:Hello World
我们将创建一个简单的应用,用户在输入框中输入姓名,点击提交后,页面会显示 "Hello, [姓名]!"。
第 1 步:创建 Maven Web 项目
在 IDEA 中,选择 File -> New -> Project,然后选择 Maven,并勾选 Create from archetype,选择 maven-archetype-webapp,填写项目信息,完成创建。
第 2 步:添加 Struts 2 依赖
打开 pom.xml 文件,在 <dependencies> 标签内添加 Struts 2 的核心依赖。
<dependencies>
<!-- Struts 2 核心依赖 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.33</version> <!-- 使用一个较新的稳定版本 -->
</dependency>
<!-- 为了支持 JSP 视图,需要包含这个依赖 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-junit-plugin</artifactId>
<version>2.5.33</version>
</dependency>
<!-- 注意:上面的 JUnit 插件是测试用的,真正支持 JSP 的是 struts2-core 自带的,
但有时会显式加入 struts2-convention-plugin 来支持约定优于配置。
这里我们先使用最核心的。 -->
<!-- Servlet API 依赖,因为 Web 项目需要 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JSP API 依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
第 3 步:配置 web.xml
在 src/main/webapp/WEB-INF/web.xml 文件中,配置 Struts 2 的核心过滤器,这个过滤器是所有请求的入口。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置 Struts 2 的核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<!-- 注意:在较新的 Struts 2 版本中,类名是 StrutsPrepareAndExecuteFilter -->
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
第 4 步:创建 Action 类
在 src/main/java 目录下创建你的包结构,com.example.action,然后创建一个 Action 类。
HelloWorldAction.java:
package com.example.action;
public class HelloWorldAction {
// 1. 定义一个属性,用于接收表单数据
private String name;
// 2. 必须提供 getter 和 setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 3. 执行业务逻辑的方法,必须是 public 且无参数
// Struts 2 会默认调用这个方法
public String execute() {
// 这里可以添加业务逻辑,比如调用 Service 层
System.out.println("HelloWorldAction.execute() is called. Name: " + name);
return "success"; // 返回一个逻辑视图名称
}
}
第 5 步:创建视图(JSP)
在 src/main/webapp 目录下创建 JSP 文件。
index.jsp (输入页面):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>Struts 2 Hello World</title>
</head>
<body>
<h2>请输入您的名字</h2>
<!-- 使用 Struts 2 的 form 标签 -->
<s:form action="hello">
<s:textfield name="name" label="姓名"/>
<s:submit value="提交"/>
</s:form>
</body>
</html>
hello.jsp (成功页面):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>欢迎页面</title>
</head>
<body>
<h2>欢迎!</h2>
<!-- 使用 s:property 标签从值栈中获取 name 属性的值 -->
<p>Hello, <s:property value="name"/>!</p>
</body>
</html>
注意:JSP 页面顶部必须引入 <%@ taglib prefix="s" uri="/struts-tags" %> 才能使用 Struts 2 的标签。
第 6 步:配置 struts.xml
这是 Struts 2 的核心配置文件,它负责将 URL 映射到 Action,以及将 Action 的返回值映射到物理视图。
- 在
src/main/resources目录下创建struts.xml文件。 - Struts 2 的 DTD 比较严格,建议直接复制以下模板。
struts.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 开发模式下,可以打印更详细的日志,但生产环境要关闭 -->
<constant name="struts.devMode" value="true"/>
<!-- package: 用于组织 Action,name 是包名,extends="struts-default" 表示继承 Struts 2 的默认配置 -->
<package name="default" namespace="/" extends="struts-default">
<!-- action: 定义一个 Action
name: 对应 URL 中的 action 名,<s:form action="hello"> 中的 hello
class: 指定处理请求的 Action 类的全限定名
method: 指定调用 Action 类中的哪个方法,默认是 execute
-->
<action name="hello" class="com.example.action.HelloWorldAction" method="execute">
<!-- result: 定义处理结果
name: 对应 Action 方法返回的字符串,execute() 返回的 "success"
type: 结果类型,默认是 "dispatcher",用于转发到 JSP
-->
<result name="success">/hello.jsp</result>
<!-- 可以定义其他结果,例如输入验证失败时 -->
<result name="input">/index.jsp</result>
</action>
</package>
</struts>
第 7 步:部署和运行
- 将项目部署到 Tomcat 或其他 Servlet 容器中。
- 启动服务器。
- 在浏览器中访问
http://localhost:8080/你的项目名/。 - 在输入框中输入你的名字,点击提交,你应该会看到跳转到
hello.jsp并显示欢迎信息。
Struts 2 核心组件详解
Action
Action 是 MVC 中的 C(控制器),它是一个简单的 POJO,不需要继承任何父类或实现接口(虽然可以实现 Action 接口来获得一些预定义的返回值常量),它的核心方法是 execute(),但你可以通过配置 method 属性来指定调用任意公共方法。
Interceptor (拦截器)
拦截器是 Struts 2 的精髓,它实现了 AOP (面向切面编程) 的思想,拦截器可以在 Action 执行之前和之后插入代码,用于处理通用的横切逻辑,如:
- 权限检查
- 日志记录
- 请求参数封装
- 数据验证
Struts 2 提供了大量的内置拦截器(在 struts-default.xml 中定义),并默认形成一个拦截器栈,你也可以自定义拦截器。
Result (结果)
当 Action 方法执行完毕后,会返回一个字符串(如 "success", "error"),框架会根据这个字符串在 struts.xml 中查找对应的 <result> 标签,然后执行相应的操作。
- dispatcher: 默认类型,用于转发到 JSP 或 HTML 页面。
- redirect: 用于重定向到另一个 URL。
- stream: 用于下载文件。
- json: 用于返回 JSON 数据,常用于 AJAX 请求。
OGNL (Object-Graph Navigation Language)
OGNL 是一种强大的表达式语言,用于在视图中访问 Action 的属性,它比 JSP 的 EL 表达式更强大。
- 访问属性:
<s:property value="name"/>(等同于action.getName()) - 访问对象方法:
<s:property value="name.toUpperCase()"/> - 访问静态方法:
<s:property value="@java.lang.Math@random()"/> - 访问 List/Map:
<s:property value="users[0].name"/>
ValueStack (值栈)
值栈是 Struts 2 的数据核心,它是一个栈结构,存放了 Action 的对象和临时变量,在 JSP 页面中,OGNL 表达式默认从值栈的栈顶开始查找数据,当你在 Action 中设置一个属性(如 setName()),这个属性就会被压入值栈,从而在视图中可以被直接访问。
常用标签库
Struts 2 提供了丰富的标签库,极大地简化了视图开发,使用前必须引入:<%@ taglib prefix="s" uri="/struts-tags" %>。
数据标签
<s:property value="expression">: 获取并显示值栈中表达式的值。<s:iterator value="collection">: 遍历集合(List, Set, Map)。<s:iterator value="users"> <p>姓名: <s:property value="name"/>, 年龄: <s:property value="age"/></p> </s:iterator>
UI 标签
UI 标签会自动生成 HTML 代码,并会自动从值栈中获取数据。
<s:form action="someAction">: 创建表单。<s:textfield name="username" label="用户名">: 创建文本输入框。<s:password name="password" label="密码">: 创建密码输入框。<s:submit value="提交">: 创建提交按钮。
控制标签
<s:if test="condition">: 条件判断。<s:elseif test="anotherCondition">: 否则如果。<s:else>: 否则。<s:if test="age > 18"> <p>成年人</p> </s:if> <s:else> <p>未成年人</p> </s:else>
数据接收与验证
Struts 2 提供了非常方便的数据接收机制。
属性驱动接收
这是最简单的方式,在 Action 类中定义属性,并提供 getter/setter,表单中 input 标签的 name 属性值必须和 Action 中的属性名一致。
Action:
public class UserAction {
private String username;
private int age;
// getter and setter...
public String execute() {
System.out.println("Username: " + username + ", Age: " + age);
return "success";
}
}
JSP:
<s:form action="saveUser">
<s:textfield name="username" label="用户名"/>
<s:textfield name="age" label="年龄"/>
<s:submit/>
</s:form>
模型驱动接收
如果表单数据需要封装到一个对象中,可以使用模型驱动。
- Action 实现
ModelDriven接口。 - 实现
getModel()方法,返回你的模型对象。
Action:
import com.opensymphony.xwork2.ModelDriven;
public class UserAction implements ModelDriven<User> {
private User user = new User(); // 必须手动实例化
@Override
public User getModel() {
return user;
}
public String execute() {
System.out.println("Username: " + user.getUsername() + ", Age: " + user.getAge());
return "success";
}
}
JSP: (和属性驱动一样,name 对应模型对象的属性)
<s:form action="saveUser">
<s:textfield name="username" label="用户名"/> <!-- 对应 user.getUsername() -->
<s:textfield name="age" label="年龄"/> <!-- 对应 user.getAge() -->
<s:submit/>
</s:form>
验证
可以在 Action 类所在目录下创建一个 ActionName-validation.xml 文件来进行声明式验证。
User.java:
public class User {
private String username;
private int age;
// getter and setter...
}
User-validation.xml:
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="username">
<field-validator type="requiredstring">
<message>用户名不能为空</message>
</field-validator>
<field-validator type="stringlength">
<param name="min">2</param>
<param name="max">10</param>
<message>用户名长度必须在2到10之间</message>
</field-validator>
</field>
<field name="age">
<field-validator type="int">
<param name="min">18</param>
<param name="max">100</param>
<message>年龄必须在18到100之间</message>
</field-validator>
</field>
</validators>
如果验证失败,Struts 2 会自动返回 input 视图,并将错误信息存放在值栈中,可以通过 <s:fielderror> 标签显示。
文件上传
Struts 2 内置了文件上传功能,非常简单。
-
Action 类:接收
File对象、文件名和文件类型。public class FileUploadAction { private File file; private String fileFileName; private String fileContentType; // getter and setter... public String execute() throws Exception { // 将文件保存到服务器 String filePath = "C:/uploads/"; FileUtils.copyFile(file, new File(filePath + fileFileName)); return "success"; } } -
JSP 表单:必须设置
enctype="multipart/form-data"。<s:form action="upload" method="post" enctype="multipart/form-data"> <s:file name="file" label="选择文件"/> <s:submit value="上传"/> </s:form> -
struts.xml:配置文件上传拦截器。
<action name="upload" class="com.example.action.FileUploadAction"> <!-- 确保文件上传拦截器在栈中 --> <interceptor-ref name="fileUpload"> <param name="allowedTypes">image/jpeg,image/png,image/gif</param> <param name="maximumSize">1048576</param> <!-- 1MB --> </interceptor-ref> <interceptor-ref name="defaultStack"/> <result name="success">/upload_success.jsp</result> <result name="input">/upload_form.jsp</result> </action>
总结与展望
通过本教程,你已经掌握了 Struts 2 的基本用法,包括环境搭建、MVC 流程、Action、配置、标签库、数据接收和验证等核心概念。
Struts 2 的未来:如前所述,Struts 2 已不再是主流,对于新的 Web 项目,强烈推荐使用 Spring Boot + Spring MVC 或现代化的 Quarkus、Micronaut 等框架,这些框架在性能、易用性、社区支持和安全性方面都更有优势。
理解 Struts 2 的设计思想和核心机制(如 MVC、拦截器、值栈)对于成为一名全面的 Java Web 开发者来说是非常有益的,它为你理解更现代的框架打下了坚实的基础。
