第一个问题
当excel中的数据量比较大时,java后台解析的过程可能要持续很久,但是又不需要用户去进行等待,这时就考虑文件的异步导入
文件异步方法的实现有着几种实现方式,这里是通过指定异步线程池实现的,即@Async(“线程池名称”)标注异步方法。
然而,在经过测试时发现,该标注的注解也都标注了,但是就是不能实现异步效果。
几经波折,发现异步方法可以调用非异步方法,是可以实现异步效果;而先是非异步方法去调用异步方法,这样就会失效。这里所说的是在同一个java类里面。
而在不同的java类里面,就不存在上面的问题
第二个问题
使用了异步方法,通过controller接收文件,service层进行处理,这时controller已经将执行成功的结果返回,剩下的就是service层中去进行解析入库,结果,万万没想到,在service中报了一个错
java.nio.file.NoSuchFileException: D:UserDataTempundertow.1407321862395783323.8400undertow4517937229384702645upload
Controller中的方法
@PostMapping("/test")
public R test(MultipartFile file) {
testService.test(file);
return R.success("导入成功");
}
Service中的方法
@Async("asyncimportExecutor")
public void test(MultipartFile file) {
try {
EasyExcelUtil.read(file.getInputStream(), Test.class, this::executeimport)
.sheet().doRead();
} catch (Exception ex) {
log.error("[test]异步导入异常:", ex);
}
}
看到这个异常NoSuchFileException后就一脸懵逼,测试是通过postman进行的,就开始怀疑postman的问题,已经排查后postman、路径啥的都没有问题,异步调用的流程也是ok的
然后就想这个异常的提示,就是找不到文件,根据打印出来的日志去本地也确实没有找到。后来就有了下面的写法
Controller中的方法
@PostMapping("/test")
public R test(MultipartFile file) {
try {
testService.test(file.getInputStream());
} catch (IOException e) {
log.error("[test]异常日志:", e);
return R.fail("导入失败");
}
return R.success("导入成功");
}
Service中的方法
@Async("asyncimportExecutor")
public void test(InputStream file) {
try {
EasyExcelUtil.read(file, Test.class, this::executeimport)
.sheet().doRead();
} catch (Exception ex) {
log.error("[test]异步导入异常:", ex);
}
}
这样就不报错了。。。
后来就进行debug调试,发现临时文件是controller层中的MultipartFile对象生成,一直在写同步方法,也没注意这个MultipartFile对象会生成临时文件。后来发现这个controller中返回结果后,临时文件也就没有了。
错误总结:
因为使用的是异步方法,这样就会有一个主线程和一个异步线程。在上传文件后会形成MultipartFile类型的实例,同时生成临时文件,此时是在主线程中。MultipartFile的实例交给异步线程处理后,该临时文件会被springboot(spring)销毁,在异步线程中去getInputStream就会出现上面的异常。
而在下面的写法是将InputStream流作为了入参,就不会产生找不到文件的情况。



