当前位置:首页 > 学习资源 > 讲师博文 > springboot异常处理

springboot异常处理 时间:2024-01-19      来源:华清远见

springboot异常处理

 我们知道 Spring Boot 已经提供了一套默认的异常处理机制,但是 Spring Boot 提供的默认异常处理机制却

并不一定适合我们实际的业务场景,因此,我们通常会根据自身的需要对 Spring Boot 全局异常进行统一定制,

例如定制错误页面,定制错误数据等。

Spring Boot 提供了一套默认的异常处理机制,其主要流程如下:

1. 发生异常时,将请求转发到 “/error”,交由 BasicErrorController(Spring Boot 默认的 Error 控制器) 进

行处理;

2. BasicErrorController 根据客户端的不同,自动适配返回的响应形式,浏览器客户端返回错误页面,机器客

户端返回 JSON 数据。

3. BasicErrorController 处理异常时,会调用 DefaultErrorAttributes(默认的错误属性处理工具) 的

getErrorAttributes() 方法获取错误数据。

自定义动态错误页面

如果 Sprng Boot 项目使用了模板引擎,当程序发生异常时,Spring Boot 的默认错误视图解析器 

(DefaultErrorViewResolver)就会解析模板引擎文件夹(resources/templates/)下 error 目录中的错误视图

页面。

 我们可以根据错误状态码(例如 404、500、400 等等)的不同,分别创建不同的动态错误页面(例如

404.html、500.html、400.html 等等),并将它们存放在模板引擎文件夹下的 error 目录中。当发生异常时,

Spring Boot 会根据其错误状态码精确匹配到对应的错误页面上

1 在模板引擎templates文件夹下 error 目录

2 在error目录下分别创建404.html,400.html,500.html,代码如下:

404.html

400.html

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

</head>

<body>

错误状态码:<span th:text="${status}"></span><br>

请求地址有错误!

</body>

</html>

500.html

3 构建成功,测试一下几个错误吧

自定义静态错误页面

若 Sprng Boot 项目没有使用模板引擎,当程序发生异常时,Spring Boot 的默认错误视图解析器

(DefaultErrorViewResolver)则会解析静态资源文件夹下 error 目录中的静态错误页面。

 我们可以根据错误状态码(例如 404、500、400 等等)的不同,分别创建不同的静态错误页面(例如

404.html、500.html、400.html 等等),并将它们存放在静态资源文件夹下的 error 目录中。当发生异常时,

Spring Boot 会根据错误状态码精确匹配到对应的错误页面上。

1. 在静态资源文件夹 src/recources/static 下创建error 目录,其他步骤和上述一样,注意因为没有使用模板

引擎,所以不支持theamleft表达式th:text="${status}"

原理解析

当发出请求的客户端为浏览器时,Spring Boot 会获取容器中所有的 ErrorViewResolver 对象(错误视图解析

器),并分别调用它们的 resolveErrorView() 方法对异常信息进行解析,其中自然也包括

DefaultErrorViewResolver(默认错误信息解析器)

DefaultErrorViewResolver 的部分代码如下。

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

</head>

<body>

错误状态码:<span th:text="${status}"></span><br>

springmvc 封装前端传来参数有问题

</body>

</html>

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

</head>

<body>

错误状态码:<span th:text="${status}"></span><br>

服务端报错,请检查服务端控制台打印错误

</body>

</html>

public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {

private static final Map<HttpStatus.Series, String> SERIES_VIEWS;

static {

Map<HttpStatus.Series, String> views = new EnumMap<>(HttpStatus.Series.class);

views.put(Series.CLIENT_ERROR, "4xx");

views.put(Series.SERVER_ERROR, "5xx");

SERIES_VIEWS = Collections.unmodifiableMap(views);

}

......

@Override

public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,

Map<String, Object> model) {

//尝试以错误状态码作为错误页面名进行解析

ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);

if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {

//尝试以 4xx 或 5xx 作为错误页面页面进行解析

modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);

}

return modelAndView;

}

private ModelAndView resolve(String viewName, Map<String, Object> model) {

//错误模板页面,例如 error/404、error/4xx、error/500、error/5xx

String errorViewName = "error/" + viewName;

//当模板引擎可以解析这些模板页面时,就用模板引擎解析

TemplateAvailabilityProvider provider =

this.templateAvailabilityProviders.getProvider(errorViewName,

this.applicationContext);

if (provider != null) {

//在模板能够解析到模板页面的情况下,返回 errorViewName 指定的视图

return new ModelAndView(errorViewName, model);

}

//若模板引擎不能解析,则去静态资源文件夹下查找 errorViewName 对应的页面

return resolveResource(errorViewName, model);

}

private ModelAndView resolveResource(String viewName, Map<String, Object> model) {

//遍历所有静态资源文件夹

for (String location : this.resources.getStaticLocations()) {

try {

Resource resource = this.applicationContext.getResource(location);

//静态资源文件夹下的错误页面,例如error/404.html、error/4xx.html、

error/500.html、error/5xx.html

resource = resource.createRelative(viewName + ".html");

//若静态资源文件夹下存在以上错误页面,则直接返回

if (resource.exists()) {

return new ModelAndView(new

DefaultErrorViewResolver.HtmlResourceView(resource), model);

}

} catch (Exception ex) {

}

}

return null;

}

