zoukankan      html  css  js  c++  java
  • 【SpirngBoot组件(3)】全局异常捕获

    个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道

    如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充

    前言

    在未进行全局捕获的情况下,异常有两种处理结果

    1. 主动try...catch捕获,对每种情况进行针对性处理。缺点如下:
      • 代码冗长,需要考虑各种各样的情况,无端增加工作量;
      • 人非完人,不可能考虑完整所有情况,有部分情况甚至无从捕获
    2. 被动处理,不捕获,异常信息最终将会被直接打印到前端。缺点如下:
      • 正常用户根本看不懂异常信息,大量的异常信息对于用户而言跟乱码无异
      • 异常信息会打印出后端的信息,泄露后端数据,造成巨大安全隐患,尤其是sql错误会打印出sql语句,直接暴露表名和字段名
      • 前端仅能判断执行成功与否,而无法根据具体情况作出处理,降低了项目的健壮性

    而进行全局异常捕获后,则可在控制器层面对所有异常进行处理,不同异常返回不同信息,与前端约定好数据格式后返回统一格式的数据。

    因而,全局异常已经成为项目必要的组件之一。

    1.介绍

    通常借助注解@ControllerAdvice@ExceptionHandler完成,当有异常被抛至控制层时,便可对其进行统一处理,返回约定好的json格式,或者某个页面

    2.集成

    1. 编写好controller层相关代码,此处不做赘述

    2. 创建Controller增强器

      @Slf4j
      @ControllerAdvice
      public class BaseExceptionHandler {
      }
      
      • @Slf4j:标记使用Slf4j日志框架,此处不做赘述
      • @ControllerAdvice:标记当前类为controller蹭强器
    3. 创建异常拦截方法,可创建多个

      • 拦截返回mav对象方法

            @ExceptionHandler({NestedServletException.class})
            @ResponseStatus(HttpStatus.OK)
            @ResponseBody
            public ModelAndView servletException(HttpServletRequest request, HttpServletResponse response, Exception exception) throws ServletException, IOException {
                ModelAndView mav = new ModelAndView();
                ReturnMsg message = ReturnMsg.FAIL;
                out(response, message);
                return mav;
            }
        
        • @ExceptionHandler:参数为拦截的异常类型,可枚举多种类型,但整个controller蹭强器下,一个异常仅被拦截处理一次(按照先后顺序)
        • @ResponseStatus:响应状态,通常用HttpStatus.OK即可
        • @ResponseBody:返回json对象
      • 拦截返回自定义对象方法

        @ExceptionHandler({Exception.class})
        @ResponseStatus(HttpStatus.OK)
        @ResponseBody
        public ReturnMsg processException(HttpServletRequest request, HttpServletResponse response, Exception exception) throws ServletException, IOException {
            // 打印异常信息至控制台,开始处理异常
            log.error("异常统一处理-Exception:" + exception.getLocalizedMessage(), exception);
            //异常默认为是操作失败
            ReturnMsg message = ReturnMsg.FAIL;
            // 检查异常的类型
            if (exception instanceof NestedServletException) {
                // 异步请求错误,已处理
            } else if (exception instanceof BaseException) {
                // 自定义类型的异常,转换为自定义异常
                message = ((BaseException) exception).asReturnMsg();
            } else {
                // 非自定义类型异常,打印错误信息至日志,封装ReturnMsg对象
                log.error(request.getRequestURI(), exception);
                message = ReturnMsg.FAIL;
            }
            //返回消息体
            return message;
        }
        
      • 数据写入response方法

            public static void out(ServletResponse response, ReturnMsg returnMsg) {
                PrintWriter out = null;
                try {
                    response.setContentType("application/json;charset=utf-8");
                    out = response.getWriter();
                    out.println(ObjectMapperFactory.getInstance().writeValueAsString(returnMsg));
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (null != out) {
                        out.flush();
                        out.close();
                    }
                }
            }
        

    3.使用

    • 需要处理的异常,可以try...catch捕获后处理,也可以直接抛出自定义异常,如throw new BaseException("密码错误"),由controller蹭强器转换为约定的格式后返回前端
    • 无需处理的异常,就不管咯,controller蹭强器处理后返回前端信息,但请自行完善增强器,以处理各种不同情况
    • 异常会被打印到控制台,并移交给日志框架处理,用于线上版本查看日志

    4.相关资料

    • 自定义异常及统一数据返回格式:请自行查阅相关资料,实现方案很简单易懂,本人也有做相关笔记

    5.补充

    • 请慎用Preconditions及其类似工具检查数据,数据违规时抛出的异常将会和其余运行异常混淆,无法区分,要么放弃此类工具,要么自行寻找解决方案
    • 尽管全局处理了,但异常就是异常,是不正常的情况。前端数据异常请返回数据告知前端,后端问题请尽可能完善代码以规避。异常就是异常,处理了仍然是异常

    BB两句

    这类框架性组件尽早定下来,当前项目已经大范围使用了Preconditions。。。花了半天没有完美解决方案,只能做出让步进行兼容处理,处女座表示相当难受


    作者:Echo_Ye

    WX:Echo_YeZ

    email :echo_yezi@qq.com

    个人站点:在搭了在搭了。。。(右键 - 新建文件夹)

  • 相关阅读:
    ad域的那些事儿
    关于vs无法创建虚拟目录的问题
    关于Java链接c#的webapi的注意事项
    创建.net framework webapi出现“Web 服务器被配置为不列出此目录的内容。”错误
    vs2017专业版和企业版的密钥
    数据库‘master’中拒绝CREATE DATABASE权限
    vue局部路由守卫使用
    记一次关于vantUI 下拉列表list加载数据的问题
    vue中使用require动态拼接img路径
    记录一次关于el-tree中让内容与左边有距离的爬坑记录
  • 原文地址:https://www.cnblogs.com/silent-bug/p/13563223.html
Copyright © 2011-2022 走看看