拒絕寫重復(fù)代碼,試試這套開源的 SpringBoot 組件,效率翻倍
一、簡介
Graceful Response是一個Spring Boot技術(shù)棧下的優(yōu)雅響應(yīng)處理器,提供一站式統(tǒng)一返回值封裝、全局異常處理、自定義異常錯誤碼等功能,使用Graceful Response進行web接口開發(fā)不僅可以節(jié)省大量的時間,還可以提高代碼質(zhì)量,使代碼邏輯更清晰。
強烈推薦你花3分鐘學(xué)會它!
本項目案例工程代碼:https://github.com/feiniaojin/graceful-response-example.git ,注意選擇最新版本的分支。
Spring Boot版本 | Graceful Response版本 | graceful-response-example分支 |
2.x | 3.2.1-boot2 | 3.2.0-boot2 |
3.x | 3.2.1-boot3 | 3.2.0-boot3 |
注意,3.2.1-boot2版本的GracefulResponse源碼由單獨的倉庫進行維護,地址為:https://github.com/feiniaojin/graceful-response-boot2。
3.2.1-boot2和3.2.1-boot3除了支持的SpringBoot版本不一樣,其他實現(xiàn)完全一致,Maven引用時只需要根據(jù)對應(yīng)的SpringBoot版本選擇Graceful Response的version即可,兩者的groupId、artifactId是一致的。
二、快速入門
1.Spring Boot接口開發(fā)現(xiàn)狀
目前,業(yè)界使用Spring Boot進行接口開發(fā)時,往往存在效率底下、重復(fù)勞動、可讀性差等問題。以下偽代碼相信大家非常熟悉,我們大部分項目的Controller接口都是這樣的。
@Controller
public class Controller {
@GetMapping("/query")
@ResponseBody
public Response query(Map<String, Object> paramMap) {
Response res = new Response();
try {
//1.校驗params參數(shù)合法性,包括非空校驗、長度校驗等
if (illegal(paramMap)) {
res.setCode(1);
res.setMsg("error");
return res;
}
//2.調(diào)用Service的一系列操作,得到查詢結(jié)果
Object data = service.query(params);
//3.將操作結(jié)果設(shè)置到res對象中
res.setData(data);
res.setCode(0);
res.setMsg("ok");
return res;
} catch (Exception e) {
//4.異常處理:一堆丑陋的try...catch,如果有錯誤碼的,還需要手工填充錯誤碼
res.setCode(1);
res.setMsg("error");
return res;
}
}
}
這段偽代碼存在什么樣的問題呢?
第一個問題,效率低下。 Controller層的代碼應(yīng)該盡量簡潔,上面的偽代碼其實只是為了將數(shù)據(jù)查詢的結(jié)果進行封裝,使其以統(tǒng)一的格式進行返回。例如以下格式的響應(yīng)體:
{
"code": 0,
"msg": "ok",
"data": {
"id": 1,
"name": "username"
}
}
查詢過程中如果發(fā)生異常,需要在Controller進行手工捕獲,根據(jù)捕獲的異常人工地設(shè)置錯誤碼,當(dāng)然,也用同樣的格式封裝錯誤碼進行返回。
可以看到,除了調(diào)用service層的query方法這一行,其他大部分的代碼都執(zhí)行進行結(jié)果的封裝,大量的冗余、低價值的代碼導(dǎo)致我們的開發(fā)活動效率很低。
第二個問題,重復(fù)勞動。 以上捕獲異常、封裝執(zhí)行結(jié)果的操作,每個接口都會進行一次,因此造成大量重復(fù)勞動。
第三個問題,可讀性低。 上面的核心代碼被淹沒在許多冗余代碼中,很難閱讀,如同大海撈針。
我們可以通過Graceful Response這個組件解決這樣的問題。
2. 快速入門
(1) 引入Graceful Response組件
Graceful Response已發(fā)布至maven中央倉庫,我們可以直接引入到項目中。
maven依賴如下:
<dependency>
<groupId>com.feiniaojin</groupId>
<artifactId>graceful-response</artifactId>
<version>{latest.version}</version>
</dependency>
Spring Boot版本 | Graceful Response最新版本 |
2.x | 3.2.1-boot2 |
3.x | 3.2.1-boot3 |
(2) 啟用Graceful Response
在啟動類中引入@EnableGracefulResponse注解,即可啟用Graceful Response組件。
@EnableGracefulResponse
@SpringBootApplication
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
(3) Controller層
引入Graceful Response后,我們不需要再手工進行查詢結(jié)果的封裝,直接返回實際結(jié)果即可,Graceful Response會自動完成封裝的操作。
Controller層示例如下:
@Controller
public class Controller {
@RequestMapping("/get")
@ResponseBody
public UserInfoView get(Long id) {
log.info("id={}", id);
return UserInfoView.builder().id(id).name("name" + id).build();
}
}
在示例代碼中,Controller層的方法直接返回了UserInfoView對象,沒有進行封裝的操作,但經(jīng)過Graceful Response處理后,我們還是得到了以下的響應(yīng)結(jié)果。
{
"status": {
"code": "0",
"msg": "ok"
},
"payload": {
"id": 1,
"name": "name1"
}
}
而對于命令操作(Command)盡量不返回數(shù)據(jù),因此command操作的方法的返回值應(yīng)該是void,Graceful Response對于對于返回值類型void的方法,也會自動進行封裝。
public class Controller {
@RequestMapping("/command")
@ResponseBody
public void command() {
//業(yè)務(wù)操作
}
}
成功調(diào)用該接口,將得到:
{
"status": {
"code": "200",
"msg": "success"
},
"payload": {}
}
(3) Service層
在引入Graceful Response前,有的開發(fā)者在定義Service層的方法時,為了在接口中返回異常碼,干脆直接將Service層方法定義為Response,淹沒了方法的正常返回值。
Response的代碼如下。
//lombok注解
@Data
public class Response {
private String code;
private String msg;
private Object data;
}
直接返回Response的Service層方法:
/**
* 直接返回Reponse的Service
* 不規(guī)范
*/
public interface Service {
public Reponse commandMethod(Command command);
}
Graceful Response引入@ExceptionMapper注解,通過該注解將異常和錯誤碼關(guān)聯(lián)起來,這樣Service方法就不需要再維護Response的響應(yīng)碼了,直接拋出業(yè)務(wù)異常,由Graceful Response進行異常和響應(yīng)碼的關(guān)聯(lián)。搜索我是程序汪公眾號,回復(fù)“面試寶典”,送你一份Java面試寶典
@ExceptionMapper的用法如下。
/**
* NotFoundException的定義,使用@ExceptionMapper注解修飾
* code:代表接口的異常碼
* msg:代表接口的異常提示
*/
@ExceptionMapper(code = "1404", msg = "找不到對象")
public class NotFoundException extends RuntimeException {
}
Service接口定義:
public interface QueryService {
UserInfoView queryOne(Query query);
}
Service接口實現(xiàn):
public class QueryServiceImpl implements QueryService {
@Resource
private UserInfoMapper mapper;
public UserInfoView queryOne(Query query) {
UserInfo userInfo = mapper.findOne(query.getId());
if (Objects.isNull(userInfo)) {
//這里直接拋自定義異常
throw new NotFoundException();
}
//……后續(xù)業(yè)務(wù)操作
}
}
當(dāng)Service層的queryOne方法拋出NotFoundException時,Graceful Response會進行異常捕獲,并將NotFoundException對應(yīng)的異常碼和異常信息封裝到統(tǒng)一的響應(yīng)對象中,最終接口返回以下JSON。
{
"status": {
"code": "1404",
"msg": "找不到對象"
},
"payload": {}
}
(5) 參數(shù)校驗
Graceful Response對JSR-303數(shù)據(jù)校驗規(guī)范和Hibernate Validator進行了增強,Graceful Response自身不提供參數(shù)校驗的功能,但是用戶使用了Hibernate Validator后,Graceful Response可以通過@ValidationStatusCode注解為參數(shù)校驗結(jié)果提供響應(yīng)碼,并將其統(tǒng)一封裝返回。
例如以下的UserInfoQuery:
@Data
public class UserInfoQuery {
@NotNull(message = "userName is null !")
@Length(min = 6, max = 12)
@ValidationStatusCode(code = "520")
private String userName;
}
- UserInfoQuery對象中定義了@NotNull和@Length兩個校驗規(guī)則,在未引入Graceful Response的情況下,會直接拋出異常;
- 在引入Graceful Response但是沒有加入@ValidationStatusCode注解的情況下,會以默認的錯誤碼進行返回;
在上面的UserInfoQuery中由于使用了@ValidationStatusCode注解,并指定異常碼為520,則當(dāng)userName字段任意校驗不通過時,都會使用異常碼520進行返回,如下:
{
"status": {
"code": "520",
"msg": "userName is null !"
},
"payload": {}
}
而對于Controller層直接校驗方法入?yún)⒌膱鼍?,Graceful Response也進行了增強,如以下Controller:
public class Controller {
@RequestMapping("/validateMethodParam")
@ResponseBody
@ValidationStatusCode(code = "1314")
public void validateMethodParam(
@NotNull(message = "userId不能為空") Long userId,
@NotNull(message = "userName不能為空") Long userName) {
//省略業(yè)務(wù)邏輯
}
}
如果該方法入?yún)⑿r炗|發(fā)了userId和userName的校驗異常,將以錯誤碼1314進行返回,如下:
{
"status": {
"code": "1314",
"msg": "userId不能為空"
},
"payload": {}
}
(6) 自定義Response格式
Graceful Response內(nèi)置了兩種風(fēng)格的響應(yīng)格式,并通過graceful-response.response-style進行配置。
graceful-response.response-style=0,或者不配置(默認情況),將以以下的格式進行返回:
{
"status": {
"code": 1007,
"msg": "有內(nèi)鬼,終止交易"
},
"payload": {
}
}
graceful-response.response-style=1,將以以下的格式進行返回:
{
"code": "1404",
"msg": "not found",
"data": {
}
}
如果這兩種格式均不滿足業(yè)務(wù)需要,Graceful Response也支持用戶自定義響應(yīng)體,關(guān)于自定義響應(yīng)體的技術(shù)實現(xiàn),請到自定義Response格式進行了解。
本項目提供的進階功能,包括:
- 第三方組件汽車(Swagger、執(zhí)行器等)
- 自定義響應(yīng)
- 異常請求放行
- 異常別名
- 常用配置項
目前該組件在GitHub上已經(jīng)有兩百多Star,很多朋友已經(jīng)開始用了,大家可以通過下方鏈接了解下:https://github.com/feiniaojin/graceful-response。