SpringBoot项目实战(004)异常处理

说明

尝试做一个springboot的框架demo,不足之处,请留言指出,不胜感谢。

异常处理

SpringBoot提供了多种Controller的异常处理,大致分为:

  • @ExceptionHandler
  • @ResponseStatus
  • 继承 AbstractHandlerExceptionResolver
  • @RestControllerAdvice(推荐)

未处理过的异常

  • 在postman测试新增,将code改为12个字符以上,可以看到,有错误提示,返回httpstatus=500:
    在这里插入图片描述

@ExceptionHandler

  • OrderController(或BaseController)中新增一段异常处理代码,这里只处理MethodArgumentNotValidException类型异常。
......
public class OrderController {
    
    
    ......
    @ExceptionHandler({
    
     MethodArgumentNotValidException.class })
    public void handlerException(){
    
    
        System.out.println("异常已经被Controller类内的ExceptionHandler处理掉了.");
    }
}
  • 再次测试Insert,可以看到返回正常1,这是因为validate异常被处理掉后,代码继续执行到dao层。
  • 由于异常被处理了,所以返回的httpstatus=200

@ResponseStatus

  • 自定义一种异常类型
package com.it_laowu.springbootstudy.springbootstudydemo.core.CustomExceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@SuppressWarnings("serial")
public class ConflictException extends RuntimeException {
    
    
}
  • 然后在OrderController中模拟一段代码抛出这种异常
public class OrderController {
    
    
    ......
    @RequestMapping(value = "/error", method = RequestMethod.GET)
    public String error() {
    
    
        throw new  ConflictException();
    }
}
  • 访问这个url,和之前的未处理异常的insert一样,返回HttpStatus=500。
  • 在异常上加上注解,这时访问,返回HttpStatus=409,即HttpStatus.CONFLICT
@ResponseStatus(value = HttpStatus.CONFLICT)
public class ConflictException extends RuntimeException {
    
    
}

继承 AbstractHandlerExceptionResolver

新建一个异常处理类,继承AbstractHandlerExceptionResolver

package com.it_laowu.springbootstudy.springbootstudydemo.core.CustomExceptions;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;

@Component
public class WithoutResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver {
    
    

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
    
    
        try {
    
    
            if (ex instanceof ConflictException) {
    
    
                return getConflictException((ConflictException) ex, response);
            }
        } catch (Exception handlerException) {
    
    
            logger.warn("异常 [" + ex.getClass().getName() + "]  无法处理。",handlerException);
        }
        return null;
    }

    private ModelAndView getConflictException(ConflictException ex, HttpServletResponse response) throws IOException {
    
    
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        return new ModelAndView();
    }
}
  1. 直接访问/order/error;返回还是HttpStatus=409
  2. 去掉@ResponseStatus(value = HttpStatus.CONFLICT);返回HttpStatus=401
  3. 结论是@ResponseStatus优先级高于WithoutResponseStatusExceptionResolver;或者说后者只能处理没有标注Status的异常。

@RestControllerAdvice

一般SpringBoot项目都推荐用这个方法;针对常见的错误类型(或者自定义一些错误类型),统一在advice做处理。
首先创建一个类:

package com.it_laowu.springbootstudy.springbootstudydemo.core.CustomExceptions;

import javax.servlet.http.HttpServletResponse;

import com.it_laowu.springbootstudy.springbootstudydemo.core.base.ResultBody;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice(basePackages = "com.it_laowu.springbootstudy.springbootstudydemo.controller")
public class ControllerAdvice {
    
    

    @ExceptionHandler(value = RuntimeException.class)
    public ResultBody defaultErrorHandler(HttpServletResponse resp, Exception e) {
    
    
        e.printStackTrace();
        return new ResultBody("555", "未知错误:"+e.getLocalizedMessage());
    }
}

测试优先级

  1. 四种方法同时存在的情况下,@ExceptionHandler 起效了。
  2. 注释@ExceptionHandler@RestControllerAdvice起效。
  3. 注释@RestControllerAdvice@ResponseStatus起效。
  4. 注释@ResponseStatus;就只剩下继承AbstractHandlerExceptionResolver可以起效了。

总结

异常处理的优先级:
@ExceptionHandler > @RestControllerAdvice > @ResponseStatus > 继承AbstractHandlerExceptionResolver

跟踪代码以后,发现异常都是在DispatcherServlethandlerExceptionResolvers中一个个遍历handler处理的。

猜你喜欢

转载自blog.csdn.net/weixin_36572983/article/details/104479460