springboot使用MultipartFile上传文件以及File与MultipartFile互转

Posted luffy5459

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot使用MultipartFile上传文件以及File与MultipartFile互转相关的知识,希望对你有一定的参考价值。

    如下所示的代码,是一个在springboot项目中使用MultipartFile进行文件上传的示例:

package com.springboot.web;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/test")
public class UploadController 

    private String path = "d:/temp";

    @PostMapping("/upload")
    public ResponseEntity upload(MultipartFile file) 
        Map<String,Object> res = new HashMap<>();
        try 
            File outFile = new File(path.concat(File.separator).concat(file.getOriginalFilename()));
            file.transferTo(outFile);
            res.put("url",outFile.getAbsolutePath());
            res.put("code",200);
         catch (Exception e) 
            e.printStackTrace();
            res.put("msg","upload fail");
            res.put("code",500);
        
        return ResponseEntity.ok(res);
    

    我们在前端页面上,进行配置上传的时候,可以使用这样的form:

  <form action="/test/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/>
    <input type="submit" value="upload"/>
  </form>

    这里需要注意的是,前端的元素<input type="file" name="file"/>这里的name属性,它要和后端接口里面MultipartFile file参数名字对应起来。否则,接口会报空指针异常。

    现在web一般流行的是异步上传,所以使用三方javascript框架的时候,也需要注意,这里代表file的属性名一定要指定为file,与接口中参数file名字对应起来。

    到这里,使用MultipartFile上传文件基本就完成了,但是,我们这种接口有一个问题,如果我们使用三方服务来调用这个接口,那么这个参数MultipartFile还不好传递,因为这个类型是一个接口类型:

public interface MultipartFile extends InputStreamSource 
    String getName();

    @Nullable
    String getOriginalFilename();

    @Nullable
    String getContentType();

    boolean isEmpty();

    long getSize();

    byte[] getBytes() throws IOException;

    InputStream getInputStream() throws IOException;

    default Resource getResource() 
        return new MultipartFileResource(this);
    

    void transferTo(File dest) throws IOException, IllegalStateException;

    default void transferTo(Path dest) throws IOException, IllegalStateException 
        FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
    

    如果java后端来写这个接口调用,我们本地的文件File有的是,问题是怎么把这个File转为MultipartFile,有一种办法就是借助spring-test依赖下的MockMultipartFile类型,代码如下所示:

package com.springboot.web;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.io.File;
import java.io.FileInputStream;

@SpringBootTest
@RunWith(SpringRunner.class)
public class UploadControllerTest 

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setup() 
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    

    @Test
    public void upload() 
        FileInputStream inputStream = null;
        File file = new File("c:\\\\users\\\\buejee\\\\pictures\\\\avatar.png");
        try 
            inputStream = new FileInputStream(file);
            MockMultipartFile multipartFile = new MockMultipartFile(
                    "file",
                    file.getName(),
                    "APPLICATION_OCTET_STREAM",
                    inputStream);
            MvcResult result = mockMvc.perform(
                    MockMvcRequestBuilders
                    .fileUpload("/test/upload")
                    .file(multipartFile))
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    .andReturn();
            String response = result.getResponse().getContentAsString();
            System.out.println(response);
         catch (Exception e) 
            e.printStackTrace();
        
    

    这里的核心代码就是这几行:

FileInputStream inputStream = null;
File file = new File("c:\\\\users\\\\buejee\\\\pictures\\\\avatar.png");
inputStream = new FileInputStream(file);
MockMultipartFile multipartFile = new MockMultipartFile(
                    "file",
                    file.getName(),
                    "APPLICATION_OCTET_STREAM",
                    inputStream);

    在构造MockMultipartFile的时候,我们传入的第一个参数就是file,这个还是上面说的,需要和接口中MultipartFile file参数的名称对应起来。

    如果不想使用spring-test依赖下的MockMultipartFile,那么就只能自定义一个MultipartFile的实现,其实实现过程完全可以参考MockMultipartFile:

public class MockMultipartFile implements MultipartFile 
    private final String name;
    private final String originalFilename;
    @Nullable
    private final String contentType;
    private final byte[] content;

    public MockMultipartFile(String name, @Nullable byte[] content) 
        this(name, "", (String)null, (byte[])content);
    

    public MockMultipartFile(String name, InputStream contentStream) throws IOException 
        this(name, "", (String)null, (byte[])FileCopyUtils.copyToByteArray(contentStream));
    

    public MockMultipartFile(String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) 
        Assert.hasLength(name, "Name must not be empty");
        this.name = name;
        this.originalFilename = originalFilename != null ? originalFilename : "";
        this.contentType = contentType;
        this.content = content != null ? content : new byte[0];
    

    public MockMultipartFile(String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream) throws IOException 
        this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
    

    public String getName() 
        return this.name;
    

    @NonNull
    public String getOriginalFilename() 
        return this.originalFilename;
    

    @Nullable
    public String getContentType() 
        return this.contentType;
    

    public boolean isEmpty() 
        return this.content.length == 0;
    

    public long getSize() 
        return (long)this.content.length;
    

    public byte[] getBytes() throws IOException 
        return this.content;
    

    public InputStream getInputStream() throws IOException 
        return new ByteArrayInputStream(this.content);
    

    public void transferTo(File dest) throws IOException, IllegalStateException 
        FileCopyUtils.copy(this.content, dest);
    

    构造出了MultipartFile实例,那么调用上传接口就方便了,在上面给出的上传接口UploadController.upload(MultipartFile file)中,其实隐含了一个操作,就是MultipartFile转File,直接借助MultipartFile.transferTo()就可以写为File类型了,最后我们返回File就可以。 

以上是关于springboot使用MultipartFile上传文件以及File与MultipartFile互转的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot: 浅谈文件上传和访问的坑 (MultiPartFile)

Springboot读取Resource资源文件并转化为MultipartFile和File

SpringBoot 2.x版本+MultipartFile设置指定文件上传大小

springboot多文件上传

当我在 Spring Boot 应用程序中使用 CommonsMultipartResolver 时,MultipartFile 为空

spring MVC 的MultipartFile转File读取