关于SpringBoot在MultipartFile上踩过的坑

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 记录坑坑历程

一、第一个问题

当excel导入的数据量比较大或者后台操作数据的逻辑耗时比较长,这个时候我们会考虑异步导入

文件异步方法的实现有着几种实现方式,这里通过指定异步线程池实现的,即@Async("线程池名称")标注异步方法。

然而,在经过测试时发现,该标注的注解也都标注了,但是不能实现异步效果。

几经波折,发现异步方法可以调用非异步方法,是可以实现异步效果;

而先是非异步方法调用异步方法,这样就会失效。这里所说的是在同一个java类里面。

而在不同的java类里面,就不存在上面的问题

二、第二个问题

使用了异步方法,通过Controller接收文件参数,service层进行处理,这时Controller已经将执行成功的结果返回,剩下的就是service层中去进行解析入库。结果,万万没想到,在service中报了一个错,就找不到文件

java.nio.file.NoSuchFileException: D:\UserData\Temp\undertow.1407321862395783323.8400\undertow4517937229384702645upload

2.1 Controller中的方法

@PostMapping("/test")
publicR<String>test(MultipartFilefile) {
testService.test(file);
returnR.success("导入成功");
}

2.2 service中的方法

@Async("asyncImportExecutor")
publicvoidtest(MultipartFilefile) {
try {
EasyExcelUtil.read(file.getInputStream(), Test.class, this::executeImport)
                    .sheet().doRead();
    } catch (Exceptionex) {
log.error("[test]异步导入异常:", ex);
    }
}

看到这个异常NoSuchFileException后就一脸懵逼,测试是通过postman进行的,就开始怀疑postman的问题,已经排查后postman、路径啥的都没有问题,异步调用的流程也是ok的


然后就想这个异常的提示,就是找不到文件,根据打印出来的日志去本地也确实没有找到。后来就有了下面的写法

2.3 改进Controller中的方法

@PostMapping("/test")
publicR<String>test(MultipartFilefile) {
try {
testService.test(file.getInputStream());
    } catch (IOExceptione) {
log.error("[test]异常日志:", e);
returnR.fail("导入失败");
    }
returnR.success("导入成功");
}

2.4 改进Service中的方法

@Async("asyncImportExecutor")
publicvoidtest(InputStreamfile) {
try {
EasyExcelUtil.read(file, Test.class, this::executeImport)
                    .sheet().doRead();
    } catch (Exceptionex) {
log.error("[test]异步导入异常:", ex);
    }
}

这样就不报错了。。。

后来就进行debug调试,发现临时文件是controller层中的MultipartFile对象生成,一直在写同步方法,也没注意这个MultipartFile对象会生成临时文件。后来发现这个controller中返回结果后,临时文件也就没有了。

2.5 错误总结

因为使用的是异步方法,这样就会有一个主线程和一个异步线程。在上传文件后会形成MultipartFile类型的实例,同时生成临时文件,此时是在主线程中。MultipartFile的实例交给异步线程处理后,该临时文件会被springboot(spring)销毁,在异步线程中去getInputStream就会出现上面的异常。

而在下面的写法是将文件流作为了入参,就不会产生找不到文件的情况。

三、第三个问题

切面日志打印

3.1 问题描述

最近做的需求,有上传文件参数的情况,即 MultipartFile 的情况

而且大家的系统框架中也有通过类似 @SysLog 注解切面打印入参日志的需要

这时存在 MultipartFile 类型的参数的时候,估计就会遇见这种类似的情况

java.io.FileNotFoundException:

MultipartFile resource [file] cannot be resolved to URL

MultipartFile resource [file] cannot be resolved to absolute file

MultipartFile resource [file] cannot be resolved to absolute file path

可能这个 MultipartFile 这是一个特殊对象的存在吧 ~ ~ ~


通过 Jackson 对 javaBean 序列化 MultipartFile 字段成json字符串的时候,有这个问题

通过 JSONObject 对 javaBean 序列化 MultipartFile 字段成 json 字符串的时候,也会有类似的问题

3.2 借鉴,特殊判断

// 请求参数处理finalMap<String, Object>paraMap=newHashMap<>(16);
if (valueinstanceofMultipartFile) {
MultipartFilemultipartFile= (MultipartFile) value;
Stringname=multipartFile.getName();
StringfileName=multipartFile.getOriginalFilename();
paraMap.put(name, fileName);
}

但是这种是针对这种情况的解决

@GetMapping("/test")
@ResponseBodypublicvoidtest(Queryquery, MultipartFilefile) {
    ...........
return;
}

像这种情况的,依然无法解决,只能是 兵来将挡水来土掩

@GetMapping("/test")
@ResponseBodypublicvoidtest(Queryquery) {
    ...........
return;
}
publicclassQuery {
privateMultipartFilefile;
privateIntegerpage;
privateIntegersize;
// 省略Get、Set..........}

这个时候就只能将参数对象中的参数Field进行逐一 instanceof MultipartFile,万一出现套娃的情况,就~ ~ ~

3.3 最后

要么将这种情况的不再进行入参的打印

要么就进行特殊的判断

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
存储 前端开发 Java
MultipartFile实现文件上传和下载(Springboot)
MultipartFile实现文件上传和下载(Springboot)
594 0
Springboot byte[] 转 MultipartFile ,InputStream 转 MultipartFile
Springboot byte[] 转 MultipartFile ,InputStream 转 MultipartFile
1125 0
Springboot Http文件的访问 Url 转换 MultipartFile ,File 转 MultipartFile
Springboot Http文件的访问 Url 转换 MultipartFile ,File 转 MultipartFile
988 0
java springboot实现上传MultipartFile类型 进行HttpRequest调用传入第三方上传接口
java springboot实现上传MultipartFile类型 进行HttpRequest调用传入第三方上传接口
|
存储 前端开发 Java
springboot 多线程使用MultipartFile读取excel文件内容报错问题
springboot 多线程使用MultipartFile读取excel文件内容报错问题
springboot 多线程使用MultipartFile读取excel文件内容报错问题
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
144 1
|
18天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
95 62
|
16天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
34 2
|
19天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。