Spring异常处理——详解(附源码)

Spring异常处理——详解

源码文件链接在最后

背景

一个较为常见的系统,会涉及控制层,服务(业务)层、缓存层、存储层以及接口调用等,其中每一个环节都不可避免的会遇到各种不可预知的异常需要处理。如果每个步骤都单独try…catch会使系统显的很杂乱,可读性差,维护成本高;常见的方式就是,实现统一的异常处理,从而将各类异常从各个模块中解耦出来;

测试案例的制作

前端error.jsp代码
文件名:/springmvc/src/main/webapp/views/error.jsp
代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div align="center">
	<h2>ERROR PAGE</h2>
	<div>
		errorINof:${exception }
	</div>
</div>
</body>
</html>

先来个简单的数组用来测试今天的异常处理
文件名:/springmvc/src/main/java/init/wuji/springboot/mvc/exception/action/SecondExceptionController.java
代码

package init.wuji.springboot.mvc.exception.action;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SecondExceptionController {

	@RequestMapping("/sectstException")
	public String sectstException(int nameIndex) {
		
		String[] userNames = {"张三", "Lisi", "小黑"};
		
		System.out.println("hello Exception! userName:"  + userNames[nameIndex]);
		
		return "success";
	}
}

那个视图解析器就不说
别return success看不懂

	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>	

配置在了上下文
也就是我的error文件在views/error.jsp

1、在上下文在配置异常处理(较常见)

<bean id="exceptionResolver"   class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionAttribute" value="myException"></property>
		<property name="exceptionMappings">
			<props>
				<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
			</props>
		</property>
	</bean>

exceptionAttribute是exception用来前端接收的名字,源码中默认为exception,如果要修改就定义成别的名字

2、@ControllerAdvice全局作用(较常见)

这里虽说是ControllerAdvice注解,其实是其与ExceptionHandler的组合使用。在上文中可以看到,单独使用@ExceptionHandler时,其必须在一个Controller中,然而当其与ControllerAdvice组合使用时就完全没有了这个限制。换句话说,二者的组合达到的全局异常捕获处理

文件名:/springmvc/src/main/java/init/wuji/springboot/mvc/exception/action/MyExceptionHandler.java
代码:

package init.wuji.springboot.mvc.exception.action;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class MyExceptionHandler{

	@ExceptionHandler(Throwable.class)
	public ModelAndView handleException(Throwable e) {
		ModelAndView mav = new ModelAndView("error");
		System.out.println("=======MyhandleException=========");
		mav.addObject("exception", e);
		return mav;
	}

}

运行结果
在这里插入图片描述
在这里插入图片描述
一般来说全局注解比较常见使用

3、注解ExceptionHandler(局部)

注解ExceptionHandler作用对象为方法,最简单的使用方法就是放在controller文件中,详细的注解定义不再介绍。如果项目中有多个controller文件,通常可以在baseController中实现ExceptionHandler的异常处理,而各个contoller继承basecontroller从而达到统一异常处理的目的。因为比较常见,简单代码如下:
文件名:/springmvc/src/main/java/init/wuji/springboot/mvc/exception/action/TestExceptionController.java
代码:

package init.wuji.springboot.mvc.exception.action;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class TestExceptionController {
	@RequestMapping("/tstException")
	public String tstException(int nameIndex) {
		
		String[] userNames = {"张三", "Lisi", "小黑"};
		
		System.out.println("hello Exception! userName:"  + userNames[nameIndex]);
		
		return "success";
	}
	
	/**
	 * 
	 * 在使用@ExceptionHandler进行异常处理时,不可以将exception直接设置到方法参数中声明的modle, 必须返回ModelAndView
	 * 
	 * @param e
	 * @param map
	 * @return
	 */
	@ExceptionHandler
	public ModelAndView handleException(Exception e) {
	
		ModelAndView mav = new ModelAndView("error");
		System.out.println("=======handleException=========");
		mav.addObject("exception", e);
		return mav;
	}
}

运行结果
在这里插入图片描述

=======handleException=========
17:06:20.458 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Resolved [java.lang.ArrayIndexOutOfBoundsException: 5] to ModelAndView [view="error"; model={exception=java.lang.ArrayIndexOutOfBoundsException: 5}]
17:06:20.458 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.DispatcherServlet - Using resolved error view: ModelAndView [view="error"; model={exception=java.lang.ArrayIndexOutOfBoundsException: 5}]
17:06:20.459 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.view.JstlView - View name 'error', model {exception=java.lang.ArrayIndexOutOfBoundsException: 5}
17:06:20.459 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.view.JstlView - Forwarding to [/views/error.jsp]
17:06:20.461 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK


4、接口

实现HandlerExceptionResolver接口
HandlerExceptionResolver本身SpringMVC内部的接口,其内部只有resolveException一个方法,通过实现该接口我们可以达到全局异常处理的目的。
只需要将该Bean加入到Spring容器,可以通过Xml配置,也可以通过注解方式加入容器。

总结(异常处理顺序)

三种都讲完了,下面说一下,当有多个exception时的运行机制,
通过实践可知,单独@ExceptionHandle异常处理排在了首位,@ControllerAdvice排在了第二位,也就是优先选择离异常近的

下课

发布了21 篇原创文章 · 获赞 25 · 访问量 4319

猜你喜欢

转载自blog.csdn.net/weixin_43419816/article/details/104268897