包括:
一. HandlerExceptionResolver 接口 实现统一异常
二. 注解方式 实现统一异常
Spring 的异常统一处理的方式有2种。
一. HandlerExceptionResolver 接口 实现统一异常
二. 注解方式 实现统一异常
Spring 的异常统一处理的方式有2种。
- 直接自己实现 HandlerExceptionResolver 接口。
- 使用注解的方式实现一个专门用于处理异常的Controller——ExceptionHandler。
一. HandlerExceptionResolver 接口 实现统一异常
HandlerExceptionResolver 是一个接口,SpringMVC 本身已经对其有了一个自身的实现 -- DefaultExceptionResolver,该解析器只是对其中的一些比较典型的异常进行了拦截处理。
1.1 SpringMVC 默认拦截器设置
1. 在SpringMVC 的 DispatcherServlet中,有如下配置:
HandlerExceptionResolver 是一个接口,SpringMVC 本身已经对其有了一个自身的实现 -- DefaultExceptionResolver,该解析器只是对其中的一些比较典型的异常进行了拦截处理。
1.1 SpringMVC 默认拦截器设置
1. 在SpringMVC 的 DispatcherServlet中,有如下配置:
protected void initStrategies(ApplicationContext context) {
......
initHandlerExceptionResolvers(context);
......
}
2. 看其以下具体实现(如果没有我们手动配置,那么会注册一个默认的HandlerExceptionResolver):
private void initHandlerExceptionResolvers(ApplicationContext context) {
......
// Ensure we have at least some HandlerExceptionResolvers, by registering
// default HandlerExceptionResolvers if no other resolvers are found.
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
3. 最后,在具体的 getDefaultStrategies() 方法中 ,有以下的注释说明了如何创建什么HandlerExceptionResolver。
/**
* Create a List of default strategy objects for the given strategy interface.
* <p>The default implementation uses the "DispatcherServlet.properties" file (in the same
* package as the DispatcherServlet class) to determine the class names. It instantiates
* the strategy objects through the context's BeanFactory.
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the List of corresponding strategy objects
*/
4. 在 DispatcherServlet.properties 中,可以看到会创建如下的HandlerExceptionResolver。
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
5. 在 DefaultHandlerExceptionResolver 中,有其具体的异常处理方式:
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
try {
if (ex instanceof NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, request, response,
handler);
}
else if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
response, handler);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
handler);
}
......
}
并且在 DefaultHandlerExceptionResolver 的父类中,实现了 HandlerExceptionResolver 接口。
1.2 如何配置自定义的拦截器
@Component
public class ExceptionTest implements HandlerExceptionResolver{
/**
* TODO 简单描述该方法的实现功能(可选).
* @see org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
*/
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
System.out.println("This is exception handler method!");
return null;
}
}
简单来说,就是实现 HandlerExceptionResolver 接口。
二. 使用注解方式
使用@ExceptionHandler进行处理有一个不好的地方是进行异常处理的方法必须与出错的方法在同一个Controller里面,例如:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import com.tiantian.blog.web.servlet.MyException;
@Controller
public class GlobalController {
/**
* 用于处理异常的
* @return
*/
@ExceptionHandler({MyException.class})
public String exception(MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
return "exception";
}
@RequestMapping("test")
public void test() {
throw new MyException("出错了!");
}
}
当发生异常的时候,上述两种方式都使用了的时候,第一种方式会将第二种方式覆盖。
总结:
- 使用HandlerExceptionResolver 接口实现统一异常:需要我们重写其接口的方式,再返回 ModelAndView 对象即可。
- 使用@ExceptionHandler 注解。缺点:处理异常的方法和出错的方法必须在同一个Controller 中。