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

完整代碼地址在結(jié)尾!!

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

第二步,編寫(xiě)application.yml配置文件,如下

server:
  port: 8085

spring:
  application:
    name: exception-demo-server

第三步,創(chuàng)建響應(yīng)碼枚舉ResponseEnums,統(tǒng)一響應(yīng)類(lèi)Response,如下

ResponseEnums

import lombok.AllArgsConstructor;
import lombok.Getter;

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

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

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

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

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

    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 通用返回類(lèi)
 */
@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)建自定義異常類(lèi)CustomException,如下

import lombok.Data;

import java.io.Serializable;

/**
 * @version 1.0
 * @author jinhaoxun
 * @date 2018-05-09
 * @description 自定義統(tǒng)一異常(相當(dāng)于業(yè)務(wù)異常)
 */
@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)一處理類(lèi)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 返回給前端的錯(cuò)誤信息提示
     */
    @ExceptionHandler(value = Exception.class)
    public Response handleException(Exception e){
        if(e instanceof CustomException) {
            CustomException ex = (CustomException)e;
            log.info("自定義業(yè)務(wù)異常: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ù)校驗(yàn)異常: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);
        }
    }

}

說(shuō)明

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

第六步,創(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 測(cè)試接口1
     */
    @GetMapping("/get1")
    public Response get1() throws Exception {
        testService.get1();
        return Response.success();
    }

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

}

解釋

  1. 從可能出現(xiàn)異常的地方往外面拋異常,本文是從service開(kāi)始,直到controller往外面拋出異常后,會(huì)被ExceptionHandle捕獲,然后自行進(jìn)行處理,打印日志,統(tǒng)一狀態(tài)碼,錯(cuò)誤信息返回給前端。

第七步,啟動(dòng)項(xiàng)目,使用postman調(diào)接口,如下圖

測(cè)試1,使用GET請(qǐng)求http://localhost:8085/test/get1

image.png
image.png

測(cè)試2,使用GET請(qǐng)求http://localhost:8085/test/get2

image.png
image.png

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容