杰瑞科技汇

Struts文件上传如何实现?

下面我将分步提供一个完整、可运行的示例。

核心概念

  1. 依赖库:

    • commons-fileupload: 用于解析 multipart/form-data 类型的请求,这是文件上传所必需的。
    • commons-io: 提供了一些实用的 IO 工具类,可以简化文件操作,虽然不是绝对必需,但强烈推荐使用。
  2. Struts 配置 (struts-config.xml):

    • struts-config.xml 中,你需要配置一个 controller 元素,并设置 processorClassorg.apache.struts.upload.CommonsMultipartRequestHandler,这会告诉 Struts 使用 commons-fileupload 来处理包含文件的请求。
    • 在 Action 的 form-bean 定义中,需要将 type 设置为 org.apache.struts.validator.DynaValidatorForm 或自定义的 ActionForm,并声明一个 org.apache.struts.upload.FormFile 类型的属性来接收上传的文件。
  3. JSP 表单:

    • 表单的 method 必须是 post
    • 表单的 enctype 必须是 multipart/form-data,这个属性告诉浏览器要以特殊的方式编码表单数据,以便能够上传文件和文本。

完整步骤示例

第 1 步:添加依赖库

确保你的项目中包含了以下 JAR 文件,如果你使用 Maven,可以在 pom.xml 中添加以下依赖:

<dependencies>
    <!-- Struts 1 Core -->
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts-core</artifactId>
        <version>1.3.10</version>
    </dependency>
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts-taglib</artifactId>
        <version>1.3.10</version>
    </dependency>
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts-el</artifactId>
        <version>1.3.10</version>
    </dependency>
    <!-- Commons FileUpload and IO for file upload -->
    <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>
    <!-- Other dependencies like Servlet API, JSTL, etc. -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

如果你不使用 Maven,请手动下载这些 JAR 文件并添加到你的项目的 WEB-INF/lib 目录下。

第 2 步:创建 JSP 上传页面 (upload.jsp)

这个页面包含一个文件输入框和一个提交按钮。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">Struts 1 文件上传示例</title>
</head>
<body>
    <h1>上传文件</h1>
    <html:form action="/upload" method="post" enctype="multipart/form-data">
        请选择文件: <html:file property="myFile" />
        <br /><br />
        <html:submit value="上传" />
    </html:form>
</body>
</html>

关键点:

  • action="/upload": 对应 struts-config.xml 中的 action-path
  • enctype="multipart/form-data": 必须设置,否则文件上传会失败。
  • property="myFile": 这个 property 的值必须与后面 ActionForm 中定义的属性名一致。

第 3 步:配置 struts-config.xml

这是最关键的一步,需要配置 controllerform-bean

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
    <!-- 1. 配置 Controller,使用 CommonsMultipartRequestHandler 处理文件上传 -->
    <controller 
        processorClass="org.apache.struts.upload.CommonsMultipartRequestHandler" 
        maxFileSize="10485760" <!-- 10MB -->
        contentType="multipart/form-data" />
    <!-- 2. 配置 FormBean -->
    <form-beans>
        <form-bean name="uploadForm" 
                   type="org.apache.struts.upload.FormFileUploadForm" />
    </form-beans>
    <!-- 3. 配置 ActionMapping -->
    <action-mappings>
        <action path="/upload"
                type="com.example.action.FileUploadAction"
                name="uploadForm"
                scope="request"
                validate="true"
                input="/upload.jsp">
            <forward name="success" path="/success.jsp" />
            <forward name="failure" path="/failure.jsp" />
        </action>
    </action-mappings>
    <!-- Message Resources 配置 -->
    <message-resources parameter="com.example.ApplicationResources" />
</struts-config>

关键点:

  • <controller>: 这是文件上传的核心配置。
    • processorClass: 指定为 CommonsMultipartRequestHandler
    • maxFileSize: (可选) 设置单个文件的最大大小,单位是字节。10485760 10MB。
    • contentType: (可选) 明确指定处理 multipart/form-data 类型。
  • <form-bean>:
    • name: uploadForm
    • type: 我们需要创建一个自定义的 ActionForm,这里先写 org.apache.struts.upload.FormFileUploadForm
  • <action>:
    • name: 指定使用 uploadForm 这个 FormBean。
    • path: /upload,与 JSP 中的 action 对应。
    • scope: requestsession,通常用 request
    • input: 如果表单验证失败,返回的页面。

第 4 步:创建自定义的 ActionForm (FormFileUploadForm.java)

这个类用于接收表单数据,特别是文件。

package com.example.form;
import org.apache.struts.upload.FormFile;
import org.apache.struts.action.ActionForm;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
public class FormFileUploadForm extends ActionForm {
    private FormFile myFile; // 必须与 JSP 中的 property="myFile" 一致
    // Getters and Setters for the FormFile
    public FormFile getMyFile() {
        return myFile;
    }
    public void setMyFile(FormFile myFile) {
        this.myFile = myFile;
    }
    // 可以添加其他普通属性,比如文件名描述等
    private String description;
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    // 可以在这里添加验证逻辑
    @Override
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        if (myFile == null || myFile.getFileSize() == 0) {
            errors.add("myFile", new ActionMessage("error.file.required"));
            return errors;
        }
        // 检查文件类型
        String contentType = myFile.getContentType();
        if (!"image/jpeg".equals(contentType) && !"image/png".equals(contentType)) {
            errors.add("myFile", new ActionMessage("error.file.type.invalid"));
        }
        return errors;
    }
}

