Spring 异常处理之全局处理

承接上文Spring异常处理之本地处理,本文介绍spring异常处理的第三种方式,也就是全局处理。为什么将该方式取名为全局处理,其实很简单,因为该方式本质上和本地处理是一样的,无非就是本地处理将异常处理方法或者说异常处理逻辑直接写在controller中,而全局处理其实就是把本地处理中的异常处理方法抽取出来,放到一个地方集中管理。

  • 控制器以及业务方法
/**
 * 结合 GlobalExceptionHandlerControllerAdvice 使用
 */
@Controller
@RequestMapping(value = {"/global"})
public class WithoutExceptionHandlerController {

    /**
     * Throws an unannotated <tt>DataIntegrityViolationException</tt>. Must be caught by an
     * exception handler.
     *
     * @return Nothing - it always throws the exception.
     * @throws DataIntegrityViolationException Always thrown.
     */
    @RequestMapping("/dataIntegrityViolation")
    String throwDataIntegrityViolationException() {
        throw new DataIntegrityViolationException("ID 重复");
    }

    /**
     * Simulates a database exception by always throwing <tt>SQLException</tt>. Must be caught by an
     * exception handler.
     *
     * @return Nothing - it always throws the exception.
     * @throws SQLException Always thrown.
     */
    @RequestMapping("/sqlException")
    public String throwSqlException() throws SQLException {
        throw new SQLException();
    }

    /**
     * Always throws a <tt>SupportInfoException</tt>. Must be caught by an exception handler.
     *
     * @return Nothing - it always throws the exception.
     */
    @RequestMapping("/supportInfoException")
    public String throwCustomException() {
        throw new SupportInfoException("出错了");
    }

}
  • 集中在一起的异常处理逻辑
/**
 * 结合 WithoutExceptionHandlerController 使用
 * 
 * 对比 ExceptionHandlerController 可以发现,其实这个全局异常处理就是通过使用 ControllerAdvice 注解将 ExceptionHandler
 * 
 * 从 controller 中提取出来集中到一处
 */
@ControllerAdvice
public class GlobalExceptionHandlerControllerAdvice {

    private static final Logger logger =
            LoggerFactory.getLogger(GlobalExceptionHandlerControllerAdvice.class);

    /**
     * 异常处理之 @ControllerAdvice 之一
     */
    @ResponseStatus(value = HttpStatus.CONFLICT, reason = "数据冲突")
    @ExceptionHandler(DataIntegrityViolationException.class)
    public void conflict() {
        // 什么也不做
    }

    /**
     * 异常处理之使用 @ControllerAdvice 之二 | 指定了 view
     *
     * @param exception 异常对象
     * @return 视图名称
     */
    @ExceptionHandler({SQLException.class})
    public String databaseError(Exception exception) {
        logger.info(exception.toString());
        return "database.error";
    }

    /**
     * 异常处理之使用 @ControllerAdvice 之三 | 完全控制 - model 、view 、有用的异常信息
     *
     * @param req 当前的 HTTP 请求对象.
     * @param exception 抛出的异常 - 也就是 {@link SupportInfoException}.
     * @return 模型和视图
     * @throws Exception 异常
     */
    @ExceptionHandler(SupportInfoException.class)
    public ModelAndView handleError(HttpServletRequest req, Exception exception) throws Exception {
        if (AnnotationUtils.findAnnotation(exception.getClass(), ResponseStatus.class) != null)
            throw exception;

        logger.error("Request: " + req.getRequestURI() + " raised " + exception);

        ModelAndView mav = new ModelAndView();
        // 注意这里,这个 exception 是一个对象 | 而 DefaultErrorAttributes 中的 exception 是异常对象的完全限定名
        mav.addObject("exception", exception);
        mav.addObject("url", req.getRequestURL());
        mav.addObject("timestamp", new Date().toString());
        mav.addObject("status", 500);

        mav.setViewName("support.error");
        return mav;
    }

}

对比上一篇文章我们可以发现,唯一的不同之处就是该方式通过使用@ControllerAdvice注解将所有的异常处理逻辑集中起来了。

到这里为止,三种异常处理的方式就介绍完了。其实我们可以看出来,本地处理全局处理其实是一样的。关于到底使用哪种方式更合适呢,个人认为第三种是最合适的,因为第一种需要绑定HTTP状态码,第二种将异常处理逻辑直接写在controller中,导致业务代码和异常处理代码混在一起,第三种明显灵活的多。

  • 参考
  1. Spring 异常处理之HTTP状态码
  2. Spring 异常处理之本地处理
  3. Spring 异常处理之全局处理
  4. Spring REST 异常处理之本地处理
  5. Spring REST 异常处理之全局处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值