文章目录
说明
尝试做一个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();
}
}
- 直接访问/order/error;返回还是HttpStatus=409
- 去掉
@ResponseStatus(value = HttpStatus.CONFLICT)
;返回HttpStatus=401 - 结论是
@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());
}
}
测试优先级
- 四种方法同时存在的情况下,
@ExceptionHandler
起效了。 - 注释
@ExceptionHandler
;@RestControllerAdvice
起效。 - 注释
@RestControllerAdvice
;@ResponseStatus
起效。 - 注释
@ResponseStatus
;就只剩下继承AbstractHandlerExceptionResolver
可以起效了。
总结
异常处理的优先级:
@ExceptionHandler
> @RestControllerAdvice
> @ResponseStatus
> 继承AbstractHandlerExceptionResolver
跟踪代码以后,发现异常都是在DispatcherServlet
的handlerExceptionResolvers
中一个个遍历handler处理的。