SpringMVC使用MultipartResolver和MultipartFile实现文件上传

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: SpringMVC使用MultipartResolver和MultipartFile实现文件上传

文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息。


SpringMVC为文件上传提供了直接支持,这种支持是通过即插即用的MultipartResolver实现的。Spring用Jakarta Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。


SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下不能处理文件上传工作,如果想使用Spring的文件上传功能,需在上下文中配置MultipartResolver。


【1】CommonsMultipartResolver配置

① CommonsMultipartResolver

Apache Commons FileUpload 1.2或更高版本的基于Servlet的 MultipartResolver实现。提供了继承于CommonsFileUploadSupport的maxUploadSize、maxInMemorySize以及defaultEncoding属性。有关默认值和接受值的详细信息,请参阅相应的ServletFileUpload/DiskFileItemFactory属性(“sizeMax”、“sizeThreshold”、“headerEncoding”)。


其会将临时文件保存到servlet容器的临时目录。需要通过应用程序上下文或通过接受ServletContext(用于独立使用)的构造函数初始化实例。

实现类如下所示,继承了CommonsFileUploadSupport并实现了MultipartResolverServletContextAware接口。


② 主要方法

① 有参构造方法

获取servletContext实例进行CommonsMultipartResolver实例化

public CommonsMultipartResolver(ServletContext servletContext) {
    this();
    setServletContext(servletContext);
}


② 获取ServletFileUpload

  @Override
  protected FileUpload newFileUpload(FileItemFactory fileItemFactory) {
    return new ServletFileUpload(fileItemFactory);
  }

③ 设置ServletContext 引用

  @Override
  public void setServletContext(ServletContext servletContext) {
    if (!isUploadTempDirSpecified()) {
      getFileItemFactory().setRepository(WebUtils.getTempDir(servletContext));
    }
  }

④ 检测是否Multipart请求

  @Override
  public boolean isMultipart(HttpServletRequest request) {
    return ServletFileUpload.isMultipartContent(request);
  }


⑤ 核心方法-将请求包装为MultipartHttpServletRequest

@Override
  public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
    Assert.notNull(request, "Request must not be null");
    if (this.resolveLazily) {
      return new DefaultMultipartHttpServletRequest(request) {
        @Override
        protected void initializeMultipart() {
          MultipartParsingResult parsingResult = parseRequest(request);
          setMultipartFiles(parsingResult.getMultipartFiles());
          setMultipartParameters(parsingResult.getMultipartParameters());
          setMultipartParameterContentTypes(parsingResult.getMultipartParameterContentTypes());
        }
      };
    }
    else {
      MultipartParsingResult parsingResult = parseRequest(request);
      return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
          parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
    }
  }


⑥ 核心方法-解析请求

protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
    String encoding = determineEncoding(request);
    FileUpload fileUpload = prepareFileUpload(encoding);
    try {
      List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
      return parseFileItems(fileItems, encoding);
    }
    catch (FileUploadBase.SizeLimitExceededException ex) {
      throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
    }
    catch (FileUploadBase.FileSizeLimitExceededException ex) {
      throw new MaxUploadSizeExceededException(fileUpload.getFileSizeMax(), ex);
    }
    catch (FileUploadException ex) {
      throw new MultipartException("Failed to parse multipart servlet request", ex);
    }
  }

⑦ 清理fileItems内容

public void cleanupMultipart(MultipartHttpServletRequest request) {
    if (!(request instanceof AbstractMultipartHttpServletRequest) ||
        ((AbstractMultipartHttpServletRequest) request).isResolved()) {
      try {
        cleanupFileItems(request.getMultiFileMap());
      }
      catch (Throwable ex) {
        logger.warn("Failed to perform multipart cleanup for servlet request", ex);
      }
    }
  }


底层是对 org.apache.commons.fileupload下面的几个类做了封装


③ 加入SpringMVC依赖的Java原生的jar

如下图所示,使用Java原生进行文件上传需要的jar包


可以使用maven依赖:

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>

④ 配置CommonsMultipartResolver

