zoukankan      html  css  js  c++  java
  • Spring 中的统一异常处理

    在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的。因此,肯定需要在Controller捕获所有异常,并且做适当处理,返回给前端一个友好的错误码。

    不过,Controller一多,我们发现每个Controller里都有大量重复的、冗余的异常处理代码,很是啰嗦。能否将这些重复的部分抽取出来,这样保证Controller层更专注于业务逻辑的处理,同时能够使得异常的处理有一个统一的控制中心点。

    1. 全局异常处理

    1.1. HandlerExceptionResolver接口

    @Component
    public class PlatExceptionHandler implements HandlerExceptionResolver {
    private static final String TAG = PlatExceptionHandler.class.getName();
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse response, Object o, Exception e) {
    Logger.getLogger(TAG).info("PlatExceptionHandler catch exception :"+e);
    ModelAndView mv = new ModelAndView();
    response.setStatus(HttpStatus.OK.value());
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    response.setCharacterEncoding("UTF-8");
    try {
    response.getWriter().write(e.getMessage());
    } catch (IOException ee) {
    ee.printStackTrace();
    }
    return mv;
    }
    }

    使用全局异常处理器只需要两步:

    实现HandlerExceptionResolver接口。
    将实现类作为Spring Bean,这样Spring就能扫描到它并作为全局异常处理器加载。

    在 resolveException 中实现异常处理逻辑。从参数上,可以看到,不仅能够拿到发生异常的函数和异常对象,还能够拿到 HttpServletResponse对象,从而控制本次请求返回给前端的行为。

    此外,函数还可以返回一个 ModelAndView 对象,表示渲染一个视图,比方说错误页面。不过,在前后端分离为主流架构的今天,这个很少用了。如果函数返回的视图为空,则表示不需要视图。

    1.4. ControllerAdvice

    1.4.1. 使用示例

    刚才介绍的是 Controller 局部的异常处理,用于处理该 Controller 内部的特有的异常处理十分有用。

    首先,定义一个存放异常处理函数的类,并使用 @ControllerAdvice 修饰。

    @ControllerAdvice(assignableTypes = {GlobalExceptionHandlerMixin.class})

    public class ExceptionAdvice {

    @ExceptionHandler(ErrorCodeWrapperException.class)

    @ResponseBody

    public ResponseDTO<?> exceptionHandler(ErrorCodeWrapperException e) {

    if ((errCodeException.getErrorCode().equals(ErrorCode.SYSTEM_ERROR))) {

    log.error(e);

    }

    return ResponseDTO.ofErroCodeWrapperException(errCodeException);

    }

    }

    @ExceptionHanlder 修饰的方法的写法和Controller内的异常处理函数写法是一样的。

    1.4.2. 控制生效的Controller范围

    注意到,我是这样编写注解的:

    @ControllerAdvice(assignableTypes = {GlobalExceptionHandlerMixin.class})

    它用来限定这些异常处理函数起作用的 Controller 的范围。如果不写,则默认对所有 Controller 有效。

    这也是 ControllerAdvice 进行统一异常处理的优点,它能够细粒度的控制该异常处理器针对哪些 Controller 有效,这样的好处是:

    一个系统里就能够存在不同的异常处理器,Controller 也可以有选择的决定使用哪个,更加灵活。
    不同的业务模块可能对异常处理的方式不同,通过该机制就能做到。
    设想一个一开始并未使用全局异常处理的系统,如果直接引入全局范围内生效的全局异常处理,势必可能会改变已有 Controller 的行为,有侵入性。

    也就是说,如果不控制生效范围,即默认对所有 Controller 生效。如果控制生效范围,则默认对所有 Controller 不生效,降低侵入性。

    以上几种方式是 Spring 专门为异常处理设计的机制。就我个人而言,由于 ControllerAdvice 具有更细粒度的控制能力,所以我更偏爱于在系统中使用 ControllerAdvice 进行统一异常处理。除了用异常来传递系统中的意外错误,也会用它来传递处于接口行为一部分的业务错误。这也是异常的优点之一

    @ControllerAdvice
    public class RRExceptionHandler {
    private Logger logger=LoggerFactory.getLogger(getClass());
    @ExceptionHandler(Exception.class)
    public ResponseEntity<BaseResultVO> handleException(Exception e){
    BaseResultVO baseResultVO=new BaseResultVO(ResponseConstant.SYSTERM_EXCEPT.getCode(),e.getMessage());
    logger.error(e.getMessage(),e);
    return new ResponseEntity(baseResultVO,HttpStatus.OK);
    }

    @ExceptionHandler(MyException.class)
    public ResponseEntity<BaseResultVO> handleException(MyException e){
    BaseResultVO baseResultVO=new BaseResultVO(ResponseConstant.SYSTERM_EXCEPT.getCode(),e.getMessage());
    logger.error(e.getMessage(),e);
    return new ResponseEntity(baseResultVO,HttpStatus.OK);
    }
    }
  • 相关阅读:
    leetcode108 Convert Sorted Array to Binary Search Tree
    leetcode98 Validate Binary Search Tree
    leetcode103 Binary Tree Zigzag Level Order Traversal
    leetcode116 Populating Next Right Pointers in Each Node
    Python全栈之路Day15
    Python全栈之路Day11
    集群监控
    Python全栈之路Day10
    自动部署反向代理、web、nfs
    5.Scss的插值
  • 原文地址:https://www.cnblogs.com/WeidLang/p/9809316.html
Copyright © 2011-2022 走看看