SpringBoot 统一异常处理--工具类

前言

实习过了一个多星期,原以为可以学点新技术,结果新技术基本没接触到,追踪源码和对理解设计模式的能力倒是有所进步。接下来就记录一下在SpringBoot中利用 @ControllerAdvice 注解实现SpringBoot的全局异常。

介绍

@ControllerAdvice 是SpringMVC中的功能,利用的是AOP的思想,也就是面向切面的思想,在SpringBoot中可以直接使用,利用这个注解可以实现以下三个功能:

  1. 全局异常处理
  2. 全局数据绑定
  3. 全局数据预处理

用法

1. 定义常量类(个人习惯,可以不使用,只是为了增强代码的可维护性)

package com.chen.mykinthtest.domain;

/**
 * 对常量进行封装,利于后期代码的维护
 *
 * @author chen
 */
public class AppConstant {

    // 文本消息
    public static final String MESSAGE = "message";

    // 单个对象
    public static final String ITEM = "item";

    // 返回的对象列表
    public static final String LIST = "list";

    // 状态码
    public static final String ERROR = "error";

    // 代表执行成功
    public static int OK = 0;

    // 代表执行失败
    public static int FAIL = 1;

    // 代表服务器运行异常
    public static int RunTime = 2;

    // 代表空指针异常
    public static int NullPointer = 3;

    // 类型转换异常
    public static int ClassCast = 4;

    // IO异常
    public static int IO = 5;

    // 未知方法异常
    public static int NoSuchMethod = 6;

    // 数组越界异常
    public static int IndexOutOfBounds = 7;

    // 400错误
    public static int HttpMessageNotReadable=8;

    // 400错误
    public static int TypeMismatch=9;

    // 400错误
    public static int MissingServletRequestParameter=10;

    // 405错误
    public static int HttpRequestMethodNotSupported=11;

    // 406错误
    public static int HttpMediaTypeNotAcceptable=12;

    // 500错误
    public static int Run500=13;

    // 栈溢出
    public static int StackOverflow=14;

    // 除数为0异常
    public static int Arithmetic=15;

    // 其他异常
    public static int other=16;

}

 2.封装要返回的实体

package com.chen.mykinthtest.restful;

import com.chen.mykinthtest.domain.AppConstant;

import java.util.HashMap;
import java.util.List;

/**
 * REST 接口返回数据
 *
 * @author chen
 */
public class RestResponse extends HashMap<String, Object> {

    /**
     * 禁止通过构造函数构造对象,只能通过静态方法获取实例。
     *
     * @see #ok()
     * @see #ok(String)
     * @see #fail()
     * @see #fail(String)
     */
    private RestResponse() {
    }

    /**
     * 设置接口返回的文本消息,属性 key: message
     *
     * @param msg
     * @return
     */
    public RestResponse msg(String msg) {
        this.put(AppConstant.MESSAGE, msg);
        return this;
    }

    /**
     * 设置接口返回的数据对象,属性 key: item
     *
     * @param item
     * @return
     */
    public RestResponse item(Object item) {
        this.put(AppConstant.ITEM, item);
        return this;
    }

    /**
     * 设置接口返回的数据对象列表,属性 key: list
     *
     * @param list
     * @return
     */
    public RestResponse list(List<?> list) {
        this.put(AppConstant.LIST, list);
        return this;
    }

    /**
     * 设置接口返回的数据项,并指定数据项的属性 key
     *
     * @param key
     * @param value
     * @return
     */
    public RestResponse put(String key, Object value) {
        super.put(key, value);
        return this;
    }

    /**
     * 接口执行成功的返回数据,其中属性 error = 0
     *
     * @return
     */
    public static RestResponse ok() {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, AppConstant.OK);
        return result;
    }

    /**
     * 接口执行成功的返回数据,并设置文本消息
     *
     * @param msg
     * @return
     */
    public static RestResponse ok(String msg) {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, AppConstant.OK).msg(msg);
        return result;
    }

    /**
     * 接口执行成功的返回数据,并设置对象数据
     *
     * @param item
     * @return
     */
    public static RestResponse ok(Object item) {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, AppConstant.OK).item(item);
        return result;
    }

    /**
     * 接口执行成功的返回数据,并设置列表对象数据
     *
     * @param list
     * @return
     */
    public static RestResponse ok(List<?> list) {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, AppConstant.OK).list(list);
        return result;
    }

    /**
     * 接口执行失败的返回数据,其中属性 error = 1
     *
     * @return
     */
    public static RestResponse fail() {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, AppConstant.FAIL);
        return result;
    }

    /**
     * 接口执行失败的返回数据,并设置文本消息,其中属性 error = 1, message = {msg}
     *
     * @param msg
     * @return
     */
    public static RestResponse fail(String msg) {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, AppConstant.FAIL).msg(msg);
        return result;
    }

    /**
     * 接口执行失败的返回数据,自定义状态码,其中属性 error = {errcode}
     *
     * @param errcode
     * @return
     */
    public static RestResponse fail(int errcode) {
        RestResponse result = new RestResponse();
        result.put(AppConstant.ERROR, errcode);
        return result;
    }
}

