Java Servlet 3文件上传完全指南:@MultipartConfig注解与Part接口详解

今天我们将通过使用@MultipartConfig注解和javax.servlet.http.Part来查看Servlet 3文件上传示例。之前我写过一篇关于Servlet文件上传的文章,当时我使用了Apache FileUpload API,但现在我们将使用Servlet 3文件上传功能。

Servlet 3 文件上传

由于文件上传是Web应用程序中常见的任务,Servlet规范3.0提供了对文件上传到服务器的额外支持,我们不需要依赖于任何第三方API。在本教程中,我们将看到如何使用Servlet 3.0 API将文件上传到服务器。

多部分配置

为了处理用于将文件上传到服务器的multipart/form-data请求,我们需要使用MultipartConfig注解来注解File Upload handler servlet。MultipartConfig注解具有以下属性:

  • fileSizeThreshold: 我们可以指定文件将被写入磁盘的大小阈值。大小值以字节为单位,所以1024*1024*10等于10MB。
  • location: 文件默认存储的目录,其默认值为””。
  • maxFileSize: 允许上传文件的最大大小,其值以字节为单位提供。默认值为-1L,表示无限制。
  • maxRequestSize: multipart/form-data请求允许的最大大小。默认值为-1L,表示无限制。

阅读《Java注解教程》以了解更多关于注解的内容。

Part接口

Part接口表示在multipart/form-data POST请求中接收到的一部分或表单项。一些重要的方法是getInputStream()和write(String fileName),我们可以使用它们来读取和写入文件。

HttpServletRequest 的改变

HttpServletRequest中添加了新的方法getParts(),用于获取multipart/form-data请求中的所有部分。我们可以使用getPart(String partName)方法获取特定部分。让我们看一个简单的项目,我们将使用上述API方法来使用servlet上传文件。我们的项目结构将如下图所示。

HTML表单

我们有一个简单的HTML页面,我们可以在其中选择要上传的文件并提交请求到服务器以完成上传。index.html

<html>
<head></head>
<body>
<form action="FileUploadServlet" method="post" enctype="multipart/form-data">
选择要上传的文件:<input type="file" name="fileName">
<br>
<input type="submit" value="上传">
</form>
</body>
</html>

文件上传Servlet

这是我们的文件上传Servlet实现。FileUploadServlet.java

package com.Olivia.servlet;
 
import java.io.File;
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
 
@WebServlet("/FileUploadServlet")
@MultipartConfig(fileSizeThreshold=1024*1024*10, 	// 10 MB 
                 maxFileSize=1024*1024*50,      	// 50 MB
                 maxRequestSize=1024*1024*100)   	// 100 MB
public class FileUploadServlet extends HttpServlet {
 
    private static final long serialVersionUID = 205242440643911308L;
	
    /**
     * 上传文件将被保存的目录,它相对于Web应用程序目录。
     */
    private static final String UPLOAD_DIR = "uploads";
     
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 获取Web应用程序的绝对路径
        String applicationPath = request.getServletContext().getRealPath("");
        // 构建保存上传文件的目录路径
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
         
        // 如果保存目录不存在则创建它
        File fileSaveDir = new File(uploadFilePath);
        if (!fileSaveDir.exists()) {
            fileSaveDir.mkdirs();
        }
        System.out.println("上传文件目录="+fileSaveDir.getAbsolutePath());
        
        String fileName = null;
        // 从请求中获取所有部分并将其写入服务器上的文件
        for (Part part : request.getParts()) {
            fileName = getFileName(part);
            part.write(uploadFilePath + File.separator + fileName);
        }
 
        request.setAttribute("message", fileName + " 文件上传成功!");
        getServletContext().getRequestDispatcher("/response.jsp").forward(
                request, response);
    }
 
    /**
     * 从HTTP头content-disposition获取文件名的工具方法
     */
    private String getFileName(Part part) {
        String contentDisp = part.getHeader("content-disposition");
        System.out.println("content-disposition头= "+contentDisp);
        String[] tokens = contentDisp.split(";");
        for (String token : tokens) {
            if (token.trim().startsWith("filename")) {
                return token.substring(token.indexOf("=") + 2, token.length()-1);
            }
        }
        return "";
    }
}

请注意使用@MultipartConfig注释来为上传文件指定不同的大小参数。我们需要使用请求头中的”content-disposition”属性来获取客户端发送的文件名,并将文件保存为相同的名称。保存文件的目录位置是相对于我正在保存文件的Web应用程序的位置,您可以将其配置为其他位置,就像在Apache Commons FileUpload示例中那样。

JSP响应

一个简单的JSP页面,一旦文件成功上传到服务器,就会作为响应发送给客户端。这个页面名为response.jsp。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>文件上传响应</title>
</head>
<body>
	<%-- 使用JSP EL从请求范围获取message属性值 --%>
    <h2>${requestScope.message}</h2>
</body>
</html>

部署描述符

在web.xml文件中,没有关于servlet文件上传的新内容,它仅用于将index.html文件设置为欢迎文件。

<?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" version="3.0">
  <display-name>ServletFileUploadExample</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

现在当我们运行应用程序时,我们会得到以下页面作为响应。日志将显示文件保存的目录位置和content-disposition头信息。

上传文件目录=/Users/scdev/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ServletFileUploadExample/uploads
content-disposition头= form-data; name="fileName"; filename="IMG_2046.jpg"

我通过Eclipse运行Tomcat,所以文件位置是这样的。如果你通过命令行运行tomcat,并将应用程序导出为WAR文件部署到webapps目录中,你会得到一个不同但是清晰的结构。

下载Servlet 3 Multipart文件上传项目

bannerAds