SpringBoot項目自定義異常墩蔓,配置全局異常統(tǒng)一處理,避免出現(xiàn)大量try/catch的問題

完整代碼地址在結(jié)尾O舳埂奸披!

第一步,創(chuàng)建一個SpringBoot項目涮雷,此處不贅述

第二步阵面,編寫application.yml配置文件,如下

server:
  port: 8085

spring:
  application:
    name: exception-demo-server

第三步洪鸭,創(chuàng)建響應碼枚舉ResponseEnums样刷,統(tǒng)一響應類Response,如下

ResponseEnums

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * @version 1.0
 * @author jinhaoxun
 * @date 2018-05-09
 * @description 響應碼枚舉
 */
@Getter
@AllArgsConstructor
public enum ResponseEnums {

    /**
     * 請求成功
     */
    SUCCESS(200,"請求成功"),
    /**
     * 系統(tǒng)異常览爵,請稍后重試
     */
    EXCEPTION(10000,"系統(tǒng)異常颂斜,請稍后重試"),
    /**
     * 請求的資源(網(wǎng)頁等)不存在
     */
    NOT_FOUND(404,"請求的資源(網(wǎng)頁等)不存在"),

    /**
     * 共6位,1:系統(tǒng)異常碼和值定義在該類中,大家公用
     * 前2位表示大板塊(10:系統(tǒng)拾枣,11:管理后臺模塊沃疮,12:文章模塊,13:公共模塊梅肤,14:上傳下載文件模塊)
     * 第3,4位表示項目的小模塊司蔬,5,6位代表具體錯誤
     */
    /**************************           系統(tǒng)模塊             *******************************/
    /**
     * 登陸超時
     */
    LOGIN_TIMEOUT(100001  ,"登陸超時"),
    /**
     * 參數(shù)有誤
     */
    WRONG_PARAM(100002  ,"參數(shù)有誤"),
    /**
     * 缺少必要的參數(shù)
     */
    MISS_PARAM(100003  ,"缺少必要的參數(shù)"),
    /**
     * Hystrix 降級開啟拋出異常
     */
    HYSTRIX_THROW_EXCEPTION(100004  ,"請求超時姨蝴,請稍后重試"),

    /**************************           賬號模塊             *******************************/
    /**
     * 您沒有該權限
     */
    MNG_PERMISSION_DENY(110101,"您沒有該權限"),
    /**
     * 密碼錯誤
     */
    PASSWORD_WRONG(110102,"密碼錯誤"),
    /**
     * 用戶不存在
     */
    USER_NOT_EXIST(110103,"用戶不存在"),
    /**
     * 賬號被封禁
     */
    ACCOUNT_IS_BLOCKED(110104,"賬號被封禁"),
    /**
     * 賬號已注銷
     */
    ACCOUNT_IS_CANCELLED(110105,"賬號已注銷"),
    /**
     * 驗證碼已過期
     */
    VERIFICATION_CODE_EXPIRED(110106,"驗證碼已過期"),
    /**
     * 從Redis中獲取驗證碼錯誤
     */
    GET_CODE_WRONG_FROM_REDIS(110107,"從Redis中獲取驗證碼錯誤"),
    /**
     * 身份信息已過期
     */
    IDENTITY_INFORMATION_IS_EXPIRED(110108,"身份信息已過期"),
    /**
     * 用戶未登錄
     */
    USER_NOT_LOG_IN(110109,"用戶未登錄"),
    /**
     * 用戶退出登錄失敗
     */
    USER_LOG_OUT_FAIL(110110,"用戶退出登錄失敗"),

    /**
     * 密碼修改失敗
     */
    PASSWORD_CHANGE_FAIL(110112,"密碼修改失敗"),
    /**
     * 賬號封禁失敗
     */
    ACCOUNT_BLOCK_FAIL(110113,"賬號封禁失敗"),
    /**
     * 賬號解封失敗
     */
    ACCOUNT_UNSEALING_FAIL(110114,"賬號解封失敗"),
    /**
     * 賬號注冊失敗
     */
    ACCOUNT_REGISTRATION_FAIL(110115,"賬號注冊失敗"),
    /**
     * 獲取手機驗證碼失敗
     */
    GET_PHONE_CODE_FAIL(110116,"獲取手機驗證碼失敗"),
    /**
     * 獲取郵箱驗證碼失敗
     */
    GET_EMAIL_CODE_FAIL(110117,"獲取郵箱驗證碼失敗"),
    /**
     * 獲取用戶信息失敗
     */
    GET_USERINFO_FAIL(110118,"獲取用戶信息失敗"),
    /**
     * 更新用戶信息失敗
     */
    UPDATE_USERINFO_FAIL(110119,"更新用戶信息失敗"),
    /**
     * 賬號注銷失敗
     */
    ACCOUNT_CANAEL_FAIL(110120,"賬號注銷失敗"),
    /**
     * 重復獲取驗證碼
     */
    REPEAT_GET_USER_LOG_IN_CODE(110121,"重復獲取驗證碼"),
    /**
     * 驗證碼已過期
     */
    USER_LOG_IN_CODE_EXPIRATIONED(110122,"驗證碼已過期"),
    /**
     * 驗證碼錯誤
     */
    USER_LOG_IN_CODE_WRONG(110123,"驗證碼錯誤"),
    ;