......

}

DefaultErrorViewResolver 解析异常信息的步骤如下:

1. 根据错误状态码(例如 404、500、400 等),生成一个错误视图 error/status,例如 error/404、

error/500、error/400。

2. 尝试使用模板引擎解析 error/status 视图,即尝试从 classpath 类路径下的 templates 目录下,查找

error/status.html,例如 error/404.html、error/500.html、error/400.html。

3. 若模板引擎能够解析到 error/status 视图,则将视图和数据封装成 ModelAndView 返回并结束整个解析流

程,否则跳转到第 4 步。

4. 依次从各个静态资源文件夹中查找 error/status.html,若在静态文件夹中找到了该错误页面,则返回并结

束整个解析流程,否则跳转到第 5 步。

5. 将错误状态码(例如 404、500、400 等)转换为 4xx 或 5xx,然后重复前 4 个步骤,若解析成功则返回并

结束整个解析流程,否则跳转第 6 步。

6. 处理默认的 “/error ”请求,使用 Spring Boot 默认的错误页面(Whitelabel Error Page)

自定义异常处理

 在实际的应用开发中,很多时候往往因为一些不可控的因素导致程序出现一些错误,这个时候就要及时把异

常信息反馈给客户端,便于客户端能够及时地进行处理,而针对代码导致的异常,我们一般有两种处理方式,一

种是throws直接抛出,一种是使用try..catch捕获,一般的话,如果逻辑的异常,需要知道异常信息,我们往往

选择将异常抛出,如果只是要保证程序在出错的情况下 依然可以继续运行,则使用try..catch来捕获。

但是try..catch会导致代码量的增加,让后期我们的代码变得臃肿且难以维护。当然,springboot作为一个如此优

秀的框架,肯定不会坐视不管的,通过springboot自带的注解,我们可以方便的自定义我们的全局异常处理器,

并且以json格式返回给我们的客户端。

 在spring框架开发中,相信很多初学者都遇到过ioc注入失败,注入对象为空指针异常,我们就以这个为例

1 创建ObjectNullException 类 ,继承 exception异常

2 定义一个处理自定义异常的通知类

@ControllerAdvice 通过AOP的方式配合@ExceptionHandler()注解捕获在Controller层面发生的异常

@ExceptionHandler 是指向处理那个自定义异常类

/**

* @Description

* @Autor 伍军

* @Date 2021/11/18 9:09

* @Version 1.0

**/

public class ObjectNullException extends Exception {

}

/**

* @Description 自定义异常

* @Autor 伍军

* @Date 2021/11/18 8:34

* @Version 1.0

**/

//@ControllerAdvice 通过AOP的方式配合@ExceptionHandler()注解捕获在Controller层面发生的异常

@ControllerAdvice(basePackages ="com.hqyj.controller")

public class MyControllerException {

/**

* 处理对象空指针异常

* @param

* @return

*/

@ResponseBody

@ExceptionHandler(value = ObjectNullException.class)

public Map<String,Object> exceptionHandler(){

Map<String,Object> map = new HashMap<String,Object>();

map.put("code",0);

map.put("msg","IOC注入失败,对象为空");

return map;

}

}

3 在 查询数据库之前,写一个判断抛出异常代码

@Autowired(required = false)

AdminMapper adminMapper;

@Override

public HashMap<String, Object> select(Admin a) throws ObjectNullException {

if(adminMapper == null){

throw new ObjectNullException();

}

....省略用adminMapper查询的代码

//查询数据库

4 测试 ,取消 @Autowired 注入模拟 注入失败异常,前端用ajax发送请求,在浏览器控制台,可以看到自定义

的错误信息,如图所示

我们在看看自定义运行异常

1 自定义一个IdNotExistExcetipn 异常列

/**

* @Description

* @Autor 伍军

* @Date 2021/11/18 8:54

* @Version 1.0

**/

public class IdNotExistExcetipn extends RuntimeException {

}

2 在自定义异常的通知类里添加 处理id传值为空的异常的方法

/**

* 处理id传值为空的异常

* @param

* @return

*/

@ResponseBody

@ExceptionHandler(value = IdNotExistExcetipn.class)

public Map<String,Object> IdNotExistExcetipnHandler(){

Map<String,Object> map = new HashMap<String,Object>();

map.put("code",1);

map.put("msg","id值不存在");

return map;

}

3 我们在数据库删除之前判断id 是否为空,抛出异常

@Override

public HashMap<String, Object> del(Integer a) {

HashMap<String, Object> map = new HashMap<String, Object>();

//抛出自定义异常

if(a==null){

throw new IdNotExistExcetipn();

}

//删除

int num = adminMapper.deleteById(a);

if(num>0){

map.put("info","保存成功");

}else{

map.put("info","保存错误");

}

return map;

}

4 测试,模拟给删除id传一个空值,来测试

上一篇:vue3添加了哪些新特性

下一篇:嵌入式核心竞争力是什么?

戳我查看2020年嵌入式每月就业风云榜

点我了解华清远见高校学霸学习秘籍

猜你关心企业是如何评价华清学员的

干货分享
相关新闻
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2024 北京华清远见科技发展有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部