前言

在前一节的学习中,慕歌带大家使用了全局结果集返回,通过使用全局结果集配置,优雅的返回后端数据,为前端的数据拿取提供了非常好的参考。同时通过不同的状态码返回,我们能够清晰的了解报错的位置,排除错误。如果大家有需要,可以使用我提供的的同一结果集以及状态码,并且可以使用全局异常拦截,实现异常的标准返回。接下来,我们一起来了解如何使用全局异常处理吧!

异常工具

先定义一个合适 的异常处理类,在之后的异常都会以这种格式返回前端,前端根据我们的异常进行自己的返回,以一种优雅的方式呈现错误,优化用户体验。
异常结果集:

/**
 * 返回结果封装
 */

@Data
public class ResultVo {
    // 状态码
    private int code;

    // 状态信息
    private String msg;

    // 返回对象
    private Object data;

    // 手动设置返回vo
    public ResultVo(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    // 手动设置返回vo
    public ResultVo(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    // 只返回状态码
    public ResultVo(StatusCode statusCode) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
    }

    // 默认返回成功状态码,数据对象
    public ResultVo(Object data) {
        this.code = ResultCode.SUCCESS.getCode();
        this.msg = ResultCode.SUCCESS.getMsg();
        this.data = data;
    }

    // 返回指定状态码,数据对象
    public ResultVo(StatusCode statusCode, Object data) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
        this.data = data;
    }

    public ResultVo(StatusCode statusCode,String msg, Object data) {
        this.code = statusCode.getCode();
        this.msg = msg;
        this.data = data;
    }
}

异常状态码,通过返回的状态码,以及状态信息,能够高效反映错误,并且可以全局统一管理,方便快捷:

@Getter
public enum ExceptionCode implements StatusCode {

    // 系统级别错误码
    ERROR(-1, "操作异常"),
    NOT_LOGIN(102, "请先登录!"),
    NO_Role(102,"无权限"),
    NO_PERMISSION(102,"无权限"),
    OUT_TIME(102,"登录信息过期"),
    DISABLE_ACCOUNT(102,"帐号已被禁用!"),
    EMAIL_DISABLE_LOGIN(102,"该邮箱账号已被管理员禁止登录!"),
    IP_REPEAT_SUBMIT(102,"访问次数过多,请稍后重试"),
    ERROR_DEFAULT(105,"系统繁忙,请稍后重试");

    //异常码
    private int code;
    //异常信息
    private String msg;

    //自定义方法
    ExceptionCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

当我们对异常通过以上工具类进行封装之后,所有异常将以一种固定的格式返回,不会导致错乱:

{3 items
	"code":105
	"msg":"系统繁忙,请稍后重试"
	"data":NULL
}

异常处理

在spring boot中需要使用异常拦截器,拦截全局的异常,不直接将异常返回,而是在我们进行处理之后,以一种清晰可读的方式返回。并且前端能够清晰解读我们的异常,呈现给用户。

//捕获校验器异常
@RestControllerAdvice
public class ControllerExceptionAdvice {
    @ExceptionHandler({BindException.class})
    public ResultVo ValidExceptionHandler(BindException e) {
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);

        return new ResultVo(ResultCode.VALIDATE_ERROR.getCode(),objectError.getDefaultMessage());
    }
}

对特定异常进行拦截,并包装异常:

/**
 * 对返回结果进行包装
 */
@RestControllerAdvice(basePackages = {"channel.cert"})
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        // response是ResultVo类型,或者注释了NotControllerResponseAdvice都不进行包装
        return !methodParameter.getParameterType().isAssignableFrom(ResultVo.class);
    }

    @Override
    public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
        // String类型不能直接包装
        if (returnType.getGenericParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // 将数据包装在ResultVo里后转换为json串进行返回
                return objectMapper.writeValueAsString(new ResultVo(data));
            } catch (JsonProcessingException e) {
                throw new APIException(ResultCode.RESPONSE_PACK_ERROR, e.getMessage());
            }
        }
        // 否则直接包装成ResultVo返回
        return new ResultVo(data);
    }
}

异常捕捉

自定义异常:

@Getter
public class APIException extends RuntimeException {
    private int code;
    private String msg;

    //自定义异枚举
    public APIException(StatusCode statusCode){
        super(statusCode.getMsg());
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
    }

    // 手动设置异常
    public APIException(StatusCode statusCode, String message) {
        // message用于用户设置抛出错误详情,例如:当前价格-5,小于0
        super(message);
        // 状态码
        this.code = statusCode.getCode();
        // 状态码配套的msg
        this.msg = statusCode.getMsg();
    }

    // 默认异常使用APP_ERROR状态码
    public APIException(String errorMsg) {
        super(errorMsg);
        this.code = ExceptionCode.ERROR_DEFAULT.getCode();
        this.msg = ExceptionCode.ERROR_DEFAULT.getMsg();
    }