spring的xml文件配置如下

  <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--需与jsp页面编码保持一致-->
    <property name="defaultEncoding" value="UTF-8"></property>
    <!--限制上传大小-->
    <property name="maxUploadSize" value="102400000"></property>  
  </bean> 

其他属性如下图所示:


属性解释如下:

resolveLazily:延迟解析,默认为false--立即解析multipart request;
defaultEncoding:解析请求的默认字符编码 ; 默认值为"ISO-8859-1"。通常设置为"UTF-8";
maxUploadSize:文件上传最大值; 默认值为 -1(表示没有限制);
maxUploadSizePerFile:每个文件上传最大值;默认值为 -1(表示没有限制);
maxInMemorySize:存储在内存的最大值;默认值为10240B(10KB);
uploadTempDir:上传文件的临时目录;默认值为WEB应用程序的临时目录;
servletContext:the servletContext to use;


【2】测试代码

① form表单

<form action="testFileUpload" method="POST" enctype="multipart/form-data">
    File: <input type="file" name="file"/>
    Desc: <input type="text" name="desc"/>
    <input type="submit" value="Submit"/>
</form>

② 后台代码

@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desc") String desc, 
    @RequestParam("file") MultipartFile file) throws IOException{
  if (!file.isEmpty()) {
    System.out.println("desc: " + desc);
    System.out.println("OriginalFilename(原始文件名字): " + file.getOriginalFilename());
    System.out.println("InputStream(获取的文件输入流): " + file.getInputStream());
    System.out.println("文件大小为(单位为字节Byte): " + file.getSize());
    System.out.println("文件内容类型为: " + file.getContentType());
    file.transferTo(new File("D:\\temDirectory\\"+file.getOriginalFilename()));
  }
  return "success";
}


如上述代码所示,可以拿到文件名与输入流以及文件大小。最后一个方法file.transferTo很有意思,可以直接保存到目标路径下的文件:

void org.springframework.web.multipart.MultipartFile.transferTo(File dest) 
throws IOException, IllegalStateException
  • 将接收到的文件传输到给定的目标文件。
  • 这可能会移动文件系统中的文件,复制文件系统中的文件,或将内存保留的内容保存到目标文件。
  • 如果目标文件已存在,将首先删除它。
  • 如果文件已在文件系统中移动,则无法再次调用此操作。
  • 因此,只需调用此方法一次,即可使用任何存储机制。


Chrome F12追踪网络展示如下:

③ 上传多个文件

表单内容:多个文件域(上传单文件时注释掉)

<form action="face/receiveImg" method="POST" enctype="multipart/form-data">
        File: <input type="file" name="file"/>
        Desc: <input type="text" name="desc"/>
<!--         File2: <input type="file" name="file"/> -->
<!--         Desc2: <input type="text" name="desc2"/> -->
        <input type="submit" value="Submit"/>
  </form>


也可以使用multiple 属性(上传单文件时去掉该属性)

<form action="face/receiveImg" method="POST" enctype="multipart/form-data">
        File: <input type="file" name="file" multiple="multiple"/>
        Desc: <input type="text" name="desc"/>
        <input type="submit" value="Submit"/>
  </form>

上传单文件时,后台使用MultipartFile file,MultipartFile[] file,@RequestParam("file")MultipartFile file,@RequestParam MultipartFile file 均可以正常接收(这里name默认为file哦)。


上传多文件时,后台只有使用 @RequestParam("file") MultipartFile[] file才可以正常接收。

【3】使用FormData上传多个文件


通过FormData对象可以组装一组用 XMLHttpRequest发送请求的键/值对。它可以更灵活方便的发送表单数据,因为可以独立于表单使用。


如果你把表单的编码类型设置为multipart/form-data ,则通过FormData传输的数据格式和表单通过submit() 方法传输的数据格式相同


即,此时使用FormData对象传送的数据不会发送格式改变

① 表单示例

这里使用两个文本域来上传两个Excel表格:

