杰瑞科技汇

Struts文件上传Java如何实现?

核心概念

  1. 依赖库:

    Struts文件上传Java如何实现?-图1
    (图片来源网络,侵删)
    • struts-core.jar: Struts 1 框架的核心库。
    • commons-fileupload.jar: Apache Commons FileUpload 库,用于解析 multipart/form-data 请求。
    • commons-io.jar: Apache Commons IO 库,提供了一些实用的 I/O 工具类(虽然不是绝对必须,但强烈推荐)。
    • commons-logging.jar: 日志库,Struts 依赖它。
  2. ActionForm 的特殊处理:

    • 用于文件上传的 ActionForm 必须继承 org.apache.struts.action.ActionForm
    • Form 中,你需要定义一个 org.apache.struts.upload.FormFile 类型的属性来接收上传的文件。
    • 关键点: Struts 1 的控制器 (ActionServlet) 会自动检测 ActionForm 中是否有 FormFile 类型的属性,如果存在,它会使用 commons-fileupload 来解析请求,并将文件内容封装到 FormFile 对象中。
  3. FormFile 接口:

    • 这是 Struts 1 封装上传文件信息的核心接口。
    • 常用方法:
      • String getFileName(): 获取原始文件名 ( my-photo.jpg)。
      • String getContentType(): 获取文件的 MIME 类型 ( image/jpeg)。
      • byte[] getFileData(): 获取文件的字节数组。
      • InputStream getInputStream(): 获取文件的输入流。
      • long getFileSize(): 获取文件的大小(字节)。

完整示例:实现一个文件上传功能

假设我们要创建一个简单的页面,允许用户上传一张图片,并显示上传结果。

第 1 步:添加依赖库

将以下 JAR 文件添加到你的 WEB-INF/lib 目录下:

  • struts-1.3.10.jar (或你使用的版本)
  • commons-fileupload-1.4.jar (或更高版本)
  • commons-io-2.11.0.jar (或更高版本)
  • commons-logging-1.2.jar

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

这个页面包含一个文件输入框和一个提交按钮,注意 enctype="multipart/form-data" 属性,这是文件上传所必需的。

<%@ 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>
    <h2>请选择要上传的图片文件</h2>
    <!-- 
      enctype="multipart/form-data" 是文件上传的必需属性
      action="/struts-file-upload/fileUpload.do" 对应 struts-config.xml 中的 path
    -->
    <html:form action="/fileUpload" enctype="multipart/form-data">
        <table>
            <tr>
                <td>选择文件:</td>
                <td>
                    <!-- html:file 标签会自动渲染为文件输入框 -->
                    <html:file property="myFile" />
                </td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <html:submit value="上传" />
                </td>
            </tr>
        </table>
    </html:form>
</body>
</html>

第 3 步:创建 ActionForm (UploadForm.java)

这个 Form 类将接收来自 upload.jsp 的数据,我们定义一个 FormFile 类型的属性 myFile,其名称必须与 JSP 中 html:file 标签的 property 属性值一致。

package com.example.form;
import org.apache.struts.action.ActionForm;
import org.apache.struts.upload.FormFile;
/**
 * 文件上传的 ActionForm
 */
public class UploadForm extends ActionForm {
    private static final long serialVersionUID = 1L;
    // FormFile 属性,用于接收上传的文件
    // 属性名 "myFile" 必须与 JSP 中 <html:file property="myFile"> 的 property 值一致
    private FormFile myFile;
    // 可以添加其他普通属性,比如文件描述等
    private String description;
    // getter 和 setter 方法
    public FormFile getMyFile() {
        return myFile;
    }
    public void setMyFile(FormFile myFile) {
        this.myFile = myFile;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
}

第 4 步:创建 Action (FileUploadAction.java)

这是处理上传逻辑的核心,我们将从 FormFile 中获取文件数据,并将其保存到服务器的指定目录。

package com.example.action;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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 org.apache.struts.upload.FormFile;
import com.example.form.UploadForm;
/**
 * 处理文件上传的 Action
 */
public class FileUploadAction extends Action {
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 1. 将 Form 转换为自定义的 UploadForm
        UploadForm uploadForm = (UploadForm) form;
        // 2. 从 Form 中获取 FormFile 对象
        FormFile file = uploadForm.getMyFile();
        // 3. 检查是否有文件被选择
        if (file == null || file.getFileSize() == 0) {
            request.setAttribute("errorMessage", "请选择一个文件!");
            return mapping.findForward("failure");
        }
        // 4. 获取文件信息
        String fileName = file.getFileName();
        long fileSize = file.getFileSize();
        String contentType = file.getContentType();
        System.out.println("正在上传文件: " + fileName);
        System.out.println("文件大小: " + fileSize + " bytes");
        System.out.println("文件类型: " + contentType);
        // 5. 定义文件在服务器上的保存路径
        // 为了安全,不要将文件保存在 Web 应用根目录下
        String uploadDir = getServlet().getServletContext().getRealPath("/uploads");
        // 确保上传目录存在
        File dir = new File(uploadDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 构建服务器上的完整文件路径
        String serverPath = uploadDir + File.separator + fileName;
        // 6. 将文件内容写入服务器
        try (InputStream inputStream = file.getInputStream();
             OutputStream outputStream = new FileOutputStream(new File(serverPath))) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            System.out.println("文件已成功保存到: " + serverPath);
        } catch (IOException e) {
            e.printStackTrace();
            request.setAttribute("errorMessage", "文件上传失败: " + e.getMessage());
            return mapping.findForward("failure");
        }
        // 7. 设置成功消息,并转发到成功页面
        request.setAttribute("successMessage", 
            "文件 '" + fileName + "' 上传成功!大小: " + (fileSize / 1024) + " KB。");
        return mapping.findForward("success");
    }
}

