SpringBoot从2.2.5升级到2.7.2问题总结

阐明

2.7.2为2.x的最终一个安稳版别。

3开端最低要求 Java 17,所以暂时不到3.x。

以下的处理办法主要针对咱们的项目,或许并不通用。

问题

1、hibernate-validator包下的类报错

Springboot从2.3以后,spring-boot-starter-web中不再引进hibernate-validator,需求手动引进。

在父pom中引进,现已参加software-center-modules模块中,子模块不需求加:

<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>6.0.18.Final</version>
  <scope>compile</scope>
</dependency>

2、ErrorController无getErrorPath办法

去掉该办法

3、logback和log4j抵触

org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j-to-slf4j
    at org.apache.logging.slf4j.Log4jLoggerFactory.validateContext(Log4jLoggerFactory.java:60)
    at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:44)
    at org.apache.logging.slf4j.Log4jLoggerFactory.newLogger(Log4jLoggerFactory.java:33)
    at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:53)
    at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:363)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:388)
    at com.ld.CreditTaskManageApplication.<clinit>(CreditTaskManageApplication.java:40)
    ... 34 more

扫除掉springboot的logging

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-batch</artifactId>
  <exclusions>
    <!-- spring boot 默许的日志框架是Logback,所以在引证log4j之前,需求先扫除该包的依靠,再引进log4j2的依靠 -->
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>

4、循环依靠:The dependencies of some of the beans in the application context form a cycle

[credit-task-manage]2022-08-04 13:54:43.411 [WARN]:Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMainConfig': Unsatisfied dependency expressed through field 'handlerAdapter'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'webMainConfig': Requested bean is currently in creation: Is there an unresolvable circular reference?  org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:591) 
​
​
The dependencies of some of the beans in the application context form a cycle:
​
┌─────┐
|  webMainConfig (field private org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter com.ld.common.config.WebMainConfig.handlerAdapter)
↑   ↓
|  org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration
└─────┘
​
​
Action:
​
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
  org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter.report(LoggingFailureAnalysisReporter.java:40) 

WebMainConfig类中 去掉报错的办法和特点handlerAdapter,修正写法

@Bean
public ConversionService getConversionService(DateConverter dateConverter) {
    ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
  Set<Converter<String, Date>> converters = new HashSet<>();
  converters.add(dateConverter);
  factoryBean.setConverters(converters);
  return factoryBean.getObject();
}

日期转化器,依靠hutool的日期东西类处理,如不满足再自行扩展

import java.util.Date;
​
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
​
import cn.hutool.core.date.DateUtil;
​
/**
 * @Description 表单方式的全局时刻类型转化器
 */
@Configuration
public class DateConverter implements Converter<String, Date> {
​
  // 能够依据前端传递的时刻格式自动匹配格式化
  @Override
  public Date convert(String source) {
    return DateUtil.parse(source);
​
   }
​
}

代码中应该尽量防止循环依靠的情况,假如呈现了,加@Lazy注解,懒加载。

代码中不鼓舞依靠循环引证,默许情况下禁止运用循环引证。假如能消除bean之间的依靠循环最好消除,假如真实改动太大,还有一种不引荐的处理办法,设置 spring.main.allow-circular-references=true

5、swagger过错:Failed to start bean ‘documentationPluginsBootstrapper’

Application run failed  org.springframework.boot.SpringApplication.reportFailure(SpringApplication.java:824)
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.22.jar:5.3.22]

启动报了“Failed to start bean ‘documentationPluginsBootstrapper’”,再往下面看到“springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider”就能够断定是跟Swagger相关的问题。

查资料发现是新版别Spring Boot将Spring MVC默许途径匹配战略由AntPathMatcher更改为PathPatternParser,因此咱们能够经过装备让其仍运用AntPathMatcher即可。

解决方案: 在application.properties里装备:

# 途径匹配战略运用旧版别的
spring.mvc.pathmatch.matching-strategy= ANT_PATH_MATCHER

顺便晋级swagger到swagger3,现已加到base公共包里了

5.1、修正后途径需求修正,默许首页由swagger-ui.html变成了

/swagger-ui/index.html

5.2、假如还想运用扩展的2个ui的版别也需求跟着晋级

<swagger-ui-layer.version>1.1.3</swagger-ui-layer.version>
<swagger-bootstrap-ui.version>1.9.6</swagger-bootstrap-ui.version>

我这儿直接删除了那2个ui运用了swagger-bootstrap-ui的晋级版:knife4j。base模块中现已引进

<knife4j.version>3.0.3</knife4j.version>
……
<dependency>
  <groupId>com.github.xiaoymin</groupId>
  <artifactId>knife4j-spring-boot-starter</artifactId>
  <version>${knife4j.version}</version>
</dependency>

5.3、swagger的装备类,注解@EnableSwagger2去掉,名字改为更通用的SwaggerConfig

@Configuration
//@EnableSwagger2
@Slf4j
public class SwaggerConfig {
​
}

5.4、删除项目中自定义的pringfox.documentation.spring.web.readers包

5.5、去掉自定义的页面,假如想修正找到新的jar包复制出页面进行调整,不然或许看到的页面里没有内容

src/main/resources/META-INF/resources/doc.html

5.6 调整过滤器途径装备

#============================ 安全访问装备(SecurityFilter)========================
# 需求过滤的urlPatterns,多个用^分隔,没有或为空则不约束
security.access.urlPatterns = /doc.html^/docs.html^/swagger-ui.html^/swagger-ui/index.html^/v2/api-docs^/swagger-resources

