前言

  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系列——自定义统一异常处理的更多相关文章

  1. Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群

    Redis总结(五)缓存雪崩和缓存穿透等问题   前面讲过一些redis 缓存的使用和数据持久化.感兴趣的朋友可以看看之前的文章,http://www.cnblogs.com/zhangweizhon ...

  2. Spring MVC自定义统一异常处理类,并且在控制台中输出错误日志

    在使用SimpleMappingExceptionResolver实现统一异常处理后(参考Spring MVC的异常统一处理方法), 发现出现异常时,log4j无法在控制台输出错误日志.因此需要自定义 ...

  3. springboot aop + logback + 统一异常处理 打印日志

    1.src/resources路径下新建logback.xml 控制台彩色日志打印 info日志和异常日志分不同文件存储 每天自动生成日志 结合myibatis方便日志打印(debug模式) < ...

  4. Web API系列(三)统一异常处理

    前面讲了webapi的安全验证和参数安全,不清楚的朋友,可以看看前面的文章,<Web API系列(二)接口安全和参数校验>,本文主要介绍Web API异常结果的处理.作为内部或者是对外提供 ...

  5. SpringBoot系列: Spring项目异常处理最佳实践

    ===================================自定义异常类===================================稍具规模的项目, 一般都要自定义一组异常类, 这 ...

  6. SpringBoot(七)_统一异常处理

    我感觉看了这节课,给我的思考还是很多的,感觉受益良多.废话不多说,一起学习. 统一的 外层结构返回 这样利于代码看着也规范,前端处理也统一 # 错误返回 { "code": 1, ...

  7. SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚

    通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...

  8. SpringCloud微服务实战——搭建企业级开发框架(七):自定义通用响应消息及统一异常处理

      平时开发过程中,无可避免我们需要处理各类异常,所以这里我们在公共模块中自定义统一异常,Spring Boot 提供 @RestControllerAdvice 注解统一异常处理,我们在GitEgg ...

  9. HandlerExceptionResolver统一异常处理 返回JSON 和 ModelAndView

    统一异常处理类的两种方式一种是前后分离,一种是一整套集合返回指定到指定的错误页面显示错误信息 1.由于前后分离,是统一返回JSON的格式 自定义Exception public class Bussi ...

随机推荐

  1. Linux 自定义快捷命令

    Linux中一些比较常用的命令总是重复敲很麻烦,这个时候就可以使用 alias 来自定义快捷命令,用以简化操作.系统会有一些预定义的快捷命令,比如 ll 的效果就和 ls -l 一样. 可以使用 al ...

  2. codefoces D. Phoenix and Science

    原题链接:https://codeforc.es/problemset/problem/1348/D 题意:给你一个体重为一克的细菌(它可以每天进行一次二分裂即一分为二体重均分:晚上体重增加1克)求最 ...

  3. 力扣 - 92. 反转链表II

    目录 题目 思路1(迭代) 代码 复杂度分析 思路2(递归) 代码 复杂度分析 题目 92. 反转链表 II 思路1(迭代) 将反转链表分成3个部分:前一段未反转的部分.待反转链表部分.后一段未反转部 ...

  4. Python的flask接收前台的ajax的post数据和get数据

    ajax向后台发送数据: ①post方式 ajax: @app.route("/find_worldByName",methods=['POST']) type:'post', d ...

  5. django+x-admin管理后台模板开发管理后台案例(设计部分)

    使用django+x-admin管理后台模板搭建管理后台 一.环境需求 1.django:3.1 2.python:3.7 3.x-admin:2.2 4.pycharm:2020.3.2 5.ubu ...

  6. 记一次踩坑之路之Ubuntu未导入镜像前配置docke/docker-composer

    更新 apt 包索引与升级 sudo apt-get update sudo apt-get upgrade 安装 apt 依赖包,用于通过HTTPS来获取仓库: sudo apt-get insta ...

  7. Java(171-194)【接口、多态】

    1.接口概述与生活举例 接口就是一种公共的规范标准 只要符合规范标准,就可以大家通用 2.接口的定义基本格式  public interface 接口名称 {       // 抽象方法      / ...

  8. linux安装cmake

    1 概述 linux下安装cmake,目前最新的版本为3.17.0-rc2,安装的方式一共有三种:通过软件包仓库安装,通过编译好的版本进行安装,从源码手动编译安装. 2 仓库安装 笔者的是deepin ...

  9. HUAWEI AppGallery Connect获得SOC国际权威认证,多举措保护信息和隐私安全

    近日,华为应用市场AppGallery Connect(简称AGC)一次性成功通过国际权威标准组织"美国注册会计师协会(AICPA)"认定的SOC1 Type2.SOC2 Type ...

  10. JDBC_11_PreparedStatement(增删改操作)

    PreparedStatement(增删改操作) * 代码: ``` import javax.swing.plaf.nimbus.State; import java.sql.*; public c ...