【使用篇二】SpringBoot异常处理(9)
异常的处理方式有多种:
- 自定义错误页面
- @ExceptionHandler注解
- @ControllerAdvice+@ExceptionHandler注解
- 配置SimpleMappingExceptionResolver处理异常
- 自定义 HandlerExceptionResolver 类处理异常
一、自定义错误页面

如果我们需要将所有的异常同一跳转到自定义的错误页面,需要在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)的更多相关文章
- SpringBoot系列教程web篇之全局异常处理
当我们的后端应用出现异常时,通常会将异常状况包装之后再返回给调用方或者前端,在实际的项目中,不可能对每一个地方都做好异常处理,再优雅的代码也可能抛出异常,那么在 Spring 项目中,可以怎样优雅的处 ...
- SpringBoot异常处理统一封装我来做-使用篇
SpringBoot异常处理统一封装我来做-使用篇 简介 重复功能我来写.在 SpringBoot 项目里都有全局异常处理以及返回包装等,返回前端是带上succ.code.msg.data等字段.单个 ...
- 源码学习系列之SpringBoot自动配置(篇二)
源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析 继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续 ...
- SpringBoot系列之集成logback实现日志打印(篇二)
SpringBoot系列之集成logback实现日志打印(篇二) 基于上篇博客SpringBoot系列之集成logback实现日志打印(篇一)之后,再写一篇博客进行补充 logback是一款开源的日志 ...
- SpringBoot系列之profles配置多环境(篇二)
SpringBoot系列之profles配置多环境(篇二) 继续上篇博客SpringBoot系列之profles配置多环境(篇一)之后,继续写一篇博客进行补充 写Spring项目时,在测试环境是一套数 ...
- SpringBoot系列教程web篇之自定义异常处理HandlerExceptionResolver
关于Web应用的全局异常处理,上一篇介绍了ControllerAdvice结合@ExceptionHandler的方式来实现web应用的全局异常管理: 本篇博文则带来另外一种并不常见的使用方式,通过实 ...
- SpringBoot异常处理(二)
参数校验机制 JSR-303 Hibernate 参数接收方式: URL路径中的参数 {id} (@PathVariable(name="id") int-whatever) UR ...
- 14 微服务电商【黑马乐优商城】:day02-springcloud(理论篇二:知道什么是SpringCloud)
本项目的笔记和资料的Download,请点击这一句话自行获取. day01-springboot(理论篇) :day01-springboot(实践篇) day02-springcloud(理论篇一: ...
- jackson学习之十(终篇):springboot整合(配置类)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Canal 实战 | 第一篇:SpringBoot 整合 Canal + RabbitMQ 实现监听 MySQL 数据库同步更新 Redis 缓存
一. Canal 简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费 早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同 ...
随机推荐
- 【香甜的黄油 Sweet Butter】
[香甜的黄油 Sweet Butter] 洛谷P1828 https://www.luogu.org/problemnew/show/P1828 JDOJ 1803 https://neooj.com ...
- LG3205/BZOJ1996 「HNOI2010」合唱队 区间DP
区间DP 区间DP: 显然是一个区间向左右拓展形成的下一个区间,具有包含关系,所以可以使用区间DP. 状态设计: 考虑和关路灯一样设计状态 因为不知道当前这个区间是从哪个区间拓展而来,即不知道这个区间 ...
- 自定义安装office
自定义安装office 1.下载office安装包:https://msdn.itellyou.cn 2.下载offiice部署工具:https://www.microsoft.com/en-us/d ...
- ASP.NET开发实战——(十)ASP.NET MVC 与数据库之MySQL&EF
之前介绍EF时介绍了provider这个配置项,而且也介绍了在ASP.NET访问MySQL数据仍然是通过ADO.NET,不同的地方仅仅是更换了MySQL的数据提供器,那么在EF中是否也只需更换“提供器 ...
- OpenDaylight开发hello-world项目之开发环境搭建
OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码 ...
- Python apply函数
Python apply函数 1.介绍 apply函数是pandas里面所有函数中自由度最高的函数.该函数如下: DataFrame.apply(func, axis=0, broadcast=Fal ...
- npm ERR! Cannot read property 'resolve' of undefined
一 .有可能是版本过低,或者软件损坏,重新安装一下试试 地址
- 题目:利用Calendar类计算自己的出生日期距今天多少天,再将自己的出生日期利用SimpleDateFormat类设定的格式输出显示
package cn.exercise; import java.util.Calendar; import java.util.Date; import java.text.SimpleDateFo ...
- 【VSFTP服务】vsftpd文件传输协议
vsftpd文件传输协议 系统环境:CentOS Linux release 7.6.1810 (Core) 一.简介 FTP(文件传输协议)全称是:Very Secure FTP Server. ...
- C# 中如何深度复制某一个类型(备注:可能有 N 个类型需要复制)的对象?
如题,针对某一个特定的类型,深度复制,没有那么难,最起码可以手动赋值,但如果要针对 N 多类型深度复制,最简单的方法,是把这个对象序列化成 XML.JSON 或其它可以序列化的载体,然后再将这个载体反 ...