Spring MVC 中的异常处理

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?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值