SpringCloud:统一异常处理
今日推荐程序猿惯用口头禅,你被击中了吗?
常见代码重构技巧(非常实用)
B站,牛啊。
程序员缺乏经验的 7 种表现
2021年4月程序员工资统计:平均14596元,南京程序员收入挤进一线。
作者:BNDong
www.cnblogs.com/bndong/p/10135370.html
在启动应用时会发现在控制台打印的日志中出现了两个路径为 {[/error]} 的访问地址,当系统中发送异常错误时,Spring Boot 会根据请求方式分别跳转到以 JSON 格式或以界面显示的 /error 地址中显示错误信息。
2018-12-18 09:36:24.627 INFO 19040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" ...
2018-12-18 09:36:24.632 INFO 19040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" ...
默认异常处理
使用 AJAX 方式请求时返回的 JSON 格式错误信息。
{"timestamp": "2018-12-18T01:50:51.196+0000","status": 404,"error": "Not Found","message": "No handler found for GET /err404","path": "/err404"
}
使用浏览器请求时返回的错误信息界面。
自定义异常处理
引入依赖
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.54</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
fastjson 是 JSON 序列化依赖, spring-boot-starter-freemarker 是一个模板引擎,用于我们设置错误输出模板。
增加配置
properties
# 出现错误时, 直接抛出异常(便于异常统一处理,否则捕获不到404)
spring.mvc.throw-exception-if-no-handler-found=true
# 不要为工程中的资源文件建立映射
spring.resources.add-mappings=false
yml
spring:# 出现错误时, 直接抛出异常(便于异常统一处理,否则捕获不到404)mvc:throw-exception-if-no-handler-found: true# 不要为工程中的资源文件建立映射resources:add-mappings: false
新建错误信息实体
/*** 信息实体*/
public class ExceptionEntity implements Serializable {private static final long serialVersionUID = 1L;private String message;private int code;private String error;private String path;@JSONField(format = "yyyy-MM-dd hh:mm:ss")private Date timestamp = new Date();public static long getSerialVersionUID() {return serialVersionUID;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getError() {return error;}public void setError(String error) {this.error = error;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public Date getTimestamp() {return timestamp;}public void setTimestamp(Date timestamp) {this.timestamp = timestamp;}
}
新建自定义异常
/*** 自定义异常*/
public class BasicException extends RuntimeException {private static final long serialVersionUID = 1L;private int code = 0;public BasicException(int code, String message) {super(message);this.code = code;}public int getCode() {return this.code;}
}
/*** 业务异常*/
public class BusinessException extends BasicException {private static final long serialVersionUID = 1L;public BusinessException(int code, String message) {super(code, message);}
}
BasicException 继承了 RuntimeException ,并在原有的 Message 基础上增加了错误码 code 的内容。而 BusinessException 则是在业务中具体使用的自定义异常类,起到了对不同的异常信息进行分类的作用。
新建 error.ftl 模板文件
位置:/src/main/resources/templates/ 用于显示错误信息
<!DOCTYPE html>
<html>
<head><meta name="robots" content="noindex,nofollow" /><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><style>h2{color: #4288ce;font-weight: 400;padding: 6px 0;margin: 6px 0 0;font-size: 18px;border-bottom: 1px solid #eee;}/* Exception Variables */.exception-var table{width: 100%;max-width: 500px;margin: 12px 0;box-sizing: border-box;table-layout:fixed;word-wrap:break-word;}.exception-var table caption{text-align: left;font-size: 16px;font-weight: bold;padding: 6px 0;}.exception-var table caption small{font-weight: 300;display: inline-block;margin-left: 10px;color: #ccc;}.exception-var table tbody{font-size: 13px;font-family: Consolas,"Liberation Mono",Courier,"微软雅黑";}.exception-var table td{padding: 0 6px;vertical-align: top;word-break: break-all;}.exception-var table td:first-child{width: 28%;font-weight: bold;white-space: nowrap;}.exception-var table td pre{margin: 0;}</style>
</head>
<body><div class="exception-var"><h2>Exception Datas</h2><table><tbody><tr><td>Code</td><td>${(exception.code)!}</td></tr><tr><td>Time</td><td>${(exception.timestamp?datetime)!}</td></tr><tr><td>Path</td><td>${(exception.path)!}</td></tr><tr><td>Exception</td><td>${(exception.error)!}</td></tr><tr><td>Message</td><td>${(exception.message)!}</td></tr></tbody></table>
</div>
</body>
</html>
编写全局异常控制类
/*** 全局异常控制类*/
@ControllerAdvice
public class GlobalExceptionHandler {/*** 404异常处理*/@ExceptionHandler(value = NoHandlerFoundException.class)@ResponseStatus(HttpStatus.NOT_FOUND)public ModelAndView errorHandler(HttpServletRequest request, NoHandlerFoundException exception, HttpServletResponse response) {return commonHandler(request, response,exception.getClass().getSimpleName(),HttpStatus.NOT_FOUND.value(),exception.getMessage());}/*** 405异常处理*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)public ModelAndView errorHandler(HttpServletRequest request, HttpRequestMethodNotSupportedException exception, HttpServletResponse response) {return commonHandler(request, response,exception.getClass().getSimpleName(),HttpStatus.METHOD_NOT_ALLOWED.value(),exception.getMessage());}/*** 415异常处理*/@ExceptionHandler(HttpMediaTypeNotSupportedException.class)public ModelAndView errorHandler(HttpServletRequest request, HttpMediaTypeNotSupportedException exception, HttpServletResponse response) {return commonHandler(request, response,exception.getClass().getSimpleName(),HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),exception.getMessage());}/*** 500异常处理*/@ExceptionHandler(value = Exception.class)public ModelAndView errorHandler (HttpServletRequest request, Exception exception, HttpServletResponse response) {return commonHandler(request, response,exception.getClass().getSimpleName(),HttpStatus.INTERNAL_SERVER_ERROR.value(),exception.getMessage());}/*** 业务异常处理*/@ExceptionHandler(value = BasicException.class)private ModelAndView errorHandler (HttpServletRequest request, BasicException exception, HttpServletResponse response) {return commonHandler(request, response,exception.getClass().getSimpleName(),exception.getCode(),exception.getMessage());}/*** 表单验证异常处理*/@ExceptionHandler(value = BindException.class)@ResponseBodypublic ExceptionEntity validExceptionHandler(BindException exception, HttpServletRequest request, HttpServletResponse response) {List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();Map<String,String> errors = new HashMap<>();for (FieldError error:fieldErrors) {errors.put(error.getField(), error.getDefaultMessage());}ExceptionEntity entity = new ExceptionEntity();entity.setMessage(JSON.toJSONString(errors));entity.setPath(request.getRequestURI());entity.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());entity.setError(exception.getClass().getSimpleName());response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());return entity;}/*** 异常处理数据处理*/private ModelAndView commonHandler (HttpServletRequest request, HttpServletResponse response,String error, int httpCode, String message) {ExceptionEntity entity = new ExceptionEntity();entity.setPath(request.getRequestURI());entity.setError(error);entity.setCode(httpCode);entity.setMessage(message);return determineOutput(request, response, entity);}/*** 异常输出处理*/private ModelAndView determineOutput(HttpServletRequest request, HttpServletResponse response, ExceptionEntity entity) {if (!(request.getHeader("accept").contains("application/json")|| (request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").contains("XMLHttpRequest")))) {ModelAndView modelAndView = new ModelAndView("error");modelAndView.addObject("exception", entity);return modelAndView;} else {response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());response.setCharacterEncoding("UTF8");response.setHeader("Content-Type", "application/json");try {response.getWriter().write(ResultJsonTools.build(ResponseCodeConstant.SYSTEM_ERROR,ResponseMessageConstant.APP_EXCEPTION,JSONObject.parseObject(JSON.toJSONString(entity))));} catch (IOException e) {e.printStackTrace();}return null;}}
}
@ControllerAdvice
作用于类上,用于标识该类用于处理全局异常。
@ExceptionHandler
作用于方法上,用于对拦截的异常类型进行处理。value 属性用于指定具体的拦截异常类型,如果有多个 ExceptionHandler 存在,则需要指定不同的 value 类型,由于异常类拥有继承关系,所以 ExceptionHandler 会首先执行在继承树中靠前的异常类型。
BindException
该异常来自于表单验证框架 Hibernate validation,当字段验证未通过时会抛出此异常。
编写测试 Controller
@RestController
public class TestController {@RequestMapping(value = "err")public void error(){throw new BusinessException(400, "业务异常错误信息");}@RequestMapping(value = "err2")public void error2(){throw new NullPointerException("手动抛出异常信息");}@RequestMapping(value = "err3")public int error3(){int a = 10 / 0;return a;}
}
使用 AJAX 方式请求时返回的 JSON 格式错误信息。
# /err
{"msg": "应用程序异常","code": -1,"status_code": 0,"data": {"path": "/err","code": 400,"error": "BusinessException","message": "业务异常错误信息","timestamp": "2018-12-18 11:09:00"}
}# /err2
{"msg": "应用程序异常","code": -1,"status_code": 0,"data": {"path": "/err2","code": 500,"error": "NullPointerException","message": "手动抛出异常信息","timestamp": "2018-12-18 11:15:15"}
}# /err3
{"msg": "应用程序异常","code": -1,"status_code": 0,"data": {"path": "/err3","code": 500,"error": "ArithmeticException","message": "/ by zero","timestamp": "2018-12-18 11:15:46"}
}# /err404
{"msg": "应用程序异常","code": -1,"status_code": 0,"data": {"path": "/err404","code": 404,"error": "NoHandlerFoundException","message": "No handler found for GET /err404","timestamp": "2018-12-18 11:16:11"}
}
使用浏览器请求时返回的错误信息界面。
示例代码:https://github.com/BNDong/spring-cloud-examples/tree/master/spring-cloud-zuul/cloud-zuul
参考资料
《微服务 分布式架构开发实战》 龚鹏 著
https://www.jianshu.com/p/1a49fa436623
推荐文章
2021年4月程序员工资统计:平均14596元,南京程序员收入挤进一线。
常见的SQL面试题:经典50例
47K Star 的SpringBoot+MyBatis+docker电商项目,附带超详细的文档!
写博客能月入10K?
一款基于 Spring Boot 的现代化社区(论坛/问答/社交网络/博客)
更多项目源码
这或许是最美的Vue+Element开源后台管理UI
推荐一款高颜值的 Spring Boot 快速开发框架
一款基于 Spring Boot 的现代化社区(论坛/问答/社交网络/博客)
13K点赞都基于 Vue+Spring 前后端分离管理系统ELAdmin,大爱
想接私活时薪再翻一倍,建议根据这几个开源的SpringBoot
SpringCloud:统一异常处理相关推荐
- ssm 异常捕获 统一处理_SSM 统一异常处理
SSM 统一异常处理 spring创建中, 处理异常可以使用try-cache处理, 也可以使用spring提供的统一异常处理 在spring中, 统一处理异常有2中方式 注解方式 @Exceptio ...
- ssm 异常捕获 统一处理_SpringMVC 统一异常处理介绍及实战
背景 什么是统一异常处理 目标 统一异常处理实战 用 Assert(断言) 替换 throw exception 定义统一异常处理器类 扩展 总结 <Java 2019 超神之路> < ...
- Spring Boot统一异常处理的拦截指南
通常我们在Spring Boot中设置的统一异常处理只能处理Controller抛出的异常.有些请求还没到Controller就出异常了,而这些异常不能被统一异常捕获,例如Servlet容器的某些异常 ...
- 使用Spring MVC统一异常处理实战
原文:http://blog.csdn.net/ufo2910628/article/details/40399539 1 描述 在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处 ...
- Spring Boot中Web应用的统一异常处理
为什么80%的码农都做不了架构师?>>> 我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛 ...
- trycatch抛出异常_Java生鲜电商平台架构中,如何统一异常处理及架构实战
补充说明:本文讲得比较细,所以篇幅较长.请认真读完,希望读完后能对统一异常处理有一个清晰的认识. 背景 软件开发过程中,不可避免的是需要处理各种异常,就我自己来说,至少有一半以上的时间都是在处理各种异 ...
- 【转】Spring mvc 统一异常处理和静态文件的配置
1.在spring mvc下实现统一异常处理很方便,只要在web.xml中配置异常时要显示的页面即可,如下: [html] view plaincopyprint? <error-page> ...
- springboot统一异常处理类及注解参数为数组的写法
springboot统一异常处理类及注解参数为数组的写法 参考文章: (1)springboot统一异常处理类及注解参数为数组的写法 (2)https://www.cnblogs.com/zhucww ...
- C#自定义异常 统一异常处理
C#自定义异常 统一异常处理 参考文章: (1)C#自定义异常 统一异常处理 (2)https://www.cnblogs.com/eedc/p/9266237.html (3)https://www ...
- 统一异常处理+错误编码设计方案
统一异常处理+错误编码设计方案 参考文章: (1)统一异常处理+错误编码设计方案 (2)https://www.cnblogs.com/wd326150354/p/10861713.html 备忘一下 ...
最新文章
- springMVC3学习(二)--ModelAndView对象
- CF452F Permutations/Luogu2757 等差子序列 树状数组、Hash
- php截取字符串函数 左右,php截取中文字符串函数的技巧
- s7-1200跟mysql_让西门子S7-1200直接连接MySQL数据库!!!
- matlab 文件之间相互调用实例
- 数据结构与算法——图解平衡二叉树及代码实现
- Eclipse中错误为 Access restriction 的解决方案
- Tomcat服务器上Servlet连接数据库连接不上出现空指针异常的解决方案
- 凝结11年技术实力 弹性计算国内首著发布
- 梦幻西游手游海外服务器维护,梦幻西游手游维护 新神器任务轩辕丘之祸开启...
- Are We Evaluating Rigorously? Benchmarking Recommendation for Reproducible Evaluation and Fair Compa
- 视频转文字怎么操作?这些方法值得收藏
- 用HTML写一首绝句古诗,《绝句二首》_杜甫的诗词_诗词名句网
- 一个百万富翁碰到一个陌生人,陌生人找他谈了一个换钱的计划.该计划如下:我每天给你10万,而你第一天给我一分钱,第二天我仍给你十万,你给我二分钱,第三天我仍给你十万,你给我四分钱......你每天给我的
- 15051:小Biu的区间和
- Macworld2007发布iPhone!
- 手机安装Linus系统
- Django REST framework+Vue 打造生鲜超市(十三)
- dl380g6服务器开机没信号,DL380 G6常见问题二
- Excel生成条形码
热门文章
- PAT:1090. Highest Price in Supply Chain (25) AC
- CSS定位(postion)和移动(float)
- 配置事务springmvc3.1 mybatis 3.1 事务不起作用
- Google搜索引擎的十大应用
- Secure CRT 自动记录日志和时间戳功能配置
- Leetcode4-寻找两个正序数组的中位数原理及代码实现
- 区块链BaaS云服务(10)用友iuap区块链平台
- python——类和对象之__str__方法的使用
- [armv8-arch64]linux kernel 5.9的异常量表介绍(irq,fiq,sync,svc)
- optee中core_init_mmu_regs函数解读