Springboot三部曲之Controller统一异常处理

SpringBoot整理的最后一块内容,Controller统一异常处理。

Controller的异常处理应该由开发组长来定义,这样再遇到问题的时候,不需要再使用if或者try等模块来对代码进行返回规范和日志记录,这类公共内容和经常进行CV编程的代码,应该统一起来,让开发人员随时随地,遇到业务无法执行的时候抛出业务异常即可,无需再次编写返回实体,这里就体现出Controller统一返回的好处了,要是不统一返回,那么异常处理的时候也没办法保证返回的内容是前端同事可以看懂的。

在没有对异常进行通过已处理的时候,我们可能总是面对这样的代码: 题外话,记住,能不用if尽量不要用,特别是队医NPE的判断,直接抛出异常即可。



@RestController
@RequestMapping("gua")
public class GuaController {
    private Logger logger = LoggerFactory.getLogger(GuaController.class);

    @GetMapping("str")
    public ResponseData str() {
        ServiveImpl servive = new ServiveImpl();
        List<String> list= servive.retSomething();
        try {
            if (list.size() > 0) {
                return ResponseDataUtil.buildSuccess(list.get(0));
            } else {
                return ResponseDataUtil.buildError();
            }
        } catch (Exception e) {
            e.printStackTrace();
            //dosomething
            return ResponseDataUtil.buildError(ResultEnums.SYSTEM_ERROR);
        }
    }
//        return ResponseDataUtil.buildSuccess("Result String");
//        throw new SystemErrorException("1001", "Collect错误", "测试补充错误");

    @GetMapping("data")
    public ResponseData data() {
        return ResponseDataUtil.buildSuccess(new User());
    }


    @GetMapping("map")
    public ResponseData map() {
        HashMap<String, Object> map = new HashMap<>(1);
        map.put("Result", "Map");
        return ResponseDataUtil.buildSuccess(map);
    }
}

class ServiveImpl {
    public List<String> retSomething() {
        return new ArrayList<>();
    }
}

当你是用了统一异常处理以后的代码是这样的:


@RestController
@RequestMapping("gua")
public class GuaController {
    private Logger logger = LoggerFactory.getLogger(GuaController.class);

    @GetMapping("str")
    public ResponseData str() {
        ServiveImpl servive = new ServiveImpl();
        List<String> list= servive.retSomething();
        return ResponseDataUtil.buildSuccess(list);
    }

    @GetMapping("data")
    public ResponseData data() {
        return ResponseDataUtil.buildSuccess(new User());
    }


    @GetMapping("map")
    public ResponseData map() {
        HashMap<String, Object> map = new HashMap<>(1);
        map.put("Result", "Map");
        return ResponseDataUtil.buildSuccess(map);
    }
}

class ServiveImpl {
    public List<String> retSomething() {
        throw new SystemErrorException("1001", "Collect错误", "测试补充错误");
    }
}

我们无需再进行复杂的逻辑判断和异常处理,这些都交由ExceptionHandle处理:

下面是ExceptionHandle代码,没什么技术含量:




package com.dong.gua.web.interceptor;

import com.dong.gua.common.enums.ResultEnums;
import com.dong.gua.common.exception.SystemErrorException;
import com.dong.gua.common.exception.SystemWarnException;
import com.dong.gua.common.pojo.ResponseData;
import com.dong.gua.common.utils.MsgUtls;
import com.dong.gua.common.utils.ResponseDataUtil;
import com.dong.gua.common.utils.ThreadPoolUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class DefaultGlobalExceptionHandle {
    private Logger logger = LoggerFactory.getLogger(DefaultGlobalExceptionHandle.class);
    @Autowired
    private MsgUtls msgUtls;

    @ExceptionHandler(Exception.class)
    public ResponseData handle(Exception e) {
        if (e instanceof SystemErrorException) {
            //高级生产异常
            SystemErrorException systemErrorException = (SystemErrorException) e;
            logger.error("系统严重异常! 发生异常类: 【" + systemErrorException.getClass() + "】, 异常信息: " + e.getCause());
            //创建异步线程,交由异常处理类处理
            ThreadPoolUtils.getSimpleThreadPool().execute(() -> MsgUtls.push2MSG4SystemError(systemErrorException));
        } else if (e instanceof SystemWarnException) {
            SystemWarnException systemWarnException = (SystemWarnException) e;
            logger.error("系统异常! 发生异常类: 【" + systemWarnException.getCause() + "】, 异常信息: " + e.getCause());
        } else {
            logger.error("一般异常! 发生异常类: 【" + e.getCause() + "】, 异常信息: " + e.getCause());
        }
        return ResponseDataUtil.buildError(ResultEnums.ERROR);
    }
}

下面是我自己定义的异常类:

基础异常类:

package com.dong.gua.common.exception;

/**
 * 异常基类,定义异常内容
 */
public class BaseSystemException extends RuntimeException {

    /**
     * 错误编码
     */
    private String errorCode;
    /**
     * 错误信息
     */
    private String errorMsg;
    /**
     * 补充内容
     */
    private String complementary;


    public BaseSystemException(String errorCode, String errorMsg, String complementary) {
        super("(っ•̀ω•́)っ errorCode: 【" + errorMsg + "】 (っ•̀ω•́)っ errorMsg: 【" + errorMsg + "】 (っ•̀ω•́)っ complementary: 【" + complementary + "】");
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.complementary = complementary;
    }

    public BaseSystemException(String message, Throwable cause, String errorCode, String errorMsg, String complementary) {
        super("(っ•̀ω•́)っ errorCode: 【" + errorMsg + "】 (っ•̀ω•́)っ errorMsg: 【" + errorMsg + "】 (っ•̀ω•́)っ complementary: 【" + complementary + "】", cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
        this.complementary = complementary;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public String getComplementary() {
        return complementary;
    }

    public void setComplementary(String complementary) {
        this.complementary = complementary;
    }
}

系统错误类:


package com.dong.gua.common.exception;

/**
 * 系统错误!严重错误,属于生产级事故,需要转消息网关处理
 */
public class SystemErrorException extends BaseSystemException {

    public SystemErrorException(String errorCode, String errorMsg, String complementary) {
        super(errorCode, errorMsg, complementary);
    }

    public SystemErrorException(String message, Throwable cause, String errorCode, String errorMsg, String complementary) {
        super(message, cause, errorCode, errorMsg, complementary);
    }
}

系统异常类:


package com.dong.gua.common.exception;

/**
 * 系统金糕级错误
 */
public class SystemWarnException extends BaseSystemException {
    public SystemWarnException(String errorCode, String errorMsg, String complementary) {
        super(errorCode, errorMsg, complementary);
    }

    public SystemWarnException(String message, Throwable cause, String errorCode, String errorMsg, String complementary) {
        super(message, cause, errorCode, errorMsg, complementary);
    }
}

这里唯一需要注意的点,就只是系统错误发生时,需要使用外部条件通知到系统管理人员,对系统进行检查。这里我使用的是一个简单的线程池,关于线程池的认识和需要注意的点,在后面的文章中我会做一点点经验的总结。

感兴趣的小伙伴么,快去试试吧!Conding才是最佳记忆的方式。下次见。




上一篇:2019 DevOps 必备面试题——持续集成篇


下一篇:SpringBoot三部曲之Controller 请求日志切面 AOP