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分别请求两次,这样同时做到了代码解耦。

posted @ 2024-08-07 11:00  Wenenenenen  阅读(5)  评论(0编辑  收藏  举报