在分佈式、微服務盛行的今天,絕大部分項目都採用的微服務框架,先後端分離方式。前端和後端進行交互,前端按照約定請求URL
路徑,並傳入相關參數,後端服務器接收請求,進行業務處理,返回數據給前端。html
因此統一接口的返回值,保證接口返回值的冪等性很重要,本文主要介紹博主當前使用的結果集。前端
{
# 是否響應成功
success: true,
# 響應狀態碼
code: 200,
# 響應數據
data: Object
# 返回錯誤信息
message: "",
}
複製代碼
public enum ResultCodeEnum {
/*** 通用部分 100 - 599***/
// 成功請求
SUCCESS(200, "successful"),
// 重定向
REDIRECT(301, "redirect"),
// 資源未找到
NOT_FOUND(404, "not found"),
// 服務器錯誤
SERVER_ERROR(500,"server error"),
/*** 這裏能夠根據不一樣模塊用不一樣的區級分開錯誤碼,例如: ***/
// 1000~1999 區間表示用戶模塊錯誤
// 2000~2999 區間表示訂單模塊錯誤
// 3000~3999 區間表示商品模塊錯誤
// 。。。
;
/** * 響應狀態碼 */
private Integer code;
/** * 響應信息 */
private String message;
ResultCodeEnum(Integer code, String msg) {
this.code = code;
this.message = msg;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
複製代碼
code
:響應狀態碼通常小夥伴們是在開發的時候須要什麼,就添加什麼。可是,爲了規範,咱們應當參考HTTP
請求返回的狀態碼。java
code區間 | 類型 | 含義 | |
---|---|---|---|
1** | 100-199 | 信息 | 服務器接收到請求,須要請求者繼續執行操做 |
2** | 200-299 | 成功 | 請求被成功接收並處理 |
3** | 300-399 | 重定向 | 須要進一步的操做以完成請求 |
4** | 400-499 | 客戶端錯誤 | 請求包含語法錯誤或沒法完成請求 |
5** | 500-599 | 服務器錯誤 | 服務器在處理的時候發生錯誤 |
常見的HTTP
狀態碼:git
200
- 請求成功;301
- 資源(網頁等)被永久轉移到其它URL
;404
- 請求的資源(網頁等)不存在;500
- 內部服務器錯誤。message
:錯誤信息在發生錯誤時,如何友好的進行提示?github
code
給予對應的錯誤碼定位;message
中,便於接口調用者更詳細的瞭解錯誤。public class HttpResult <T> implements Serializable {
/** * 是否響應成功 */
private Boolean success;
/** * 響應狀態碼 */
private Integer code;
/** * 響應數據 */
private T data;
/** * 錯誤信息 */
private String message;
// 構造器開始
/** * 無參構造器(構造器私有,外部不能夠直接建立) */
private HttpResult() {
this.code = 200;
this.success = true;
}
/** * 有參構造器 * @param obj */
private HttpResult(T obj) {
this.code = 200;
this.data = obj;
this.success = true;
}
/** * 有參構造器 * @param resultCode */
private HttpResult(ResultCodeEnum resultCode) {
this.success = false;
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
// 構造器結束
/** * 通用返回成功(沒有返回結果) * @param <T> * @return */
public static<T> HttpResult<T> success(){
return new HttpResult();
}
/** * 返回成功(有返回結果) * @param data * @param <T> * @return */
public static<T> HttpResult<T> success(T data){
return new HttpResult<T>(data);
}
/** * 通用返回失敗 * @param resultCode * @param <T> * @return */
public static<T> HttpResult<T> failure(ResultCodeEnum resultCode){
return new HttpResult<T>(resultCode);
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "HttpResult{" +
"success=" + success +
", code=" + code +
", data=" + data +
", message='" + message + '\'' +
'}';
}
}
複製代碼
說明:spring
success
是一個Boolean
值,經過這個值,能夠直接觀察到該次請求是否成功;data
表示響應數據,用於請求成功後,返回客戶端須要的數據。@RestController
@RequestMapping("/httpRest")
@Api(tags = "統一結果測試")
public class HttpRestController {
@ApiOperation(value = "通用返回成功(沒有返回結果)", httpMethod = "GET")
@GetMapping("/success")
public HttpResult success(){
return HttpResult.success();
}
@ApiOperation(value = "返回成功(有返回結果)", httpMethod = "GET")
@GetMapping("/successWithData")
public HttpResult successWithData(){
return HttpResult.success("風塵博客");
}
@ApiOperation(value = "通用返回失敗", httpMethod = "GET")
@GetMapping("/failure")
public HttpResult failure(){
return HttpResult.failure(ResultCodeEnum.NOT_FOUND);
}
}
複製代碼
這裏
Swagger
以及SpringMVC
的配置就沒貼出來了,詳見Github 示例代碼。後端
http://localhost:8080/swagger-ui.html#/api
{
"code": 200,
"success": true
}
複製代碼
{
"code": 200,
"data": "風塵博客",
"success": true
}
複製代碼
{
"code": 404,
"message": "not found",
"success": false
}
複製代碼
使用統一返回結果時,還有一種狀況,就是程序的報錯是因爲運行時異常致使的結果,有些異常是咱們在業務中拋出的,有些是沒法提早預知。springboot
所以,咱們須要定義一個統一的全局異常,在Controller
捕獲全部異常,而且作適當處理,並做爲一種結果返回。服務器
TokenVerificationException
),捕獲針對項目或業務的異常;@ExceptionHandler
註解捕獲自定義異常和通用異常;@ControllerAdvice
集成@ExceptionHandler
的方法到一個類中;public class TokenVerificationException extends RuntimeException {
/** * 錯誤碼 */
protected Integer code;
protected String msg;
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
/** * 有參構造器,返回碼在枚舉類中,這裏能夠指定錯誤信息 * @param msg */
public TokenVerificationException(String msg) {
super(msg);
}
}
複製代碼
@ControllerAdvice
註解是一種做用於控制層的切面通知(Advice
),可以將通用的@ExceptionHandler
、@InitBinder
和@ModelAttributes
方法收集到一個類型,並應用到全部控制器上。
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/** * 異常捕獲 * @param e 捕獲的異常 * @return 封裝的返回對象 **/
@ExceptionHandler(Exception.class)
public HttpResult handlerException(Exception e) {
ResultCodeEnum resultCodeEnum;
// 自定義異常
if (e instanceof TokenVerificationException) {
resultCodeEnum = ResultCodeEnum.TOKEN_VERIFICATION_ERROR;
resultCodeEnum.setMessage(getConstraintViolationErrMsg(e));
log.error("tokenVerificationException:{}", resultCodeEnum.getMessage());
}else {
// 其餘異常,當咱們定義了多個異常時,這裏能夠增長判斷和記錄
resultCodeEnum = ResultCodeEnum.SERVER_ERROR;
resultCodeEnum.setMessage(e.getMessage());
log.error("common exception:{}", JSON.toJSONString(e));
}
return HttpResult.failure(resultCodeEnum);
}
/** * 獲取錯誤信息 * @param ex * @return */
private String getConstraintViolationErrMsg(Exception ex) {
// validTest1.id: id必須爲正數
// validTest1.id: id必須爲正數, validTest1.name: 長度必須在有效範圍內
String message = ex.getMessage();
try {
int startIdx = message.indexOf(": ");
if (startIdx < 0) {
startIdx = 0;
}
int endIdx = message.indexOf(", ");
if (endIdx < 0) {
endIdx = message.length();
}
message = message.substring(startIdx, endIdx);
return message;
} catch (Throwable throwable) {
log.info("ex caught", throwable);
return message;
}
}
}
複製代碼
@RestControllerAdvice
,等同於@ControllerAdvice
+ @ResponseBody
@RestController
@RequestMapping("/exception")
@Api(tags = "異常測試接口")
public class ExceptionRestController {
@ApiOperation(value = "業務異常(token 異常)", httpMethod = "GET")
@GetMapping("/token")
public HttpResult token() {
// 模擬業務層拋出 token 異常
throw new TokenVerificationException("token 已通過期");
}
@ApiOperation(value = "其餘異常", httpMethod = "GET")
@GetMapping("/errorException")
public HttpResult errorException() {
//這裏故意形成一個其餘異常,而且不進行處理
Integer.parseInt("abc123");
return HttpResult.success();
}
}
複製代碼
http://localhost:8080/swagger-ui.html#/
{
"code": 500,
"message": "For input string: \"abc123\"",
"success": false
}
複製代碼
{
"code": 4000,
"message": "token 已通過期",
"success": false
}
複製代碼
@RestControllerAdvice
和@ExceptionHandler
會捕獲全部Rest
接口的異常並封裝成咱們定義的HttpResult
的結果集返回,可是:處理不了攔截器裏的異常
沒有哪種方案是適用於各類狀況的,如:分頁狀況,還能夠增長返回分頁結果的靜態方案,具體實現,這裏就不展現了。因此,適合本身的,具備必定可讀性都是很好的,歡迎持不一樣意見的大佬給出意見建議。