首页 > 其他分享 >@ControllerAdvice全局异常处理

@ControllerAdvice全局异常处理

时间:2022-09-03 20:33:48浏览次数:79  
标签:code return String errorCode ControllerAdvice 全局 异常 public

@ControllerAdvice全局异常处理

Exception,分为运行时异常(RuntimeException)和非运行时异常
可查的异常(checked exceptions): Exception下除了RuntimeException外的异常
不可查的异常(unchecked exceptions):RuntimeException及其子类和错误(Error)
  • 1
  • 2
  • 3

在这里插入图片描述
可查的异常在我们编码的时候就会catch解决,运行时异常则是不可控的,比如一些空指针异常,数组越界之类的异常。
代码里到处写try-catch也不太好,这时候就需要利用AOP做全局异常处理。


一、设计方案

  • 有多语言支持,需要一个语言本地化工具类(没这个需求的可不要) ,InternationalizationUtil.java
  • 定义一个业务异常类,必须继承自RuntimeException, BusinessException.java
  • 定义一个业务异常code类,BusinessErrorCode.java
  • 定义Controller增强,ExceptionAdvice.java
  • 统一返回格式,Result.java
    在业务逻辑处理中会有业务逻辑出错的提示,比如提示用户密码错误,余额不足等等。这些信息都需要传给前端,提示给用户。
    流程:业务逻辑出错,抛个BusinessException异常,传入异常BusinessErrorCode,ExceptionAdvice捕获异常进行处理,根据Code,调用本地化语言工具类获取到对应语言的提示信息,封装为Result返回给前端。

二、代码

自定义BusinessException业务异常类。注意,必须继承RuntimeException

