前后端分離異常統一處理


作為一個程序員,雖然技術不厲害,但是都有一個向上的心,原來一直負責業務開發,梳理業務、設計流程、開發代碼,最近開始接觸一些架構類的設計和思路

全國醫改在即,項目組接了一個醫療改革相關的供應商項目,主要是針對物流方向的。

技術架構:領導要求用springcloud但是新來的成員都沒有相關開發經驗,項目負責人直接在網上扒了一套微服務的代碼(個人感覺不太成熟),好多東西不太全,

所以需要重新整理,由於項目負責人比較忙,自己有迫切的想要了解一些東西,所以針對架構層次的代碼學習了一下,

自己原來只做業務,從不關心架構的設計是否合理優美,甚至在業務方向已經做到管理層次,后來跳槽離職后才發現自己技術的短板,所以一直在補充學習

其實只需要架構師搭建微服務架構即可,項目組成員還是針對不同的功能模塊進行業務開發,和原來的SSM沒有本質區別,只是增加了一些新的注解,和組件的使用

這里就不對微服務的組件進行介紹了,只是針對自己部署的異常處理進行記錄——只是個人理解,如有好的設計歡迎指正

問題描述

技術架構是前后端分離,想着統一返處理回值(包括正常結果和異常結果),但是架構代碼只是做了一個自己的返回類Map類型,如下

package com.bootdo.clouddocommon.utils;

import java.util.HashMap;
import java.util.Map;

public class R extends HashMap<String, Object> {
    private static final long serialVersionUID = 1L;
    public R() {
        put("code", 0);
        put("msg", "操作成功");
    }
    public static R error() {
        return error(500, "操作失敗");
    }
    public static R operate(boolean b){
        if(b){
            return R.ok();
        }
        return R.error();
    }
    public static R error(String msg) {
        return error(500, msg);
    }
    public static R error(int code, String msg) {
        R r = new R();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }
    public static R ok(String msg) {
        R r = new R();
        r.put("msg", msg);
        return r;
    }
    public static R ok(Map<String, Object> map) {
        R r = new R();
        r.putAll(map);
        return r;
    }
    public static R ok() {
        return new R();
    }
    public static R error401() {
        return error(401, "你還沒有登錄");
    }
    public static R error403() {
        return error(403, "你沒有訪問權限");
    }
    public static R data(Object data){
        return R.ok().put("data",data);
    }
    public static R page(Object page){
        return R.ok().put("page",page);
    }
    @Override
    public R put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

這種這種類封裝方式很好的處理的所有Controller類的返回結果 例如;