    public Integer code;
    public String msg;

}

Response

import com.luoyu.exception.constant.ResponseEnums;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Response
 *
 * @author luoyu
 * @date 2018/10/07 13:28
 * @description 通用返回類
 */
@Data
public class Response implements Serializable {

    private String msg;
    private int code;
    private Object data;
    private String time;

    private Response() {
    }

    private Response(int code, String msg) {
        this.code = code;
        this.msg = msg;
        this.time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
    }

    private Response(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
        this.time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
    }

    public static Response success() {
        return new Response(ResponseEnums.SUCCESS.getCode(), ResponseEnums.SUCCESS.getMsg());
    }

    public static Response success(Object data) {
        return new Response(ResponseEnums.SUCCESS.getCode(), ResponseEnums.SUCCESS.getMsg(), data);
    }

    public static Response success(Object data, String msg) {
        return new Response(ResponseEnums.SUCCESS.getCode(), msg, data);
    }

    public static Response fail() {
        return new Response(ResponseEnums.EXCEPTION.getCode(), ResponseEnums.EXCEPTION.getMsg());
    }

    public static Response fail(ResponseEnums responseEnums) {
        return new Response(responseEnums.getCode(), responseEnums.getMsg());
    }

    public static Response fail(ResponseEnums responseEnums, Object data) {
        return new Response(responseEnums.getCode(), responseEnums.getMsg(), data);
    }

    public static Response fail(int code, String msg) {
        return new Response(code, msg);
    }

    public static Response fail(int code, String msg, Object data) {
        return new Response(code, msg, data);
    }

}

第四步俊啼,創(chuàng)建自定義異常類CustomException,如下

import lombok.Data;

import java.io.Serializable;

/**
 * @version 1.0
 * @author jinhaoxun
 * @date 2018-05-09
 * @description 自定義統(tǒng)一異常(相當于業(yè)務異常)
 */
@Data
public class CustomException extends Exception implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer code;

    private String log;

    /**
     * @author jinhaoxun
     * @description 構(gòu)造器
     * @param code 異常狀態(tài)碼
     * @param log 異常打印日志
     * @param msg 異常返回信息
     */
    public CustomException(Integer code, String log, String msg) {
        super(msg);
        this.code = code;
        this.log = log;
    }

}

第五步左医,創(chuàng)建全局異常統(tǒng)一處理類ExceptionHandle授帕,如下

import com.luoyu.exception.constant.ResponseEnums;
import com.luoyu.exception.entity.vo.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @version 1.0
 * @author jinhaoxun
 * @date 2018-05-09
 * @description 統(tǒng)一的異常處理
 */
@Slf4j
@RestControllerAdvice
public class ExceptionHandle {

    /**
     * @author jinhaoxun
     * @description 統(tǒng)一的異常處理方法
     * @param e 拋出的異常
     * @return 返回給前端的錯誤信息提示
     */
    @ExceptionHandler(value = Exception.class)
    public Response handleException(Exception e){
        if(e instanceof CustomException) {
            CustomException ex = (CustomException)e;
            log.info("自定義業(yè)務異常:msg:" + ex.getMessage() + ",log:" + ex.getLog(), e);
            return Response.fail(ex.getCode(), ex.getMessage(),null);
        }else if(e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException)e;
            log.error("參數(shù)校驗異常:msg:" + ex.getBindingResult().getFieldError().getDefaultMessage());
            return Response.fail(ResponseEnums.WRONG_PARAM.getCode(),
                    ResponseEnums.WRONG_PARAM.getMsg() + ":"
                            + ex.getBindingResult().getFieldError().getDefaultMessage(), null);
        }else{
            log.error("統(tǒng)一系統(tǒng)異常:msg:" + e.getMessage(), e);
            return Response.fail(ResponseEnums.EXCEPTION.getCode(), ResponseEnums.EXCEPTION.getMsg(), null);
        }
    }

}

