springboot2.x文件上传

栏目: Java · 发布时间: 5年前

内容简介:这时候系统将会出现这是什么原因呢?可以进入而后我们再进入

pom包的配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

启动项类修改

/**
  * 防止文件大于10M时Tomcat连接重置
  *
  * @return
  */
@Bean
public TomcatServletWebServerFactory tomcatEmbedded() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
        if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
            ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
        }
    });
    return tomcat;
}

配置文件修改

# 禁用 thymeleaf 缓存
spring.thymeleaf.cache=false
# 是否支持批量上传   (默认值 true)
spring.servlet.multipart.enabled=true
# 上传文件的临时目录 (一般情况下不用特意修改)
spring.servlet.multipart.location=
# 上传文件最大为 1M (默认值 1M 根据自身业务自行控制即可)
spring.servlet.multipart.max-file-size=10MB
# 上传请求最大为 10M(默认值10M 根据自身业务自行控制即可)
spring.servlet.multipart.max-request-size=10MB
# 文件大小阈值,当大于这个阈值时将写入到磁盘,否则存在内存中,(默认值0 一般情况下不用特意修改)
spring.servlet.multipart.file-size-threshold=0
# 判断是否要延迟解析文件(相当于懒加载,一般情况下不用特意修改)
spring.servlet.multipart.resolve-lazily=false

file.upload.path: /file/upload

单文件上传

@PostMapping("/upload")
public Map<String, String> upload(@RequestParam MultipartFile file) throws IOException {
    //创建本地文件
    File localFile = new File(path, file.getOriginalFilename());
    //把传上来的文件写到本地文件
    file.transferTo(localFile);
    //返回localFile文件路径
    Map<String, String> path = new HashMap<>();
    path.put("path", localFile.getAbsolutePath());
    return path;
}

这时候系统将会出现 FileNotFoundException ,日志类似下面这样:

java.io.FileNotFoundException:C:\Users\cheng\AppData\Local\Temp\tomcat.7543349588424487992.9000\work\Tomcat\localhost\ROOT\file\upload\tmp\file\upload\1558332190813.jpg (系统找不到指定的路径。)

这是什么原因呢?可以进入 transferTo 方法

@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
    this.part.write(dest.getPath());
    if (dest.isAbsolute() && !dest.exists()) {
        // Servlet 3.0 Part.write is not guaranteed to support absolute file paths:
        // may translate the given path to a relative location within a temp dir
        // (e.g. on Jetty whereas Tomcat and Undertow detect absolute paths).
        // At least we offloaded the file from memory storage; it'll get deleted
        // from the temp dir eventually in any case. And for our user's purposes,
        // we can manually copy it to the requested location as a fallback.
        FileCopyUtils.copy(this.part.getInputStream(),         Files.newOutputStream(dest.toPath()));
    }
}

而后我们再进入 write 方法

@Override
public void write(String fileName) throws IOException {
    File file = new File(fileName);
    if (!file.isAbsolute()) {
        file = new File(location, fileName);
    }
    try {
        fileItem.write(file);
    } catch (Exception e) {
        throw new IOException(e);
    }
}

这时候我们看到如果 file.isAbsolute() 成立,也就是我们没有使用绝对路径,那么 file = new File(location,fileName); 会在原来的基础上加上location路径.这就是原因所在,可以通过修改绝对路径解决

  1. 直接将file.upload.path修改为绝对路径即可
  2. 在代码中控制

    @PostMapping("/upload")
        public Map<String, String> upload(@RequestParam MultipartFile file) throws IOException {
            //创建本地文件
            String classpath = ResourceUtils.getURL("classpath:").getPath();
            File localFile = new File(classpath + path, file.getOriginalFilename());
            //把传上来的文件写到本地文件
            file.transferTo(localFile);
            //返回localFile文件路径
            Map<String, String> path = new HashMap<>();
            path.put("path", localFile.getAbsolutePath());
            return path;
        }

    通过 ResourceUtils.getURL("classpath:").getPath() 获得项目路径,然后加上设置的相对路径。

    网络上还有一种修改 location 值的方式,可以看 这篇博客 但是我个人使用是一直不可以。

  3. 或者可以不使用transferTo,代码如下

    @PostMapping("/singleFileUpload")
    public String singleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
    byte[] bytes = file.getBytes();
        Path filePath = Paths.get(path + file.getOriginalFilename());
    Files.write(filePath, bytes);
        return file.getOriginalFilename();
    }

    Paths.get 所使用的也是绝对路径,如果您在Windows机器上使用了这种路径(从/开始的路径),那么路径将被解释为相对于当前驱动器,例如

    /file/upload/1.txt

    而您的项目位于D盘。那么这条路径就会对应这条完整的路径:

    D:\file\upload\1.txt

