1. 程式人生 > >spring boot1.0升級為2.0的問題

spring boot1.0升級為2.0的問題

Spring Boot 1.0 升級到 2.0 的時候也遇到了一些問題,在修改的過程中記錄下來,今天整理一下分享出來,方便後續升級的朋友少踩一些坑。

1、第一個問題:啟動類報錯

Spring Boot 部署到 Tomcat 中去啟動時需要在啟動類新增SpringBootServletInitializer,2.0 和 1.0 有區別。

// 1.0
import org.springframework.boot.web.support.SpringBootServletInitializer;
// 2.0
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); } publicstaticvoidmain(String[] args) throws Exception { SpringApplication.run
(UserManageApplication.class, args); } }

這個問題好解決只需要重新導包就行。

2、日誌類報錯:Spring Boot 2.0 預設不包含 log4j,建議使用 slf4j 。

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

改為:

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

這個也比較好改動,就是需要替換的檔案比較多。

3、Spring Boot 2.0 去掉了findOne()方法。

以前的findOne()方法其實就是根據傳入的 Id 來查詢物件,所以在 Spring Boot 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);

4、雲收藏升級到 2.0 之後,插入資料會報錯,錯誤資訊如下:

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'

這個問題稍稍花費了一點時間,報錯提示的是主鍵衝突,跟蹤資料庫的資料發現並沒有主鍵衝突,最後才發現是 Spring Boot 2.0 需要指定主鍵的自增策略,這個和 Spring Boot 1.0 有所區別,1.0 會使用預設的策略。

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;

改動也比較簡單,需要在所有的主鍵上面顯示的指明自增策略。

5、Thymeleaf 3.0 預設不包含佈局模組。

這個問題比較尷尬,當我將 Pom 包升級到 2.0 之後,訪問首頁的時候一片空白什麼都沒有,檢視後臺也沒有任何的報錯資訊,首先嚐試著跟蹤了 http 請求,對比了一下也沒有發現什麼異常,在查詢 Thymeleaf 3.0 變化時才發現:Spring Boot 2.0 中spring-boot-starter-thymeleaf 包預設並不包含佈局模組,需要使用的時候單獨新增,添加布局模組如下:

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

改完之後再訪問首頁,一切正常,但是回頭檢視日誌資訊發現有一個告警資訊:

2018-05-10 10:47:00.029  WARN 1536 --- [nio-8080-exec-2] 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.
2018-05-10 10:47:00.154  WARN 1536 --- [nio-8080-exec-2] 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:decoratorlayout:decorate即可。

6、分頁元件PageRequest變化。

在 Spring Boot 2.0 中 ,方法new PageRequest(page, size, sort) 已經過期不再推薦使用,推薦使用以下方式來構建分頁資訊:

Pageable pageable =PageRequest.of(page, size, Sort.by(Sort.Direction.ASC,"id"));

跟蹤了一下原始碼發現PageRequest.of()方法,內部還是使用的new PageRequest(page, size, sort),只是最新的寫法更簡潔一些。

public static PageRequest of(int page, int size, Sort sort) {
    return new PageRequest(page, size, sort);
}

7、關聯查詢時候組合返回物件的預設值有變化。

在使用 Spring Boot 1.0 時,使用 Jpa 關聯查詢時我們會構建一個介面物件來接收結果集,類似如下:

public interface CollectView{
   Long getId();
   Long getUserId();
   String getProfilePicture();
   String getTitle();
}

在使用 Spring Boot 1.0 時,如果沒有查詢到對應的欄位會返回空,在 Spring Boot 2.0 中會直接報空指標異常,對結果集的檢查會更加嚴格一些。