public class BusinessException extends RuntimeException {
    private static final long serialVersionUID = 5317403756736254689L;
    private int code;
    private Object[] args;
    public BusinessException(int messageCode) {
        super(getCodeMessage(messageCode));
        this.code = messageCode;
    }
    public BusinessException(int messageCode,Object... args) {
        super(getCodeMessage(messageCode));
        this.code = messageCode;
        this.args = args;
    }
    private static String getCodeMessage(int messageCode) {
        List<String> fieldName = new ArrayList<>();
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            Class businessErrorCode = classLoader.loadClass("com.demo.common.BusinessErrorCode");
            Field[] fields = businessErrorCode.getDeclaredFields();
            List<Field> fieldList = Arrays.asList(fields);
            fieldList.stream().forEach(field -> {
                try {
                    field.isAccessible();
                    if (Integer.parseInt(field.get(businessErrorCode).toString()) == messageCode) {
                        fieldName.add(field.getName());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            return fieldName.get(0);
        } catch (Exception e) {
            e.printStackTrace();
            return "FAIL";
        }
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public Object[] getArgs() {
        return args;
    }
    public void setArgs(Object[] args) {
        this.args = args;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

我这里因为做国际化,考虑到日志信息显示,对code和message做了特殊处理。一般需求可以直接不要这个getCodeMessage()方法。
定义BusinessErrorCode

public class BusinessErrorCode {
	/**
     * 参数错误!
     */
    public static final int PARAMETER_FAIL = 10000;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

假如service里有这么一段,抛出参数错误的异常

    @Override
    public void changeDefaultGradeNo(Long defaultGradeNo, Long groupId, Long uid) {
        logger.info("groupId:{} defaultGradeNo:{}", groupId, defaultGradeNo);
        if (defaultGradeNo == null) {
            throw new BusinessException(BusinessErrorCode.PARAMETER_FAIL);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在Controller不需要对这个service的changeDefaultGradeNo方法做try-catch处理,用AOP知识,写一个异常增强类统一拦截异常,封装Result返回给前端。
定义异常增强类ExceptionAdvice

@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
    private Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);
    @Autowired
    private InternationalizationUtil i18nUtil;
    /**
     * 处理BusinessException异常返回信息
     *
     * @param businessException
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Result handleBusinessException(BusinessException businessException) {
        String message = businessException.getMessage();
        Integer errorCode = businessException.getCode();
        if (StringUtils.isEmpty(errorCode.toString())) {
            errorCode = SystemErrorCode.SYSTEM_ERROR;
        }
        String resultMessage = i18nUtil.i18n(errorCode+"",businessException.getArgs());
        logger.info("业务异常:{}-{}-{}", errorCode, message, resultMessage);
        return new Result(errorCode, resultMessage);
    }
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Object handle(RuntimeException runtimeException) {
        logger.error("运行时异常:", runtimeException);
        return new Result(BusinessErrorCode.FAIL, i18nUtil.i18n(SystemErrorCode.SYSTEM_ERROR));
    }
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handle(Exception exception) {
        logger.error("异常:", exception);
        return new Result(BusinessErrorCode.FAIL, i18nUtil.i18n(SystemErrorCode.SYSTEM_ERROR));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

可以定义好对不同异常的不同处理方式。
关于本地化语言工具类InternationalizationUtil

@Component
public class InternationalizationUtil {
    @Autowired
    private MessageSource messageSource;
    /**
     * 根据errorCode和本地化对象Local获取国际化提示信息
     *
     * @param errorCode
     * @return
     */
    public String i18n(int errorCode) {
        return i18n(String.valueOf(errorCode));
    }
    public String i18n(String errorCode) {
        return messageSource.getMessage(errorCode, null, errorCode, LocaleContextHolder.getLocale());
    }
    public String i18n(String errorCode, Object[] args) {
        return messageSource.getMessage(errorCode, args, LocaleContextHolder.getLocale());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

如果不用spring默认的文件配置,要指定message资源的位置,参考Spring国际化

spring:
  profiles:
    active: dev
  messages:
    basename: i18n/messages
    encoding: UTF-8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述
对应的中文,英文资源文件
在这里插入图片描述
最后看结果封装类Result

public class Result {
    public static final String SUCCESS_MESSAGE = "";
    private int code = BusinessErrorCode.OK;
    private String message = SUCCESS_MESSAGE;
    private Object data;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这样一套流程走下来,前端看到的就是

{
	"code": 10000,
	"message":"参数错误",
	"data":
}
  • 1
  • 2
  • 3
  • 4
  • 5

如果不需要国际化,会简单些。

https://blog.csdn.net/Axela30W/article/details/89520890

标签:code,return,String,errorCode,ControllerAdvice,全局,异常,public
From: https://www.cnblogs.com/sunny3158/p/16653572.html

相关文章

  • 统一异常处理
    代码托管地址:https://gitee.com/ZomiCC/code/tree/master/exception此文应用到了[统一校验]部分功能,没有看多可先参考上文:统一校验统一处理,我们很容易会想到spring中的AO......
  • vue3 基础-全局组件和局部组件
    组件和页面的关系可以理解为,组件是页面的一部分.形象地理解组件就和盖房子一样的,可以将房子粗略拆分3个组件(组成部分)房顶,房身,地基.同时房顶又可以拆分...........
  • statement(not found)异常
    mybatis里的异常statement(notfound)“异常原因是maven工程里默认识别‘resources’包里面的xml,当我们在java包里写的xml则要进行配置”,请看下面步骤启动类要覆盖(@Map......
  • node41-node全局对象global
     global.console.log('我是歌谣');global.setTimeout(function(){console.log('123');},2000) ......
  • php exec 函数执行shell命令,中文参数异常的问题
    exec("/usr/local/bin/wkhtmltopdf--page-sizeA4--footer-font-nameFangSong--footer-line--header-font-size13--footer-font-size9--footer-center[page]--......
  • selenium元素定位---ElementClickInterceptedException(元素点击交互异常)解决方法
    1、异常原因在编写ui自动化时,执行报错元素无法点击:ElementClickInterceptedException具体报错:selenium.common.exceptions.ElementClickInterceptedException:Message:......
  • SpringMVC异常处理
    基于配置的异常处理SpringMVC提供了一个处理控制器,在方法执行过程中所出现的异常的接口:HandlerExceptionResolver,该接口的实现类有:DefaultHandlerExceptionResolver和Sim......
  • pod中进行vi操作导致内存异常触发重启
    前天应用反馈说有个集群的访问异常抖动,于是查看了一下配置。发现pod异常重启了。于是怀疑是jmv异常,于是在pod中查看相关的日志。结果又重启了2次。于是对这二次进行分析......
  • vue如何全局清除默认样式
    为什么要清除CSS的默认样式?1、首先每个浏览器对html标签都有自己的默认样式,用来保证在没有自定义样式的情况下也能被有据可循的渲染,然而各厂商都有自己的风格,需求也不......
  • EasyCVR平台设备通道下拉列表异常该如何解决?
    EasyCVR平台基于云边端一体化管理,支持多协议、多类型的视频设备接入,对外可分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。在视频功能上,可提供服务器集群、视频监控直播......