BUG笔记
1. spring boot启动报错@activatedProperties
@
时有时无 -> ERROR
org.springframework.boot.SpringApplication
- Application run failed
org.yaml.snakeyaml.scanner.ScannerException
: while scanning for the next token
found character '@' that cannot start any token. (Do not use @ for indentation)
in 'reader', line 11, column 13:
active: @activatedProperties
@
解决方法 -> pom.xml 加上以下代码
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<!--开启过滤,解决@activatedProperties@报错-->
<filtering>true</filtering>
</resource>
</resources>
</build>
2. spring cloud 2020 引用 LoadBalancerClient
启动报错
A component required a bean of type 'org.springframework.cloud.client.loadbalancer.LoadBalancerClient' that could not be found.
原因:spring cloud 2020版本,移除了以前自动引入的ribbon,换成了
LoadBalancer
,但是需要手动引入包
解决方法 -> pom.xml加上
<!-- LB 扩展 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
引申错误,找不到服务名的URL
java.net.UnknownHostException: cloud-nacos-provider
需要确保
restTemplate
上加有@LoadBalanced
注解,并且有ribbon引用或者LoadBalancer
引用包才行
3. easy-poi 读取时间列读到的值为44197
原因:Excel日期格式自定义读取为44197 就是自1900.1.1以来的天数 手动转换一下 转换失败就按照
EEE MMM dd HH:mm:ss zzz yyyy
格式来读取
解决方法 -> 用Calendar或者改Excel日期格式
Calendar instance = Calendar.getInstance();
for (DimensionTimeTable timeTable : excelList) {
instance.set(1900, Calendar.JANUARY, 1);
String timeName = timeTable.getTimeName();
try {
int days = Integer.parseInt(timeName);
instance.add(Calendar.DAY_OF_MONTH, days);
} catch (NumberFormatException numberFormatException) {
log.warn(numberFormatException.getMessage());
Date parse = DateUtil.parse(timeName);
instance.setTime(parse);
}
timeTable.setTimeName(instance.get(Calendar.YEAR) + "年" + (instance.get(Calendar.MONTH)+1) + "月");
}
4. spring boot项目报错找不到Tomcat临时文件夹
报错:
Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location
[/tmp/tomcat.34315()5664888818074.8081/work/Tomcat/localhost/ROOT] is not valid
原因:在Linux系统中,spring boot应用服务再启动(java -jar 命令启动服务)的时候,会在操作系统的
/tmp
目录下生成一个tomcat*的文件目录,上传的文件先要转换成临时文件保存在这个文件夹下面。由于临时/tmp
目录下的文件,在长时间(10天)没有使用的情况下,就会被系统机制自动删除掉。所以如果系统长时间无人问津的话,就可能导致上面这个问题
解决方法 -> 三种
1、重启服务
2、项目的配置文件中,手动给这个临时文件夹设定目录,这样子就不会被Linux删除了
server:
tomcat:
basedir: /usr/local/tmp/ #修改内置Tomcat临时文件夹 避免在tmp里被定时清理
3.写个配置类,通过@Bean的方式配置目录:
@Configuration
public class MultipartConfig {
/**
* 文件上传临时路径
*/
@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
String location = System.getProperty("user.home") + "/.xiangmu/file/tmp";
File tmpFile = new File(location);
if (!tmpFile.exists()) {
tmpFile.mkdirs();
}
factory.setLocation(location);
return factory.createMultipartConfig();
}
}
4.1 又遇到另一种情况的这个错误,在异步文件上传时出现
报错:
java.io.IOException: java.io.FileNotFoundException: E:\usr\local\tmp\work\Tomcat\localhost\ROOT\upload_46bf3b51_d9c2_450c_b849_8ea6d4948f52_00000002.tmp (系统找不到指定的文件。)
和上面的报错及其相似,导致我用上面的方式反复尝试了半天无果,后来往回倒,发现是
@Async
异步的原因,去掉异步之后无异常,加上异步之后时有时无。思考了一下推断出大概的原因可能是:从前端传来的流写到服务器本地的过程中产生的临时文件(
file.transferTo(serverFile)
),异步的话是重新开了个线程做这件事,原线程直接返回了,相当于是controller提前结束了,临时文件就会被删除掉,再请求就会找不到了。所以就不能使用
transferTo
方法了,得直接复制流到目标文件,这样临时文件即使删除也不会影响到copy
写过程,找了一下已有的工具类包,hutool
没有,commons-io
里有个copyInputStreamToFile
。
pom
文件坐标
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
引入工具类,把从文件copy到文件改为从流copy到文件
import org.apache.commons.io.FileUtils;
......
File serverFile = new File(serverZipPath);
//file.transferTo(serverFile); //因为异步 会报错Tomcat临时文件夹找不到 用以下方式
FileUtils.copyInputStreamToFile(file.getInputStream(), serverFile);
......
-----------------------------------------------------------------------补充-----------------------------------------------------------------------
又大意了,上面的写法还是没有根治问题,只是出现报错的频率变小了,如果请求
QPS
高的话,还是会偶发出现。问题还是出在异步上,所以文件上传还是不要异步了。因为业务上是上传CSV
压缩包,然后解析,要异步的原因是解析入库太慢,所以把文件上传和异步解析拆分开来,只把解析入库进行异步处理,在controller
分别请求两次,这样同时做到了代码解耦。