說明

  1. @ExceptionHandler用于統(tǒng)一處理某一類異常浮梢,從而能夠減少代碼重復率和復雜度跛十,所有拋出來的異常都會在這里被捕獲

第六步,創(chuàng)建TestService秕硝,TestServiceImpl芥映,TestController,如下

TestService

/**
 * @Description:
 * @Author: jinhaoxun
 * @Date: 2020/7/10 10:31 上午
 * @Version: 1.0.0
 */
public interface TestService {

    void get1() throws Exception;

    void get2() throws Exception;

}

TestServiceImpl

import com.luoyu.exception.exception.CustomException;
import com.luoyu.exception.service.TestService;
import org.springframework.stereotype.Service;

/**
 * @Description:
 * @Author: jinhaoxun
 * @Date: 2020/7/10 10:32 上午
 * @Version: 1.0.0
 */
@Service
public class TestServiceImpl implements TestService {

    @Override
    public void get1() throws Exception {
        int i = 1/0;
    }

    @Override
    public void get2() throws Exception {
        try {
            int i = 1/0;
        }catch (Exception e){
            throw new CustomException(10086, "自定義打印異常", "自定義返回異常");
        }
    }
    
}

TestController

import com.luoyu.exception.entity.vo.Response;
import com.luoyu.exception.service.TestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Description:
 * @Author: jinhaoxun
 * @Date: 2020/7/10 10:31 上午
 * @Version: 1.0.0
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Resource
    private TestService testService;

    /**
     * @author jinhaoxun
     * @description 測試接口1
     */
    @GetMapping("/get1")
    public Response get1() throws Exception {
        testService.get1();
        return Response.success();
    }

    /**
     * @author jinhaoxun
     * @description 測試接口2
     */
    @GetMapping("/get2")
    public Response get2() throws Exception {
        testService.get2();
        return Response.success();
    }

}

解釋

  1. 從可能出現(xiàn)異常的地方往外面拋異常,本文是從service開始奈偏,直到controller往外面拋出異常后坞嘀,會被ExceptionHandle捕獲,然后自行進行處理惊来,打印日志丽涩,統(tǒng)一狀態(tài)碼,錯誤信息返回給前端裁蚁。

第七步内狸,啟動項目,使用postman調(diào)接口厘擂,如下圖

測試1,使用GET請求http://localhost:8085/test/get1

image.png
image.png

測試2锰瘸,使用GET請求http://localhost:8085/test/get2

image.png
image.png

完整代碼地址:https://github.com/Jinhx128/springboot-demo

注:此工程包含多個module刽严,本文所用代碼均在exception-demo模塊下

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市避凝,隨后出現(xiàn)的幾起案子舞萄,更是在濱河造成了極大的恐慌,老刑警劉巖管削,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倒脓,死亡現(xiàn)場離奇詭異,居然都是意外死亡含思,警方通過查閱死者的電腦和手機崎弃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來含潘,“玉大人饲做,你說我怎么就攤上這事《羧酰” “怎么了盆均?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漱逸。 經(jīng)常有香客問我泪姨,道長,這世上最難降的妖魔是什么饰抒? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任肮砾,我火速辦了婚禮,結(jié)果婚禮上袋坑,老公的妹妹穿的比我還像新娘唇敞。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布疆柔。 她就那樣靜靜地躺著咒精,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旷档。 梳的紋絲不亂的頭發(fā)上模叙,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音鞋屈,去河邊找鬼范咨。 笑死,一個胖子當著我的面吹牛厂庇,可吹牛的內(nèi)容都是我干的渠啊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼权旷,長吁一口氣:“原來是場噩夢啊……” “哼替蛉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拄氯,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤躲查,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后译柏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镣煮,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年鄙麦,在試婚紗的時候發(fā)現(xiàn)自己被綠了典唇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡胯府,死狀恐怖蚓聘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盟劫,我是刑警寧澤夜牡,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站侣签,受9級特大地震影響塘装,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜影所,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一蹦肴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猴娩,春花似錦阴幌、人聲如沸勺阐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渊抽。三九已至,卻和暖如春议忽,著一層夾襖步出監(jiān)牢的瞬間懒闷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工栈幸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留愤估,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓速址,卻偏偏與公主長得像玩焰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子芍锚,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容