3.利用 @ControllerAdvice 结合 @ExceptionHandler 对异常进行切面

package com.chen.mykinthtest.aop;

import com.chen.mykinthtest.domain.AppConstant;
import com.chen.mykinthtest.restful.RestResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;

/**
 * 全局异常处理类
 *
 * @author chen
 */
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    private static final String logExceptionFormat = "服务器异常: Code: %s Detail: %s";
    private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    //运行时异常
    @ExceptionHandler(RuntimeException.class)
    public RestResponse runtimeExceptionHandler(RuntimeException ex) {
        System.err.println("RuntimeException:");
        return resultOut(AppConstant.RunTime, "服务器内部错误,运行异常", ex);
    }

    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public RestResponse nullPointerExceptionHandler(NullPointerException ex) {
        System.err.println("NullPointerException:");
        return resultOut(AppConstant.NullPointer, "空指针异常", ex);
    }

    //类型转换异常
    @ExceptionHandler(ClassCastException.class)
    public RestResponse classCastExceptionHandler(ClassCastException ex) {
        System.err.println("ClassCastException:");
        return resultOut(AppConstant.ClassCast, "类型转换异常", ex);
    }

    //IO异常
    @ExceptionHandler(IOException.class)
    public RestResponse iOExceptionHandler(IOException ex) {
        System.err.println("IOException:");
        return resultOut(AppConstant.IO, "IO异常", ex);
    }

    //未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)
    public RestResponse noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        System.err.println("NoSuchMethodException:");
        return resultOut(AppConstant.NoSuchMethod, "未知方法异常", ex);
    }

    //数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public RestResponse indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        System.err.println("IndexOutOfBoundsException:");
        return resultOut(AppConstant.IndexOutOfBounds, "数组越界异常", ex);
    }

    //400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public RestResponse requestNotReadable(HttpMessageNotReadableException ex) {
        System.err.println("HttpMessageNotReadableException");
        return resultOut(AppConstant.HttpMessageNotReadable, "400 bad request", ex);
    }

    //400错误
    @ExceptionHandler({TypeMismatchException.class})
    public RestResponse requestTypeMismatch(TypeMismatchException ex) {
        System.err.println("TypeMismatchException:");
        return resultOut(AppConstant.TypeMismatch, "400 bad request", ex);
    }

    //400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public RestResponse requestMissingServletRequest(MissingServletRequestParameterException ex) {
        System.err.println("MissingServletRequestParameterException:");
        return resultOut(AppConstant.MissingServletRequestParameter, "400 bad request", ex);
    }

    //405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public RestResponse request405(HttpRequestMethodNotSupportedException ex) {
        System.err.println("HttpRequestMethodNotSupportedException:");
        return resultOut(AppConstant.HttpRequestMethodNotSupported, "405 Method not allowed", ex);
    }

    //406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public RestResponse request406(HttpMediaTypeNotAcceptableException ex) {
        System.err.println("HttpMediaTypeNotAcceptableException:");
        return resultOut(AppConstant.HttpMediaTypeNotAcceptable, "406 Not Acceptable", ex);
    }

    //500错误
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public RestResponse server500(RuntimeException ex) {
        System.err.println("RuntimeException:");
        return resultOut(AppConstant.HttpMediaTypeNotAcceptable, "500 error", ex);
    }

    //栈溢出
    @ExceptionHandler({StackOverflowError.class})
    public RestResponse requestStackOverflow(StackOverflowError ex) {
        System.err.println("StackOverflowError:");
        return resultOut(AppConstant.StackOverflow, "栈溢出异常", ex);
    }

    //除数不能为0
    @ExceptionHandler({ArithmeticException.class})
    public RestResponse arithmeticException(ArithmeticException ex) {
        System.err.println("ArithmeticException:");
        return resultOut(AppConstant.Arithmetic, "除数不能为0", ex);
    }

    //其他错误
    @ExceptionHandler({Exception.class})
    public RestResponse exception(Exception ex) {
        System.err.println("Exception:");
        return resultOut(AppConstant.other, "其他异常", ex);
    }

    /**
     * 对返回数据集中处理
     *
     * @param code
     * @param msg
     * @param ex
     * @param <T>
     * @return
     */
    private <T extends Throwable> RestResponse resultOut(int code, String msg, T ex) {
        ex.printStackTrace();
        log.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return RestResponse.fail(code).msg(msg);
    }

}

 4.测试

package com.chen.mykinthtest.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ExceptionController {

    @RequestMapping("exceptionTest")
    public int exceptionTest() {
        return 10 / 0;
    }

}

 结果:

发布了125 篇原创文章 · 获赞 67 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_42109746/article/details/104010972