为了简便,以下代码均是使用绝对路径。

文件上传控制器编写

多文件上传

@PostMapping("/uploads")
public Map<String, String> uploads(@RequestParam MultipartFile[] files) throws IOException {
    StringBuilder sb = new StringBuilder();
    Map<String, String> paths = new HashMap<>();
    for (MultipartFile file : files) {
        //创建本地文件
        File localFile = new File(path, file.getOriginalFilename());
        //把传上来的文件写到本地文件
        file.transferTo(localFile);
        sb.append(localFile.getAbsolutePath()).append(",");
        paths.put(file.getOriginalFilename(), localFile.getAbsolutePath());
    }
    //返回localFile文件路径
    return paths;
}

多文件上传+表单提交

@PostMapping("/uploadsWithForm")
public Map<String, String> uploadsWithForm(@RequestParam String tmpString, @RequestParam MultipartFile[] files) throws IOException {
    StringBuilder sb = new StringBuilder();
    Map<String, String> paths = new HashMap<>();
    paths.put("tmpString", tmpString);
    for (MultipartFile file : files) {
        //创建本地文件
        File localFile = new File(path, file.getOriginalFilename());
        //把传上来的文件写到本地文件
        file.transferTo(localFile);
        sb.append(localFile.getAbsolutePath()).append(",");
        paths.put(file.getOriginalFilename(), localFile.getAbsolutePath());
    }
    //返回localFile文件路径
    return paths;
}

多文件上传+Json数据提交

/**
     * 测试多文件上传+json接口
     *
     * @param files
     * @return
     */
    @ApiOperation("测试多文件上传接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "jsonMap", value = "json数据", dataType = "Map"),
            @ApiImplicitParam(name = "files", value = "文件流对象,接收数组格式", required = true, dataType = "__File"),
    })
    @PostMapping(value = "/uploadsWithJson")
    public Map<String, String> uploadsWithJson(@RequestPart("files") MultipartFile[] files, @RequestPart("jsonMap") Map<String, Object> jsonMap) throws IOException {

        StringBuilder sb = new StringBuilder();
        Map<String, String> paths = new HashMap<>();
        System.out.println(jsonMap);
        for (MultipartFile file : files) {
            //创建本地文件
            File localFile = new File(path, file.getOriginalFilename());
            //把传上来的文件写到本地文件
            file.transferTo(localFile);
            sb.append(localFile.getAbsolutePath()).append(",");
            paths.put(file.getOriginalFilename(), localFile.getAbsolutePath());
        }
        paths.put("jsonMap", JsonUtils.obj2json(jsonMap));
        //返回localFile文件路径
        return paths;
    }

呵呵,不好用对不对。项目抛出了个异常, HttpMediaTypeNotSupportedException

WARN  o.s.w.s.m.support.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported]

所以我们需要添加个转换器类

@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {

    /**
     * Converter for support http request with header Content-Type: multipart/form-data
     */
    public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    protected boolean canWrite(MediaType mediaType) {
        return false;
    }
}

这样就能够识别了

总结

感觉把springboot文件上传所能遇到的坑全踩了个变,心累。

如果需要项目代码,可以去我的 github 中下载;


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A Philosophy of Software Design

A Philosophy of Software Design

John Ousterhout / Yaknyam Press / 2018-4-6 / GBP 14.21

This book addresses the topic of software design: how to decompose complex software systems into modules (such as classes and methods) that can be implemented relatively independently. The book first ......一起来看看 《A Philosophy of Software Design》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具