前言
??緣由
博友的需求就是我最大的動(dòng)力
博友一說(shuō)話,本狗笑哈哈。博友要我寫(xiě)啥,我就寫(xiě)啥。
特來(lái)一篇關(guān)于SpringBoot接口返回結(jié)果及異常統(tǒng)一處理,雖說(shuō)封不封裝都能用,但咱后端也得給前端小姐姐留個(gè)好印象不是。項(xiàng)目前后端分離,規(guī)范的數(shù)據(jù)傳輸格式,讓REST風(fēng)格的API具有簡(jiǎn)單、易讀、易用的特點(diǎn)。不僅代碼優(yōu)美,也可以讓帶刀的前端小姐姐變得更漂亮。以下例子參考多個(gè)實(shí)際項(xiàng)目,最終總結(jié)來(lái)跟大家進(jìn)行分享,大佬勿噴。
??主要目標(biāo)
實(shí)現(xiàn)2大重點(diǎn)
1. 統(tǒng)一接口返回結(jié)果
2. 配置全局異常處理
正文
??一.統(tǒng)一接口返回結(jié)果
前端接口請(qǐng)求后臺(tái)端,后端將返回結(jié)果統(tǒng)一封裝。提高交互的規(guī)范性及通用性,也提高了前后端聯(lián)調(diào)效率。前端根據(jù)規(guī)范格式返回結(jié)構(gòu)體進(jìn)行統(tǒng)一映射處理,就避免一個(gè)接口一個(gè)返回格式的問(wèn)題。
1.統(tǒng)一封裝結(jié)果包含如下參數(shù)
- 狀態(tài)碼:code
- 狀態(tài)信息:status
- 返回信息:message
- 數(shù)據(jù):data
2.統(tǒng)一封裝結(jié)果包含如下方法
- 全參數(shù)方法
- 成功返回(無(wú)參)
- 成功返回(枚舉)
- 成功返回(狀態(tài)碼+返回信息)
- 成功返回(返回信息 + 數(shù)據(jù))
- 成功返回(狀態(tài)碼+返回信息+數(shù)據(jù))
- 成功返回(數(shù)據(jù))
- 成功返回(返回信息)
- 失敗返回(無(wú)參)
- 失敗返回(枚舉)
- 失敗返回(狀態(tài)碼+返回信息)
- 失敗返回(返回信息+數(shù)據(jù))
- 失敗返回(狀態(tài)碼+返回信息+數(shù)據(jù))
- 失敗返回(數(shù)據(jù))
- 失敗返回(返回信息)
3.ResponseResult封裝返回結(jié)果代碼
package net.javadog.common.result;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.javadog.common.enums.HttpStatusEnum;
/**
* 返回結(jié)果集
*
* @author javadog
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("統(tǒng)一結(jié)果集處理器")
public class ResponseResult<T> {
/**
* 狀態(tài)碼
*/
@ApiModelProperty(value = "狀態(tài)碼")
private Integer code;
/**
* 狀態(tài)信息
*/
@ApiModelProperty(value = "狀態(tài)信息")
private Boolean status;
/**
* 返回信息
*/
@ApiModelProperty(value = "返回信息")
private String message;
/**
* 數(shù)據(jù)
*/
@ApiModelProperty(value = "數(shù)據(jù)")
private T data;
/**
* 全參數(shù)方法
*
* @param code 狀態(tài)碼
* @param status 狀態(tài)
* @param message 返回信息
* @param data 返回?cái)?shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
private static <T> ResponseResult<T> response(Integer code, Boolean status, String message, T data) {
ResponseResult<T> responseResult = new ResponseResult<>();
responseResult.setCode(code);
responseResult.setStatus(status);
responseResult.setMessage(message);
responseResult.setData(data);
return responseResult;
}
/**
* 全參數(shù)方法
*
* @param code 狀態(tài)碼
* @param status 狀態(tài)
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
private static <T> ResponseResult<T> response(Integer code, Boolean status, String message) {
ResponseResult<T> responseResult = new ResponseResult<>();
responseResult.setCode(code);
responseResult.setStatus(status);
responseResult.setMessage(message);
return responseResult;
}
/**
* 成功返回(無(wú)參)
*
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success() {
return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), null);
}
/**
* 成功返回(枚舉參數(shù))
*
* @param httpResponseEnum 枚舉參數(shù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(HttpStatusEnum httpResponseEnum) {
return response(httpResponseEnum.getCode(), true, httpResponseEnum.getMessage());
}
/**
* 成功返回(狀態(tài)碼+返回信息)
*
* @param code 狀態(tài)碼
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(Integer code, String message) {
return response(code, true, message);
}
/**
* 成功返回(返回信息 + 數(shù)據(jù))
*
* @param message 返回信息
* @param data 數(shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(String message, T data) {
return response(HttpStatusEnum.SUCCESS.getCode(), true, message, data);
}
/**
* 成功返回(狀態(tài)碼+返回信息+數(shù)據(jù))
*
* @param code 狀態(tài)碼
* @param message 返回信息
* @param data 數(shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(Integer code, String message, T data) {
return response(code, true, message, data);
}
/**
* 成功返回(數(shù)據(jù))
*
* @param data 數(shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(T data) {
return response(HttpStatusEnum.SUCCESS.getCode(), true, HttpStatusEnum.SUCCESS.getMessage(), data);
}
/**
* 成功返回(返回信息)
*
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> success(String message) {
return response(HttpStatusEnum.SUCCESS.getCode(), true, message, null);
}
/**
* 失敗返回(無(wú)參)
*
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail() {
return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), null);
}
/**
* 失敗返回(枚舉)
*
* @param httpResponseEnum 枚舉
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(HttpStatusEnum httpResponseEnum) {
return response(httpResponseEnum.getCode(), false, httpResponseEnum.getMessage());
}
/**
* 失敗返回(狀態(tài)碼+返回信息)
*
* @param code 狀態(tài)碼
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(Integer code, String message) {
return response(code, false, message);
}
/**
* 失敗返回(返回信息+數(shù)據(jù))
*
* @param message 返回信息
* @param data 數(shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(String message, T data) {
return response(HttpStatusEnum.ERROR.getCode(), false, message, data);
}
/**
* 失敗返回(狀態(tài)碼+返回信息+數(shù)據(jù))
*
* @param code 狀態(tài)碼
* @param message 返回消息
* @param data 數(shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(Integer code, String message, T data) {
return response(code, false, message, data);
}
/**
* 失敗返回(數(shù)據(jù))
*
* @param data 數(shù)據(jù)
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(T data) {
return response(HttpStatusEnum.ERROR.getCode(), false, HttpStatusEnum.ERROR.getMessage(), data);
}
/**
* 失敗返回(返回信息)
*
* @param message 返回信息
* @param <T> 泛型
* @return {@link ResponseResult<T>}
*/
public static <T> ResponseResult<T> fail(String message) {
return response(HttpStatusEnum.ERROR.getCode(), false, message, null);
}
}
4.HttpStatusEnum返回結(jié)果代碼
package net.javadog.common.enums;
import lombok.Getter;
/**
* Http狀態(tài)返回枚舉
*
* @author javadog
**/
@Getter
public enum HttpStatusEnum {
/**
* 操作成功
*/
SUCCESS(200, "操作成功"),
/**
* 對(duì)象創(chuàng)建成功
*/
CREATED(201, "對(duì)象創(chuàng)建成功"),
/**
* 請(qǐng)求已經(jīng)被接受
*/
ACCEPTED(202, "請(qǐng)求已經(jīng)被接受"),
/**
* 操作已經(jīng)執(zhí)行成功,但是沒(méi)有返回?cái)?shù)據(jù)
*/
NO_CONTENT(204, "操作已經(jīng)執(zhí)行成功,但是沒(méi)有返回?cái)?shù)據(jù)"),
/**
* 資源已被移除
*/
MOVED_PERM(301, "資源已被移除"),
/**
* 重定向
*/
SEE_OTHER(303, "重定向"),
/**
* 資源沒(méi)有被修改
*/
NOT_MODIFIED(304, "資源沒(méi)有被修改"),
/**
* 參數(shù)列表錯(cuò)誤(缺少,格式不匹配)
*/
BAD_REQUEST(400, "參數(shù)列表錯(cuò)誤(缺少,格式不匹配)"),
/**
* 未授權(quán)
*/
UNAUTHORIZED(401, "未授權(quán)"),
/**
* 訪問(wèn)受限,授權(quán)過(guò)期
*/
FORBIDDEN(403, "訪問(wèn)受限,授權(quán)過(guò)期"),
/**
* 資源,服務(wù)未找到
*/
NOT_FOUND(404, "資源,服務(wù)未找!"),
/**
* 不允許的http方法
*/
BAD_METHOD(405, "不允許的http方法"),
/**
* 資源沖突,或者資源被鎖
*/
CONFLICT(409, "資源沖突,或者資源被鎖"),
/**
* 不支持的數(shù)據(jù),媒體類型
*/
UNSUPPORTED_TYPE(415, "不支持的數(shù)據(jù),媒體類型"),
/**
* 系統(tǒng)內(nèi)部錯(cuò)誤
*/
ERROR(500, "系統(tǒng)內(nèi)部錯(cuò)誤"),
/**
* 接口未實(shí)現(xiàn)
*/
NOT_IMPLEMENTED(501, "接口未實(shí)現(xiàn)"),
/**
* 系統(tǒng)警告消息
*/
WARN(601,"系統(tǒng)警告消息");
private final Integer code;
private final String message;
HttpStatusEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
5.SysLoginController實(shí)操調(diào)試
/**
* 登錄驗(yàn)證
*
* @author javadog
*/
@RestController
public class SysLoginController {
@Resource
private SysLoginService loginService;
/**
* 登錄方法
*
* @param loginRequest 登錄信息
* @return 結(jié)果
*/
@PostMapping("/login")
public ResponseResult login(@RequestBody LoginRequest loginRequest) {
// 生成令牌
String token = loginService.login(loginRequest.getUsername(), loginRequest.getPassword());
return ResponseResult.success(token);
}
}
??二.配置全局異常處理
在使用上方統(tǒng)一返回結(jié)果的加持下,規(guī)范的同時(shí)也不可避免程序異常情況。因此我們必須提前定義一個(gè)統(tǒng)一全局異常來(lái)捕獲這些異常信息,并將其當(dāng)作一種結(jié)果返回給控制層,友好的處理異常信息。
1.全局異常處理注解
@RestControllerAdvice
@RestControllerAdvice什么是?
-
@RestControllerAdvice注解是Spring MVC和Spring Boot應(yīng)用程序中用于定義全局異常處理類的注解,它是@ControllerAdvice注解的特殊版本,是一個(gè)組合注解,由@ControllerAdvice、@ResponseBody組成。
-
@ControllerAdvice繼承了@Component,因此@RestControllerAdvice本質(zhì)上是個(gè)組件,用于定義@ExceptionHandler,@InitBinder和@ModelAttribute方法,適用于所有使用@RequestMapping方法。
@RestControllerAdvice有什么特點(diǎn)?
- 注解@RestControllerAdvice的類的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。
- @RestControllerAdvice注解將作用于所有注解了@RequestMapping的控制器的方法上。
- @ExceptionHandler:用于指定異常處理方法,與@RestControllerAdvice配合使用時(shí),用于全局處理控制器里的異常。
- @InitBinder:用來(lái)設(shè)置WebDataBinder,用于自動(dòng)綁定前臺(tái)請(qǐng)求參數(shù)到Model中。
- @ModelAttribute:本來(lái)作用是綁定鍵值對(duì)到Model中,當(dāng)與@ControllerAdvice配合使用時(shí),可以讓全局的@RequestMapping都能獲得在此處設(shè)置的鍵值對(duì)
2.@ExceptionHandler常用異常攔截
- 權(quán)限校驗(yàn)異常:AccessDeniedException(spring-security中異常)
- 請(qǐng)求方式不支持:HttpRequestMethodNotSupportedException
- 業(yè)務(wù)異常:ServiceException(自己業(yè)務(wù)定義異常)
- 攔截未知的運(yùn)行時(shí)異常:RuntimeException
- 系統(tǒng)異常:Exception
- 自定義驗(yàn)證異常:BindException
- 自定義驗(yàn)證異常:MethodArgumentNotValidException
3.全局異常處理代碼
package net.javadog.common.exception;
import cn.hutool.core.util.ObjectUtil;
import net.javadog.common.enums.HttpStatusEnum;
import net.javadog.common.result.ResponseResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
/**
* 異常處理 配置
*
* @author javadog
*/
@RestControllerAdvice
public class GlobalException {
private static final Logger log = LoggerFactory.getLogger(GlobalException.class);
/**
* 權(quán)限校驗(yàn)異常
*/
@ExceptionHandler(AccessDeniedException.class)
public ResponseResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("請(qǐng)求地址'{}',權(quán)限校驗(yàn)失敗'{}'", requestURI, e.getMessage());
return ResponseResult.fail(HttpStatusEnum.FORBIDDEN.getCode(), HttpStatusEnum.FORBIDDEN.getMessage());
}
/**
* 請(qǐng)求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("請(qǐng)求地址'{}',不支持'{}'請(qǐng)求", requestURI, e.getMethod());
return ResponseResult.fail(e.getMessage());
}
/**
* 業(yè)務(wù)異常
*/
@ExceptionHandler(ServiceException.class)
public ResponseResult handleServiceException(ServiceException e) {
log.error(e.getMessage(), e);
Integer code = e.getCode();
return ObjectUtil.isNotNull(code) ? ResponseResult.fail(code, e.getMessage()) : ResponseResult.fail(e.getMessage());
}
/**
* 攔截未知的運(yùn)行時(shí)異常
*/
@ExceptionHandler(RuntimeException.class)
public ResponseResult handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("請(qǐng)求地址'{}',發(fā)生未知異常.", requestURI, e);
return ResponseResult.fail(e.getMessage());
}
/**
* 系統(tǒng)異常
*/
@ExceptionHandler(Exception.class)
public ResponseResult handleException(Exception e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("請(qǐng)求地址'{}',發(fā)生系統(tǒng)異常.", requestURI, e);
return ResponseResult.fail(e.getMessage());
}
/**
* 自定義驗(yàn)證異常
*/
@ExceptionHandler(BindException.class)
public ResponseResult handleBindException(BindException e) {
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return ResponseResult.fail(message);
}
/**
* 自定義驗(yàn)證異常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage(), e);
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return ResponseResult.fail(message);
}
}
4.全局異常處理實(shí)操調(diào)試
總結(jié)
本文通過(guò)多個(gè)SpringBoot實(shí)際項(xiàng)目進(jìn)行歸納整理,從統(tǒng)一接口返回結(jié)果和配置全局異常處理兩個(gè)方面出發(fā),介紹如何優(yōu)雅的封裝規(guī)范后端接口輸出,詳細(xì)刨析@RestControllerAdvice和@ExceptionHandler注解及使用方式,增加后端服務(wù)健壯性和與前端對(duì)接規(guī)范性,希望由此化繁為簡(jiǎn),能夠幫到博友分毫。
??猜你想問(wèn)
如何與狗哥聯(lián)系進(jìn)行探討
關(guān)注公眾號(hào)【JavaDog程序狗】
公眾號(hào)回復(fù)【入群】或者【加入】,便可成為【程序員學(xué)習(xí)交流摸魚(yú)群】的一員,問(wèn)題隨便問(wèn),牛逼隨便吹。
此群優(yōu)勢(shì):
- 技術(shù)交流隨時(shí)溝通
- 任何私活資源免費(fèi)分享
- 實(shí)時(shí)科技動(dòng)態(tài)搶先知曉
- CSDN資源免費(fèi)下載
- 本人一切源碼均群內(nèi)開(kāi)源,可免費(fèi)使用
2.踩踩狗哥博客
javadog.net
大家可以在里面留言,隨意發(fā)揮,有問(wèn)必答
??猜你喜歡
文章推薦
【項(xiàng)目實(shí)戰(zhàn)】SpringBoot+uniapp+uview2打造H5+小程序+APP入門學(xué)習(xí)的聊天小項(xiàng)目
【項(xiàng)目實(shí)戰(zhàn)】SpringBoot+uniapp+uview2打造一個(gè)企業(yè)黑紅名單吐槽小程序
【模塊分層】還不會(huì)SpringBoot項(xiàng)目模塊分層?來(lái)這手把手教你!
【ChatGPT】手摸手,帶你玩轉(zhuǎn)ChatGPT
【ChatGPT】SpringBoot+uniapp+uview2對(duì)接OpenAI,帶你開(kāi)發(fā)玩轉(zhuǎn)ChatGPT文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-709875.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-709875.html
到了這里,關(guān)于【規(guī)范】SpringBoot接口返回結(jié)果及異常統(tǒng)一處理,這樣封裝才優(yōu)雅的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!