Uploading Files with Servlets and JSP – 用Servlet和JSP上传文件

最后修改: 2018年 5月 19日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this quick tutorial, we’ll see how to upload a file from a servlet.

在这个快速教程中,我们将看到如何从一个servlet上传一个文件。

To achieve this, we’ll first see the vanilla Jakarta EE solution with file upload capabilities provided by native @MultipartConfig annotation.

为了实现这一点,我们首先看看香草式的Jakarta EE解决方案,它具有由本地@MultipartConfig注释提供的文件上传功能。

Then, we’ll go over the Apache Commons FileUpload library, for earlier versions of the Servlet API.

然后,我们将介绍Apache Commons FileUpload库,用于Servlet API的早期版本。

2. Using Jakarta EE @MultipartConfig

2.使用Jakarta EE @MultipartConfig

Jakarta EE has the ability to support multi-part uploads out of the box.

Jakarta EE有能力支持开箱即用的多部分上传。

As such, it’s probably a default go-to when enriching a Jakarta EE app with file upload support.

因此,在丰富Jakarta EE应用程序的文件上传支持时,它可能是一个默认的选择。

First, let’s add a form to our HTML file:

首先,让我们在我们的HTML文件中添加一个表单。

<form method="post" action="multiPartServlet" enctype="multipart/form-data">
    Choose a file: <input type="file" name="multiPartServlet" />
    <input type="submit" value="Upload" />
</form>

The form should be defined using the enctype=”multipart/form-data” attribute to signal a multipart upload.

该表格应使用enctype=”multipart/form-data”属性定义,以示多部分上传。

Next, we’ll want to annotate our HttpServlet with the correct information using the @MultipartConfig annotation:

接下来,我们要使用@MultipartConfig注解为我们的HttpServlet注解正确的信息

@MultipartConfig(fileSizeThreshold = 1024 * 1024,
  maxFileSize = 1024 * 1024 * 5, 
  maxRequestSize = 1024 * 1024 * 5 * 5)
public class MultipartServlet extends HttpServlet {
    //...
}

Then, let’s make sure that our default server upload folder is set:

然后,让我们确保我们的默认服务器上传文件夹被设置。

String uploadPath = getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY;
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) uploadDir.mkdir();

Finally, we can easily retrieve our inbound File from the request using the getParts() method, and save it to the disk:

最后,我们可以使用getParts() method轻松地从request 中获取我们的入站文件,并将其保存到磁盘中。

for (Part part : request.getParts()) {
    fileName = getFileName(part);
    part.write(uploadPath + File.separator + fileName);
}

Note that, in this example, we’re using a helper method getFileName():

注意,在这个例子中,我们使用了一个辅助方法getFileName()。

private String getFileName(Part part) {
    for (String content : part.getHeader("content-disposition").split(";")) {
        if (content.trim().startsWith("filename"))
            return content.substring(content.indexOf("=") + 2, content.length() - 1);
        }
    return Constants.DEFAULT_FILENAME;
}

For Servlet 3.1. projects, we could alternatively use the Part.getSubmittedFileName() method:

对于Servlet 3.1.项目,我们可以选择使用Part.getSubmittedFileName()方法:

fileName = part.getSubmittedFileName();

3. Using Apache Commons FileUpload

3.使用Apache Commons FileUpload

If we’re not on a Servlet 3.0 project, we can use the Apache Commons FileUpload library directly.

如果我们不是在Servlet 3.0项目上,我们可以直接使用Apache Commons FileUpload库。

3.1. Setup

3.1.设置

We’ll want to use the following pom.xml dependencies to get our example running:

我们要使用以下pom.xml依赖项来使我们的例子运行。

<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>

The most recent versions can be found with a quick search on Maven’s Central Repository: commons-fileupload and commons-io.

在Maven的中央仓库中快速搜索就能找到最新的版本。commons-fileuploadcommons-io

3.2. Upload Servlet

3.2.上传Servlet

The three main parts to incorporating Apache’s FileUpload library go as follows:

纳入Apache的FileUpload库的三个主要部分如下。

  • An upload form in a .jsp page.
  • Configuring your DiskFileItemFactory and ServletFileUpload object.
  • Processing the actual contents of a multipart file upload.

The upload form is the same as the one in the previous section.

上传表格与上一节中的表格相同。

Let’s move on to creating our Jakarta EE servlet.

让我们继续创建我们的Jakarta EE servlet。

In our request processing method, we can wrap the incoming HttpRequest with a check to see if it’s a multi-part upload.

在我们的请求处理方法中,我们可以对传入的HttpRequest进行检查,看它是否是一个多部分的上传。

We’ll also specify what resources to allocate to the file upload temporarily (while being processed) on our DiskFileItemFactory.

我们还将在我们的DiskFileItemFactory上指定为文件上传临时分配哪些资源(在处理中)。

Lastly, we’ll create a ServletFileUpload object which will represent the actual file itself. It will expose the contents of the multi-part upload for final persistence server side:

最后,我们将创建一个ServletFileUpload对象,它将代表实际的文件本身。它将暴露出多部分上传的内容,以便在服务器端进行最终的持久化。

if (ServletFileUpload.isMultipartContent(request)) {

    DiskFileItemFactory factory = new DiskFileItemFactory();
    factory.setSizeThreshold(MEMORY_THRESHOLD);
    factory.setRepository(new File(System.getProperty("java.io.tmpdir")));

    ServletFileUpload upload = new ServletFileUpload(factory);
    upload.setFileSizeMax(MAX_FILE_SIZE);
    upload.setSizeMax(MAX_REQUEST_SIZE);
    String uploadPath = getServletContext().getRealPath("") 
      + File.separator + UPLOAD_DIRECTORY;
    File uploadDir = new File(uploadPath);
    if (!uploadDir.exists()) {
        uploadDir.mkdir();
    }
    //...
}

And, then we can extract those contents and write them to disk:

然后,我们可以提取这些内容并将其写入磁盘。

if (ServletFileUpload.isMultipartContent(request)) {
    //...
    List<FileItem> formItems = upload.parseRequest(request);
    if (formItems != null && formItems.size() > 0) {
        for (FileItem item : formItems) {
	    if (!item.isFormField()) {
	        String fileName = new File(item.getName()).getName();
	        String filePath = uploadPath + File.separator + fileName;
                File storeFile = new File(filePath);
                item.write(storeFile);
                request.setAttribute("message", "File "
                  + fileName + " has uploaded successfully!");
	    }
        }
    }
}

4. Running the Example

4.运行实例

After we’ve compiled our project into a .war, we can drop it into our local Tomcat instance and start it up.

在我们把项目编译成.war之后,我们可以把它放到本地Tomcat实例中并启动它。

From there, we can bring up the main upload view where we’re presented with a form:

从那里,我们可以调出主上传视图,在那里我们会看到一个表格。

choosefile

After successfully uploading our file, we should see the message:

在成功上传我们的文件后,我们应该看到这样的信息。

filesuccess

Lastly, we can check the location specified in our servlet:

最后,我们可以检查我们的servlet中指定的位置。

imagesaved

5. Conclusion

5.结论

That’s it! We’ve learned how to provide multi-part file uploads using Jakarta EE, as well as Apache’s Common FileUpload library!

这就是了!我们已经学会了如何使用Jakarta EE以及Apache的通用FileUpload库来提供多部分的文件上传!

Code snippets, as always, can be found over on GitHub.

像往常一样,可以在GitHub上找到代码片段