核心概念
- 表单: HTML 表单必须设置
enctype="multipart/form-data",这是浏览器能正确发送文件数据的关键。 - Struts2 拦截器:
fileUpload拦截器会自动处理multipart/form-data请求,它会解析请求,将文件内容、文件名等信息封装到 Action 对象的相应属性中。 - Action 属性: 你需要在 Action 类中定义三个属性:
- 一个
File类型:用于接收上传的文件内容。 - 一个
String类型:用于接收原始的文件名。 - 一个
File[]或List<File>类型:用于支持多文件上传(可选)。
- 一个
- 配置: 在
struts.xml中配置 Action,并确保fileUpload拦截器在栈中(它默认在defaultStack中)。 - 服务器存储: Action 接收到文件后,需要使用 Java I/O 操作(如
Files.copy())将其从临时目录移动到你指定的服务器目标目录。
详细步骤
第 1步:项目环境准备
确保你的 Struts2 项目已经搭建好,并且包含了必要的 Struts2 核心依赖,如果你使用 Maven,pom.xml 中至少需要包含:

<dependencies>
<!-- Struts2 核心包 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.33</version> <!-- 使用一个稳定的版本 -->
</dependency>
<!-- 为了更好的文件上传体验,建议添加 commons-io 和 commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
第 2步:创建上传页面 (upload.jsp)
在 WebContent (或 webapp) 目录下创建一个 JSP 页面,用于显示上传表单。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">Struts2 图片上传</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.upload-form { border: 1px solid #ccc; padding: 20px; width: 500px; }
.form-group { margin-bottom: 15px; }
.form-group label { display: block; margin-bottom: 5px; }
.form-group input[type="file"] { width: 100%; }
.form-group input[type="submit"] { padding: 10px 15px; background-color: #007bff; color: white; border: none; cursor: pointer; }
</style>
</head>
<body>
<h2>上传图片</h2>
<div class="upload-form">
<!--
1. method="post": 必须使用 POST 方法。
2. enctype="multipart/form-data": 必须设置,用于上传文件。
-->
<s:form action="uploadImage" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="myImage">选择图片:</label>
<!--
name 属性必须与 Action 中的 File 类型属性名完全一致。
accept 属性用于限制文件类型,是前端的一个友好提示。
-->
<s:file name="myImage" accept="image/*" label="选择图片"/>
</div>
<div class="form-group">
<s:submit value="上传"/>
</div>
</s:form>
</div>
</body>
</html>
第 3步:创建 Action 类 (UploadImageAction.java)
这是处理上传逻辑的核心,Action 会接收文件,并将其保存到服务器的指定目录。
package com.example.action;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import com.opensymphony.xwork2.ActionSupport;
public class UploadImageAction extends ActionSupport {
// 1. 接收上传的文件 (与 JSP 中 s:file 的 name 属性对应)
private File myImage;
// 2. 接收原始文件名
private String myImageFileName;
// 3. 接收文件类型 (可选)
private String myImageContentType;
// 服务器上保存文件的根目录 ( WebContent/uploads/)
// 注意: 在实际部署中,最好将文件保存在 WebContent 之外的目录,"D:/uploads"
// 这里为了方便演示,我们放在 WebContent 下。
private static final String SAVE_DIR = "uploads/";
@Override
public String execute() {
// 检查是否有文件被选择
if (myImage == null) {
addActionError("请选择一个文件!");
return INPUT;
}
try {
// 创建服务器上的保存目录 (如果不存在)
Path uploadPath = Paths.get(getServletContext().getRealPath("") + SAVE_DIR);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// 构建目标文件路径
Path destination = Paths.get(uploadPath.toString(), myImageFileName);
// 使用 Commons-IO 的 copy 方法将文件从临时位置复制到目标位置
// Files.copy(myImage.toPath(), destination, StandardCopyOption.REPLACE_EXISTING);
FileUtils.copyFile(myImage, destination.toFile());
System.out.println("文件上传成功!");
System.out.println("原始文件名: " + myImageFileName);
System.out.println("文件类型: " + myImageContentType);
System.out.println("保存路径: " + destination.toString());
return SUCCESS; // 返回成功
} catch (IOException e) {
e.printStackTrace();
addActionError("文件上传失败: " + e.getMessage());
return ERROR; // 返回失败
}
}
// --- Getters and Setters ---
// Struts2 拦截器需要通过 setter 来设置这些属性
public File getMyImage() {
return myImage;
}
public void setMyImage(File myImage) {
this.myImage = myImage;
}
public String getMyImageFileName() {
return myImageFileName;
}
public void setMyImageFileName(String myImageFileName) {
this.myImageFileName = myImageFileName;
}
public String getMyImageContentType() {
return myImageContentType;
}
public void setMyImageContentType(String myImageContentType) {
this.myImageContentType = myImageContentType;
}
// 为了获取 ServletContext,我们需要在 struts.xml 中注入
private javax.servlet.ServletContext servletContext;
public void setServletContext(javax.servlet.ServletContext servletContext) {
this.servletContext = servletContext;
}
public javax.servlet.ServletContext getServletContext() {
return servletContext;
}
}
重要说明:
myImage:File对象指向的是 Tomcat 等服务器在内存中创建的临时文件,当execute()方法执行完毕后,这个临时文件会被自动删除,所以你必须将它复制或移动到其他地方。myImageFileName: 客户端选择的原始文件名(如 "my-photo.jpg")。ServletContext 注入**: 为了获取 Web 应用的真实路径 (getServletContext().getRealPath("")),我们需要在struts.xml中配置params拦截器来注入ServletContext`。
第 4步:配置 struts.xml
在 src/main/resources 目录下的 struts.xml 文件中配置你的 Action。

<?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 name="default" namespace="/" extends="struts-default">
<!--
配置 uploadImage Action
1. name: 与 JSP 中 s:form 的 action 属性对应。
2. class: 对应的 Action 类全名。
3. method: 指定调用的方法,默认是 execute。
-->
<action name="uploadImage" class="com.example.action.UploadImageAction" method="execute">
<!--
注入 ServletContext,以便 Action 可以获取 Web 应用根目录。
这个配置需要放在 defaultStack 之前,或者确保 params 拦截器在它之前被执行。
-->
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servletRequest\..*,^servletResponse\..*</param>
</interceptor-ref>
<!--
fileUpload 拦截器默认在 defaultStack 中,所以不需要显式配置。
但你可以在这里覆盖它的参数,例如设置最大允许上传的文件大小。
-->
<interceptor-ref name="fileUpload">
<param name="allowedTypes">image/jpeg, image/png, image/gif, image/bmp</param>
<param name="maximumSize">1048576</param> <!-- 1MB -->
</interceptor-ref>
<!-- 再次引用默认栈,因为它包含了 fileUpload 等其他必要拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 结果配置 -->
<result name="success">/success.jsp</result>
<result name="input">/upload.jsp</result> <!-- 输入验证失败时返回上传页面 -->
<result name="error">/error.jsp</result>
</action>
</package>
</struts>
第 5步:创建结果页面
-
成功页面 (
success.jsp)<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8">上传成功</title> </head> <body> <h2>上传成功!</h2> <p>文件名: <s:property value="myImageFileName"/></p> <p>文件类型: <s:property value="myImageContentType"/></p> <p>你可以在这里显示上传的图片:</p> <img src="<s:property value="'uploads/' + myImageFileName"/>" alt="上传的图片" style="max-width: 300px;"/> </body> </html> -
错误页面 (
error.jsp)<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8">上传失败</title> </head> <body> <h2 style="color: red;">上传失败!</h2> <s:property value="actionErrors"/> <p><a href="javascript:history.back()">返回上传页面</a></p> </body> </html>
运行和测试
- 部署项目: 将你的项目部署到 Tomcat 或其他支持 Servlet 的容器中。
- 启动服务器。
- 访问页面: 在浏览器中访问
http://localhost:8080/你的项目名/upload.jsp。 - 上传文件: 选择一张图片(
.jpg或.png文件),点击“上传”按钮。 - 查看结果:
- 如果成功,页面会跳转到
success.jsp,并显示上传的图片。 - 如果失败(例如文件类型不符或超过大小限制),页面会跳转到
error.jsp或upload.jsp,并显示错误信息。
- 如果成功,页面会跳转到
总结与最佳实践
- 文件大小和类型:
fileUpload拦截器是文件上传的第一道防线,通过配置maximumSize和allowedTypes可以有效阻止非法或过大的文件上传。 - 安全性: 永远不要直接使用用户上传的文件名,恶意用户可能提交包含 的文件名,用于路径遍历攻击,你应该对文件名进行清理和重命名,例如使用 UUID 或时间戳。
// 在 execute 方法中,修改文件名 String fileExtension = myImageFileName.substring(myImageFileName.lastIndexOf(".")); String newFileName = UUID.randomUUID().toString() + fileExtension; Path destination = Paths.get(uploadPath.toString(), newFileName); - 存储位置: 不要将文件存放在 WebContent 目录下,因为它会被直接暴露在公网上,更好的做法是存放在应用服务器之外的目录,并通过一个专门的 Servlet 或 Action 来提供文件下载服务,这样可以进行权限控制。
- 多文件上传: 如果需要支持多文件上传,将 Action 中的属性改为
List<File> myImages和List<String> myImageFileNames,并在 JSP 中使用<s:file name="myImages" ... multiple="multiple"/>。
通过以上步骤,你就可以在 Struts2 应用中稳定、安全地实现图片上传功能了。

