SpringBoot系列——自定义统一异常处理
前言
springboot内置的/error错误页面并不一定适用我们的项目,这时候就需要进行自定义统一异常处理,本文记录springboot进行自定义统一异常处理。
1、使用@ControllerAdvice、@RestControllerAdvice捕获运行时异常。
2、重写ErrorController,手动抛出自定义ErrorPageException异常,方便404、403等被统一处理。
代码
项目结构
引入我们父类pom即可,无需引入其他依赖
开始之前,需要先定下统一返回对象、自定义异常枚举类
/**
* 自定义异常枚举类
*/
public enum ErrorEnum {
//自定义系列
USER_NAME_IS_NOT_NULL("10001","【参数校验】用户名不能为空"),
PWD_IS_NOT_NULL("10002","【参数校验】密码不能为空"), //400系列
BAD_REQUEST("400","请求的数据格式不符!"),
UNAUTHORIZED("401","登录凭证过期!"),
FORBIDDEN("403","抱歉,你无权限访问!"),
NOT_FOUND("404", "请求的资源找不到!"), //500系列
INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
SERVICE_UNAVAILABLE("503","服务器正忙,请稍后再试!"), //未知异常
UNKNOWN("10000","未知异常!"); /** 错误码 */
private String code; /** 错误描述 */
private String msg; ErrorEnum(String code, String msg) {
this.code = code;
this.msg = msg;
} public String getCode() {
return code;
} public String getMsg() {
return msg;
}
}
/**
* 统一返回对象
*/ @Data
public class Result<T> implements Serializable {
/**
* 通信数据
*/
private T data;
/**
* 通信状态
*/
private boolean flag = true;
/**
* 通信描述
*/
private String msg = "操作成功"; /**
* 通过静态方法获取实例
*/
public static <T> Result<T> of(T data) {
return new Result<>(data);
} public static <T> Result<T> of(T data, boolean flag) {
return new Result<>(data, flag);
} public static <T> Result<T> of(T data, boolean flag, String msg) {
return new Result<>(data, flag, msg);
} public static <T> Result<T> error(ErrorEnum errorEnum) {
return new Result(errorEnum.getCode(), false, errorEnum.getMsg());
} @Deprecated
public Result() { } private Result(T data) {
this.data = data;
} private Result(T data, boolean flag) {
this.data = data;
this.flag = flag;
} private Result(T data, boolean flag, String msg) {
this.data = data;
this.flag = flag;
this.msg = msg;
} }
新增两个自定义异常,便于统一处理时捕获异常
/**
* 自定义业务异常
*/
public class ServiceException extends RuntimeException { /**
* 自定义异常枚举类
*/
private ErrorEnum errorEnum; /**
* 错误码
*/
private String code; /**
* 错误信息
*/
private String errorMsg; public ServiceException() {
super();
} public ServiceException(ErrorEnum errorEnum) {
super("{code:" + errorEnum.getCode() + ",errorMsg:" + errorEnum.getMsg() + "}");
this.errorEnum = errorEnum;
this.code = errorEnum.getCode();
this.errorMsg = errorEnum.getMsg();
} public ServiceException(String code,String errorMsg) {
super("{code:" + code + ",errorMsg:" + errorMsg + "}");
this.code = code;
this.errorMsg = errorMsg;
} public ErrorEnum getErrorEnum() {
return errorEnum;
} public String getErrorMsg() {
return errorMsg;
} public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
} public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
}
}
/**
* 自定义错误页面异常
*/
public class ErrorPageException extends ServiceException { public ErrorPageException(ErrorEnum errorEnum) {
super(errorEnum);
}
}
重写ErrorController,不在跳转原生错误页面,而是抛出我们的自定义异常
/**
* 自定义errorPage
*/
@Controller
public class ErrorPageConfig implements ErrorController{ private final static String ERROR_PATH = "/error" ; @Override
public String getErrorPath() {
return ERROR_PATH;
} @RequestMapping(ERROR_PATH)
public void errorPathHandler(HttpServletResponse response) {
//抛出ErrorPageException异常,方便被ExceptionHandlerConfig处理
ErrorEnum errorEnum;
switch (response.getStatus()) {
case 404:
errorEnum = ErrorEnum.NOT_FOUND;
break;
case 403:
errorEnum = ErrorEnum.FORBIDDEN;
break;
case 401:
errorEnum = ErrorEnum.UNAUTHORIZED;
break;
case 400:
errorEnum = ErrorEnum.BAD_REQUEST;
break;
default:
errorEnum = ErrorEnum.UNKNOWN;
break;
}
throw new ErrorPageException(errorEnum);
}
}
@RestControllerAdvice,统一异常处理,捕获并返回统一返回对象Result,同时把异常信息打印到日志中
/**
* 统一异常处理
*/
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerConfig{ /**
* 业务异常 统一处理
*/
@ExceptionHandler(value = ServiceException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public Result exceptionHandler400(ServiceException e){
//把错误信息输入到日志中
log.error(ErrorUtil.errorInfoToString(e));
return Result.error(e.getErrorEnum());
} /**
* 错误页面异常 统一处理
*/
@ExceptionHandler(value = ErrorPageException.class)
@ResponseBody
public Result exceptionHandler(ErrorPageException e){
//把错误信息输入到日志中
log.error(ErrorUtil.errorInfoToString(e));
return Result.error(e.getErrorEnum());
} /**
* 空指针异常 统一处理
*/
@ExceptionHandler(value =NullPointerException.class)
@ResponseBody
public Result exceptionHandler500(NullPointerException e){
//把错误信息输入到日志中
log.error(ErrorUtil.errorInfoToString(e));
return Result.error(ErrorEnum.INTERNAL_SERVER_ERROR);
} /**
* 未知异常 统一处理
*/
@ExceptionHandler(value =Exception.class)
@ResponseBody
public Result exceptionHandler(Exception e){
//把错误信息输入到日志中
log.error(ErrorUtil.errorInfoToString(e));
return Result.error(ErrorEnum.UNKNOWN);
}
}
新建测试controller,新增几个测试接口,模拟多种异常报错的情况
/**
* 模拟异常测试
*/
@RestController
@RequestMapping("/test/")
public class TestController {
/**
* 正常返回数据
*/
@GetMapping("index")
public Result index(){
return Result.of("正常返回数据");
} /**
* 模拟空指针异常
*/
@GetMapping("nullPointerException")
public Result nullPointerException(){
//故意制造空指针异常
String msg = null;
msg.equals("huanzi-qch");
return Result.of("正常返回数据");
} /**
* 模拟业务异常,手动抛出业务异常
*/
@GetMapping("serviceException")
public Result serviceException(){
throw new ServiceException(ErrorEnum.USER_NAME_IS_NOT_NULL);
}
}
效果
正常数据返回
http://localhost:10010/test/index
模拟空指针异常
http://localhost:10010/test/nullPointerException
模拟业务异常
http://localhost:10010/test/serviceException
调用错误接口,404
http://localhost:10010/test/serviceException111
后记
自定义统一异常处理暂时先记录到这,后续再进行补充。
代码开源
代码已经开源、托管到我的GitHub、码云:
GitHub:https://github.com/huanzi-qch/springBoot
码云:https://gitee.com/huanzi-qch/springBoot
SpringBoot系列——自定义统一异常处理的更多相关文章
- Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群
Redis总结(五)缓存雪崩和缓存穿透等问题 前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...
- Spring MVC自定义统一异常处理类,并且在控制台中输出错误日志
在使用SimpleMappingExceptionResolver实现统一异常处理后(参考Spring MVC的异常统一处理方法), 发现出现异常时,log4j无法在控制台输出错误日志.因此需要自定义 ...
- springboot aop + logback + 统一异常处理 打印日志
1.src/resources路径下新建logback.xml 控制台彩色日志打印 info日志和异常日志分不同文件存储 每天自动生成日志 结合myibatis方便日志打印(debug模式) < ...
- Web API系列(三)统一异常处理
前面讲了webapi的安全验证和参数安全,不清楚的朋友,可以看看前面的文章,<Web API系列(二)接口安全和参数校验>,本文主要介绍Web API异常结果的处理.作为内部或者是对外提供 ...
- SpringBoot系列: Spring项目异常处理最佳实践
===================================自定义异常类===================================稍具规模的项目, 一般都要自定义一组异常类, 这 ...
- SpringBoot(七)_统一异常处理
我感觉看了这节课,给我的思考还是很多的,感觉受益良多.废话不多说,一起学习. 统一的 外层结构返回 这样利于代码看着也规范,前端处理也统一 # 错误返回 { "code": 1, ...
- SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚
通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...
- SpringCloud微服务实战——搭建企业级开发框架(七):自定义通用响应消息及统一异常处理
平时开发过程中,无可避免我们需要处理各类异常,所以这里我们在公共模块中自定义统一异常,Spring Boot 提供 @RestControllerAdvice 注解统一异常处理,我们在GitEgg ...
- HandlerExceptionResolver统一异常处理 返回JSON 和 ModelAndView
统一异常处理类的两种方式一种是前后分离,一种是一整套集合返回指定到指定的错误页面显示错误信息 1.由于前后分离,是统一返回JSON的格式 自定义Exception public class Bussi ...
随机推荐
- B. Johnny and Grandmaster
原题链接:https://codeforc.es/problemset/problem/1361/B 题意:给你n个k求把pk分成两组数和的最小差值对1e9+7取余. 题解:运用贪心的思想取最大的数减 ...
- 10 分钟轻松学会 Jackson 反序列化自动适配子类
作者:丁仪 来源:https://chengxuzhixin.com/blog/post/Jackson-fan-xu-lie-hua-zi-dong-shi-pei-zi-lei.html json ...
- 攻防世界 reverse easy_Maze
easy_Maze 从题目可得知是简单的迷宫问题 int __cdecl main(int argc, const char **argv, const char **envp) { __int64 ...
- Docker上安装Redis
Docker可以很方便的进行服务部署和管理,下面我们通过docker来搭建Redis的单机模式.Redis主从复制.Redis哨兵模式.Redis-Cluster模式 一.在Docker上安装单机版R ...
- ASP.NET Core分布式日志系统ELK实战演练
一.ELK简介 ELK是Elasticsearch.Logstash和Kibana首字母的缩写.这三者均是开源软件,这三套开源工具组合起来形成了一套强大的集中式日志管理平台. • Elastics ...
- Android学习之CoordinatorLayout+AppBarLayout
•AppBarLayout 简介 AppbarLayout 是一种支持响应滚动手势的 app bar 布局: 基本使用 新建一个项目,命名为 TestAppBarLayout: 修改 activity ...
- 可读性友好的JavaScript:两个专家的故事
每个人都想成为专家,但什么才是专家呢?这些年来,我见过两种被称为"专家"的人.专家一是指对语言中的每一个工具都了如指掌的人,而且无论是否有帮助,都一定要用好每一点.专家二也知道每一 ...
- 这一次,彻底搞懂 Go Cond
hi,大家好,我是 haohongfan. 本篇文章会从源码角度去深入剖析下 sync.Cond.Go 日常开发中 sync.Cond 可能是我们用的较少的控制并发的手段,因为大部分场景下都被 Cha ...
- IdentityServer4+OAuth2.0+OpenId Connect 详解
一 Oauth 2.0 1 定义 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. ...
- 中文NER的那些事儿1. Bert-Bilstm-CRF基线模型详解&代码实现
这个系列我们来聊聊序列标注中的中文实体识别问题,第一章让我们从当前比较通用的基准模型Bert+Bilstm+CRF说起,看看这个模型已经解决了哪些问题还有哪些问题待解决.以下模型实现和评估脚本,详见 ...