异常的处理方式有多种:

  • 自定义错误页面
  • @ExceptionHandler注解
  • @ControllerAdvice+@ExceptionHandler注解
  • 配置SimpleMappingExceptionResolver处理异常
  • 自定义 HandlerExceptionResolver 类处理异常

一、自定义错误页面

SpringBoot 默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制。一旦程序中出现了异常,SpringBoot 会向/error 的 url 发送请求。在SpringBoot 中提供了一个叫 BasicExceptionController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。

如果我们需要将所有的异常同一跳转到自定义的错误页面,需要在src/main/resources/templates(使用模板引擎时采用)或WEB-INF/jsp(与application.properties配置的视图映射一致)下创建自己的异常页面,名称必须是error。

(1) application.properties全局配置

#jsp视图映射配置
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

(2) WEB-INF/jsp/error.jsp内容

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page isErrorPage="true"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>error页面</title>
</head>
<body>
<h5>出错了,联系管理员......</h5>
<p><%=exception.getMessage()%></p>
</body>
</html>

(3) 编写controller

@RestController
public class DemoController { @RequestMapping("/showPage1")
public Object showPage(){
ModelAndView view = new ModelAndView();
String demo = null;
demo.toString(); //模拟异常
view.setViewName("error");
return view;
} }

二、@ExceptionHandler注解

将指定的异常交由具体的方法处理,显示特定的页面。

1. 由@ExceptionHandler注解指定特定异常的处理

@RestController
public class DemoController {
/**
* 模拟java.lang.NullPointerException异常
*/
@RequestMapping("/showPage1")
public Object showPage() {
ModelAndView view = new ModelAndView();
String demo = null;
demo.toString();
view.setViewName("index");
return view;
} /**
* java.lang.NullPointerException 处理空指针异常
* 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视 图的指定
* 参数 Exception e:会将产生异常对象注入到方法中
*/
@ExceptionHandler(value = { java.lang.NullPointerException.class })
public ModelAndView nullPointerExceptionHandler(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("error", e.toString());
mv.setViewName("error2");
return mv;
}
}

2. 编写error2.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page isErrorPage="true"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>error页面</title>
</head>
<body>
<h5>出错了,联系管理员......@ExceptionHandler</h5>
<p>${error }</p>
</body>
</html>

三、@ControllerAdvice+@ExceptionHandler注解

仅使用@ExceptionHandler处理异常,需要主方法与异常处理方法在同一个Controller,这样异常处理的方法不能被其他Controller使用,有代码冗余。

使用@ControllerAdvice就可以解决这个问题。

1. 模拟异常的主方法

@RestController
public class DemoController { /**
* 模拟java.lang.NullPointerException异常
*/
@RequestMapping("/showPage1")
public Object showPage() {
ModelAndView view = new ModelAndView();
String demo = null;
demo.toString();
view.setViewName("index");
return view;
} }

2. 创建异常处理的Controller

/**
* @RestControllerAdvice或@ControllerAdvice
*/
@RestControllerAdvice
public class ExceptionController {
/**
* java.lang.NullPointerException 处理空指针异常
* 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视 图的指定
* 参数 Exception e:会将产生异常对象注入到方法中
*/
@ExceptionHandler(value = { java.lang.NullPointerException.class })
public ModelAndView nullPointerExceptionHandler(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("error", e.toString());
mv.setViewName("error3");
return mv;
}
}

3. 编写jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page isErrorPage="true"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>error页面</title>
</head>
<body>
<h5>出错了,联系管理员......@ControllerAdvice</h5>
<p>${error }</p>
</body>
</html>

四、配置SimpleMappingExceptionResolver处理异常

这种方法只能是对异常和视图进行关联,无法传递错误信息

//声明成一个配置类
@Configuration
public class GlobalException {
/**
* 该方法必须要有返回值。返回值类型必须是: SimpleMappingExceptionResolver
**/
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
/**
* 参数一:异常的类型,注意必须是异常类型的全名
* 参数二:视图名称
**/
mappings.put("java.lang.ArithmeticException", "error1");
mappings.put("java.lang.NullPointerException", "error4");
// 设置异常与视图映射信息的
resolver.setExceptionMappings(mappings);
return resolver;
}
}

五、自定义 HandlerExceptionResolver 类处理异常

创建一个实现现 HandlerExceptionResolver 接口的全局异常处理类

//声明成一个配置类
@Configuration
public class GlobalException implements HandlerExceptionResolver{ @Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
ModelAndView view = new ModelAndView();
//判断不同异常类型,做不同视图跳转
if(ex instanceof NullPointerException){
view.setViewName("error2");
view.addObject("error", ex.toString());
}
return view;
} }

六、以JSON字符返回的方式统一处理异常

