03.27 基於SpringBoot的WebAPI開發框架

基於SpringBoot的WebAPI開發框架

臺有必要重新搭建一個內部的開發框架,由於沒有歷史積累,直接使用SpringBoot作為基礎框架,在此之上再做一個封裝。

分享出來給大家參考,此框架適應於中小企業Java實現的WebAPI項目(前後端分離)。大家可以直接使用,但是最好還是理解並修改成適用自己團隊的框架。

1.基本結構

基於SpringBoot的WebAPI開發框架

如上圖,我們的框架包含很多庫,其中d1.framework.webapi和d1.framework.cache是所有webapi項目都必須依賴的,其它的庫是看需求選擇依賴的。下面列出所有庫的基本功能:

d1.framework.webapi: 業務項目依賴的基本庫,包含springboot相關很多功能的封裝,比如Application、Entity、Service、Controller等基類,還有swagger、跨域,權限統一認證,日誌相關等等,後面單獨說明。

d1.framework.cache: 緩存相關的庫,因為d1.framework.webapi依賴這個庫,所以所有業務項目也都依賴它,一個接口外加ehcache和redis的實現,實際業務項目中選擇一種就可以。

d1.framework.storage: 不是必須依賴的庫,一個接口外加本地文件存儲和七牛雲存儲的實現。

d1.framework.util:不是必須依賴的庫,實現一系列工具類,是在業務項目開發過程中逐漸積累的一些和業務無關的靜態方法。

d1.framework.push:不是必須依賴的庫,實現極光推送,這個是我們團隊比較常用的app推送第三方庫的封裝。

d1.framework.sms:不是必須依賴的庫,一個接口外加二種第三方的短信封裝,主要用於註冊等短信驗證。

d1.framework.weixin:不是必須依賴的庫,微信小程序、公眾號、app等開發平臺相關封裝。

d1.framework.ocr: 不是必須依賴的庫,封裝了阿里的二個圖形識別服務,也是實際業務項目用到了後封裝的。

d1.framework.mqttclient:不是必須依賴的庫,是對mqtt協議的實現,也是對一個開源庫的封裝。

2. 基本說明

springboot已經非常方便了,但是還是有必要把一些重複的不變的功能封裝成框架,開發框架和開發業務應該分開。

框架裡有一些我們團隊特有的約定,並不一定適合所有人的習慣。

所有業務項目使用gradle工具構建,主要是覺得gradle比maven更簡潔。

框架所有項目都上傳到我們內部的Nexus

搭建的maven庫,搭建的方法可以參考我以前發的貼。 業務項目通過gradle來配置依賴:

repositories {

mavenCentral()

maven{ url 'http://你的nexus庫地址/repository/d1-java/'}

}

除d1.framework.webapi庫強制依賴springboot以外,其它庫都沒有依賴springboot,這樣其它庫也可以很方便用於非springboot的業務項目

大部分庫都是先定義接口,再對這個接口進行實現,通常有好幾種實現。

很多第三方庫已經很簡單了,但是還是有必要做一次封裝,主要還是第三方庫功能很多,但是我們通常用到的很少,而且有很多缺省用法,封裝後使用更簡單,也能讓第三方庫版本變化後對現有業務項目也沒影響。

每個庫項目都由一個springboot業務項目作為測試庫的入口以及一個庫真正實現的module,這個module修改完後build成jar包並推送到nexus服務上。

所有業務項目都是在IDEA下開發,沒有使用Eclipse。

框架是在業務項目不斷的開發中逐漸積累和完善的,功能會越來越多,bug會越來越少。

3. 源碼

源碼都上傳到github,下載後要跑起來還需修改:

搭建自己的nexus服務,或者改造業務項目生成jar包,然後使用本地依賴方式。

所有第三方對應的密鑰信息都已經修改成一些隨便的數字,確保安全性,

源碼裡除了框架庫代碼,還有一個d1project項目是用於使用框架的一個webapi模板項目。如果新建一個業務項目可以通過拷貝這個項目作為基礎。

基於SpringBoot的WebAPI開發框架

d1.framework.webapi 庫是基礎封裝,每個 webapi 項目都必須使用,裡面包含功能很多。

1. BaseApplication

所有業務項目的主入口 Application 類都需繼承此類

@SpringBootApplication

public class DemoApplication extends BaseApplication{

}

這個類主要是增加幾個缺省註解,比如激活 Swagger,確保對包進行掃描是從 d1 開始。

所以約定我們所有的業務項目的 package 都是 d1 開頭,比如d1.project.xxxx

@EnableSwagger2

@ComponentScan("d1")

@EntityScan("d1")

@EnableJpaRepositories("d1")

public class BaseApplication {

}

2. 封裝 webapi 接口的返回 Result

所有 controller 返回的值都是一個 Result 對象,基本結構是

{

"code": 1,

"msg": "返回的消息,通常是字符串",

"data": "返回的數據,通常又是一個json對象"

}

使用方式:

return ResultUtil.result(10001,"自定義的消息",數據對象);

return ResultUtil.fail("自定義的消息",數據對象);

return ResultUtil.success("自定義的消息",數據對象);

3. ControllerAdvice

利用註解 @ControllerAdvice 實現統一攔截處理所有 controller 沒有 catch 的錯誤