第 5 步:配置 struts-config.xml

这是连接所有组件的关键,我们需要配置 ActionFormAction 以及它们之间的映射。

<?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>
    <!-- ========== Form Bean Definitions ========== -->
    <form-beans>
        <!-- 
            name: 在 Action 中使用的 Form 名称
            type: 对应的 Form 类的全限定名
        -->
        <form-bean name="uploadForm" type="com.example.form.UploadForm" />
    </form-beans>
    <!-- ========== Global Forward Definitions ========== -->
    <global-forwards>
        <!-- 可以定义一些全局的转发,比如首页 -->
        <forward name="welcome" path="/upload.jsp" />
    </global-forwards>
    <!-- ========== Action Mapping Definitions ========== -->
    <action-mappings>
        <!-- 
            path: 请求的 URL 路径,对应 JSP 中的 action="/fileUpload"
            type: 处理该请求的 Action 类的全限定名
            name: 使用的 Form Bean 的名称
            scope: Form Bean 的作用域 (request 或 session)
            validate: 是否在调用 Action 的 execute 方法前调用 Form 的 validate 方法
            input: 如果验证失败,返回的页面
            forward: 一个简单的转发
        -->
        <action path="/fileUpload"
                type="com.example.action.FileUploadAction"
                name="uploadForm"
                scope="request"
                validate="false"
                input="/upload.jsp">
            <!-- 定义 Action 的内部转发 -->
            <forward name="success" path="/success.jsp" />
            <forward name="failure" path="/upload.jsp" />
        </action>
    </action-mappings>
    <!-- ========== Message Resources Definitions ========== -->
    <message-resources parameter="com.example.ApplicationResources" />
</struts-config>

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

success.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">上传成功</title>
</head>
<body>
    <h2>上传结果</h2>
    <hr>
    <p style="color: green; font-weight: bold;">
        ${successMessage}
    </p>
    <hr>
    <p>
        <html:link page="/upload.jsp">返回上传页面</html:link>
    </p>
</body>
</html>

upload.jsp (修改失败提示部分)upload.jsp 的表单上方添加一个错误显示区域:

<!-- 在 <body> 标签后添加 -->
<c:if test="${not empty errorMessage}">
    <p style="color: red; font-weight: bold;">
        ${errorMessage}
    </p>
</c:if>

注意:你需要在页面顶部添加 JSTL 核心库的 taglib 指令: <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

第 7 步:配置 web.xml

确保 ActionServlet 已经正确配置,struts-config.xml 被加载。

<?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 1 的核心控制器 -->
    <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>
    <!-- 将所有 .do 请求交给 ActionServlet 处理 -->
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

重要注意事项

  1. 文件大小限制:

    • 默认情况下,commons-fileupload 对上传文件的大小有限制(通常为 250MB),如果上传的文件超过这个限制,会抛出 SizeLimitExceededException
    • 你可以通过修改 struts-config.xml 中的 controller 元素来调整这个限制。
    • <struts-config> 根标签下添加:
      <controller
          maxFileSize="10MB"
          maxFileSize="10MB"
          bufferSize="4096" />
      • maxFileSize: 单个文件的最大大小。
      • maxFileSize: 整个请求(所有文件)的最大大小。
      • bufferSize: 用于读取文件的缓冲区大小。
  2. 安全性和性能:

    • 文件名安全: 不要直接使用用户提供的文件名,它可能包含恶意路径(如 ../../malicious.txt),你应该对文件名进行清理,例如只保留文件名部分,并生成一个唯一的文件名来避免覆盖。
    • 存储位置: 不要将文件存储在 Web 应用可以直接访问的目录下(如 webapp/uploads),否则用户可以直接通过 URL 访问上传的文件,最佳实践是存储在 WEB-INF 之外的某个安全位置,并通过一个专门的 Servlet 或 Action 来提供文件下载服务,并在此过程中进行权限验证。
    • 内存使用: FormFile.getFileData() 会将整个文件加载到内存中,对于非常大的文件,这可能会导致 OutOfMemoryError,更安全的方式是使用 FormFile.getInputStream()OutputStream 逐块读写文件,如示例代码所示。
  3. commons-fileupload 版本:

    • Struts 1 依赖于 commons-fileupload,确保你使用的 commons-fileupload 版本与 Struts 1 版本兼容,较新的 Struts 1 版本通常支持较新的 commons-fileupload 版本。

这个示例涵盖了 Struts 1 文件上传的所有核心步骤,你可以基于此进行扩展和优化。

分享:
扫描分享到社交APP
上一篇
下一篇