    //自定义参数 错误码 错误信息
    public APIException(int errorCode, String errorMsg) {
        super(errorMsg);
        this.code = errorCode;
        this.msg = ExceptionCode.ERROR_DEFAULT.getMsg();
    }

    //自定义参数 错误码 错误信息 异常
    public APIException(int errorCode, String errorMsg, Throwable cause) {
        super(errorMsg);
        this.code = errorCode;
        this.msg = errorMsg;
    }
}

对自定义异常进行捕获,通过定义好的异常的结果集返回。

/**
 * 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {

    // Assert业务异常
    @ExceptionHandler(IllegalArgumentException.class)
    public ResultVo AssertExceptionHandler(IllegalArgumentException ex) {
        log.error( " msg : "   ex.getMessage(), ex);
        if(StringUtils.isBlank(ex.getLocalizedMessage())){
            return new ResultVo(ExceptionCode.ERROR_DEFAULT);
        }
        return new ResultVo(ex.getMessage());
    }

    // 登录失效异常
    @ExceptionHandler(SaTokenException.class)
    public ResultVo LoginOutExceptionHandler(SaTokenException ex) {
        log.error( " msg : "   ex.getMessage(), ex);
        return new ResultVo(ExceptionCode.OUT_TIME);
    }

    // 登录异常
    @ExceptionHandler(NotLoginException.class)
    public ResultVo NotLoginExceptionHandler(NotLoginException ex) {
        log.error( " msg : "   ex.getMessage(), ex);
        return new ResultVo(ExceptionCode.NOT_LOGIN);
    }

    // 权限异常
    @ExceptionHandler(NotPermissionException.class)
    public ResultVo NotPermissionExceptionHandler(NotPermissionException ex) {
        log.error( " msg : "   ex.getMessage(), ex);
        return new ResultVo(ExceptionCode.NO_PERMISSION);
    }

    //角色异常
    @ExceptionHandler(NotRoleException.class)
    public ResultVo NotRoleExceptionHandler(NotRoleException ex) {
        log.error( " msg : "   ex.getMessage(), ex);
        return new ResultVo(ExceptionCode.NO_Role);
    }

    //处理自定义异常
    @ExceptionHandler(APIException.class)
    public ResultVo APIExceptionHandler(APIException e) {
        log.error(e.getMessage(), e);
        return new ResultVo(e.getCode(), e.getMsg());
    }

    //处理运行异常
    @ExceptionHandler(RuntimeException.class)
    public ResultVo RuntimeExceptionHandler(RuntimeException e) {
        log.error(e.getMessage(), e);
        return new ResultVo(ExceptionCode.ERROR_DEFAULT);
    }
}

通过以上自定义,我们就能在项目中,使用自定义异常,在我们认为可能的报错处插入,当发生错误时,我们更快定位是之前记录的错误点导致。

//查询数字证书
    @Override
    public GroupUser searchCert(String certCode) {
        try {
            //查询证书编号
            GroupUser user = queryCert(certCode);
            if(ObjectUtil.isNotNull(user)){
                return user;
            }
        }catch (Exception e){
            throw new APIException("区块链调用失败" e);
        }
        return null;
    }

以上就是SpringBoot优雅地实现异常处理的方法详解的详细内容,更多关于SpringBoot全局异常处理的资料请关注Devmax其它相关文章!

SpringBoot优雅地实现全局异常处理的方法详解的更多相关文章

  1. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  2. SpringBoot本地磁盘映射问题

    这篇文章主要介绍了SpringBoot本地磁盘映射问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

  4. SpringBoot整合Javamail实现邮件发送的详细过程

    日常开发过程中,我们经常需要使用到邮件发送任务,比方说验证码的发送、日常信息的通知等,下面这篇文章主要给大家介绍了关于SpringBoot整合Javamail实现邮件发送的详细过程,需要的朋友可以参考下

  5. Python图像运算之图像阈值化处理详解

    这篇文章将详细讲解图像阈值化处理,涉及阈值化处理、固定阈值化处理和自适应阈值化处理,这是图像边缘检测或图像增强等处理的基础,感兴趣的可以了解一下

  6. SpringBoot详细讲解视图整合引擎thymeleaf

    这篇文章主要分享了Spring Boot整合使用Thymeleaf,Thymeleaf是新一代的Java模板引擎,类似于Velocity、FreeMarker等传统引擎,关于其更多相关内容,需要的小伙伴可以参考一下

  7. Springboot集成mybatis实现多数据源配置详解流程

    在日常开发中,若遇到多个数据源的需求,怎么办呢?通过springboot集成mybatis实现多数据源配置,简单尝试一下,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  8. SpringBoot使用Minio进行文件存储的实现

    本文主要介绍了SpringBoot使用Minio进行文件存储的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能

    这篇文章主要介绍了SpringBoot中使用LoadTimeWeaving技术实现AOP功能,AOP面向切面编程,通过为目标类织入切面的方式,实现对目标类功能的增强,本文给大家介绍的非常详细,需要的朋友可以参考下

  10. 详解springboot测试类注解

    这篇文章主要介绍了springboot测试类注解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部