@ExceptionHandler(Exception.class)

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

@ResponseBody

public Result all(Exception e) {

return ResultUtil.result(ResultCode.UN_CATCH_ERROR.code, e.getMessage(), e);

}

4. 封裝Swagger自動生成API文檔

只需要在 application.properties 配置文件裡添加以下幾個配置,業務項目的 API 文檔就可以自動生成並以服務的方式來訪問,訪問的url是http://域名或地址/swagger-ui.html#/

#application.properties

d1.framework.webapi.swagger.enable=true #生產環境下通常改成false

d1.framework.webapi.swagger.title=項目的標題

d1.framework.webapi.swagger.desc=項目的描述

d1.framework.webapi.swagger.version=項目API的版本

d1.framework.webapi.swagger.host=www.xxxx.com:8089

在 contorller 裡使用註解標記 API 的方法參考文檔

4. 跨域設置

只需要在 application.properties 配置文件裡添加以下配置,業務項目的前端頁面可以實現跨域訪問,當然生產環境的時候需要嚴格控制可跨域的域名。

#application.properties

#生成環境需要把*換成真實的域名,多個域名可以用逗號隔開

d1.framework.webapi.cors=*

5. BaseEntity

這是所有 Entity 的基類,主要是強行設置一個字段叫 Id,這個 Id 缺省是32位 uuid,在業務系統上建議所有 entity 都繼承它。

6. User相關封裝

DoUserBaseEntity 定義了用戶表的常用字段,業務系統直接繼承做一些擴展就可以了。

DoUserServiceImplBase 實現用戶相關的 service,主要是創建 token,登錄驗證 token,缺省 token 都是用 d1.framework.cache 來緩存。

7. Auth相關

這裡也是基於團隊內部的一個約定,所有 webapi 接口如果需要驗證權限,都需要在 http 請求的 header 裡設置 Authorization 屬性,屬性的值有2種情況:

Authorization = token xxxxxxx 表示是通過用戶登錄後返回的 token 來驗證

Authorization = sign xxxxxxx 表示服務間通過 HMAC 簽名來校驗

定義AuthFilter(繼承Filter)來驗證用戶的請求Header裡的Authoriztion對應的值如果是token的話,從d1.framework.cache裡對應的緩存裡查詢token是否存在並是否沒有過期。

另外通過定義一個自定義的註解Auth來設定web api接口是屬於某種特定的用戶。

@Auth("webadmin")

@RestController

@RequestMapping("/webadmin/user")

@Api(value = "/webadmin/user", description = "管理用戶管理")

public class WebAdminUserController extends DoBaseController<webadminuser> {/<webadminuser>

......

}

@Auth("webadmin")標識這個controller裡所有方法都必須是webadmin用戶登錄後才可以訪問,這個註解也可以單獨給特定方法使用

8. DestroyEhcacheBean

JVM 退出時先 shutdown ehcache,確保內存裡的 cache 內容正確寫入本地文件

public class DestroyEhcacheBean implements DisposableBean, ExitCodeGenerator {

......

@Override

public void destroy() throws Exception {

if (cache != null)

cache.shutDown();

}

}

9. DoServiceImpBase

包含 service 常用方法,其它 service 都繼承這個方法,裡面主要包括基本的增刪改查,這是一個 abstract 方法,最主要是需要子類繼承的時候返回一個實際的 dao 類。

這個基類還實現了根據 token 查詢對應的用戶對象。

public abstract class DoServiceImpBase {

......

protected abstract JpaRepository getDao();

......

}

10. DoBaseController類

controller 基類,封裝了最基本的增刪改查,子類只需要繼承,常見的接口都已定義。

11. 日誌

在項目的resource下有一個 logback.xml,沒有特殊的需求的話,所有業務系統都可以用這個默認的日誌配置。

另外定義了一個 LoggerController 實現通過 webapi 接口查看日誌和下載日誌文件,這樣遠程就可以查看日誌。

12. HMACSignService

添加HMAC校驗簽名的基類service, 實現了服務間HMAC接口驗證方式,規則參考微信的服務校驗

13. SignInRetryLimitService

封裝用戶登錄重試次數校驗,超過一定次數將被鎖住不能再試了。

需要在application.properties裡添加2個配置:

#登錄密碼錯誤重試的次數,沒有這個值或值為0表示不限制

d1.framework.webapi.sign-in.retry-count=5

#登錄密碼錯誤重試到一定次數後,鎖住用戶一段時間,單位是分鐘

d1.framework.webapi.sign-in.lock-period=60

使用這個服務通過3個函數:

if (user == null) throw new Exception("用戶:" + username + "不存在");

if (retryService.verifyIsLocked(username)) throw new Exception("用戶重試錯誤密碼多次,導致用戶被鎖");

if (!user.getPassword().equals(password)) {

retryService.signInWithWrongPwd(username);

throw new Exception("密碼不對");

}

retryService.signInSuccess(username);

以上是 d1.framework.webapi 的基本功能,很多功能都是在開發實際項目的過程中逐漸添加上去的,包含的功能是雜七雜八的需求。

其它庫都是針對特定的功能,這裡不一一詳述了。

基於SpringBoot的WebAPI開發框架


分享到:


相關文章: