作者: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

MySQL用得好好的,为什么要转ES?
Spring 中的 Controller 和Service是线程安全的吗?JAVA实现PDF和EXCEL生成和数据动态插入以及导出SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务一个 SpringBoot 项目该包含哪些?
发现一款牛逼的IDEA插件:检测代码漏洞,一键修复!
springboot+redis+Interceptor+自定义annotation实现接口自动幂等100W个微信红包封面,速度领取!!!
API接口的安全设计验证:ticket,签名,时间戳点击阅读全文前往微服务电商教程

​Spring Cloud:统一异常处理相关推荐

  1. Spring Boot统一异常处理实践

    Spring Boot统一异常处理实践 参考文章: (1)Spring Boot统一异常处理实践 (2)https://www.cnblogs.com/fundebug/p/springboot-ex ...

  2. 编程小白入门分享三:Spring AOP统一异常处理

    编程小白入门分享三:Spring AOP统一异常处理 参考文章: (1)编程小白入门分享三:Spring AOP统一异常处理 (2)https://www.cnblogs.com/lxk12345/p ...

  3. spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler)

    spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler) 参考文章: (1)spring mvc统一异常处理(@ControllerAdvice ...

  4. Spring MVC统一异常处理

    Spring MVC统一异常处理 一.为什么需要统一异常处理? 1.1 try catch带来的问题 平时项目中处理Controller层异常很多时候都会使用try catch去捕获异常(包括Cont ...

  5. Spring Boot统一异常处理的拦截指南

    通常我们在Spring Boot中设置的统一异常处理只能处理Controller抛出的异常.有些请求还没到Controller就出异常了,而这些异常不能被统一异常捕获,例如Servlet容器的某些异常 ...

  6. 使用Spring MVC统一异常处理实战

    原文:http://blog.csdn.net/ufo2910628/article/details/40399539 1 描述  在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处 ...

  7. 【转】Spring mvc 统一异常处理和静态文件的配置

    1.在spring mvc下实现统一异常处理很方便,只要在web.xml中配置异常时要显示的页面即可,如下: [html] view plaincopyprint? <error-page> ...

  8. Spring Cloud 统一配置

    本文使用 Spring Cloud 进行集中式配置管理,将以往的配置文件从项目中摘除后放到git 或svn中集中管理,并在需要变更的时候,可以通知到各应用程序,应用程序刷新配置不需要重启. 先套用下面 ...

  9. 从零开始学 Java - Spring MVC 统一异常处理

    看到 Exception 这个单词都心慌 如果有一天你发现好久没有看到Exception这个单词了,那你会不会想念她?我是不会的.她如女孩一样的令人心动又心慌,又或者你已经练功到了孤独求败,等了半辈子 ...

  10. 分布式服务跟踪及Spring Cloud的实现

    在分布式服务架构中,需要对分布式服务进行治理--在分布式服务协同向用户提供服务时,每个请求都被哪些服务处理?在遇到问题时,在调用哪个服务上发生了问题?在分析性能时,调用各个服务都花了多长时间?哪些调用 ...

最新文章

  1. 2020年,最适合AI的5种编程语言
  2. java一个点围着另一个点转_Java:按指定的度数值旋转另一个
  3. MySQL 高可用架构在业务层面的应用分析
  4. 程序员修神之路--分布式系统使用网关到底是好还是坏?
  5. 前端工程师如何与设计师合作能提高效率
  6. visual studio 2015 比较代码差异的几种方法
  7. STM32系统框图学习笔记
  8. ESP32 WS2812B灯带 代码
  9. VS2012配置WTL
  10. 海伦公式c语言double,海伦公式
  11. matlab-高数 diff 求在(x0,y0)处偏导数 数值
  12. 股票量化分析工具QTYX使用攻略——RPS指标选取强势股(更新2.6.3)
  13. HDFS 的深入了解,深入浅出,面试必备(Hadoop的三部曲——上)
  14. 最新域名升级是什么?
  15. 设置按钮5秒后可以点击下一步||5秒后自动关闭网页
  16. 胡适先生给中国公学十八年级毕业赠言:要防御两方面的堕落
  17. [RedHat笔记]第一课:Linux的发展史 以及 基础命令的使用
  18. 微信公众平台 - 授权接口说明
  19. 【系统分析师之路】我的软考修行路(写在2019年最后一周)
  20. 基于深度学习立体匹配中的‘Cost Volume‘

热门文章

  1. 2021-09-13 备份
  2. Programming Ruby 读书笔记(六)
  3. cuda 和 pytorch 安装
  4. 低代码平台如何打造个性化督办管理系统
  5. smarty-wap端
  6. 微型计算机从外观上看可以分为,冯.诺依曼计算机 1.3 计算机系统的组成 计算机系统概述 EDVAC的3个特点:...
  7. Matlab分析系统的动态性能
  8. 图像分类halcon
  9. ios点击推送闪退_王者ios14苹果手机闪退已修复,腾讯痛失百万玩家能否再回来...
  10. App接入阿里云号码认证服务 一键登录 Java后端服务部分