SpringBoot整合jwt和mybatis-plus的腳手架專案
近期給公司弄了個腳手架專案,打算以後後臺開發就用這個了, 求star~
概述
Volcano是一個基於springboot後臺開發簡易腳手架。能實現當作一個單獨專案或者作為微服務的一個節點進行快速開發和部署。
更新日誌
2019-11-14 新增swagger異常解決方案
專案結構
javasea-volcano 父類,用於springcloud和springboot的版本管控,maven外掛,倉庫統一管控等.
|--javasea-volcano-base: 測試類和相關業務配置, 依賴common
專案中的元件,開發的時候在該專案的基礎上新增新增業務程式碼即可。
|--javasea-volcano-common:常用元件和工具類
專案環境
中介軟體 | 版本 | 備註 |
---|---|---|
JDK | 1.8+ | JDK1.8及以上 |
MySQL | 5.6+ | 5.6及以上 |
Redis | 3.2+ |
基本功能
參考包com.zhirui.lmwy.wms.demo
下的配置
引數校驗
JSR校驗
spring-boot-starter-web
已經預設集成了JSR303校驗,只需要直接使用註解校驗即可。
參考測試類: com.zhirui.lmwy.wms.demo.web.controller.TestCheckParamController
手動校驗
Assert
類定義了不滿足條件後快速斷言的方式,可以在校驗引數中使用。
還可以採用Spring的Assert進行校驗
//第一個引數為false則丟擲IllegalArgumentException異常
Assert.isTrue(concurrentConsumers > 0,"'concurrentConsumers' value must be at least 1 (one)");
Assert.isTrue(!this.exclusive || concurrentConsumers == 1,"When the consumer is exclusive,the concurrency must be 1");
複製程式碼
也可以採用Optional進行校驗
ZOrder order = this .getOrderByOrderNum(orderNum);
Optional.ofNullable(order).filter(o -> {
return null != o && (0 == o.getStatus() || 3 == o.getStatus() || 9 == o.getStatus());
}).orElseThrow(() -> new ParamException("獲取資料異常,訂單號有誤或者訂單狀態異常!"));
複製程式碼
還可以通過guava的Preconditions類來進行引數檢查。有需要請自行百度。
引數轉換
參考測試類:TestDateConverterAndJson
URL方式傳值到後端轉換
URL傳參到後端包括 如下三種方式傳參:
@GetMapping("testDateConverter") public Student testDateConverter(@RequestParam Student student){...} @GetMapping("testDateConverter") public Student testDateConverter(Student student){...} @GetMapping("testDateConverter/{id}") public Student testDateConverter(@PathVariable Integer id){...} 複製程式碼
com.zhirui.lmwy.common.converter
包下定義了很多轉換類:
-
StringToDateConverter
如果實體屬性是Date,通過該轉換器將String轉Date型別。效果和日期屬性上的註解
@DatetimeFormat
相同。但是啟用該轉換器的時候,實體屬性上的註解@DatetimeFormat
不再生效。 -
StringToDoubleConverter
如果實體屬性是Double,通過該轉換器將String轉Double型別。
-
StringToIntegerConverter
如果實體屬性是Integer,通過該轉換器將String轉Integer型別。
請求體方式傳值到後端轉換
請求體方式傳參到後端 包括如下方式:
@PostMapping("testDateConverter2") public Student testDateConverter2(@RequestBody Student student){...} 複製程式碼
com.zhirui.lmwy.common.json.jackson
包下定義了JSON的序列化和反序列化方式:
-
deserializer 包下的序列化類
在@RequestBody接參時候,會呼叫該包中的
序列化類
將JSON轉換成實體接參。 -
serializer 包下的序列化類
用於後端傳值給前端。
後端傳值給前端
com.zhirui.lmwy.common.json.jackson.serializer
包下的定義了序列化類 。
在Controller類上新增註解@ResponseBody或者@RestController,那麼後端傳值給前端是JSON方式。
如果是返回值是物件或者集合,會用序列化類進行引數型別轉換。
如下列子中,Student中的兩個屬性日期會轉換成serializer 定義的格式“yyyy-MM-dd HH:mm:ss”。
序列化類``JacksonDateSerializer
的作用相當於在屬性上添加了@JsonFormat(pattern="yyyy-MM-dd")
,實現將Date型別轉換成String,但是新增JacksonDateSerializer
後@JsonFormat(pattern="yyyy-MM-dd")
失效。
@PostMapping("testDateConverter2")
public Student testDateConverter2(@RequestBody Student student){
System.out.println(student);
Student s = new Student();
s.setBirth(new Date());
s.setCreateTime(LocalDateTime.now());
return s;
}
複製程式碼
異常處理
在com.zhirui.lmwy.common.exception.impl
中定義了三大類異常:
BusinessException: 通用業務異常
ParamException:引數校驗異常
AuthenticationException:認證失敗異常
複製程式碼
Exceptions
類定義了快捷丟擲異常的一些通用方法,在需要丟擲異常時請不要去throw new XXXException()
,而是用Exceptions
類的方法進行操作。
已經定義了全域性異常處理器GlobalExceptionHandler
對各種異常可以進行處理,請不要在controller和service中try..catch
。
返回值處理
controller的返回前端使用ResultModel
類進行封裝,裡面有code
,msg
,data
等欄位。
各種場景下的ResultModel返回:
//插入後返回方式, msg:插入成功;插入失敗
public ResultModel resultInsert(){
boolean flag = false;
return ResultModel.resultInsert(flag);
}
//更新後返回方式, msg:更新成功;更新失敗
public ResultModel resultUpdate(){
boolean flag = false;
return ResultModel.resultUpdate(flag);
}
//刪除後返回方式, msg:刪除成功;刪除失敗
public ResultModel resultDelete(){
boolean flag = false;
return ResultModel.resultDelete(flag);
}
//刪除後返回方式, msg:操作成功;操作失敗
public ResultModel result(){
boolean flag = false;
return ResultModel.result(flag);
}
//認證失敗返回方式, msg:認證資訊異常
public ResultModel errorTokenMsg(){
boolean flag = false;
//如果msg引數為null,那麼是預設的msg:認證資訊異常
return ResultModel.errorTokenMsg(null);
}
複製程式碼
推薦優先上面的放回方式,如果不能滿足,還可以使用如下通用的
失敗
、成功
的返回方式:
ResultModel.error(); //失敗返回方式 ResultModel.ok(); //成功返回方式 複製程式碼
AOP 日誌輸出
- 新增座標
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- console彩色日誌 -->
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>1.18</version>
</dependency>
複製程式碼
- 定義AOP類實現彩色日誌輸出
參考:com.zhirui.lmwy.common.aop.LogAop
整合 絲襪哥
在common專案中集成了swagger
- pom中新增註解
<!-- swagger start -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- swagger end -->
複製程式碼
-
新增配置
兩個配置類:
com.zhirui.lmwy.common.swagger.SwaggerConfiguration
com.zhirui.lmwy.common.swagger.SwaggerProperties
-
設定自定義顯示引數
在base專案的
application.yaml
中新增如下配置進行設定:
swagger:
# open: true #是否開啟swagger,在生產環境下需要關閉
protocol: http #協議,http或https
base-package: com.zhirui.lmwy.wms #一定要寫對,會在這個路徑下掃描controller定義
title: volcano-base專案
version: 1.0
description: volcano-base專案絲襪哥測試
複製程式碼
-
在controller和model中使用swagger
controller類中使用參考:
com.zhirui.lmwy.wms.demo.web.controller.TestCurdController
model類中使用參考:
com.zhirui.lmwy.wms.demo.web.entity.User
-
通過swagger進行http請求
-
http://localhost:8080/swagger-ui.html#/
絲襪哥預設的訪問方式
-
通過controller 重定向後的訪問方式
swagger在2.9.2可能會報錯如下:
Illegal DefaultValue null for parameter type integer 複製程式碼
根據上面這句報錯資訊,點進去AbstractSerializableParameter.java:412可以看到
if(BaseIntegerProperty.TYPE.equals(type)){ return Long.valueOf(example); } 複製程式碼
就是說如果實體屬性型別是Integer,就把example轉為Long型別,而example預設為"",導致轉換錯誤。
解決辦法
方法一: 實體類中,Integer型別的屬性加@ApiModelProperty時,必須要給example引數賦值,且值必須為數字型別。
@ApiModelProperty(value = "試卷ID",example = "1") private int pageId; 複製程式碼
方法二:
將版本改成2.8.0
<!-- swagger start --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.8.0</version> </dependency> 複製程式碼
-
整合 mybatis-plus(下文中稱為MP)
ORM框架使用mybatis-plus,簡便了CURD操作
-
新增pom
<!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <!-- 程式碼生成器 start --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.2.0</version> </dependency> <!-- 程式碼生成器需要的引擎模板 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.0</version> </dependency> <!-- 程式碼生成器 end --> 複製程式碼
-
在yml中進行配置
mybatis-plus: mapper-locations: classpath:mapper/**/*.xml global-config: db-config: id-type: AUTO #主鍵自增長 複製程式碼
-
新增配置類配置
下列程式碼中使用了租戶模式,如果只是單純需要新增分頁外掛,只需要如下方式即可:
@Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); return paginationInterceptor; } 複製程式碼
/** 分頁外掛: 實現物理分頁 */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); ArrayList<ISqlParser> iSqlParsers = new ArrayList<>(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId(boolean where) { return new StringValue(tenantId); } @Override public String getTenantIdColumn() { //指定表中的租戶列 return "tenant_id"; } @Override public boolean doTableFilter(String tableName) { return false; } }); iSqlParsers.add(tenantSqlParser); paginationInterceptor.setSqlParserList(iSqlParsers); return paginationInterceptor; } 複製程式碼
通過MP進行CRUD操作
參考測試類和官網:com.zhirui.lmwy.wms.demo.web.controller.TestCurdController
程式碼生成器
採用了MP的程式碼生成器,實現了兩個程式碼生成器。
在
javasea-volcano-base
專案的src/test/java
目錄的 com.zhirui.lmwy.wms包下,按照註釋修改為自己需要的配置執行即可。看個人習慣,推薦用PrimaryCodeGenerator
。
-
SencondCodeGenerator
通過資料庫表生成基本的entity,mapper,controller和service類等基本類。
-
PrimaryCodeGenerator
在
SencondCodeGenerator
功能的基礎上,controller,entity中生成swagger的註解。controller、service生成常用的crud方法。
整合redis
- 新增pom座標
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
複製程式碼
- yml中進行配置
spring:
redis:
host: 127.0.0.1
port: 6379
password: zhirui888
timeout: 2000
database: 6
lettuce:
pool:
max-active: 8
max-wait: 1
max-idle: 8
min-idle: 0
複製程式碼
-
配置類中進行配置
-
定義redis的RedisTemplate
詳見:com.zhirui.lmwy.common.redis.RedisTemplateConfig
-
開啟springcache
詳見:com.zhirui.lmwy.common.redis.RedisCacheConfig
-
redis工具類
詳見:com.zhirui.lmwy.common.redis.RedisUtils
-
整合 JWT
新增jwt座標
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
<scope>compile</scope>
</dependency>
複製程式碼
yml中配置jwt
custom:
jwt:
header: token
secret: 666666 #密碼,用於生成簽名
issuer: volcano #簽發人
subject: volcano-jwt #主題
audience: web #簽發的目標
expire-minutes: 20 #過期時間
interceptor:
jwt:
exclude:
path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/login,/verificationCode,/doc/**,/error/**,/docs,/test/**
permission:
exclude:
path: /swagger-resources/**,/adminLogin,/sysLogin,/login.html,/docs
token-timeout:
exclude:
path: /swagger-resources/**,/docs
複製程式碼
新增登陸介面
登陸後會將token資訊儲存到redis
詳見登陸controller:com.zhirui.lmwy.wms.security.controller.LoginController
新增jwt攔截器
攔截到請求後會進行校驗,校驗方式如下:
// 驗證token是否有效
Jws<Claims> jws = JwtUtil.verify(token);
複製程式碼
token未過期且合法的才能校驗通過,否則丟擲401異常。
詳見jwt攔截器:com.zhirui.lmwy.wms.security.interceptor.JwtInterceptor
在swagger進行token測試
- 執行登陸操作,token見返回值中
返回值為:
{
"code": 200,"msg": "操作成功","data": {
"loginSysUser": {
"id": "1","userName": "admin"
},"token": "eyJjdHkiOiJjdHkiLCJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ2b2xjYW5vLWp3dCIsImF1ZCI6IndlYiIsImlzcyI6InZvbGNhbm8iLCJleHAiOjE1Njg3MTI0MDcsImlhdCI6MTU2ODcxMDYwNywianRpIjoiNDM4NjMwMDAwOTlmNDFkNDk1Y2FlOWVkNWUzNDZhOTgifQ.wVZOx-J2knqUxdnRjRXZqr2nf1S-Qwmap2-0nGXJDXM"
},"time": "2019-09-17 16:56:51"
}
複製程式碼
- 點選
Authorize
按鈕
-
將token設定到value中,後面絲襪哥所有的請求都會帶一個叫做“Authorization”的請求頭。
在jwt攔截器
JwtInterceptor
中會獲取該請求頭進行校驗。
專案啟動和部署
單獨作為專案使用
javasea-volcano
預設是一個獨立的springboot專案,可以直接啟動javasea-volcano-base
專案,在base
專案的基礎上,直接編寫業務程式碼即可。
整合到現有的springcloud中
-
啟用bootstrap.yml的配置(放開註釋)
#spring: # cloud: # config: # uri: ${WMS_CONFIG_SERVER_URL} # name: zhirui-lmwy2-wms${WMS_DEVELOPER_NAME:} # profile: ${config.profile:dev} # 複製程式碼
-
base專案的pom中開啟對應eureka client的座標,啟動類
WmsApplication
通過註解@EnableDiscoveryClient
啟用eureka client。<!-- springboot 1.X --> <!--<dependency>--> <!--<groupId>org.springframework.cloud</groupId>--> <!--<artifactId>spring-cloud-starter-eureka</artifactId>--> <!--</dependency>--> <!-- springboot 2.X --> <!--<dependency>--> <!--<groupId>org.springframework.cloud</groupId>--> <!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>--> <!--</dependency>--> 複製程式碼
-
IDE中配置vm引數,使用已經已經存在的
eureka註冊中心
和配置中心
在IDE中配置VM引數只能是作為測試,如果需要部署後生效,那麼需要配置到伺服器的環境變數或者在啟動的java -jar後新增配置。之後我會新增關於服務部署的文章。
-Dmultipart-location=D:/wms/temp -DDiskLocation=D:/wms/ -DWMS_CONFIG_SERVER_URL=http://192.168.1.230:8861 -DWMS_EUREKA_SERVER_URL=http://192.168.1.230:8090/eureka/ -DWMS_DEVELOPER_NAME=-longxiaonan -Dconfig.profile=dev 複製程式碼
Maven方式打包
mvn clean package -Dmaven.test.skip=true
複製程式碼