从 SpringBoot 1.x 升级到 2.x 的时候所踩的坑

hresh 665 0

从 SpringBoot 1.x 升级到 2.x 的时候所踩的坑

由于工作项目中目前还是采用的是 SpringBoot 1.x ,私下学习 2.x 的时候,将项目从 SpringBoot 1.x 升级到 2.x 的时候所踩的坑记录下来。

1、启动类报错

SpringBoot 部署到 Tomcat 中去启动时需要在启动类添加 SpringBootServletInitializer,2.x 和 1.x 有区别。该问题重新导入包即可。

// 1.x
import org.springframework.boot.web.support.SpringBootServletInitializer;
// 2.x
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class UserManageApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(UserManageApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(UserManageApplication.class, args);
    }
}

2、日志类报错

SpringBoot 2.x 默认不包含 log4j,建议使用 slf4j 。

#1.x

import org.apache.log4j.Logger;
protected Logger logger = Logger.getLogger(this.getClass());

改为:

#2.x
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
protected Logger logger =  LoggerFactory.getLogger(this.getClass());

3、Thymeleaf 3.x 默认不包含布局模块

当我将 Pom 包升级到 2.x 之后,访问首页的时候一片空白什么都没有,查看后台也没有任何的报错信息,首先尝试着跟踪了 http 请求,对比了一下也没有发现什么异常,在查询 Thymeleaf 3.x 变化时才发现:SpringBoot 2.x 中spring-boot-starter-thymeleaf 包默认并不包含布局模块,需要使用的时候单独添加,添加布局模块如下:

<dependency>
   <groupId>nz.net.ultraq.thymeleaf</groupId>
   <artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

添加相关依赖后,发现日志中有这么一个警告信息:

2019-11-26 21:37:15.247  WARN 9616 --- [nio-8080-exec-4] n.n.u.t.decorators.DecoratorProcessor    : The layout:decorator/data-layout-decorator processor has been deprecated and will be removed in the next major version of the layout dialect.  Please use layout:decorate/data-layout-decorate instead to future-proof your code.  See https://github.com/ultraq/thymeleaf-layout-dialect/issues/95 for more information.
2019-11-26 21:37:15.441  WARN 9616 --- [nio-8080-exec-4] n.n.u.t.expressions.ExpressionProcessor  : Fragment expression "layout" is being wrapped as a Thymeleaf 3 fragment expression (~{...}) for backwards compatibility purposes.  This wrapping will be dropped in the next major version of the expression processor, so please rewrite as a Thymeleaf 3 fragment expression to future-proof your code.  See https://github.com/thymeleaf/thymeleaf/issues/451 for more information.

修改以前的布局标签 layout:decorator 为 layout:decorate 即可。

#1.x
<html xmlns:th="http://www.thymeleaf.org"  xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout" layout:decorator="layout">

改为:

#2.x
<html xmlns:th="http://www.thymeleaf.org"  xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout" layout:decorate="~{layout}">

还有一点,当 SpringBoot 为 1.x 版本的时候,导入 thymeleaf 模块会自动包含 web 模块。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

从 SpringBoot 1.x 升级到 2.x 的时候所踩的坑

如图所示,spring-boot-starter-thymeleaf会自动包含spring-boot-starter-web,所以我们就不需要单独引入web依赖了。

但是当 SpringBoot 升级为 2.x 的时候,就需要单独导入 web 模块了。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

从 SpringBoot 1.x 升级到 2.x 的时候所踩的坑

最后给出完整的 pom.xml 文件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>chapter6</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>chapter6</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>nz.net.ultraq.thymeleaf</groupId>
            <artifactId>thymeleaf-layout-dialect</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--通用mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.1.5</version>
        </dependency>
        <!--pagehelper 分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>

</project>

相关依赖包的版本信息如下:

maven项目依赖

关于 SpringBoot 2.x 和 thymeleaf 模块版本匹配问题需要小心注意。

4、Spring Boot 2.x 去掉了findOne()方法

以前的findOne()方法其实就是根据传入的 Id 来查找对象,所以在 SpringBoot 2.0 的 Repository 中我们可以添加findById(long id)来替换使用。

例如:

User user=userRepository.findOne(Long id)

改为手动在 userRepository 手动添加 findById(long id)方法,使用时将 findOne()调用改为 findById(long id)。

User user=userRepository.findById(long id)

delete()方法和 findOne()类似也被去掉了,可以使用 deleteById(Long id)来替换,还有一个不同点是 deleteById(Long id)默认实现返回值为 void。

Long deleteById(Long id);

改为

//delete 改为 void 类型
void deleteById(Long id);

当然我们还有一种方案可以解决上述的两种变化,就是自定义 Sql,但是没有上述方案简单不建议使用。

@Query("select t from Tag t where t.tagId = :tagId")
Tag getByTagId(@Param("tagId") long tagId);

5、Spring Boot 2.x 插入数据会报错

错误信息如下:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
....
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '299' for key 'PRIMARY'

报错提示的是主键冲突,跟踪数据库的数据发现并没有主键冲突,最后才发现是 SpringBoot 2.x 需要指定主键的自增策略,这个和 SpringBoot 1.x 有所区别,1.x 会使用默认的策略。

#2.x 需要在所有的主键上面显示的指明自增策略。
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;

发表评论 取消回复
表情 图片 链接 代码

分享