一、第一个问题
当excel导入的数据量比较大或者后台操作数据的逻辑耗时比较长,这个时候我们会考虑异步导入
文件异步方法的实现有着几种实现方式,这里通过指定异步线程池
实现的,即@Async("线程池名称")
标注异步方法。
然而,在经过测试时发现,该标注的注解也都标注了,但是不能实现异步效果。
几经波折,发现异步方法可以调用非异步方法,是可以实现异步效果;
而先是非异步方法调用异步方法,这样就会失效。这里所说的是在同一个java类里面。
而在不同的java类里面,就不存在上面的问题
二、第二个问题
使用了异步方法,通过Controller接收文件参数,service层进行处理,这时Controller已经将执行成功的结果返回,剩下的就是service层中去进行解析入库。结果,万万没想到,在service中报了一个错,就找不到文件
java.nio.file.NoSuchFileException: D:\UserData\Temp\undertow.1407321862395783323.8400\undertow4517937229384702645upload
2.1 Controller中的方法
"/test") (publicR<String>test(MultipartFilefile) { testService.test(file); returnR.success("导入成功"); }
2.2 service中的方法
"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中的方法
"/test") (publicR<String>test(MultipartFilefile) { try { testService.test(file.getInputStream()); } catch (IOExceptione) { log.error("[test]异常日志:", e); returnR.fail("导入失败"); } returnR.success("导入成功"); }
2.4 改进Service中的方法
"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); }
但是这种是针对这种情况的解决
"/test") (publicvoidtest(Queryquery, MultipartFilefile) { ........... return; }
像这种情况的,依然无法解决,只能是 兵来将挡水来土掩 了
"/test") (publicvoidtest(Queryquery) { ........... return; } publicclassQuery { privateMultipartFilefile; privateIntegerpage; privateIntegersize; // 省略Get、Set..........}
这个时候就只能将参数对象中的参数Field进行逐一 instanceof MultipartFile,万一出现套娃的情况,就~ ~ ~
3.3 最后
要么将这种情况的不再进行入参的打印
要么就进行特殊的判断