SpringBoot:如何優(yōu)雅地進(jìn)行參數(shù)傳遞、響應(yīng)數(shù)據(jù)封裝、異常處理?

作者:云深i不知處
blog.csdn.net/mu_wind/article/details/99960645
在項目開發(fā)中,接口與接口之間、前后端之間的數(shù)據(jù)傳輸都使用 JSON 格式。
1 fastjson使用
阿里巴巴的 fastjson是目前應(yīng)用最廣泛的JSON解析框架。本文也將使用fastjson。
1.1 引入依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
2 統(tǒng)一封裝返回數(shù)據(jù)
在web項目中,接口返回數(shù)據(jù)一般要包含狀態(tài)碼、信息、數(shù)據(jù)等,例如下面的接口示例:
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author guozhengMu
* @version 1.0
* @date 2019/8/21 14:55
* @description
* @modify
*/
@RestController
@RequestMapping(value = "/test", method = RequestMethod.GET)
public class TestController {
@RequestMapping("/json")
public JSONObject test() {
JSONObject result = new JSONObject();
try {
// 業(yè)務(wù)邏輯代碼
result.put("code", 0);
result.put("msg", "操作成功!");
result.put("data", "測試數(shù)據(jù)");
} catch (Exception e) {
result.put("code", 500);
result.put("msg", "系統(tǒng)異常,請聯(lián)系管理員!");
}
return result;
}
}
這樣的話,每個接口都這樣處理,非常麻煩,需要一種更優(yōu)雅的實(shí)現(xiàn)方式。
2.1 定義統(tǒng)一的JSON結(jié)構(gòu)
統(tǒng)一的 JSON 結(jié)構(gòu)中屬性包括數(shù)據(jù)、狀態(tài)碼、提示信息,其他項可以自己根據(jù)需要添加。一般來說,應(yīng)該有默認(rèn)的返回結(jié)構(gòu),也應(yīng)該有用戶指定的返回結(jié)構(gòu)。由于返回數(shù)據(jù)類型無法確定,需要使用泛型,代碼如下:
public class ResponseInfo<T> {
/**
* 狀態(tài)碼
*/
protected String code;
/**
* 響應(yīng)信息
*/
protected String msg;
/**
* 返回數(shù)據(jù)
*/
private T data;
/**
* 若沒有數(shù)據(jù)返回,默認(rèn)狀態(tài)碼為 0,提示信息為“操作成功!”
*/
public ResponseInfo() {
this.code = 0;
this.msg = "操作成功!";
}
/**
* 若沒有數(shù)據(jù)返回,可以人為指定狀態(tài)碼和提示信息
* @param code
* @param msg
*/
public ResponseInfo(String code, String msg) {
this.code = code;
this.msg = msg;
}
/**
* 有數(shù)據(jù)返回時,狀態(tài)碼為 0,默認(rèn)提示信息為“操作成功!”
* @param data
*/
public ResponseInfo(T data) {
this.data = data;
this.code = 0;
this.msg = "操作成功!";
}
/**
* 有數(shù)據(jù)返回,狀態(tài)碼為 0,人為指定提示信息
* @param data
* @param msg
*/
public ResponseInfo(T data, String msg) {
this.data = data;
this.code = 0;
this.msg = msg;
}
// 省略 get 和 set 方法
}
2.2 使用統(tǒng)一的JSON結(jié)構(gòu)
我們封裝了統(tǒng)一的返回數(shù)據(jù)結(jié)構(gòu)后,在接口中就可以直接使用了。如下:
import com.example.demo.model.ResponseInfo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author guozhengMu
* @version 1.0
* @date 2019/8/21 14:55
* @description
* @modify
*/
@RestController
@RequestMapping(value = "/test", method = RequestMethod.GET)
public class TestController {
@RequestMapping("/json")
public ResponseInfo test() {
try {
// 模擬異常業(yè)務(wù)代碼
int num = 1 / 0;
return new ResponseInfo("測試數(shù)據(jù)");
} catch (Exception e) {
return new ResponseInfo(500, "系統(tǒng)異常,請聯(lián)系管理員!");
}
}
}
如上,接口的返回數(shù)據(jù)處理便優(yōu)雅了許多。針對上面接口做個測試,啟動項目,通過瀏覽器訪問:localhost:8096/test/json,得到響應(yīng)結(jié)果:
{"code":500,"msg":"系統(tǒng)異常,請聯(lián)系管理員!","data":null}
3 全局異常處理
3.1 系統(tǒng)定義異常處理
新建一個 ExceptionHandlerAdvice 全局異常處理類,然后加上 @RestControllerAdvice 注解即可攔截項目中拋出的異常,如下代碼中包含了幾個異常處理,如參數(shù)格式異常、參數(shù)缺失、系統(tǒng)異常等,見下例:
@RestControllerAdvice
@Slf4j
public class ExceptionHandlerAdvice {
// 參數(shù)格式異常處理
@ExceptionHandler({IllegalArgumentException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseInfo badRequestException(IllegalArgumentException exception) {
log.error("參數(shù)格式不合法:" + e.getMessage());
return new ResponseInfo(HttpStatus.BAD_REQUEST.value() + "", "參數(shù)格式不符!");
}
// 權(quán)限不足異常處理
@ExceptionHandler({AccessDeniedException.class})
@ResponseStatus(HttpStatus.FORBIDDEN)
public ResponseInfo badRequestException(AccessDeniedException exception) {
return new ResponseInfo(HttpStatus.FORBIDDEN.value() + "", exception.getMessage());
}
// 參數(shù)缺失異常處理
@ExceptionHandler({MissingServletRequestParameterException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseInfo badRequestException(Exception exception) {
return new ResponseInfo(HttpStatus.BAD_REQUEST.value() + "", "缺少必填參數(shù)!");
}
// 空指針異常
@ExceptionHandler(NullPointerException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseInfo handleTypeMismatchException(NullPointerException ex) {
log.error("空指針異常,{}", ex.getMessage());
return new JsonResult("500", "空指針異常");
}
@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public JsonResult handleUnexpectedServer(Exception ex) {
log.error("系統(tǒng)異常:", ex);
return new JsonResult("500", "系統(tǒng)發(fā)生異常,請聯(lián)系管理員");
}
// 系統(tǒng)異常處理
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseInfo exception(Throwable throwable) {
log.error("系統(tǒng)異常", throwable);
return new ResponseInfo(HttpStatus.INTERNAL_SERVER_ERROR.value() + "系統(tǒng)異常,請聯(lián)系管理員!");
}
}
@RestControllerAdvice 注解包含了 @Component 注解,說明在 Spring Boot 啟動時,也會把該類作為組件交給 Spring 來管理。 @RestControllerAdvice 注解包含了 @ResponseBody 注解,為了異常處理完之后給調(diào)用方輸出一個 JSON 格式的封裝數(shù)據(jù)。 @RestControllerAdvice 注解還有個 basePackages 屬性,該屬性用來攔截哪個包中的異常信息,一般我們不指定這個屬性,我們攔截項目工程中的所有異常。 在方法上通過 @ExceptionHandler 注解來指定具體的異常,然后在方法中處理該異常信息,最后將結(jié)果通過統(tǒng)一的 JSON 結(jié)構(gòu)體返回給調(diào)用者。 但在項目中,我們一般都會比較詳細(xì)地去攔截一些常見異常,攔截 Exception 雖然可以一勞永逸,但是不利于我們?nèi)ヅ挪榛蛘叨ㄎ粏栴}。實(shí)際項目中,可以把攔截 Exception 異常寫在 GlobalExceptionHandler 最下面,如果都沒有找到,最后再攔截一下 Exception 異常,保證輸出信息友好。
下面我們通過一個接口來進(jìn)行測試:
@RestController
@RequestMapping(value = "/test", method = RequestMethod.POST)
public class TestController {
@RequestMapping("/json")
public ResponseInfo test(@RequestParam String userName, @RequestParam String password) {
try {
String data = "登錄用戶:" + userName + ",密碼:" + password;
return new ResponseInfo("0", "操作成功!", data);
} catch (Exception e) {
return new ResponseInfo("500", "系統(tǒng)異常,請聯(lián)系管理員!");
}
}
}
接口調(diào)用,password這項故意空缺:

SpringBoot+Gradle+ MyBatisPlus3.x搭建企業(yè)級的后臺分離框架(實(shí)戰(zhàn)版)
springboot+redis+Interceptor+自定義annotation實(shí)現(xiàn)接口自動冪等

