我開源了團(tuán)隊(duì)內(nèi)部基于SpringBoot Web快速開發(fā)的API腳手架stater

我們現(xiàn)在使用「SpringBoot」 做Web 開發(fā)已經(jīng)比之前SprngMvc 那一套強(qiáng)大很多了。 但是 用SpringBoot Web 做API 開發(fā)還是不夠簡潔有一些。
每次Web API常用功能都需要重新寫一遍。或者復(fù)制之前項(xiàng)目代碼。于是我封裝了這么一個(gè)

抽出「SpringBoot Web API」 每個(gè)項(xiàng)目必備需要重復(fù)寫的模塊,和必備功能。 并且擴(kuò)展了我工作中用到的 所有工具庫。
基于它,你可以輕松開發(fā)SpringBoot WEB API,提高效率。不在去關(guān)心一些繁瑣。重復(fù)工作,而是把重點(diǎn)聚焦到業(yè)務(wù)。
目前更新版本到1.5.2 功能如下
支持一鍵配置自定義RestFull API 統(tǒng)一格式返回
支持RestFull API 錯(cuò)誤國際化
支持全局異常處理,全局參數(shù)驗(yàn)證處理
業(yè)務(wù)錯(cuò)誤斷言工具封裝,遵循錯(cuò)誤優(yōu)先返回原則
封裝Redis key,value 操作工具類。統(tǒng)一key管理 spring cache緩存實(shí)現(xiàn)
RestTemplate 封裝 POST,GET 請求工具
日志集成。自定義日志路徑,按照日志等級分類,支持壓縮和文件大小分割。按時(shí)間顯示
工具庫集成 集成了lombok,hutool,commons-lang3,guava。不需要自己單個(gè)引入
集成mybatisPlus一鍵代碼生成
日志記錄,服務(wù)監(jiān)控,支持日志鏈路查詢。自定義數(shù)據(jù)源
OpenApi3文檔一鍵配置。支持多種文檔和自動配置
接口限流,Ip城市回顯
HttpUserAgent請求設(shè)備工具封裝
RequestUtil參數(shù)解析封裝工具
后續(xù)會持續(xù)更新。項(xiàng)目中重復(fù)使用,必備模塊和工具。
GitHub 地址
gitee 地址
「rest-api-spring-boot-starter」 適用于SpringBoot Web API 快速構(gòu)建讓開發(fā)人員快速構(gòu)建統(tǒng)一規(guī)范的業(yè)務(wù)RestFull API 不在去關(guān)心一些繁瑣。重復(fù)工作,而是把重點(diǎn)聚焦到業(yè)務(wù)。
快速開始
項(xiàng)目pom中引入依賴
<dependency>
????<groupId>cn.soboys</groupId>
????<artifactId>rest-api-spring-boot-starter</artifactId>
????<version>1.5.0</version>
</dependency>
在SpringBoot啟動類或者配置類上通過 「@EnableRestFullApi」注解開啟rest-api
public?class?SuperaideApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(SuperaideApplication.class,?args);
????}
}
到此你項(xiàng)目中就可以使用所有的功能了。
RestFull API
在Controller
中我們寫普通的請求接口如:
"/chat")
(
public?HashMap?chatDialogue()?{
????HashMap?m?=?new?HashMap();
????m.put("age",?26);
????m.put("name",?"Judy");
????return?m;
}
返回的就是全局統(tǒng)一RestFull API
{
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"IPbHLE5SZ1fqI0lgNXlB",
????"timestamp":?"2023-07-09?02:39:40",
????"data":?{
????????"name":?"judy",
????????"hobby":?"swing",
????????"age":?18
????}
}
也可以基于Result
構(gòu)建
"/chat")
(
public?Result?chatDialogue(@Validated?EntityParam?s)?{
????return?Result.buildSuccess(s);
}
分頁支持
我們在日常中分頁是一個(gè)比較特殊返回。也是非常常用的。
"/page")
(
("分頁查詢用戶數(shù)據(jù)")
public?Result?page(@Validated?EntityParam?s)?{
????ResultPage<List<EntityParam>>?resultPage=new?ResultPage<>();
????List?a=new?ArrayList();
????a.add(s);
????resultPage.setPageData(a);
????return?ResultPage.buildSuccess(resultPage);
}
構(gòu)建自定義自己的分頁數(shù)據(jù)
ResultPage<List<EntityParam>>?resultPage=new?ResultPage<>();
通過
ResultPage.buildSuccess(resultPage)
進(jìn)行構(gòu)建返回
返回統(tǒng)一響應(yīng)格式
{
????"previousPage":?1,
????"nextPage":?1,
????"pageSize":?1,
????"totalPageSize":?1,
????"hasNext":?"false",
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"D9AMALgkZ6gVfe6Pi0Oh",
????"timestamp":?"2023-07-09?02:39:40",
????"data":?[
????????{
????????????"name":?"judy",
????????????"hobby":?"swing",
????????????"age":?18
????????}
????]
}
自定義返回格式
{
????"previousPage":?1,
????"nextPage":?1,
????"pageSize":?1,
????"totalPageSize":?1,
????"hasNext":?"false",
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"D9AMALgkZ6gVfe6Pi0Oh",
????"timestamp":?"2023-07-09?02:39:40",
????"data":?[
????????{
????????????"name":?"judy",
????????????"hobby":?"swing",
????????????"age":?18
????????}
????]
}
上述統(tǒng)一返回格式,可能不符合你項(xiàng)目中接口統(tǒng)一格式如:
{
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"ztf4S-lP9yrtKPSiwldZ",
????"timestamp":?"2023-07-11?13:46:53",
????"data":?{
????????"previousPage":?1,
????????"nextPage":?1,
????????"pageSize":?1,
????????"totalPageSize":?1,
????????"hasNext":?"false",
????????"pageData":?[
????????????{
????????????????"name":?"judy",
????????????????"hobby":?"swing",
????????????????"age":?18
????????????}
????????]
????}
}
page
分頁數(shù)據(jù)是在data
里面你可以定義pageWrap
屬性true
包裝返回定義pageData
的key
值如records
等
你需要自定義key
如 msg
你可能對應(yīng)message
,success
你可能對應(yīng)status
只需要在配置文件中配置自定義key
自定義返回成功值你的成功返回可能是200
你可以配置code-success-value
值
rest-api:
??enabled:?false
??msg:?msg
??code:?code
??code-success-value:?OK
??success:?success
??previousPage:?previousPage
??nextPage:?nextPage
??pageSize:?pageSize
??hasNext:?hasNext
??totalPageSize:?totalPageSize
??data:?info
當(dāng) enabled
開啟后會讀取你自定義配置的key
如
rest-api:
??enabled:?true
??msg:?msg1
??code:?code1
??code-success-value:?200
??success:?success1
??previousPage:?previousPage1
??nextPage:?nextPage1
??pageSize:?pageSize1
??hasNext:?hasNext1
??totalPageSize:?totalPageSize1
??data:?info
對應(yīng)返回內(nèi)容
{
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"ztf4S-lP9yrtKPSiwldZ",
????"timestamp":?"2023-07-11?13:46:53",
????"data":?{
????????"previousPage":?1,
????????"nextPage":?1,
????????"pageSize":?1,
????????"totalPageSize":?1,
????????"hasNext":?"false",
????????"pageData":?[
????????????{
????????????????"name":?"judy",
????????????????"hobby":?"swing",
????????????????"age":?18
????????????}
????????]
????}
}
自定義返回
有時(shí)候我們需要自定義返回。不去包裝統(tǒng)一響應(yīng)RestFull API
格式
可以通過注解
@NoRestFulApi
實(shí)現(xiàn)如
"/test")
(
public?Map?chatDialogue()?{
????Map??m=?new?HashMap<>();
????m.put("name","judy");
????m.put("age",26);
????return?m;
}
通過類掃描去實(shí)現(xiàn) 默認(rèn)會過濾
String
類型認(rèn)為是頁面路徑。
通過屬性配置文件include-packages
需要統(tǒng)一返回包。exclude-packages
不需統(tǒng)一返回的包
include-packages:?cn.soboys.superaide.controller
exclude-packages:?xx.xxx.xxx
OpenApi文檔生成
已經(jīng)內(nèi)置自動支持。swagger
文檔。和最新的OpenApi3
文檔。項(xiàng)目啟動后即可訪問。
swagger-ui.html 文檔。路徑
/swagger-ui.html
基于spring-doc 文檔UI增強(qiáng) 路徑
/doc.html
接口文檔屬性信息
??openapi:
????description:
????title:
????version:
????license:?
????contact:
??????name:
??????email:
??????url:?
啟動項(xiàng)目后,訪問 http://server:port/context-path/swagger-ui.html 即可進(jìn)入 Swagger UI 頁面,OpenAPI 描述將在以下 json 格式的 url 中 提供:http://server:port/context-path/v3/api-docs
server:域名 或 IP
port:服務(wù)器端口
context-path:應(yīng)用程序的上下文路徑,springboot 默認(rèn)為空
文檔也可以 yaml 格式提供,位于以下路徑:/v3/api-docs.yaml
如果嫌棄官方提供的 swagger-ui 不美觀,或者使用不順手,可以選擇關(guān)閉 ui,還可以剔除掉 ui 相關(guān)的 webjar 的引入。
springdoc:
??swagger-ui:
????enabled:?false
OpenAPI 文檔信息,默認(rèn)可在此 url 中獲取: http://server:port/context-path/v3/api-docs。 可以利用其他支持 OpenAPI 協(xié)議的工具,通過此地址,進(jìn)行 API 展示,如 Apifox。 ( Postman 的 api 測試也可以利用此地址進(jìn)行導(dǎo)入生成 )
Knife4j (原 swagger-bootstrap-ui) 3.x 版本提供了對于 OpenAPI 協(xié)議的部分支持。
::: tip Knife4j 很多地方?jīng)]有按照協(xié)議規(guī)范實(shí)現(xiàn),所以使用起來會有很多問題,另外項(xiàng)目也很久沒有維護(hù)了,不推薦使用。 :::
?由于 knife4j 對于規(guī)范支持的不全面,無法直接使用單文檔源數(shù)據(jù),所以必須進(jìn)行分組或者 urls 的指定。
?
#?urls
springdoc:
??swagger-ui:
????urls:
??????-?{?name:?'sample',?url:?'/v3/api-docs'?}
或者
#分組
springdoc:
??group-configs:
????-?{?group:?'sample',?packages-to-scan:?'com.example'?}
Knife4j 的 UI 訪問地址有所不同,頁面映射在 doc.html
路徑下,啟動項(xiàng)目后,訪問 http://server:port/context-path/doc.html
即可進(jìn)入 Knife4j 的 Swagger UI 頁面。
全局錯(cuò)誤攔截,參數(shù)校驗(yàn)
幫你封裝好了所有http常見錯(cuò)誤,和所有請求參數(shù)驗(yàn)證錯(cuò)誤。
如請求錯(cuò)誤
{
????"success":?false,
????"code":?"405",
????"msg":?"方法不被允許",
????"timestamp":?"2023-07-03?22:36:47",
????"data":?"Request?method?'GET'?not?supported"
}
請求資源不存在等
{
????"success":?false,
????"code":?"404",
????"msg":?"請求資源不存在",
????"timestamp":?"2023-07-03?22:42:35",
????"data":?"/api"
}
?如果需要攔截上面錯(cuò)誤請?jiān)趕pringboot 配置文件中加入
?
#出現(xiàn)錯(cuò)誤時(shí),?直接拋出異常
spring.mvc.throw-exception-if-no-handler-found=true
#不要為我們工程中的資源文件建立映射
spring.web.resources.add-mappings=false
「參數(shù)校驗(yàn)錯(cuò)誤」
驗(yàn)證Studen對象參數(shù)
/**
?*?@author?公眾號?程序員三時(shí)
?*?@version?1.0
?*?@date?2023/6/26?22:10
?*?@webSite?https://github.com/coder-amiao
?*/
public?class?Student?{
????
????private?String?nam;
????
????private?String?hobby;
}????"/chat")
(
????public?HashMap?chatDialogue(@Validated??Student?student)?{
????????HashMap?m?=?new?HashMap();
????????m.put("age",?26);
????????m.put("name",?"Judy");
????????return?m;
????}
請求結(jié)果

JSON Body參數(shù)
????"/chat")
(
????public?HashMap?chatDialogue(@RequestBody?@Validated??Student?student)?{
????????HashMap?m?=?new?HashMap();
????????m.put("age",?26);
????????m.put("name",?"Judy");
????????return?m;
????}


錯(cuò)誤國際化
內(nèi)置封裝錯(cuò)誤默認(rèn)支持英文和中文兩種國際化。你不做任何配置自動支持
如果需要內(nèi)置支持更多語言,覆蓋即可。
自定義自己錯(cuò)誤國際化和語言
??i18n:
????#?若前端無header傳參則返回中文信息
????i18n-header:?Lang
????default-lang:?cn
????message:
??????#?admin
??????internal_server_error:
????????en:?Internal?Server?Error
????????cn:?系統(tǒng)錯(cuò)誤
??????not_found:
????????en:?Not?Found
????????cn:?請求資源不存在
message 對應(yīng)錯(cuò)誤提示 對應(yīng)internal_server_error 自定義 下面語言自己定義 和前端傳入i18n-header 對應(yīng)上,就顯你定義錯(cuò)誤語言
我不傳錯(cuò)誤國際化默認(rèn)就是中文在 「default-lang: cn」進(jìn)行配置

當(dāng)我傳入 指定語言 就會按照你配置的國際化自定義返回錯(cuò)誤提示

日志鏈路追蹤
RestFull API 統(tǒng)一返回有一個(gè)requestId
它是每個(gè)接口唯一標(biāo)識。用于接口請求日志鏈路追蹤。日志查詢。 如:
{
????"msg":?"操作成功",
????"code":?"OK",
????"previousPage":?1,
????"success":?true,
????"requestId":?"udYNdbbMFE45R84OPu9m",
????"nextPage":?1,
????"pageSize":?1,
????"totalPageSize":?1,
????"hasNext":?"false",
????"timestamp":?"2023-07-09?03:00:27",
????"info":?[
????????{
????????????"name":?"judy",
????????????"hobby":?"swing",
????????????"age":?18
????????}
????]
}
通過requestId你可以很輕松的在你的日志文件查詢定位到每次錯(cuò)誤的請求。
通過Log
注解記錄你想要記錄請求
"/page")
(
(value?=?"查詢用戶數(shù)據(jù)",apiType=?LogApiTypeEnum.USER,CURDType=?LogCURDTypeEnum.RETRIEVE)
public?Result?page(@Validated?EntityParam?s)?{
????ResultPage<List<EntityParam>>?resultPage=new?ResultPage<>();
????List?a=new?ArrayList();
????a.add(s);
????resultPage.setPageData(a);
????return?ResultPage.buildSuccess(resultPage);
}
?系統(tǒng)默認(rèn)日志記錄數(shù)據(jù)源為日志文件。如
?
2023-07-13?11:21:25?INFO??http-nio-8888-exec-2?cn.soboys.restapispringbootstarter.aop.LimitAspect?IP:192.168.1.8?第?1?次訪問key為?[_kenx:chat192.168.1.8],描述為?[接口限流]?的接口
2023-07-13?11:21:26?INFO??http-nio-8888-exec-2?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?{
????"description":?"日志記錄測試",
????"method":?"cn.soboys.restapispringbootstarter.controller.ApiRestController.chatDialogue()",
????"params":?{
????},
????"logType":?"INFO",
????"requestIp":?"192.168.1.8",
????"path":?"/chat",
????"address":?"0|0|0|內(nèi)網(wǎng)IP|內(nèi)網(wǎng)IP",
????"time":?128,
????"os":?"Mac",
????"browser":?"Chrome",
????"result":?{
????????"success":?true,
????????"code":?"OK",
????????"msg":?"操作成功",
????????"requestId":?"5RgKzWGFNa9XSPwhw2Pi",
????????"timestamp":?"2023-07-13?11:21:25",
????????"data":?"接口限流測試"
????},
????"apiType":?"USER",
????"device":?"Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10_15_7)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/114.0.0.0?Safari/537.36"
}
你可以自定義自己的日志數(shù)據(jù)源實(shí)現(xiàn)LogDataSource
接口 日志操作支持異步。需要在配置類。或者啟動類加上@EnableAsync
注解
package?cn.soboys.restapispringbootstarter.log;
import?org.springframework.scheduling.annotation.Async;
import?java.util.Map;
/**
?*?@Author:?kenx
?*?@Since:?2021/6/23?13:55
?*?@Description:
?*/
public?interface?LogDataSource?{
????/**
?????*?獲取拓展數(shù)據(jù)
?????*?@return
?????*?@param?logEntry
?????*/
????
????void??save(LogEntry?logEntry);
}
或者你可以繼承我默認(rèn)的日志數(shù)據(jù)源實(shí)現(xiàn)類LogFileDefaultDataSource
重寫save(LogEntry logEntry)
方法。
4j
public?class?LogFileDefaultDataSource?implements?LogDataSource?{
????/**
?????*?自定義保存數(shù)據(jù)源
?????*
?????*?@param
?????*?@return?LogEntry
?????*/
????
????public?void?save(LogEntry?logEntry)?{
????????log.info(JSONUtil.toJsonPrettyStr(logEntry));
????}
}
?如果是自定義日志數(shù)據(jù)源實(shí)現(xiàn)需要再配置文件,配置日志數(shù)據(jù)源。如:
?
logging:
????path:?./logs???#日志存儲路徑(服務(wù)器上絕對)
????max-history:?90?#?保存多少天
????max-file-size:?3MB??#?每個(gè)文件大小
????max-total-size-cap:?1GB??#總文件大小超過多少壓縮
????level-root:?INFO????#?這里的INFO可以替換為其他日志等級,如DEBUG,?WARN,?ERROR,?TRACE,?FATAL,?OFF等。?日志等級由低到高分別是debugger-info-warn-error
????logDataSourceClass:?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?#?日志數(shù)據(jù)源
Ip城市記錄
日志記錄提供Ip
城市回顯記錄
"/page")
(
(value?=?"查詢用戶數(shù)據(jù)",?apiType?=?LogApiTypeEnum.USER,?CURDType?=?LogCURDTypeEnum.RETRIEVE,ipCity?=?true)
public?Result?page(@Validated?EntityParam?s)?{
????ResultPage<List<EntityParam>>?resultPage?=?new?ResultPage<>();
????List?a?=?new?ArrayList();
????a.add(s);
????resultPage.setPageData(a);
????return?ResultPage.buildSuccess(resultPage);
}
通過配置ipCity
屬性,默認(rèn)是true
會記錄IP對應(yīng)物理地址詳細(xì)信息即國家城市等Ip
城市查詢通過ip2region
獲取。
你可配置屬性 location
配置自己的ip2region.xdb
文件。
??ip2region:
????external:?false
????location:?classpath:ip2region/ip2region.xdb
默認(rèn)不配置會幫你自動生成一個(gè)?;?.7.x最新的數(shù)據(jù) 獲取最新自定義ip數(shù)據(jù) Github 倉庫
當(dāng)然也幫你封裝了。你可以通過工具類HttpUserAgent
的靜態(tài)方法getIpToCityInfo(String ip)
去獲取查詢ip對應(yīng)城市信息
屬性配置
配置語言國際化,日志等,
::: tip 默認(rèn)不用配置任何參數(shù)。會使用默認(rèn)的,配置了會使用你項(xiàng)目中的配置。 :::
默認(rèn)配置
rest-api:
??enabled:?false
??msg:?msg
??code:?code
??code-success-value:?OK
??success:?success
??previousPage:?previousPage
??nextPage:?nextPage
??pageSize:?pageSize
??hasNext:?hasNext
??totalPageSize:?totalPageSize
??data:?info
??include-packages:?cn.soboys.superaide.controller
??exclude-packages:?xx.xxx.xxx
??redis:
????key-prefix:?rest
??openapi:
????description:
????title:
????version:
????license:?
????contact:
??????name:
??????email:
??????url:
??logging:
????path:?./logs???#日志存儲路徑(服務(wù)器上絕對)
????max-history:?90?#?保存多少天
????max-file-size:?3MB??#?每個(gè)文件大小
????max-total-size-cap:?1GB??#總文件大小超過多少壓縮
????level-root:?INFO????#?這里的INFO可以替換為其他日志等級,如DEBUG,?WARN,?ERROR,?TRACE,?FATAL,?OFF等。?日志等級由低到高分別是debugger-info-warn-error
????logDataSourceClass:?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?#?日志數(shù)據(jù)源
??i18n:
????#?若前端無header傳參則返回中文信息
????i18n-header:?Lang
????default-lang:?cn
????message:
??????#?admin
??????internal_server_error:
????????en:?Internal?Server?Error
????????cn:?系統(tǒng)錯(cuò)誤
??????bad_gateway:
????????en:?Bad?Gateway
????????cn:?錯(cuò)誤的請求
??????unauthorized:
????????en:?Unauthorized
????????cn:?未授權(quán)
??????forbidden:
????????en:?Forbidden
????????cn:?資源禁止訪問
??????method_not_allowed:
????????en:?Method?Not?Allowed
????????cn:?方法不被允許
??????request_timeout:
????????en:?Request?Timeout
????????cn:?請求超時(shí)
??????invalid_argument:
????????en:?Invalid?Argument?{}
????????cn:?參數(shù)錯(cuò)誤?{}
??????argument_analyze:
????????en:?Argument?Analyze?{}
????????cn:?參數(shù)解析異常?{}
??????business_exception:
????????en:?Business?Exception
????????cn:?業(yè)務(wù)錯(cuò)誤
??????not_found:
????????en:?Not?Found
????????cn:?請求資源不存在
代碼生成配置
支持MybatisPlus
代碼一鍵生成 默認(rèn)不引入MybatisPlus
生成依賴需要手動引入
package?cn.soboys.restapispringbootstarter.config;
import?lombok.Data;
/**
?*?@author?公眾號?程序員三時(shí)
?*?@version?1.0
?*?@date?2023/7/5?00:05
?*?@webSite?https://github.com/coder-amiao
?*/
public?class?GenerateCodeConfig?{
????/**
?????*?數(shù)據(jù)庫驅(qū)動
?????*/
????private?String?driverName;
????/**
?????*?數(shù)據(jù)庫連接用戶名
?????*/
????private?String?username;
????/**
?????*?數(shù)據(jù)庫連接密碼
?????*/
????private?String?password;
????/**
?????*?數(shù)據(jù)庫連接url
?????*/
????private?String?url;
????/**
?????*?生成代碼?保存路徑。默認(rèn)當(dāng)前項(xiàng)目下。
?????*?如需修改,使用覺得路徑
?????*/
????private?String?projectPath;
????/**
?????*?代碼生成包位置
?????*/
????private?String?packages;
}
RestFull API
Controller中直接使用
"/chat")
(
public?HashMap?chatDialogue()?{
????HashMap?m?=?new?HashMap();
????m.put("age",?26);
????m.put("name",?"Judy");
????return?m;
}
Result構(gòu)建返回
"/chat")
(
public?Result?chatDialogue()?{
????HashMap?m?=?new?HashMap();
????m.put("age",?26);
????m.put("name",?"Judy");
????return?Result.buildSuccess(m);
}
分頁支持
我們在日常中分頁是一個(gè)比較特殊返回。也是非常常用的。
"/page")
(
("分頁查詢用戶數(shù)據(jù)")
public?Result?page(@Validated?EntityParam?s)?{
????ResultPage<List<EntityParam>>?resultPage=new?ResultPage<>();
????List?a=new?ArrayList();
????a.add(s);
????resultPage.setPageData(a);
????return?ResultPage.buildSuccess(resultPage);
}
構(gòu)建自定義自己的分頁數(shù)據(jù)
ResultPage<List<EntityParam>>?resultPage=new?ResultPage<>();
通過
ResultPage.buildSuccess(resultPage)
進(jìn)行構(gòu)建返回
返回統(tǒng)一響應(yīng)格式
{
????"previousPage":?1,
????"nextPage":?1,
????"pageSize":?1,
????"totalPageSize":?1,
????"hasNext":?"false",
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"D9AMALgkZ6gVfe6Pi0Oh",
????"timestamp":?"2023-07-09?02:39:40",
????"data":?[
????????{
????????????"name":?"judy",
????????????"hobby":?"swing",
????????????"age":?18
????????}
????]
}
自定義返回格式
{
????"previousPage":?1,
????"nextPage":?1,
????"pageSize":?1,
????"totalPageSize":?1,
????"hasNext":?"false",
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"D9AMALgkZ6gVfe6Pi0Oh",
????"timestamp":?"2023-07-09?02:39:40",
????"data":?[
????????{
????????????"name":?"judy",
????????????"hobby":?"swing",
????????????"age":?18
????????}
????]
}
上述統(tǒng)一返回格式,可能不符合你項(xiàng)目中接口統(tǒng)一格式如:
{
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"ztf4S-lP9yrtKPSiwldZ",
????"timestamp":?"2023-07-11?13:46:53",
????"data":?{
????????"previousPage":?1,
????????"nextPage":?1,
????????"pageSize":?1,
????????"totalPageSize":?1,
????????"hasNext":?"false",
????????"pageData":?[
????????????{
????????????????"name":?"judy",
????????????????"hobby":?"swing",
????????????????"age":?18
????????????}
????????]
????}
}
page
分頁數(shù)據(jù)是在data
里面你可以定義pageWrap
屬性true
包裝返回定義pageData
的key
值如records
等
你需要自定義key
如 msg
你可能對應(yīng)message
,success
你可能對應(yīng)status
只需要在配置文件中配置自定義key
自定義返回成功值你的成功返回可能是200
你可以配置code-success-value
值
rest-api:
??enabled:?false
??msg:?msg
??code:?code
??code-success-value:?OK
??success:?success
??previousPage:?previousPage
??nextPage:?nextPage
??pageSize:?pageSize
??hasNext:?hasNext
??totalPageSize:?totalPageSize
??data:?info
當(dāng) enabled
開啟后會讀取你自定義配置的key
如
rest-api:
??enabled:?true
??msg:?msg1
??code:?code1
??code-success-value:?200
??success:?success1
??previousPage:?previousPage1
??nextPage:?nextPage1
??pageSize:?pageSize1
??hasNext:?hasNext1
??totalPageSize:?totalPageSize1
??data:?info
對應(yīng)返回內(nèi)容
{
????"success":?true,
????"code":?"OK",
????"msg":?"操作成功",
????"requestId":?"ztf4S-lP9yrtKPSiwldZ",
????"timestamp":?"2023-07-11?13:46:53",
????"data":?{
????????"previousPage":?1,
????????"nextPage":?1,
????????"pageSize":?1,
????????"totalPageSize":?1,
????????"hasNext":?"false",
????????"pageData":?[
????????????{
????????????????"name":?"judy",
????????????????"hobby":?"swing",
????????????????"age":?18
????????????}
????????]
????}
}
自定義返回
有時(shí)候我們需要自定義返回。不去包裝統(tǒng)一響應(yīng)RestFull API
格式
可以通過注解
@NoRestFulApi
實(shí)現(xiàn)如
"/test")
(
public?Map?chatDialogue()?{
????Map??m=?new?HashMap<>();
????m.put("name","judy");
????m.put("age",26);
????return?m;
}
通過類掃描去實(shí)現(xiàn) 默認(rèn)會過濾
String
類型認(rèn)為是頁面路徑。
通過屬性配置文件include-packages
需要統(tǒng)一返回包。exclude-packages
不需統(tǒng)一返回的包
include-packages:?cn.soboys.superaide.controller
exclude-packages:?xx.xxx.xxx
錯(cuò)誤國際化支持
內(nèi)置常見的錯(cuò)誤??梢钥碒ttpStatus。默認(rèn)錯(cuò)誤支持中文和英文兩種國際化。配置如下
??i18n:
????#?若前端無header傳參則返回中文信息
????i18n-header:?Lang
????default-lang:?cn
????message:
??????#?admin
??????internal_server_error:
????????en:?Internal?Server?Error
????????cn:?系統(tǒng)錯(cuò)誤
??????bad_gateway:
????????en:?Bad?Gateway
????????cn:?錯(cuò)誤的請求
??????unauthorized:
????????en:?Unauthorized
????????cn:?未授權(quán)
??????forbidden:
????????en:?Forbidden
????????cn:?資源禁止訪問
??????method_not_allowed:
????????en:?Method?Not?Allowed
????????cn:?方法不被允許
??????request_timeout:
????????en:?Request?Timeout
????????cn:?請求超時(shí)
??????invalid_argument:
????????en:?Invalid?Argument?{}
????????cn:?參數(shù)錯(cuò)誤?{}
??????argument_analyze:
????????en:?Argument?Analyze?{}
????????cn:?參數(shù)解析異常?{}
??????business_exception:
????????en:?Business?Exception
????????cn:?業(yè)務(wù)錯(cuò)誤
??????not_found:
????????en:?Not?Found
????????cn:?請求資源不存在
可以自行覆蓋擴(kuò)充
全局錯(cuò)誤攔截和響應(yīng)
默認(rèn)攔所有未知錯(cuò)誤異常和validation
參數(shù)校驗(yàn)失敗異常,以及Http請求異常。
還有全局自定義「BusinessException」 業(yè)務(wù)異常 自動集成spring-boot-starter-validation
你項(xiàng)目中不需要再單獨(dú)引入
<!--參數(shù)校驗(yàn)-->
<dependency>
????<groupId>org.springframework.boot</groupId>
????<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
也內(nèi)置擴(kuò)展了許多自定義參數(shù)校驗(yàn)參考

第三方請求
有時(shí)候我們項(xiàng)目中需要調(diào)用第三方接口服務(wù)?;?code>RestTemplate 進(jìn)一步封裝了直接的POST,GET,請求。
在需要使用地方注入RestFulTemp
private?RestFulTemp?restFulTemp;
GET請求
"/doGet")
(
public?Result?doGet()?{
????ResponseEntity<String>?response?=?restFulTemp.doGet("http://127.0.0.1:9000/redis/get");
????return?Result.buildSuccess();
}
POST 請求
/**
?*?POST?請求參?數(shù)為body?json體格式
?*?@return
?*/
("/doPost")
public?Result?doPost()?{
????Student?s=new?Student();
????s.setHobby("swing");
????s.setNam("judy");
????//自動把對象轉(zhuǎn)換為JSON
????ResponseEntity<String>?response?=?
????????????restFulTemp.doPost("http://127.0.0.1:9000/redis/get",s);
????return?Result.buildSuccess();
}/**
?*?POST請求?參數(shù)為FORM?表單參數(shù)
?*?@return
?*/
("/doPost")
public?Result?doPostForm()?{
????EntityParam?s=new?EntityParam();
????s.setAge(19);
????s.setHobby("swing");
????s.setName("judy");
????ResponseEntity<String>?response?=
????????????restFulTemp.doPostForm("http://127.0.0.1:8000/chat",?BeanUtil.beanToMap(s));
????return?Result.buildSuccess(response.getBody());
}
DELETE請求
"/doDelete")
(
public?Result?doDelete()?{
????restFulTemp.doDelete("http://127.0.0.1:8000/chat");
????return?Result.buildSuccess();
}
PUT請求
"/doPut")
(
public?Result?doPut()?{
????EntityParam?s=new?EntityParam();
????restFulTemp.doPut("http://127.0.0.1:8000/chat",s);
????return?Result.buildSuccess(s);
}
錯(cuò)誤異常自定義
我內(nèi)置錯(cuò)誤異常和業(yè)務(wù)異常可能無法滿足你自身接口業(yè)務(wù)異常需要。你可以自定義錯(cuò)誤異常類,和錯(cuò)誤響應(yīng)枚舉碼。
?自定義錯(cuò)誤枚舉 需要實(shí)現(xiàn)「ResultCode」接口
?
package?cn.soboys.restapispringbootstarter;
import?cn.soboys.restapispringbootstarter.i18n.I18NKey;
/**
*?@author?公眾號?程序員三時(shí)
*?@version?1.0
*?@date?2023/6/26?10:21
*?@webSite?https://github.com/coder-amiao
*?響應(yīng)碼接口,自定義響應(yīng)碼,實(shí)現(xiàn)此接口
*/
public?interface?ResultCode?extends?I18NKey?{
???String?getCode();
???String?getMessage();
}
如果要支持國際化還需要實(shí)現(xiàn)國際化接口「I18NKey」 參考我內(nèi)部「HttpStatus」實(shí)現(xiàn)即可
package?cn.soboys.restapispringbootstarter;
import?cn.soboys.restapispringbootstarter.i18n.I18NKey;
/**
?*?@author?公眾號?程序員三時(shí)
?*?@version?1.0
?*?@date?2023/6/26?11:01
?*?@webSite?https://github.com/coder-amiao
?*/
public?enum?HttpStatus?implements?ResultCode,?I18NKey?{
????/**
?????*?系統(tǒng)內(nèi)部錯(cuò)誤
?????*/
????INTERNAL_SERVER_ERROR("500",?"internal_server_error"),
????BAD_GATEWAY("502",?"bad_gateway"),
????NOT_FOUND("404",?"not_found"),
????UNAUTHORIZED("401",?"unauthorized"),
????FORBIDDEN("403",?"forbidden"),
????METHOD_NOT_ALLOWED("405",?"method_not_allowed"),
????REQUEST_TIMEOUT("408",?"request_timeout"),
????INVALID_ARGUMENT("10000",?"invalid_argument"),
????ARGUMENT_ANALYZE("10001",?"argument_analyze"),
????BUSINESS_EXCEPTION("20000",?"business_exception");
????private?final?String?value;
????private?final?String?message;
????HttpStatus(String?value,?String?message)?{
????????this.value?=?value;
????????this.message?=?message;
????}
????
????public?String?getCode()?{
????????return?value;
????}
????
????public?String?getMessage()?{
????????return?message;
????}
????
????public?String?key()?{
????????return?message;
????}
}rest-api:
??enabled:?false
??i18n:
????#?若前端無header傳參則返回中文信息
????i18n-header:?Lang
????default-lang:?cn
????message:
??????#?admin
??????internal_server_error:
????????en:?Internal?Server?Error
????????cn:?系統(tǒng)錯(cuò)誤
??????bad_gateway:
????????en:?Bad?Gateway
????????cn:?錯(cuò)誤的請求
??????unauthorized:
????????en:?Unauthorized
????????cn:?未授權(quán)
??????forbidden:
????????en:?Forbidden
????????cn:?資源禁止訪問
??????method_not_allowed:
????????en:?Method?Not?Allowed
????????cn:?方法不被允許
??????request_timeout:
????????en:?Request?Timeout
????????cn:?請求超時(shí)
??????invalid_argument:
????????en:?Invalid?Argument?{}
????????cn:?參數(shù)錯(cuò)誤?{}
??????argument_analyze:
????????en:?Argument?Analyze?{}
????????cn:?參數(shù)解析異常?{}
??????business_exception:
????????en:?Business?Exception
????????cn:?業(yè)務(wù)錯(cuò)誤
??????not_found:
????????en:?Not?Found
????????cn:?請求資源不存在




業(yè)務(wù)斷言
封裝了業(yè)務(wù)錯(cuò)誤斷言工具。Assert
遵循錯(cuò)誤優(yōu)先返回原則。
你要自定義自己的業(yè)務(wù)異常。繼承BusinessException
重寫對應(yīng)方法
package?cn.soboys.restapispringbootstarter.exception;
import?cn.soboys.restapispringbootstarter.HttpStatus;
import?cn.soboys.restapispringbootstarter.ResultCode;
import?lombok.Data;
/**
?*?@author?公眾號?程序員三時(shí)
?*?@version?1.0
?*?@date?2023/6/26?16:45
?*?@webSite?https://github.com/coder-amiao
?*/
public?class?BusinessException?extends?RuntimeException?{
????/**
?????*?錯(cuò)誤碼
?????*/
????private?String?code="20000";
????/**
?????*?錯(cuò)誤提示
?????*/
????private?String?message;
????public?BusinessException(String?message)?{
????????this.message?=?message;
????}
????public?BusinessException(String?message,?String?code)?{
????????this.message?=?message;
????????this.code?=?code;
????}
????public?BusinessException(ResultCode?resultCode)?{
????????this.message?=?resultCode.getMessage();
????????this.code?=?resultCode.getCode();
????}
}
項(xiàng)目中日志是非常常用的,而且還是必須的。已經(jīng)自動配置集成spring-boot-starter-logging
你不需要在項(xiàng)目中單獨(dú)引入
<!--日志集成-->
<dependency>
????<groupId>org.springframework.boot</groupId>
????<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
默認(rèn)日志配置
logging:
????path:?./logs???#日志存儲路徑(服務(wù)器上絕對)
????max-history:?90?#?保存多少天
????max-file-size:?3MB??#?每個(gè)文件大小
????max-total-size-cap:?1GB??#總文件大小超過多少壓縮
????level-root:?INFO????#?這里的INFO可以替換為其他日志等級,如DEBUG,?WARN,?ERROR,?TRACE,?FATAL,?OFF等。?日志等級由低到高分別是debugger-info-warn-error
????logDataSourceClass:?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?#?日志數(shù)據(jù)源
日志記錄與追蹤
RestFull API 統(tǒng)一返回有一個(gè)requestId
它是每個(gè)接口唯一標(biāo)識。用于接口請求日志鏈路追蹤。日志查詢。 如:
{
????"msg":?"操作成功",
????"code":?"OK",
????"previousPage":?1,
????"success":?true,
????"requestId":?"udYNdbbMFE45R84OPu9m",
????"nextPage":?1,
????"pageSize":?1,
????"totalPageSize":?1,
????"hasNext":?"false",
????"timestamp":?"2023-07-09?03:00:27",
????"info":?[
????????{
????????????"name":?"judy",
????????????"hobby":?"swing",
????????????"age":?18
????????}
????]
}
通過requestId你可以很輕松的在你的日志文件查詢定位到每次錯(cuò)誤的請求。
通過Log
注解記錄你想要記錄請求
"/page")
(
(value?=?"查詢用戶數(shù)據(jù)",apiType=?LogApiTypeEnum.USER,CURDType=?LogCURDTypeEnum.RETRIEVE)
public?Result?page(@Validated?EntityParam?s)?{
????ResultPage<List<EntityParam>>?resultPage=new?ResultPage<>();
????List?a=new?ArrayList();
????a.add(s);
????resultPage.setPageData(a);
????return?ResultPage.buildSuccess(resultPage);
}
?系統(tǒng)默認(rèn)日志記錄數(shù)據(jù)源為日志文件。如
?
2023-07-09?03:00:32?INFO??http-nio-8000-exec-2?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?{
????"description":?"查詢用戶數(shù)據(jù)",
????"method":?"cn.soboys.restapispringbootstarter.controller.ApiRestController.page()",
????"logType":?"INFO",
????"time":?3,
????"result":?{
????????"success":?true,
????????"code":?"OK",
????????"msg":?"操作成功",
????????"requestId":?"udYNdbbMFE45R84OPu9m",
????????"timestamp":?"2023-07-09?03:00:27",
????????"data":?{
????????????"previousPage":?1,
????????????"nextPage":?1,
????????????"pageSize":?1,
????????????"totalPageSize":?1,
????????????"hasNext":?"false",
????????????"pageData":?[
????????????????{
????????????????????"name":?"judy",
????????????????????"hobby":?"swing",
????????????????????"age":?18
????????????????}
????????????],
????????????"requestId":?"qJTOejQmY-OOf7fagegB",
????????????"timestamp":?"2023-07-09?03:00:27"
????????}
????},
????"apiType":?"USER"
}
2023-07-09?03:08:03?INFO??http-nio-8000-exec-4?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?{
????"description":?"查詢用戶數(shù)據(jù)",
????"method":?"cn.soboys.restapispringbootstarter.controller.ApiRestController.page()",
????"logType":?"INFO",
????"time":?1,
????"result":?{
????????"success":?true,
????????"code":?"OK",
????????"msg":?"操作成功",
????????"requestId":?"kP3yPP-H7wI2x1ak6YFA",
????????"timestamp":?"2023-07-09?03:00:27",
????????"data":?{
????????????"previousPage":?1,
????????????"nextPage":?1,
????????????"pageSize":?1,
????????????"totalPageSize":?1,
????????????"hasNext":?"false",
????????????"pageData":?[
????????????????{
????????????????????"name":?"judy",
????????????????????"hobby":?"swing",
????????????????????"age":?18
????????????????}
????????????],
????????????"requestId":?"pGbbiEj8GQ1eTxQpF2Jr",
????????????"timestamp":?"2023-07-09?03:00:27"
????????}
????},
????"apiType":?"USER"
}
你可以自定義自己的日志數(shù)據(jù)源實(shí)現(xiàn)LogDataSource
接口 日志操作支持異步。需要在配置類。或者啟動類加上@EnableAsync
注解
package?cn.soboys.restapispringbootstarter.log;
import?org.springframework.scheduling.annotation.Async;
import?java.util.Map;
/**
?*?@Author:?kenx
?*?@Since:?2021/6/23?13:55
?*?@Description:
?*/
public?interface?LogDataSource?{
????/**
?????*?獲取拓展數(shù)據(jù)
?????*?@return
?????*?@param?logEntry
?????*/
????
????void??save(LogEntry?logEntry);
}
或者你可以繼承我默認(rèn)的日志數(shù)據(jù)源實(shí)現(xiàn)類LogFileDefaultDataSource
重寫save(LogEntry logEntry)
方法。
4j
public?class?LogFileDefaultDataSource?implements?LogDataSource?{
????/**
?????*?自定義保存數(shù)據(jù)源
?????*
?????*?@param
?????*?@return?LogEntry
?????*/
????
????public?void?save(LogEntry?logEntry)?{
????????log.info(JSONUtil.toJsonPrettyStr(logEntry));
????}
}
?如果是自定義日志數(shù)據(jù)源實(shí)現(xiàn)需要再配置文件,配置日志數(shù)據(jù)源。如:
?
logging:
????path:?./logs???#日志存儲路徑(服務(wù)器上絕對)
????max-history:?90?#?保存多少天
????max-file-size:?3MB??#?每個(gè)文件大小
????max-total-size-cap:?1GB??#總文件大小超過多少壓縮
????level-root:?INFO????#?這里的INFO可以替換為其他日志等級,如DEBUG,?WARN,?ERROR,?TRACE,?FATAL,?OFF等。?日志等級由低到高分別是debugger-info-warn-error
????logDataSourceClass:?cn.soboys.restapispringbootstarter.log.LogFileDefaultDataSource?#?日志數(shù)據(jù)源
緩存和redis
項(xiàng)目中緩存使用是非常常見的。用的最多的是基于Redis
緩存。于是我封裝了對于Redis
Key和Value常用操作。
::: tip 默認(rèn)不引入Redis依賴,如果要使用Redis需要自己單獨(dú)引入 :::
<dependency>
????<groupId>org.springframework.boot</groupId>
????<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
項(xiàng)目使用
注入redisTempUtil
private?RedisTempUtil?redisTempUtil;
如示列
private?RedisTempUtil?redisTempUtil;
("/redis")
public?Result?chatDialogue(?)?{
????redisTempUtil.set("test","111");
????redisTempUtil.get("test");
????redisTempUtil.set("user","userObj",7200l);
????redisTempUtil.getAllKey("xx");??//*表達(dá)式
????redisTempUtil.clean();
????redisTempUtil.deleteObject("test");
????redisTempUtil.hasKey("");
????return?Result.buildSuccess();
}
統(tǒng)一緩存管理
上面我們是直接通過工具類redisTempUtil
直接自己定義key
然后去存儲,這種方式是不可取的如果key很多隨意定義就會很混亂
。我提供了統(tǒng)一緩存key管理接口CacheTmp
參考實(shí)現(xiàn)CacheKey
基于枚舉形式,把所有key集中管理
package?cn.soboys.restapispringbootstarter.cache;
import?lombok.Getter;
/**
?*?@author?公眾號?程序員三時(shí)
?*?@version?1.0
?*?@date?2023/7/2?11:04
?*?@webSite?https://github.com/coder-amiao
?*?緩存枚舉
?*/
public?enum?CacheKey?implements?CacheTmp?{
????//?密碼的重置碼
????PWD_RESET_CODE("reset:code:",?true),
????;
????private?String?key;
????/**
?????*?Key是否是Key前綴,?true時(shí)直接取key=key,如果false時(shí)key=key+suffix
?????*/
????private?boolean?hasPrefix;
????CacheKey(String?key,?boolean?hasPrefix)?{
????????this.key?=?key;
????????this.hasPrefix?=?hasPrefix;
????}
????
????public?Boolean?getHasPrefix()?{
????????return?this.hasPrefix;
????}
????
????public?String?getKey()?{
????????return?this.key;
????}
}
使用
存儲對于key
"/redis")
(
public?Result?chatDialogue()?{
????CacheKey.PWD_RESET_CODE.valueSetAndExpire("test",?60l,?TimeUnit.SECONDS,?"judy");
????return?Result.buildSuccess();
}
獲取對應(yīng)的key
"/redis/get")
(
public?Result?redisGet()?{
????String?a?=?CacheKey.PWD_RESET_CODE.valueGet("judy");
????return?Result.buildSuccess(a);
}
spring Cache實(shí)現(xiàn)
封裝了spring Cache
進(jìn)一步使用 項(xiàng)目中在配置類或者啟動類通過注解@EnableCaching
開啟直接使用即可
"testCache",?keyGenerator?=?"keyGeneratorStrategy")
(cacheNames?=?
("/redis/springCache")
public?Result?springCache()?{
????String?a?=?"test?cache";
????return?Result.buildSuccess(a);
}
工具類使用springCacheUtil
支持提供不是基于注解的使用方式
"/redis/springCache")
(
public?Result?redisSpringCache()?{
????String?a?=?"111344";
????springCacheUtil.putCache("test","key","121e1");
????return?Result.buildSuccess(a);
}
::: tip 默認(rèn)不引入Redis依賴,緩存基于內(nèi)存實(shí)現(xiàn)(你項(xiàng)目引入redis依賴后會自定切換數(shù)據(jù)源為Redis緩存) :::
redis配置
多個(gè)項(xiàng)目或者模塊使用一個(gè)key可能會造成混亂,于是提供了一個(gè)全局配置key。
??redis:
????key-prefix:?rest?
代碼中添加一個(gè) String 類型的 key:testKey
,其實(shí)際在 redis 中存儲的 key name 為 rest:testKey
全局 key 前綴的配置,并不影響對 key 的其他操作,例如獲取對應(yīng)的 value 時(shí),依然是傳入 testKey
,而不是 rest:testKey
String?key?=?"testKey";
String?value?=?redisTempUtil.get(key);
String?value1?=?CacheKey.PWD_RESET_CODE.valueGet(key);
OpenApi文檔生成
已經(jīng)內(nèi)置自動支持。swagger
文檔。和最新的OpenApi3
文檔。項(xiàng)目啟動后即可訪問。
swagger-ui.html 文檔。路徑
/swagger-ui.html
基于spring-doc 文檔UI增強(qiáng) 路徑
/doc.html
接口文檔屬性信息
??openapi:
????description:
????title:
????version:
????license:?
????contact:
??????name:
??????email:
??????url:?
啟動項(xiàng)目后,訪問 http://server:port/context-path/swagger-ui.html 即可進(jìn)入 Swagger UI 頁面,OpenAPI 描述將在以下 json 格式的 url 中 提供:http://server:port/context-path/v3/api-docs
server:域名 或 IP
port:服務(wù)器端口
context-path:應(yīng)用程序的上下文路徑,springboot 默認(rèn)為空
文檔也可以 yaml 格式提供,位于以下路徑:/v3/api-docs.yaml
如果嫌棄官方提供的 swagger-ui 不美觀,或者使用不順手,可以選擇關(guān)閉 ui,還可以剔除掉 ui 相關(guān)的 webjar 的引入。
springdoc:
??swagger-ui:
????enabled:?false
OpenAPI 文檔信息,默認(rèn)可在此 url 中獲取: http://server:port/context-path/v3/api-docs。 可以利用其他支持 OpenAPI 協(xié)議的工具,通過此地址,進(jìn)行 API 展示,如 Apifox。 ( Postman 的 api 測試也可以利用此地址進(jìn)行導(dǎo)入生成 )
Knife4j (原 swagger-bootstrap-ui) 3.x 版本提供了對于 OpenAPI 協(xié)議的部分支持。
::: tip Knife4j 很多地方?jīng)]有按照協(xié)議規(guī)范實(shí)現(xiàn),所以使用起來會有很多問題,另外項(xiàng)目也很久沒有維護(hù)了,不推薦使用。 :::
?由于 knife4j 對于規(guī)范支持的不全面,無法直接使用單文檔源數(shù)據(jù),所以必須進(jìn)行分組或者 urls 的指定。
?
#?urls
springdoc:
??swagger-ui:
????urls:
??????-?{?name:?'sample',?url:?'/v3/api-docs'?}
或者
#分組
springdoc:
??group-configs:
????-?{?group:?'sample',?packages-to-scan:?'com.example'?}
Knife4j 的 UI 訪問地址有所不同,頁面映射在 doc.html
路徑下,啟動項(xiàng)目后,訪問 http://server:port/context-path/doc.html
即可進(jìn)入 Knife4j 的 Swagger UI 頁面。
代碼自動生成
項(xiàng)目中我們使用mybatis
或者mybatisPlus
一些簡單的單表業(yè)務(wù)代碼,增刪改成。我們可以一鍵生成。不需要重復(fù)寫。 我封裝了mybatisPlus
代碼生成工具
::: tip
默認(rèn)不引入mybatisPlus
代碼生成依賴,如果要使用mybatisPlus
代碼生成需自行單獨(dú)引入
:::
<dependency>
????<groupId>com.baomidou</groupId>
????<artifactId>mybatis-plus-generator</artifactId>
????<version>3.4.1</version>
</dependency>
<!--?MySQL?-->
<dependency>
????<groupId>mysql</groupId>
????<artifactId>mysql-connector-java</artifactId>
????<version>8.0.28</version>
</dependency>
<!--代碼生成依賴的模板引擎-->
<dependency>
????<groupId>org.freemarker</groupId>
????<artifactId>freemarker</artifactId>
????<version>2.3.31</version>
</dependency>
項(xiàng)目使用
代碼生成配置類
package?cn.soboys.restapispringbootstarter.config;
import?lombok.Data;
/**
?*?@author?公眾號?程序員三時(shí)
?*?@version?1.0
?*?@date?2023/7/5?00:05
?*?@webSite?https://github.com/coder-amiao
?*/
public?class?GenerateCodeConfig?{
????/**
?????*?數(shù)據(jù)庫驅(qū)動
?????*/
????private?String?driverName;
????/**
?????*?數(shù)據(jù)庫連接用戶名
?????*/
????private?String?username;
????/**
?????*?數(shù)據(jù)庫連接密碼
?????*/
????private?String?password;
????/**
?????*?數(shù)據(jù)庫連接url
?????*/
????private?String?url;
????/**
?????*?生成代碼?保存路徑。默認(rèn)當(dāng)前項(xiàng)目下。
?????*?如需修改,使用絕對路徑
?????*/
????private?String?projectPath;
????/**
?????*?代碼生成包位置
?????*/
????private?String?packages;
}
示列如:
public?class?Test?{
????public?static?void?main(String[]?args)?{
????????GenerateCodeConfig?config=new?GenerateCodeConfig();
????????config.setDriverName("com.mysql.cj.jdbc.Driver");
????????config.setUsername("root");
????????config.setPassword("root");
????????config.setUrl("jdbc:mysql://127.0.0.1:3306/ry?useUnicode=true&useSSL=false&characterEncoding=utf8");
????????//config.setProjectPath("superaide");
????????config.setPackages("cn.soboys.superaide");
????????MyBatisPlusGenerator.generate(config);
????}
}
常見問題
在使用過程中盡量使用最新版本。我會持續(xù)更新更多的內(nèi)容。 會第一時(shí)間發(fā)布在我的公眾號 程序員三時(shí)。全網(wǎng)同名
可以關(guān)注 公眾號 「程序員三時(shí)」。用心分享持續(xù)輸出優(yōu)質(zhì)內(nèi)容。希望可以給你帶來一點(diǎn)幫助