前面几种异常处理都是返回到相应的错误页面,平常我们用到的大部分还是用JSON字符串返回(ajax提交的方式)。

第一种:使用@ControllerAdvice和@ExceptionHandler注解

第二种: 使用ErrorController类来实现。

以JSON格式返回统一对象:

/**
* 响应对象
* @param <T>
*/
public class ResponseVo<T> implements Serializable {
private static final long serialVersionUID = 1L; public static final int RESULT_FAIL = 0;
public static final int RESULT_SUCCESS = 1; /**
* 状态码.
*/
private Integer code; /**
* 提示信息.
*/
private String msg; /**
* 具体的数据.
*/
private T data; public ResponseVo() { } public ResponseVo(Integer code, String msg) {
this.code = code;
this.msg = msg;
} public ResponseVo(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
} public Integer getCode() {
return code;
} public void setCode(Integer code) {
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public T getData() {
return data;
} public void setData(T data) {
this.data = data;
} @Override
public String toString() {
return "ResponseVo{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}

1. 使用@RestControllerAdvice和@ExceptionHandler注解

/**
* @RestControllerAdvice 方法的返回值以字符串返回,
* 等同于@ControllerAdvice + 方法上添加@ResponseBody
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* java.lang.NullPointerException 处理空指针异常
* 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视 图的指定
* 参数 Exception e:会将产生异常对象注入到方法中
*/
@ExceptionHandler(value = { java.lang.NullPointerException.class })
public ResponseVo<String> nullPointerExceptionHandler(HttpServletResponse response, NullPointerException ex) {
//这里最好也是判断下ex.getMessage()的信息是否为空(或"null"),如果是这样的话,使用ex.toString()将完整的错误信息展示出来
ResponseVo<String> responseVo = new ResponseVo<String>(ResponseVo.RESULT_FAIL, ex.getMessage());
return responseVo;
}
}

注解@RestControllerAdvice表示这是一个控制器增强类,当控制器发生异常且符合类中定义的拦截异常类,将会被拦截。可以使用basePackages属性定义拦截的控制器所在的包路径。

2. 使用ErrorController类来实现。

SpringBoot默认的错误处理类为BasicErrorController,这里编写一个自己的错误处理类,那么默认的处理类将不会起作用。

其中getErrorPath()返回的路径服务器将会重定向到该路径对应的处理类,本例中为error方法。

/**
* @RestController直接以字符串的形式返回
* 等同于@Controller + 方法上添加@ResponseBody
*/
@RestController
public class HttpErrorController implements ErrorController { private final static String ERROR_PATH = "/error"; @RequestMapping(path = ERROR_PATH)
public ResponseVo<String> error(HttpServletRequest request, HttpServletResponse response) {
ResponseVo<String> result = new ResponseVo<String>(ResponseVo.RESULT_FAIL, "HttpErrorController error:" + response.getStatus());
return result;
} @Override
public String getErrorPath() {
return ERROR_PATH;
}
}

3. 测试

@RestController
public class DemoController { @RequestMapping("/showPage")
public Object showPage(){
throw new NullPointerException("DemoController have exception");
}
}

(1) 发出一个错误的请求,也就是没有对应的处理类。从返回可以看到是由HttpErrorController类处理

{"code":0,"msg":"HttpErrorController error:404","data":null}

(2) 发出一个正常的请求(DemoController的showPage()处理),处理类中抛出空异样

{"code":0,"msg":"TestController have exception","data":null}

4. 两者的区别

(1) 注解@RestControllerAdvice方式只能处理控制器抛出的异常。此时请求已经进入控制器中。

(2) ErrorController方式可以处理所有的异常,包括未进入控制器的错误,比如404,401等错误

(3) 如果应用中两者共同存在,则@RestControllerAdvice方式处理控制器抛出的异常,类ErrorController方式未进入控制器的异常。

(4) @RestControllerAdvice方式可以定义多个拦截方法,拦截不同的异常类,并且可以获取抛出的异常信息,自由度更大。

5. 总结

(1) 因为返回的是JSON字符串,所以可以使用@RestXXXX格式或@XXXX+@ResponseBody的组合

(2) ErrorController的处理范围比第一种处理方式要大,如果两种异常处理的方式在一个web应用同时存在,需要确保第一种处理方式是返回JSON字符串,否则可能会被ErrorController再一次处理。

【使用篇二】SpringBoot异常处理(9)的更多相关文章

  1. SpringBoot系列教程web篇之全局异常处理

    当我们的后端应用出现异常时,通常会将异常状况包装之后再返回给调用方或者前端,在实际的项目中,不可能对每一个地方都做好异常处理,再优雅的代码也可能抛出异常,那么在 Spring 项目中,可以怎样优雅的处 ...

  2. SpringBoot异常处理统一封装我来做-使用篇

    SpringBoot异常处理统一封装我来做-使用篇 简介 重复功能我来写.在 SpringBoot 项目里都有全局异常处理以及返回包装等,返回前端是带上succ.code.msg.data等字段.单个 ...

  3. 源码学习系列之SpringBoot自动配置(篇二)

    源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析 继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续 ...

  4. SpringBoot系列之集成logback实现日志打印(篇二)

    SpringBoot系列之集成logback实现日志打印(篇二) 基于上篇博客SpringBoot系列之集成logback实现日志打印(篇一)之后,再写一篇博客进行补充 logback是一款开源的日志 ...

  5. SpringBoot系列之profles配置多环境(篇二)

    SpringBoot系列之profles配置多环境(篇二) 继续上篇博客SpringBoot系列之profles配置多环境(篇一)之后,继续写一篇博客进行补充 写Spring项目时,在测试环境是一套数 ...

  6. SpringBoot系列教程web篇之自定义异常处理HandlerExceptionResolver

    关于Web应用的全局异常处理,上一篇介绍了ControllerAdvice结合@ExceptionHandler的方式来实现web应用的全局异常管理: 本篇博文则带来另外一种并不常见的使用方式,通过实 ...

  7. SpringBoot异常处理(二)

    参数校验机制 JSR-303 Hibernate 参数接收方式: URL路径中的参数 {id} (@PathVariable(name="id") int-whatever) UR ...

  8. 14 微服务电商【黑马乐优商城】:day02-springcloud(理论篇二:知道什么是SpringCloud)

    本项目的笔记和资料的Download,请点击这一句话自行获取. day01-springboot(理论篇) :day01-springboot(实践篇) day02-springcloud(理论篇一: ...

  9. jackson学习之十(终篇):springboot整合(配置类)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  10. Canal 实战 | 第一篇:SpringBoot 整合 Canal + RabbitMQ 实现监听 MySQL 数据库同步更新 Redis 缓存

    一. Canal 简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费 早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同 ...

随机推荐

  1. jdbc工具类是多例的

    一直以为他 是单例的, 以为创建个工具类就是为了单例, 节省效率 , 其实 是为了封装代码, 简洁 ! 还有重要一点  :  所欲工具类里面不要抛异常 要捕捉异常  !

  2. Wwise音频解决方案概述

    Wwise(Wave Works Interactive Sound Engine,Wwise基础知识,wiki)是Audiokinetic公司提供的跨平台游戏音频解决方案,有着高效完整工作流和工具链 ...

  3. 【2019年08月26日】A股最便宜的股票

    查看更多A股最便宜的股票:androidinvest.com/CNValueTop/ 便宜指数 = PE + PB + 股息 + ROE,四因子等权,数值越大代表越低估. 本策略只是根据最新的数据来选 ...

  4. 有状态 Vs 无状态

    NET Core 分布式框架 公司物联网项目集成Orleans以支持高并发的分布式业务,对于Orleans也是第一次接触,本文就分享下个人对Orleans的理解. 这里先抛出自己的观点:Orleans ...

  5. C++:Name Lookup & Best Match

    名字查找 每当一个变量或者一个对象出现,编译器都会进行名字查找(name lookup),以确认这个变量或对象的具体属性.一般情况下,程序会从变量出现的地方开始向上查找,由内向外查找各级作用域直到全局 ...

  6. jquery改变表单某个输入框的值时,另一个或几个输入框的值同步变化,这里演示的是改变数量时价格同步变化

    效果如下,当我输入数量时,下面的价格同步变化 代码如下: 上图圈起来的事件是当input 框里面的值改变时触发的事件. 补图

  7. 使用Node.js时如何引入jQuery

    使用Node.js时如何引入jQuery 首先安装jQuery依赖 npm install jquery 然后安装jsdom npm install jsdom 引入jQuery 新版正确的依赖方式 ...

  8. Python urlib 模块

    Python urlib 模块 urlib 模块 当前再爬虫领域使用的比较少,不过它对图片爬取处理会比较方便.这里我们只使用它的图片爬取. 使用 urlib.request.urlretrieve(u ...

  9. Window权限维持(四):快捷方式修改

    Windows快捷方式包含对系统上安装的软件或文件位置(网络或本地)的引用.自从恶意软件出现之初,便已将快捷方式用作执行恶意代码以实现持久性的一种方法.快捷方式的文件扩展名是.LNK,它为红队提供了很 ...

  10. Lucene的全文检索学习

    Lucene的官方网站(Apache的顶级项目):http://lucene.apache.org/ 1.什么是Lucene? Lucene 是 apache 软件基金会的一个子项目,由 Doug C ...