关键点:

  • 这个类必须继承 ActionForm
  • 属性 myFile 的类型必须是 org.apache.struts.upload.FormFile
  • 属性名 myFile 必须与 JSP 的 propertystruts-config.xml 中 FormBean 的引用完全一致。
  • FormFile 对象包含了文件的所有信息:文件名、内容类型、文件大小和文件内容(字节数组)。

第 5 步:创建 Action 类 (FileUploadAction.java)

Action 类负责处理业务逻辑,包括保存文件。

package com.example.action;
import com.example.form.FormFileUploadForm;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
public class FileUploadAction extends Action {
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        FormFileUploadForm uploadForm = (FormFileUploadForm) form;
        org.apache.struts.upload.FormFile file = uploadForm.getMyFile();
        // 1. 检查是否有文件上传
        if (file == null || file.getFileSize() == 0) {
            // 如果没有文件,可以返回错误页面或添加错误信息
            // 这里我们直接返回失败
            return mapping.findForward("failure");
        }
        // 2. 获取文件信息
        String fileName = file.getFileName();
        String contentType = file.getContentType();
        long fileSize = file.getFileSize();
        InputStream inputStream = file.getInputStream();
        // 3. 定义服务器上存储文件的目录
        // 为了安全,不要将文件直接放在 WebRoot 下,最好放在 WEB-INF 外部
        // 这里为了方便示例,我们放在 WebContent/uploads 目录下
        String uploadDir = getServlet().getServletContext().getRealPath("/uploads");
        File uploadDirFile = new File(uploadDir);
        // 如果目录不存在,则创建
        if (!uploadDirFile.exists()) {
            uploadDirFile.mkdirs();
        }
        // 4. 为上传的文件生成一个唯一文件名,防止覆盖
        // 使用时间戳 + 原始文件名
        String uniqueFileName = new Date().getTime() + "_" + fileName;
        File destFile = new File(uploadDir, uniqueFileName);
        // 5. 将文件内容写入到服务器
        try (FileOutputStream outputStream = new FileOutputStream(destFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
            // 写入失败,返回失败页面
            return mapping.findForward("failure");
        } finally {
            // 确保流被关闭
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 6. 可以将上传成功的文件信息存入 request 或 session,供后续页面显示
        request.setAttribute("uploadedFileName", uniqueFileName);
        request.setAttribute("originalFileName", fileName);
        request.setAttribute("fileSize", fileSize);
        request.setAttribute("contentType", contentType);
        // 7. 返回成功
        return mapping.findForward("success");
    }
}

第 6 步:创建成功和失败页面

success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">上传成功</title>
</head>
<body>
    <h1>文件上传成功!</h1>
    <p>原始文件名: <bean:write name="uploadedFileName" scope="request" /></p>
    <p>服务器文件名: <bean:write name="originalFileName" scope="request" /></p>
    <p>文件大小: <bean:write name="fileSize" scope="request" /> bytes</p>
    <p>文件类型: <bean:write name="contentType" scope="request" /></p>
    <p>文件已保存在服务器的 "uploads" 目录下。</p>
</body>
</html>

failure.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">上传失败</title>
</head>
<body>
    <h1 style="color: red;">文件上传失败!</h1>
    <p>请检查文件是否选择,或文件是否符合要求。</p>
    <p><a href="javascript:history.back()">返回</a></p>
</body>
</html>

第 7 步:配置 web.xml

确保 web.xml 中正确配置了 Struts 的 ActionServletfilter(如果使用)。

<?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">
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
        <init-param>
            <param-name>config</param-name>
            <param-value>/WEB-INF/struts-config.xml</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>2</param-value>
        </init-param>
        <init-param>
            <param-name>detail</param-name>
            <param-value>2</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

完成以上所有步骤后,你的 Struts 1 文件上传功能就可以工作了。

  1. 用户访问 upload.jsp
  2. 用户选择文件并点击“上传”按钮。
  3. 请求发送到 FileUploadAction
  4. Struts 框架 根据 struts-config.xml 的配置,使用 CommonsMultipartRequestHandler 解析请求,将文件数据填充到 FormFileUploadFormmyFile 属性中。
  5. FileUploadActionFormFile 中获取文件流,并将其写入到服务器的 uploads 目录。
  6. 根据执行结果,Action 转发到 success.jspfailure.jsp

注意事项

  • 安全性:
    • 文件名: 不要直接使用用户提供的文件名,因为它可能包含恶意字符或路径(如 ../../../malicious.txt),建议重命名文件,如使用 UUID 或时间戳。
    • 文件类型: 检查文件的 Content-Type 和文件扩展名,防止上传可执行文件(如 .jsp, .php, .exe)。
    • 文件大小: 在 struts-config.xml 中设置 maxFileSize 限制,防止上传过大的文件导致服务器资源耗尽。
  • 目录权限: 确保 Web 服务器对 uploads 目录有写入权限。
  • 性能: 上传大文件会消耗较多内存和 CPU,请合理配置服务器和上传限制。
  • Struts 2 的区别: Struts 2 的文件上传机制更简单,它内置了对文件上传的支持,并且使用了更现代的 interceptor(拦截器)模式,与 Struts 1 的 RequestHandler 方式完全不同,如果你现在开始新项目,强烈建议使用 Struts 2 或更现代的框架如 Spring MVC。
分享:
扫描分享到社交APP
上一篇
下一篇