用户HTTP状态码(ResponseStatus)
//在自定义的异常上使用ResponseStatus注解。
//当我们的Controller抛出异常,并且没有被处理的时候,他将返回HTTP STATUS 为指定值的 HTTP RESPONSE
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Order") // 404
public class OrderNotFoundException extends RuntimeException {
// ...
}
在一个controller 异常处理(@ExceptionHandler)
在一个Controller中,使用注解@ExceptionHandler 来处理@RequestMapping方法抛出的异常,注意这种只在单个Controller中有效。这么做可以:
- 发生异常后,改变Response status, 一般而言,发生异常返回HTTP STATUS 500.。
- 发生错误后转到错误页面
- 可以为不同异常定义不同处理(如不同的错误页面,不同的Response status)
@Controller
public class ExceptionHandlingController {
// 我们标注了@RequestMapping的方法
...
//处理异常的方法。
// 把我们定义的异常转换为特定的Http status code
@ResponseStatus(value=HttpStatus.CONFLICT, reason="Data integrity violation") // 409
@ExceptionHandler(DataIntegrityViolationException.class)
public void conflict() {
// Nothing to do
}
// 捕获SQLException,DataAccessException异常,转到特定的页面。
@ExceptionHandler({SQLException.class,DataAccessException.class})
public String databaseError() {
return "databaseError";
}
// 通过ModelAndView返回页面,以及往页面传相应的值
@ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception exception) {
logger.error("Request: " + req.getRequestURL() + " raised " + exception);
ModelAndView mav = new ModelAndView();
mav.addObject("exception", exception);
mav.addObject("url", req.getRequestURL());
mav.setViewName("error");
return mav;
}
}
全局异常处理(@ControllerAdvice)
在类上使用 @ControllerAdvice注解,可以使得我们处理整个程序中抛出的异常, 然后方法上使用@ExceptionHandler来定义处理不同的异常。
如果我们要处理所有的异常, 可以这么做:
@ControllerAdvice
class GlobalDefaultExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
//如果这个异常被@ResponseStatus注释,抛出异常.并且让框架处理它,就像这个文档开始的那个例子:OrderNotFoundException异常.
//AnnotationUtils 是一个spring框架的实用工具类
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
throw e;
}
// 否则跳转到默认的error-view.
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
深入
实现HandlerExceptionResolver接口,SpringMVC可以使用他来处理Controller中抛出的异常
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex);
}
SpringMVC使用三种默认的HandlerExceptionResolver来处理我们的异常
- ExceptionHandlerExceptionResolver:处理匹配@ExceptionHandler注解的异常。
- ResponseStatusExceptionResolver: 处理被@ResponseStatus注解的异常
- DefaultHandlerExceptionResolver:把Spring定义的一些标准异常,转换为HTTP STATUS CODE.
Spring内置的SimpleMappingExceptionResolver实现了HandlerExceptionResolver接口,也是我们经常使用的.
XML配置如下:
<bean id="simpleMappingExceptionResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<map>
<!-- key为异常类型,value为要转到的页面 -->
<entry key="DatabaseException" value="databaseError"/>
<entry key="InvalidCreditCardException" value="creditCardError"/>
</map>
</property>
<!-- 默认的异常页面 -->
<property name="defaultErrorView" value="error"/>
<!-- 在页面我们可以通过ex拿到异常信息 -->
<property name="exceptionAttribute" value="ex"/>
<!-- 用来记录异常的日志名称. 默认不设置,所以日志是被禁用的(不记录异常信息) -->
<property name="warnLogCategory" value="example.MvcLogger"/>
</bean>