前言

      本章讲解SpringBoot中异常处理的方式

方法

1.概念

在springBoot中,一旦程序发生了异常,那么会直接跳转到错误页面,如下所示:

spring boot Autowired报错 spring boot /error_java

显然,这对我们程序员来说无所谓!我们可以看到是500错误。

如果是用户看到的话,它们会感到十分困惑,这是个什么玩意儿?

基于用户的体验,我们需要对异常的处理进行调整,以满足用户的需求。

2.自定义异常页面

SpringBoot默认的异常处理机制为:

当程序中出现异常时,springBoot会向/error发送请求,springBoot中存在一个BasicExceptionController的类负责处理该异常请求,然后跳转到默认的异常页面显示相应的信息,也就是我们上面图中看到的内容。

那么这个默认的页面叫什么呢?其实也叫error,我们可以在templates目录下新建一个html,名字为error.html

spring boot Autowired报错 spring boot /error_java_02

启动项目,使得controller中产生异常,观察错误页面显示:

spring boot Autowired报错 spring boot /error_exception_03

我们可以发现,我们成功的覆盖了其默认的error页面显示!!

但是,所有的异常将统一跳转到该页面,有些时候我们并不希望这样,而是我们关心的异常显示不同的界面,其他一律跳转到固定页面。很显然,目前的方式做不到这一点!

3.@ExceptionHandler方式处理异常

为了解决上面的缺点,我们将使用@ExceptionHandler注解来进行异常的处理。

代码示例如下:

package cn.edu.ccut.controller;

import java.util.Date;

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 UserController {
	//产生NullPointerException
	@RequestMapping("/showPage")
	public String showPage(){
		Date date = null;
		date.getTime();
		return "login";
	}
	//产生ArithmeticException
	@RequestMapping("/showPage2")
	public String showPage2(){
		int a = 1/0;
		return "login";
	}
	/**
	 * 使用@ExceptionHandler注解处理程序中出现的异常
	 * 这里展示处理ArithmeticException和NullPointerException
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value={ArithmeticException.class,NullPointerException.class})
	public ModelAndView exceptionHandler(Exception e){
		ModelAndView mv = new ModelAndView();
		if(e instanceof ArithmeticException){
			mv.setViewName("error1");
		}else if(e instanceof NullPointerException){
			mv.setViewName("error2");
		}
		mv.addObject("error", e.toString());
		return mv;
	}
}

我们将error1和error2进行创建并简单的修改其中的内容。

error1:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>错误页面ArithmeticException</title>
</head>
<body>
    出错啦 !<br/>
    <span th:text="${error}"></span>
</body>
</html>

error2:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>错误页面NullPointerException</title>
</head>
<body>
    出错啦 !<br/>
    <span th:text="${error}"></span>
</body>
</html>

接下来访问showPage和showPage2观察结果:

spring boot Autowired报错 spring boot /error_springBoot_04

spring boot Autowired报错 spring boot /error_springBoot_05

由此可见,我们成功的实现了异常分类页面的显示!

但是,你还会发现一个问题,该处理方法只是在该controller生效!这是一个比较尴尬的问题!

4.@ControllerAdvice + @ExceptionHandler方式处理异常

上面我们发现,其处理方法只能在一个controller中生效,其他的controller要想处理异常的话,也需要将处理方法进行一个拷贝,那么就造成了代码的冗余,难于维护!

本次的处理方法是将处理的方法放到一个专门的异常处理类中进行处理,使其对所有controller生效,有效的复用代码。

其中加上注解@ControllerAdvice

package cn.edu.ccut.exception;

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

@ControllerAdvice
public class GlobalExceptionHandler {
	
	/**
	 * 使用@ExceptionHandler注解处理程序中出现的异常
	 * 这里展示处理ArithmeticException和NullPointerException
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value={ArithmeticException.class,NullPointerException.class})
	public ModelAndView exceptionHandler(Exception e){
		ModelAndView mv = new ModelAndView();
		if(e instanceof ArithmeticException){
			mv.setViewName("error1");
		}else if(e instanceof NullPointerException){
			mv.setViewName("error2");
		}
		mv.addObject("error", e.toString());
		return mv;
	}
}

这样的话,所有的controller的相应异常我们就都能够捕捉到了。

5.SimpleMappingExceptionResolver处理异常

通过@ControllerAdvice + @ExceptionHandler方式处理异常的方式,我们可以轻松的做到异常分类处理,springBoot还提供SimpleMappingExceptionResolver处理异常

将GlobalExceptionHandle类做如下修改,使得处理异常的额代码变的简洁:

package cn.edu.ccut.exception;

import java.util.Properties;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

@Configuration
public class GlobalExceptionHandler {
	
	@Bean
	public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
		SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
		
		Properties properties = new Properties();
		// key为异常全称,value为跳转视图名
		properties.put("java.lang.ArithmeticException", "error1");
		properties.put("java.lang.NullPointerException", "error2");
		
		resolver.setExceptionMappings(properties);
		return resolver;
	}
}

访问showPage结果如下:

spring boot Autowired报错 spring boot /error_springBoot_06

我们发现,该方式处理异常无法向前台返回异常的一些信息,这是他的缺点!

6.自定义HandlerExceptionResolver

如果我们使用了上面的方式,没有达到向前台传递异常信息的目标,那么我们还可以这么做,将GlobalExceptionHandle类做如下修改:

注意:它需要我们实现HandlerExceptionResolver

package cn.edu.ccut.exception;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

@Configuration
public class GlobalExceptionHandler implements HandlerExceptionResolver{

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception e) {
		ModelAndView mv = new ModelAndView();
		if(e instanceof ArithmeticException){
			mv.setViewName("error1");
		}else if(e instanceof NullPointerException){
			mv.setViewName("error2");
		}
		mv.addObject("error", e.toString());
		return mv;
	}
}

大体上和@ControllerAdvice + @ExceptionHandler方式相似!

spring boot Autowired报错 spring boot /error_html_07