Servlet 3.0 结合WebMultipart注解实现文件上传

1. 背景

在Servlet 3.0之前,上传文件需要借助第三方的jar包,而在3.0版本,servlet提供了自己的文件上传API。主要是一个类Part和一个注解@MultipartConfig

2. API介绍

Servlet接收到文件上传请求,会将其封装为一个Part对象。
Part对象持有文件名、文件流、请求数据以及自己的名字等信息。
我们可以通过request#getParts()方法和request.getPart(name)方法来获取封装的part实例。具体如下:

2.1 @WebMultipart注解

该注解主要是为了辅助 Servlet 3.0 中 HttpServletRequest 提供的对上传文件的支持。该注解标注在 Servlet 上面,以表示该 Servlet 希望处理的请求的 MIME 类型是 multipart/form-data。另外,它还提供了若干属性用于简化对上传文件的处理。具体如下:

属性名类型是否可选描述
fileSizeThresholdint当数据量大于该值时,内容将被写入文件。
locationString存放生成的文件地址。
maxFileSizelong允许上传的文件最大值。默认值为 -1,表示没有限制。
maxRequestSizelong针对该 multipart/form-data 请求的最大数量,默认值为 -1,表示没有限制。

其中location属性的值比较特殊,需要注意一下,后面会讲解。
Note: 表单的enctype属性最好指定为multipart/form-data

2.2 获取part

  • Collection<Part> getParts()
    返回一个Part对象集合,代表上传到这个servlet所有文件对应的part实例。
  • Part getPart(String name)
    根据传入的name获取part实例,name是part实例的名字,等价于文件上传表单中<input type=file name="myfile">标签中的name属性的值。
  • Note:
    很多博客直接使用getPart(name)方法获取part,愚以为不妥。因为这样会导致name硬编码,我推荐通过getParts()来获取所有part,然后遍历处理。这样一来,即使前端name属性的值变化,我们后端的servlet也能正确处理。

2.3 Part

在这里插入图片描述

重要的方法有两个(图中圈出来了):

  • write(String filename)
    将上传的文件写入磁盘,写入路径为:@MultipartConfig注解的location值 + 分隔符 + filename参数的值
    比如@MultipartConfig(location="F\\a\\b\\upload"),然后调用part.write("2020-08-12\\myfile”),则文件在磁盘中的绝对路径为F\a\b\upload\2020-08-12\myfile
  • getSumbittedFileName() 顾名思义,获取上传的文件的名字,包括扩展名

3 案例实现

3.1 前端表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%-- method必须是post,enctype必须是multipart/form-data -- %>
<form action="hi" method="post"  enctype="multipart/form-data">
<%-- type指定为file,可以选择一个文件传入
	 name属性的值任意 --%>
    <input type="file" name="file">
    <input type="submit" value="上传文件">
</form>
</body>
</html>

3.2 后端Servlet实现

//这个注解用来代替xml配置servlet,读者使用xml配置不会影响结果
@WebServlet(urlPatterns = "/hi")
@MultipartConfig(location = "F:\\IntelliJ IDEA 2018.2.8\\projects\\java-web-review\\servlet-review\\src\\main\\resources\\upload")
public class HiServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        try {
            Enumeration<String> parameterNames = request.getParameterNames();
            //使用getParts而不是直接getPart(name),避免上传文件表单name硬编码
            request.getParts().forEach(part -> {
                //获取上传文件名
                System.out.println(part.getSubmittedFileName());
                //生成随机UUID,因为不同用户可能上传同名的文件,所以通过uuid生成不重复的字符串拼接到文件名后。
                //实际上很多东西没考虑到,这个案例只是参考而已,不建议用来作为开发中的最佳实践。
                String uuid = UUID.randomUUID().toString();
                try {
                    //写入文件
                    part.write("myfile" + uuid);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        } catch (IOException | ServletException e) {
            e.printStackTrace();
        }
    }
}

3.3 结果

略,最总文件路径为F:\IntelliJ IDEA 2018.2.8\projects\java-web-review\servlet-review\src\main\resources\upload\myfile7abbd4d0-d2ba-41ef-80fa-d7128255e403
更多servlet 3.0 新特性参考这个

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值