SpringMVC中的异常处理
前言
Spring项目(SSM项目)的异常处理原理如图:
正文
Spring的异常处理方式有三种:
1、全局级别的异常处理器,实现HandlerExceptionResolver接口
2、在Controller层面使用注解@ExceptionHandler
3、全局级别的异常处理器,使用注解@ControllerAdvice + @ExceptionHandler
一、全局异常处理器,通过HandlerExceptionResolver接口实现
第一步,创建自定义异常类,继承Exception类
public class MyException extends Exception {
private String msg;
public MyException(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
第二步,创建类MyHandlerExceptionResolver(自定义名称)实现HandlerExceptionResolver接口
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
ModelAndView mv = new ModelAndView();
//获取异常信息
String errorMsg = " ";
//判断异常信息类型 instanceof 返回boolean,判断左边是否为右边的实例
if(ex instanceof MyException) {
//执行自定义异常处理
errorMsg = "<b>异常原因:</b>自定义异常" + "<br/>" + ((MyException)ex).getMessage() + "<br/>" + "<b>出错来源:</b>" + handler;//handler 出错来源
}else {
errorMsg = "<b>异常原因:</b>运行时异常" + "<br/>" + ex.getMessage() + "<br/>" + "<b>出错来源:</b>" + handler;
}
//将异常信息输出到错误页面
mv.addObject("error", errorMsg);//ex.getMessage() 获取异常信息
//设置要跳转的视图名称
mv.setViewName("/error.jsp");
return mv;
}
}
第三步,在Spring配置文件(一般名称为applicationContext.xml)中配置异常处理器
(或者不配置xml文件,直接使用注解)
<!-- 异常处理器 -->
<bean class="cn.sx.exception.MyHandlerExceptionResolver" />
//class的名称就是实现HandlerExceptionResolver接口的那个类名
这样就可以实现自定义的异常捕获了!
二、在Controller层面使用注解@ExceptionHandler
针对可能出现异常的Controller,添加注解捕获异常
@Controller
@RequestMapping("/testController")
public class TestController {
@RequestMapping("/demo1")
@ResponseBody
public Object demo1(){
int i = 1 / 0;
return new Date();
}
@ExceptionHandler({RuntimeException.class})
public ModelAndView fix(Exception ex){
System.out.println("do This");
return new ModelAndView("error",new ModelMap("ex",ex.getMessage()));
}
}
注意事项:
1、 一个Controller下多个@ExceptionHandler上的异常类型不能出现一样的,否则运行时抛异常 Ambiguous @ExceptionHandler method mapped for;
2、@ExceptionHandler下方法返回值类型支持多种,常见的ModelAndView,@ResponseBody注解标注,ResponseEntity等类型都OK.
3、@ExceptionHandler:用于捕获所有控制器里面的异常,并进行处理。
三、全局级别的异常处理器,使用注解@ControllerAdvice + @ExceptionHandler
@ControllerAdvice
public class GlobalController {
@ExceptionHandler(RuntimeException.class)
public ModelAndView fix1(Exception e){
System.out.println("全局的异常处理器");
ModelMap mmp=new ModelMap();
mmp.addAttribute("ex",e);
return new ModelAndView("error",mmp);
}
}
这种情况下 @ExceptionHandler 与第二种方式用法相同,返回值支持ModelAndView,@ResponseBody等多种形式.
注意:被@ControllerAdvice注解的全局异常处理类也是一个 Controller ,我们需要配置扫描路径,确保能够扫描到这个Controller。
结论
Spring的异常处理方式的三种方法:
1、全局级别的异常处理器,实现HandlerExceptionResolver接口
2、在Controller层面使用注解@ExceptionHandler
3、全局级别的异常处理器,使用注解@ControllerAdvice + @ExceptionHandler
它们的对比:
1.优先级来说,@Controller+@ExceptionHandler优先级最高,其次是@ControllerAdvice+
@ExceptionHandler,最后才是HandlerExceptionResolver,说明假设三种方式并存的情况 优先级越高的越先选择,而且被一个捕获处理了就不去执行其他的。
2.三种方式都支持多种返回类型
@Controller+@ExceptionHandler、@ControllerAdvice+@ExceptionHandler可以使用Spring支持的@ResponseBody、ResponseEntity,而HandlerExceptionResolver方法声明返回值类型只能是 ModelAndView,如果需要返回JSON、xml等需要自己实现.
3.缓存利用
@Controller+@ExceptionHandler的缓存信息在ExceptionHandlerExceptionResolver的exceptionHandlerCache。
@ControllerAdvice+@ExceptionHandler的缓存信息在ExceptionHandlerExceptionResolver的exceptionHandlerAdviceCache中。
而HandlerExceptionResolver接口是不做缓存的,在前面两种方式都fail的情况下才会走自己的HandlerExceptionResolver实现类,多少有点性能损耗。
参考:
https://blog.csdn.net/liuchang19950703/article/details/103661770
https://www.cnblogs.com/lvbinbin2yujie/p/10574812.html#type1
https://blog.csdn.net/weixin_45924969/article/details/103240850
https://blog.csdn.net/hbtj_1216/article/details/81102063?