前言

  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. 安装anaconda和第三方库tushare

    安装anaconda和第三方库tushare 血泪教训 下载32位的anaconda(同你Python版本,不然会碰到第三方库无法import的问题) 安装anaconda 安装到C盘会比较快,安装到 ...

  2. Android 开发学习进程0.30 builder模式创建popwindow

    builder模式创建自定义popwindow builder设计模式 将一个复杂的对象构建与它的表示分离,简化代码的使用方式.当对象有多个参数或多个零件同时初始化方法同时初始化方法有默认值时,采用此 ...

  3. c++一些概念

    面向对象语言三大特征: 封装,多态,继承 封装: 1.将函数定义到结构体内部,就是封装. 2.编译器会自动传递结构体的指针给函数. 类: 带有函数的结构体,称为类. 成员函数: 结构体里面的函数,称为 ...

  4. 基于SageMath的数学网站——本科毕业开发项目

    1 绪论 1.1研究背景 我国是一个拥有15亿人口的大国.其中,据2017年的统计,全国共有大学生2600万左右.如此数量众多的大学生,都会有着学习基础数理课程的需求.而在高校的数学教学中,教授最多最 ...

  5. Python 网络编程 C/S建立Socket连接

    分为客户端和服务端 服务端 server.py 客户端 1 #coding=utf-8 2 import socket 3 4 client = socket.socket() #生成socket连接 ...

  6. Database | 浅谈Query Optimization (1)

    综述 由于SQL是声明式语言(declarative),用户只告诉了DBMS想要获取什么,但没有指出如何计算.因此,DBMS需要将SQL语句转换成可执行的查询计划(Query Plan).但是对同样的 ...

  7. 翻译:《实用的Python编程》08_03_Debugging

    目录 | 上一节 (8.2 日志) | 下一节 (9 包) 8.3 调试 调试建议 假设程序崩溃了: bash % python3 blah.py Traceback (most recent cal ...

  8. OO_Unit3总结

    OO_Unit3总结 一.JML情况 理论基础 JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言,为严格的程序设计提供了一套行之有效的方法.通过J ...

  9. Kafka优雅应用

    Kafka API实战 注意版本问题这个,kafka-client要和kafka的版本一致 <dependency> <groupId>org.apache.kafka< ...

  10. Ambassador-04- Mapping 资源

    官方文档:https://www.getambassador.io/docs/latest/topics/using/intro-mappings/#resources Ambassador 通过Ma ...