6、跳转登录页犯错

假如呈现跳转时犯错:

Cannot forward to error page for request [/a/] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false  org.springframework.boot.web.servlet.support.ErrorPageFilter.handleCommittedResponse(ErrorPageFilter.java:219)

解决方案同5

7、日期转化犯错

晋级后发现java中是Date类型,数据库中datetime类型(Timestamp类型没有问题)的数据不是转化为Timestamp,而是直接转为LocalDateTime类型了,解决办法:com.ld.shieldsb.dao.MyBeanProcessor修正type2Bean办法,增加LocalDateTime和LocalDate的处理

if (value != null && fieldType.equals(Date.class)) {
  if (value.getClass().equals(String.class)) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {
      field.set(model, sdf.parse((String) value));
     } catch (ParseException e) {
      log.error("日期字段读取失利," + fieldType + ",error:" + e.getMessage());
     }
   } else if (value.getClass().equals(LocalDateTime.class)) {
    field.set(model, DateTimeUtil.localDateTime2Date((LocalDateTime) value));
   } else if (value.getClass().equals(LocalDate.class)) {
    field.set(model, DateTimeUtil.localDate2Date((LocalDate) value));
   } else {
    field.set(model, value);
   }
} 

咱们运用的是mysql检查依靠jar包看到mysql-connector-java的版别从8.0.19变成了8.0.29

原因找到com.mysql.cj.jdbc.result.ResultSetImpl类的getObject(int columnIndex)办法能够看到Datetime类型的确实换了类型

case DATETIME:
    return getTimestamp(columnIndex);
// 改为了
case DATETIME:
    return getLocalDateTime(columnIndex);

8、flyway:org.flywaydb.core.api.FlywayException: Unsupported Database: MySQL 5.7

Application run failed  org.springframework.boot.SpringApplication.reportFailure(SpringApplication.java:824)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Unsupported Database: MySQL 5.7
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.22.jar:5.3.22]
        ……
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:343) [bootstrap.jar:9.0.31]
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:474) [bootstrap.jar:9.0.31]
Caused by: org.flywaydb.core.api.FlywayException: Unsupported Database: MySQL 5.7
    at org.flywaydb.core.internal.database.DatabaseTypeRegister.getDatabaseTypeForConnection(DatabaseTypeRegister.java:106) ~[flyway-core-8.5.13.jar:?]
        ……org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.22.jar:5.3.22]
    ... 49 more

flyway对数据库版别有要求,例如flyway-core的当前版别V8.4.3,不能运用 MySQL 5.7, 当flyway-core 降低到V7.15.0后 问题解决,所以匹配flyway-core和数据库版别后问题即可解决。

<properties>
……
    <flyway.version>7.15.0</flyway.version>
</properties>
……
        <!-- 增加 flyway 的依靠,flyway需求区分版别,不同版别对不同数据库版别支撑不同 -->
       <dependency>
          <groupId>org.flywaydb</groupId>
          <artifactId>flyway-core</artifactId>
          <version>${flyway.version}</version>
       </dependency>
……

9、Junit运行后没有反应

晋级后默许运用junit5,而依靠的jar包中引进了junit4的jar包抵触了,去掉junit4的jar包即可。

留意运用junit5后包的名字发生了改变,下面箭头前后分别是junit4和junit5的

org.junit.Test》org.junit.jupiter.api.Test
org.junit.runner.RunWith》org.junit.jupiter.api.extension.ExtendWith
//运用时
@RunWith(SpringRunner.class)》@ExtendWith(SpringExtension.class)

10、晋级后json中Long类型字段精度丢掉

呈现如下情况,前面是真实值后边为json传递后的值

344280995828072448》344280995828072450
344268472663932928》344268472663932900
343301120241696768》343301120241696800

原项目中是有Long转字符串的处理的。

问题原因:经检查,默许现已有多个消息转化器了。而 configureMessageConverters 办法中是一个 list 参数。直接向其间增加 HttpMessageConverter 后,默许是排在最终的。就造成了你自定义的消息转化器不生效。其实是被其他转化器接管了。

解决办法:加到第一个就行了。add(0, customConverter())

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
    ……
    // 支撑text 转string
    converters.add(0, customJackson2HttpMessageConverter());
    converters.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    converters.add(0, fastConverter);
​
   }

假如运用的是@bean注解,掩盖的fastjson则不需求改,如下:

@Bean
  public HttpMessageConverters customConverters() {
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
    // 创立装备类
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteMapNullValue,
        SerializerFeature.WriteNullStringAsEmpty);
​
    // 解决 Long 转json 精度丢掉的问题
    SerializeConfig serializeConfig = SerializeConfig.globalInstance;
    serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
    serializeConfig.put(Long.class, ToStringSerializer.instance);
    serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
    fastJsonConfig.setSerializeConfig(serializeConfig);
​
    // 此处是全局处理方式
    fastJsonConfig.setDateFormat(DATE_FORMAT);
    fastJsonConfig.setCharset(StandardCharsets.UTF_8);
    fastConverter.setFastJsonConfig(fastJsonConfig);
​
    List<MediaType> supportedMediaTypes = new ArrayList<>();
    supportedMediaTypes.add(MediaType.APPLICATION_JSON);
    fastConverter.setSupportedMediaTypes(supportedMediaTypes);
    // 支撑text 转string
    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
    return new HttpMessageConverters(fastConverter, stringHttpMessageConverter);
   }

\