深入了解SpringBoot中的統(tǒng)一返回和統(tǒng)一異常處理
上篇文章我們學(xué)習了基于 Token 認證的登錄功能實現(xiàn),分別使用了過濾器和攔截器去實現(xiàn)登錄功能,這篇文章我們來學(xué)習項目中常用的統(tǒng)一返回結(jié)果和統(tǒng)一異常處理。
一、統(tǒng)一返回結(jié)果
前后端分離時代,如果沒有一個統(tǒng)一的數(shù)據(jù)返回格式,前后端調(diào)試時,前端開發(fā)人員會罵娘的,同時約定相同的返回接口數(shù)據(jù)也有助于高效的工作。
通常統(tǒng)一返回的格式包含三部分:
code:狀態(tài)碼,一般200表示正常message:狀態(tài)碼對應(yīng)的描述。data:返回的數(shù)據(jù)
1.1、統(tǒng)一返回對象
新建一個 SpringBoot 項目定義通用的響應(yīng)對象
package com.laoxiang.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
/**
* @author db
* @version 1.0
* @description ResponseResult
* @since 2023/7/12
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> implements Serializable {
private static final long serialVersionUID = 2233637474601103587L;
// 接口響應(yīng)狀態(tài)碼
private Integer code;
// 接口響應(yīng)信息
private String msg;
// 接口響應(yīng)的數(shù)據(jù)
private T data;
public ResponseResult() {
this.code = AppHttpCodeEnum.SUCCESS.getCode();
this.msg = AppHttpCodeEnum.SUCCESS.getMsg();
}
public ResponseResult(Integer code, T data) {
this.code = code;
this.data = data;
}
public ResponseResult(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResponseResult(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static ResponseResult errorResult(int code, String msg) {
ResponseResult result = new ResponseResult();
return result.error(code, msg);
}
public static ResponseResult okResult() {
ResponseResult result = new ResponseResult();
return result;
}
public static ResponseResult okResult(int code, String msg) {
ResponseResult result = new ResponseResult();
return result.ok(code, null, msg);
}
public static ResponseResult okResult(Object data) {
ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg());
if (data != null) {
result.setData(data);
}
return result;
}
public static ResponseResult errorResult(AppHttpCodeEnum enums) {
return setAppHttpCodeEnum(enums, enums.getMsg());
}
public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg) {
return setAppHttpCodeEnum(enums, msg);
}
public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums) {
return okResult(enums.getCode(), enums.getMsg());
}
private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg) {
return okResult(enums.getCode(), msg);
}
public ResponseResult<?> error(Integer code, String msg) {
this.code = code;
this.msg = msg;
return this;
}
public ResponseResult<?> ok(Integer code, T data) {
this.code = code;
this.data = data;
return this;
}
public ResponseResult<?> ok(Integer code, T data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
return this;
}
public ResponseResult<?> ok(T data) {
this.data = data;
return this;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
1.2、系統(tǒng)常量
上面代碼中提到了常量 AppHttpCodeEnum,定義自己的應(yīng)用程序特定狀態(tài)碼,來表示具體的情況。通過定義的狀態(tài)碼就可以知道具體代表什么意思。
package com.laoxiang.utils;
/**
* @author db
* @version 1.0
* @description AppHttpCodeEnum
* @since 2023/7/12
*/
public enum AppHttpCodeEnum {
// 成功
SUCCESS(200,"操作成功"),
// 失敗
ERROR(500,"操作失敗"),
int code;
String msg;
AppHttpCodeEnum(int code, String errorMessage){
this.code = code;
this.msg = errorMessage;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
1.3、web 層統(tǒng)一響應(yīng)結(jié)果
下面的例子,可以看到在實際項目中接口返回值。

二、統(tǒng)一異常處理
程序開發(fā)中不可避免的會遇到異?,F(xiàn)象,如果不進行處理,遇到異常時,開發(fā)人員不能清晰地處理問題,或者使用 try{...}catch{...} 代碼塊進行處理,但是滿屏的 try{...}catch{...} 代碼塊造成代碼過于臃腫。
有沒有更好的處理方式呢?全局統(tǒng)一異常處理應(yīng)運而生。@ControllerAdvice 注解搭配 @ExceptionHandler 進行全局統(tǒng)一異常處理。
2.1、@ControllerAdvice注解
@ControllerAdvice注解:用于聲明一個全局控制器 Advice,相當于把 @ExceptionHandler、@InitBinder 和 @ModelAttribute 注解的方法集中到一個地方。放在特定類上,被認為是全局異常處理器。
2.2、ExceptionHandler 注解
用于定義異常處理方法,處理特定類型的異常。放在全局異常處理器類中的具體方法上。 通過這兩個注解的配合,可以實現(xiàn)全局的異常處理。當控制器中拋出異常時,SpringBoot 會自動調(diào)用匹配的 @ExceptionHandler 方法來處理異常,并返回定義的響應(yīng)。
步驟如下:
- 新建一個統(tǒng)一異常處理類
- 類上標注
@RestControllerAdvice注解 - 在方法上標注
@ExceptionHandler注解,并且指定需要捕獲的異常,可以同時捕獲多個。
新建 exception 包,在包下新建 GlobalExceptionHandler 類。代碼如下:
package com.duan.execption;
import com.duan.pojo.AppHttpCodeEnum;
import com.duan.pojo.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author db
* @version 1.0
* @description GlobalExceptionHandler
* @since 2023/7/23
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 全局異常
@ExceptionHandler(Exception.class)
public ResponseResult exceptionHandler(Exception e){
//打印異常信息
log.error("出現(xiàn)了異常! {}",e);
//從異常對象中獲取提示信息封裝返回
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage());
}
// 自定義異常
@ExceptionHandler(LxAdminException.class)
public ResponseResult LxAdminExceptionHandler(LxAdminException e){
//打印異常信息
log.error("出現(xiàn)了異常! {}",e);
//從異常對象中獲取提示信息封裝返回
return ResponseResult.errorResult(e.getCode(),e.getMsg());
}
}
在exception包下新建自定義異常處理類 LxAdminException
package com.duan.execption;
import com.duan.pojo.AppHttpCodeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author db
* @version 1.0
* @description LxAdminException 自定義異常
* @since 2023/7/23
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LxAdminException extends RuntimeException{
private int code;
private String msg;
public LxAdminException(AppHttpCodeEnum httpCodeEnum) {
super(httpCodeEnum.getMsg());
this.code = httpCodeEnum.getCode();
this.msg = httpCodeEnum.getMsg();
}
}
2.3、統(tǒng)一異常處理使用
在業(yè)務(wù)開發(fā)中,可以在 service 層處理業(yè)務(wù)時,可以手動拋出異常,由全局異常處理器處理進行統(tǒng)一處理。
package com.duan.controller;
import com.duan.execption.LxAdminException;
import com.duan.pojo.AppHttpCodeEnum;
import com.duan.pojo.ResponseResult;
import com.duan.pojo.User;
import com.duan.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.UUID;
/**
* @author db
* @version 1.0
* @description LoginController
* @since 2023/12/19
*/
@RestController
@Slf4j
public class LoginController {
@PostMapping("/login")
public ResponseResult login(@RequestBody User user){
log.info("這是正常日志");
if(!"admin".equals(user.getUsername()) && !"123456".equals(user.getPassword())){
throw new LxAdminException(AppHttpCodeEnum.LOGIN_ERROR);
}else{
HashMap<String, Object> map = new HashMap<>();
map.put("id", UUID.randomUUID().toString());
// 生成token
String token = JWTUtils.generateJwt(map);
return ResponseResult.okResult(token);
}
}
}
當我們請求接口時,假如用戶名稱或者密碼錯誤,接口就會響應(yīng):
{
"code": 505,
"msg": "用戶名或密碼錯誤",
"data": null
}
實際開發(fā)中還有許多的異常需要捕獲,比如 Token 失效、過期等異常, 如果整合了其他的框架,還要注意這些框架拋出的異常,比如Spring Security 等框架。
代碼地址:https://gitee.com/duan138/practice-code/tree/dev/resultException
三、總結(jié)
在 SpringBoot 項目中,統(tǒng)一返回和統(tǒng)一異常處理是非常常用的一環(huán),它們能提高應(yīng)用的可讀性和可維護性,統(tǒng)一返回有助于保持代碼一致性和規(guī)范性,在前后端聯(lián)調(diào)時更加方便,統(tǒng)一異常處理,減少了代碼冗余,對異常處理更加易于管理。
以上就是深入了解SpringBoot中的統(tǒng)一返回和統(tǒng)一異常處理的詳細內(nèi)容,更多關(guān)于SpringBoot統(tǒng)一返回和統(tǒng)一異常處理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java kafka寫入數(shù)據(jù)到HDFS問題
這篇文章主要介紹了java kafka寫入數(shù)據(jù)到HDFS問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
mybatis-plus無法通過logback-spring輸出的解決方法
本文主要介紹了mybatis-plus無法通過logback-spring輸出,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
SpringBoot Test 多線程報錯的根本原因(dataSource already
在使用Springboot test進行相關(guān)測試的時候,發(fā)現(xiàn)開啟線程操作數(shù)據(jù)庫的時候異常,這篇文章主要介紹了SpringBoot Test 多線程報錯:dataSource already closed的根本原因及解決方法,需要的朋友可以參考下2022-06-06
java?kafka如何動態(tài)設(shè)置用戶讀寫權(quán)限
這篇文章主要介紹了java?kafka如何動態(tài)設(shè)置用戶讀寫權(quán)限問題,具有很好的參考家價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
如何在IDE部署springboot項目(有swagger和無swagger都是一樣的)到服務(wù)器或者虛擬機上的docke
這篇文章主要介紹了如何在IDE部署springboot項目(有swagger和無swagger都是一樣的)到服務(wù)器或者虛擬機上的docker,本文給大家分享我的安裝歷程,需要的朋友可以參考下2023-01-01