    @Log("停用記錄")
    @ApiOperation(value = "停用信息記錄")
    @PutMapping("/stop")
    R stop(@RequestBody List<Long> idList) {

        return R.operate(consumeMaterialService.stop(idList,getUser()) > 0);
    }
  @Log("獲取耗材信息列表(無分頁)")
    @ApiOperation(value = "獲取耗材信息列表(無分頁)")
    @ApiImplicitParam(name = "params", value = "map參數集合(基礎的參數格式——可在結構內增加其他過濾條件字段)", example = "{consumeName:10}")
    @GetMapping("/allList")
    R list(@RequestParam Map<String, Object> params) {
        List<ConsumeMaterialDO> list = consumeMaterialService.list(params);
        return R.data(list);

    }

這種方式特點

1、很好的統一了Controller層的返回結果

2、沒有一套錯誤編碼和對應的信息,需要硬編碼的形式在代碼提現,例如:(該問題可以通過增加一個錯誤信息的枚舉類來解決——下文中會說明)

R findMaterialBySupplierIdNotAddList(@RequestParam Map<String, Object> params){
        if(params.isEmpty()){
            return R.error("30032",”"醫院ID和供應商ID不能為空");//可以只寫錯誤信息,也可以加上編碼
        }else{
            Long id=new Long(params.get("hospitalId").toString());
            if(id==null||id==0){
                return R.error("醫院ID不能為空");
            }
            Long sid=new Long(params.get("supplierId").toString());
            if(sid==null||sid==0){
                return R.error("供應商ID不能為空");
            }
        }
        //查詢列表數據
        Query query = new Query(params);
        List<ConsumeMaterialDO> materialList = supplierService.findMaterialBySupplierIdNotAddList(query);
        int total = supplierService.findMaterialBySupplierIdNotAddCount(query);
        PageUtils pageUtils = new PageUtils(materialList, total);
        //返回狀態字典
        List<SysDictDO> statusList = initDataService.getSysDictByType("status");
        //返回耗材狀態
        List<SysDictDO> measurementStatusList = initDataService.getSysDictByType("unit");
        return R.ok().put("page",pageUtils).put("suppliermaterialstatusoptions",statusList).put("measurementstatusoptions",measurementStatusList);
    }

3、沒有辦法處理service層的異常返回,因為service 層返回的都是具體的實體或者整數

因為原來做過的項目中有過相關的異常處理——記得是定義一個統一的異常接收類對返回值結構進行處理,其他地方直接拋出異常即可,當然需要定義一套錯誤信息枚舉類,用於統一返回信息內容

隨意根據自己的理解和經驗,查找相關代碼做了一套異常處理的代碼,代碼和原理很簡單

參考鏈接:https://segmentfault.com/a/1190000016576329

1、首先在原來的基礎上增加一個錯誤信息的枚舉類——代碼比較多刪減了一部分,可以根據自己的需求添加

package com.bootdo.clouddocommon.constants;

/**
 * 異常處理狀態碼
 */
public enum ResultCode {

    SUCCESS(0, "請求成功"),
    Unknown_Exception(-1, "未知異常"),

    USER_NOT_FOUND(10001, "沒有找到此用戶"),
    USERNAME_NOT_BLANK(10002, "用戶名不能為空"),
    USERNAME_EXIST(10003, "用戶名已經存在"),
    USERTYPE_ERROR(100031, "用戶類型不正確"),   
    
    DEVICE_ID_EMPTY(10052,"設備ID:deviceId不能為空"),
    DELETE_CONNECT_ERROR(10053,"刪除connect出錯");

    private int code;
    private String message;

    ResultCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

2、添加一個自定義的異常類用於拋出:主要是將自己的錯誤編碼和信息整合進去——原生的異常類也是可以的,只是好像沒有自定的編碼返回(自定義的異常類也需要集成原生的異常類——紅色部分——有興趣的同學可以看一下源碼)

package com.bootdo.clouddoadmin.config;

import com.bootdo.clouddocommon.constants.ResultCode;
/**
 * 功能描述: <br>
 * 〈異常類封裝——定義拋出的異常類〉

 * @return:
 * @since: 1.0.0
 * @Author:
 * @Date:
 */
public class DomainException extends RuntimeException {
    private int errCode = ResultCode.Unknown_Exception.getCode();

    public DomainException() {
        super(ResultCode.Unknown_Exception.getMessage());
    }

    public DomainException(ResultCode resultCode) {
        super(resultCode.getMessage());
        this.errCode = resultCode.getCode();
    }

    public int getErrCode() {
        return errCode;
    }

    public void setErrCode(int errCode) {
        this.errCode = errCode;
    }
}

3、添加統一的異常返回處理——RestControllerAdvice(ControllerAdvice)攔截異常並統一處理

package com.bootdo.clouddoadmin.config;

import com.bootdo.clouddocommon.utils.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
/**
 * 功能描述: <br>
 * 〈統一異常處理返回〉

 * @return:
 * @since: 1.0.0
 * @Author:
 * @Date:
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = DomainException.class)
    public R domainExceptionHandler(HttpServletRequest req,
                                    DomainException e) throws Exception {
        e.printStackTrace();
        return   R.error(e.getErrCode(), e.getMessage());
    }
}

這樣整體就設計完了,無論是在service或者controller中都可以拋出異常,然后經過處理成為統一格式的返回值

例如:

throw new DomainException(ResultCode.CODE_EMPTY);

 經測試是有效的——結果截圖就不再展示了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM