日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

物聯網設備數據流轉之搭建后端服務框架:SpringBoot統一響應封裝,全局異常攔截

作者:Heartsuit 更新時間: 2022-05-17 編程語言

背景

本篇內容相對比較簡單,不涉及具體的物聯網技術,是作為后端工程師的基本操作,算是對基礎框架的封裝工作,我們使用 SpringBootRestControllerAdviceExceptionHandler 等注解實現對客戶端請求響應的統一封裝以及異常信息攔截封裝。

為了保證我們前端在對接服務接口時采用統一的規范,業界主流的做法便是將所有請求的結果進行封裝,當然在遇到異常信息時也進行一層封裝,這樣可以使所有接口的響應結構是一致的,響應體的內容包括狀態碼與數據,當出現錯誤時還包含錯誤信息,一般地,響應體如下:

  • 正常響應
{
  "code": 200,
  "msg": "success",
  "data": "hello everyone."
}
  • 異常響應
{
  "code": 500,
  "msg": "/ by zero"
}

后續內容將在上一篇文章中 IDEA 項目的基礎上,添加一個 common 包(具體的文件位置可以從下圖中左側項目結構獲得)。

統一響應封裝

2022-05-15-Result.jpg

通過 RestControllerAdvice 注解,實現對請求的攔截,統一封裝結果為 Result

@RestControllerAdvice(basePackages = "com.heartsuit.common.controller")
public class ResultAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (o instanceof String) {
            return objectMapper.writeValueAsString(Result.success(o));
        }
        if (o instanceof Result) {
            return o;
        }
        return Result.success(o);
    }
}
  • Result.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
    /** 結果狀態 ,正常響應200,其他狀態碼都為失敗*/
    private int code;
    private String msg;
    private T data;

    // Static methods
    /**
     * 成功時候的調用
     */
    public static <T> Result<T> success(T data) {
        return new Result<T>(data, CodeMsg.SUCCESS);
    }
    public static <T> Result<T> success() {
        return new Result<T>(CodeMsg.SUCCESS);
    }

    /**
     * 失敗時候的調用
     */
    public static <T> Result<T> error(Integer code, String msg) {
        return new Result<T>(code, msg);
    }
    public static <T> Result<T> error(CodeMsg codeMsg) {
        return new Result<T>(codeMsg);
    }
    public static <T> Result<T> error(String msg) {
        CodeMsg codeMsg = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg);
        return new Result<T>(codeMsg);
    }

    // Constructor
    private Result(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private Result(T data, CodeMsg codeMsg) {
        this.data = data;
        if (codeMsg != null) {
            this.code = codeMsg.getCode();
            this.msg = codeMsg.getMsg();
        }
    }
    private Result(CodeMsg codeMsg) {
        if (codeMsg != null) {
            this.code = codeMsg.getCode();
            this.msg = codeMsg.getMsg();
        }
    }
}
  • CodeMsg.java
@Getter
public class CodeMsg {
    private int code;
    private String msg;

    // 通用的錯誤碼
    public static final CodeMsg SUCCESS =new CodeMsg(HttpStatus.OK.value(), "success");
    public static final CodeMsg BAD_REQUEST = new CodeMsg(HttpStatus.BAD_REQUEST.value(), "請求無效");
    public static final CodeMsg SERVER_ERROR = new CodeMsg(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服務端異常");
    public static final CodeMsg NO_HANDLER_FOUND = new CodeMsg(HttpStatus.NOT_FOUND.value(), "未找到對應資源");
    public static final CodeMsg UNAUTHORIZED = new CodeMsg(HttpStatus.UNAUTHORIZED.value(), "未認證或登錄狀態過期");
    public static final CodeMsg FORBIDDEN = new CodeMsg(HttpStatus.FORBIDDEN.value(), "未授權");
    // 自定義錯誤碼
    public static final CodeMsg PARAMETER_ERROR = new CodeMsg(4000, "參數不正確!");
    /*用戶相關:驗證碼*/
    public static final CodeMsg CAPTCHA_EXPIRED = new CodeMsg(4001, "驗證碼不存在或已過期");
    public static final CodeMsg CAPTCHA_INVALID = new CodeMsg(4002, "驗證碼錯誤");
    /*用戶相關:認證授權*/
    public static final CodeMsg BAD_CREDENTIAL = new CodeMsg(4003, "用戶名或密碼錯誤");
    public static final CodeMsg ACCOUNT_NOT_FOUND = new CodeMsg(4004, "賬號不存在");
    public static final CodeMsg ACCOUNT_NOT_ACTIVATED = new CodeMsg(4005, "賬號未激活");
    // 限流
    public static final CodeMsg RATE_LIMIT = new CodeMsg(4006,"達到閾值啦!");
    // 熔斷
    public static final CodeMsg DEGRADE = new CodeMsg(4007,"熔斷啦!");

    public static CodeMsg error(String msg){
        return new CodeMsg(HttpStatus.BAD_REQUEST.value(),msg);
    }
    public CodeMsg(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

全局異常攔截

2022-05-15-Exception.jpg
默認攔截所有異常(也可自定義異常進行封裝),同樣通過 RestControllerAdvice 注解,實現對異常響應的統一封裝。

  • RestExceptionHandler.java
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> exception(Exception e) {
        log.error("Global exception: {}", null == e.getMessage() ? e.toString() : e.getMessage(), e);
        return Result.error(CodeMsg.SERVER_ERROR.getCode(), null == e.getMessage() ? e.toString() : e.getMessage());
    }
}

用于測試的Controller

@RestController
@RequestMapping("demo")
public class HelloController {
    @GetMapping("hello")
    public String hello() {
        return "hello everyone.";
    }

    @GetMapping("error")
    public Result error() {
        int value = 8 / 0;
        return Result.success(value);
    }
}

小總結

至此,我們在基于 SpringBoot 的后端服務中完成了響應封裝、異常攔截。下一篇我們的主角 TDengine 將閃亮登場: TDengine 集成 SpringBoot , MyBatisPlus 實現 ORM 與 基礎的 CRUD 功能。


If you have any questions or any bugs are found, please feel free to contact me.

Your comments and suggestions are welcome!

原文鏈接:https://blog.csdn.net/u013810234/article/details/124787685

欄目分類
最近更新