资讯专栏INFORMATION COLUMN

springboot2.x文件上传

ChristmasBoy / 727人阅读

摘要:项目抛出了个异常,。所以我们需要添加个转换器类这样就能够识别了总结感觉把文件上传所能遇到的坑全踩了个变,心累。

pom包的配置

    org.springframework.boot
    spring-boot-starter-web
启动项类修改
/**
  * 防止文件大于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 upload(@RequestParam MultipartFile file) throws IOException {
    //创建本地文件
    File localFile = new File(path, file.getOriginalFilename());
    //把传上来的文件写到本地文件
    file.transferTo(localFile);
    //返回localFile文件路径
    Map path = new HashMap<>();
    path.put("path", localFile.getAbsolutePath());
    return path;
}

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

java.io.FileNotFoundException:C:UserschengAppDataLocalTemp	omcat.7543349588424487992.9000workTomcatlocalhostROOTfileupload	mpfileupload1558332190813.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路径.这就是原因所在,可以通过修改绝对路径解决

直接将file.upload.path修改为绝对路径即可

在代码中控制

    @PostMapping("/upload")
    public Map 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 path = new HashMap<>();
        path.put("path", localFile.getAbsolutePath());
        return path;
    }

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

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

或者可以不使用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:fileupload1.txt

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

文件上传控制器编写 多文件上传
@PostMapping("/uploads")
public Map uploads(@RequestParam MultipartFile[] files) throws IOException {
    StringBuilder sb = new StringBuilder();
    Map 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 uploadsWithForm(@RequestParam String tmpString, @RequestParam MultipartFile[] files) throws IOException {
    StringBuilder sb = new StringBuilder();
    Map 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数据提交
@PostMapping(value = "/uploadsWithJson")
public Map uploadsWithJson(@RequestPart("files") MultipartFile[] files, @RequestPart("jsonMap") Map jsonMap) throws IOException {

    StringBuilder sb = new StringBuilder();
    Map 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中下载;具体代码可以查看file.upload目录

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74556.html

相关文章

  • springboot2.x集成swagger

    摘要:页面如下集成由于个人感觉原生的不太好看,网上提供了。 集成swagger pom包配置 io.springfox springfox-swagger2 2.9.2 io.springfox springfox-swagger-ui ${swagger.version} 添加Swagger配置文件 @Configuration @...

    gekylin 评论0 收藏0
  • SpringBoot2.x【一】从零开始环境搭建

    摘要:一从零开始环境搭建对于之前的框架的使用,各种配置文件一旦出错之后错误难寻,这也是为什么被推上主流的原因,的配置简单,说分钟能从框架的搭建到运行也不为过现在更是微服务当道,所以在此总结下的一些知识,新手教程是一个基于和概念的项目自动化构建开源 SpringBoot2.x【一】从零开始环境搭建 对于之前的Spring框架的使用,各种配置文件XML、properties一旦出错之后错误难寻,...

    whjin 评论0 收藏0
  • ApiBoot 2.0.4.RELEASE版本发布

    摘要:是一款基于的接口服务集成基础框架,内部提供了框架的封装集成,让接口开发者完成开箱即用,不再为搭建接口框架而犯愁,从而极大的提高开发效率。 ApiBoot是一款基于SpringBoot1.x、SpringBoot2.x的接口服务集成基础框架,内部提供了框架的封装集成,让接口开发者完成开箱即用,不再为搭建接口框架而犯愁,从而极大的提高开发效率。通过在我的SpringBoot系列教程中得到的...

    JellyBool 评论0 收藏0
  • Centos下SpringBoot项目启动与停止脚本

    摘要:使用脚本在服务器中启动与停止项目首先项目需要引用的插件启动项目脚本以项目名为为例需先执行停止项目脚本以上版本的插件发布为了规避指令冲突参数统一加上前缀包发布脚本为项目停止脚本以项目名为为例在项目中文件夹然 使用Maven脚本在Centos服务器中启动与停止项目 首先项目需要引用Maven的SpringBoot插件 boot-repac...

    adam1q84 评论0 收藏0
  • SpringBoot 2.X Kotlin与Swagger2生成API文档

    摘要:再通过函数创建的之后,用来创建该的基本信息这些基本信息会展现在文档页面中。函数返回一个实例用来控制哪些接口暴露给来展现,本例采用指定扫描的包路径来定义,会扫描该包下所有定义的,并产生文档内容除了被指定的请求。 showImg(http://download.qfeoo.com/kotlin_springboot_logo.png); 这里有个地方需要注意,在测试WebFlux集成Swa...

    cyqian 评论0 收藏0

发表评论

0条评论

ChristmasBoy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<