<form id="myform" name="myform" action="<%=basePath%>data/saveDataImport.do" class="layui-form"  method="post" enctype="multipart/form-data" >
    <div  class="layui-form-item">
    <label class="layui-form-label">请选择POS表:</label>
    <div class="layui-input-block">
      <input id="pos" type="file" name="pos"  >
    </div>
    </div>
    <div  class="layui-form-item" >
    <label class="layui-form-label">请选择商品表:</label>
    <div class="layui-input-block">
      <input id="goods" type="file" name="goods"  >
    </div>
    </div>
    <div class="layui-form-item" style="margin-top: 40px;">
    <div class="layui-input-block">
      <button  id = "upload" class="layui-btn" type="button">确定</button>
      <button name="cancel"  type="button" class="layui-btn" onclick="f_cancel();">取消</button>
    </div>
  </div>
</form>


② 构建FormData对象

下面两种正确方式:

var posFormData = new FormData($("#myform")[0]);
 or
var posFormData = new FormData($("form")[0]);


参数对比如下图:


FormData对象


③ ajax提交

$(function(){
  $("#upload").click(function(){
    var posFormData = new FormData($("#myform")[0]);
    $.ajax({
              url: url,
              type: 'POST',
              data: posFormData,
              contentType: false, //禁止设置请求类型
              processData: false, //禁止jquery对DAta数据的处理,默认会处理
              beforeSend: function(){
                  //返回的参数item,即为当前的input DOM对象
            index = layer.load(1,{shade: [0.3,'grey']});
              },
              success: function(data) {
                 if (typeof data != "object") {
                  jsonReturn = eval("("+data+")");
              }else{
                jsonReturn=data;
              }
                   //关闭遮罩层
                 layer.close(index);
              if(jsonReturn.code == "true"){
               layer.msg(jsonReturn.message,{icon:1,time: 1000},function(){
                f_cancel();
                        top.f_getframe("goods_index_do").f_goods_sale_query();
               });
              }else{
               layer.msg(jsonReturn.message,{icon: 7,time: 2000});
              }
              }
    });
  });
 });


上传参数如下图:


使用submit方式上传文件参数如下图:

对比发现,二者数据格式完全一致!

④ 后台接收

@RequestMapping(value="saveDataImport",produces="application/json;charset=utf-8" )
@ResponseBody
public String saveDataImport(@RequestParam(value="pos",required=false)MultipartFile posFile,@RequestParam(value="goods",required=false)MultipartFile goodsFile){
//...
}


目录
相关文章
|
9月前
MultipartFile转为File
MultipartFile转为File
|
2月前
|
Java 测试技术 Spring
|
2月前
|
Java 测试技术 Spring
MultipartFile介绍
MultipartFile介绍
50 0
|
3月前
|
XML Java Maven
如何将MultipartFile转换为File
该文介绍了MultipartFile(Spring框架)与File(Java标准库)的区别,主要讨论了如何将MultipartFile转换为File的三种方法:使用`transferTo`、`FileOutputStream`和Java NIO,并提到了File转MultipartFile常用于测试,可通过MockMultipartFile实现。
|
3月前
|
Java
【Java报错】MultipartFile 类型文件上传 Current request is not a multipart request 问题处理(postman添加MultipartFile)
【Java报错】MultipartFile 类型文件上传 Current request is not a multipart request 问题处理(postman添加MultipartFile)
412 0
|
8月前
下载文件url为MultipartFile
下载文件url为MultipartFile
117 0
|
9月前
MultipartFile多文件上传/通过文件夹解析所有文件
MultipartFile多文件上传/通过文件夹解析所有文件
135 0
|
9月前
File转换成MultiPartFile
File转换成MultiPartFile
Springboot Http文件的访问 Url 转换 MultipartFile ,File 转 MultipartFile
Springboot Http文件的访问 Url 转换 MultipartFile ,File 转 MultipartFile
804 0
Springboot byte[] 转 MultipartFile ,InputStream 转 MultipartFile
Springboot byte[] 转 MultipartFile ,InputStream 转 MultipartFile
1059 0