SpringBoot系列(十)统一异常处理与统一结果返回

往期推荐

SpringBoot系列(一)idea新建Springboot项目

SpringBoot系列(二)入门知识

springBoot系列(三)配置文件详解

SpringBoot系列(四)web静态资源配置详解

SpringBoot系列(五)Mybatis整合完整详细版

SpringBoot系列(六)集成thymeleaf详解版

Springboot系列(七) 集成接口文档swagger,使用,测试

SpringBoot系列(八)分分钟学会Springboot多种解决跨域方式

SpringBoot系列(九)单,多文件上传的正确姿势

目录

引言

 日常开发过程中,难免有的程序会因为某些原因抛出异常,而这些异常一般都是利用try ,catch的方式处理异常或者throw,throws的方式抛出异常不管。这种方法对于程序员来说处理也比较麻烦,对客户来说也不太友好,所以我们希望既能方便程序员编写代码,不用过多的自己去处理各种异常编写重复的代码又能提升用户的体验,这时候全局异常处理就显得很重要也很便捷了,是一种不错的选择。

1. 全局异常捕获与处理

 因为现在主流的都是前后端分离的项目,所以我们的异常处理也根据前后端分离来讲述。

 Springboot对于异常的处理也做了不错的支持,它提供了一个 @ControllerAdvice注解以及 @ExceptionHandler注解,前者是用来开启全局的异常捕获,后者则是说明捕获哪些异常,对那些异常进行处理。

@ControllerAdvice
public class MyExceptionHandler { @ExceptionHandler(value =Exception.class)
public String exceptionHandler(Exception e){
System.out.println("发生了一个异常"+e);
return e.getMessage();
}
}

 上面这段代码就是说,只要是代码运行过程中有异常就会进行捕获,并输出出这个异常。然后我们随便编写一个会发生异常的代码,测试出来的异常是这样的。

 这对于我们前后端分离来说并不好,前后端分离之后唯一的交互就是json了,我们也希望将后端的异常变成json返回给前端处理。下面我们看看统一结果处理。

2. 统一结果返回与统一异常

代码:

public class Result<T> {
//是否成功
private Boolean success;
//状态码
private Integer code;
//提示信息
private String msg;
//数据
private T data;
public Result() { }
//自定义返回结果的构造方法
public Result(Boolean success,Integer code, String msg,T data) {
this.success = success;
this.code = code;
this.msg = msg;
this.data = data;
}
//自定义异常返回的结果
public static Result defineError(DefinitionException de){
Result result = new Result();
result.setSuccess(false);
result.setCode(de.getErrorCode());
result.setMsg(de.getErrorMsg());
result.setData(null);
return result;
}
//其他异常处理方法返回的结果
public static Result otherError(ErrorEnum errorEnum){
Result result = new Result();
result.setMsg(errorEnum.getErrorMsg());
result.setCode(errorEnum.getErrorCode());
result.setSuccess(false);
result.setData(null);
return result;
}
}

 说明:其中省略了get,set方法。另外方法之中包含了一个自定义的枚举。代码如下:

public enum ErrorEnum {
// 数据操作错误定义
SUCCESS(200, "nice"),
NO_PERMISSION(403,"你没得权限"),
NO_AUTH(401,"你能不能先登录一下"),
NOT_FOUND(404, "未找到该资源!"),
INTERNAL_SERVER_ERROR(500, "服务器跑路了"),
; /** 错误码 */
private Integer errorCode; /** 错误信息 */
private String errorMsg; ErrorEnum(Integer errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
} public Integer getErrorCode() {
return errorCode;
} public String getErrorMsg() {
return errorMsg;
}
}

说明:枚举类中定义了常见的错误码以及错误的提示信息。这里我们就定义好了统一的结果返回,其中里面的静态方法是用来当程序异常的时候转换成异常返回规定的格式。

 然后我们需要自定义异常处理类。代码如下:

public class DefinitionException extends RuntimeException{

    protected Integer errorCode;
protected String errorMsg; public DefinitionException(){ }
public DefinitionException(Integer errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
} public Integer getErrorCode() {
return errorCode;
} public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
} public String getErrorMsg() {
return errorMsg;
} public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}

 其中包含了错误的状态码,错误的提示信息。然后我们可以自定义一个全局异常处理类,来处理各种异常,包括自己定义的异常和内部异常。这样可以简化不少代码,不用自己对每个异常都使用try,catch的方式来实现。

@ControllerAdvice
public class GlobalExceptionHandler { /**
* 处理自定义异常
*
*/
@ExceptionHandler(value = DefinitionException.class)
@ResponseBody
public Result bizExceptionHandler(DefinitionException e) {
return Result.defineError(e);
} /**
* 处理其他异常
*
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result exceptionHandler( Exception e) {
return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR);
}
}

说明:每个方法上面加上一个 @ResponseBody的注解,用于将对象解析成json,方便前后端的交互,也可以使用 @ResponseBody放在异常类上面。

3. controller代码测试与结果

 controller代码:

@RestController
@RequestMapping("/result")
public class ResultController {
@GetMapping("/getStudent")
public Result getStudent(){
Student student = new Student();
student.setAge(21);
student.setId(111);
student.setName("学习笔记");
Result result = new Result();
result.setCode(200);
result.setSuccess(true);
result.setData(student);
result.setMsg("学生列表信息");
return result;
}
@RequestMapping("/getDeException")
public Result DeException(){
throw new DefinitionException(400,"我出错了");
}
@RequestMapping("/getException")
public Result Exception(){
Result result = new Result();
int a=1/0;
return result;
}
}

 其中的Student类就是前面一直在用的类了。包含三个属性。其中省略了get,set方法。

public class Student  {
/**
* 唯一标识id
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age; }

 然后启动项目,来挨个测试。首先测试正常没有异常发生的数据。浏览器输入:localhost:8095/result/getStudent

 可以看到数据是正常返回json串。没有异常。然后我们测试第二个自定义异常处理接口。浏览器输入localhost:8095/result/getDeException。

 可以看到这个自定义的异常是捕获到了,并且返回了一个json串。最后我们测试一下其他的异常。浏览器输入:localhost:8095/result/getException

 到这里我们就处理完了异常并且正确的返回了前端。

 这里说一下,测试接口又很多方法,可以使用postman,或者idea自带的接口测试工具都很好用。

 但是,你可能会发现一个问题,这种方法是不能处理404异常的,捕获不到。该怎么办呢?

4. 404异常特殊处理。

 默认情况下,SpringBoot是不会抛出404异常的,所以@ControllerAdvice也不能捕获到404异常。我们可以通过以下配置来让这个注解能捕获到404异常。

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

 其中第一句是表示:当发现404异常时直接抛出异常。第二句关闭默认的静态资源路径映射。这样404错误也能被捕获到,但是这个配置会让你的静态资源访问出现问题,也就是不适合前后端不分离的情况。

 但是我们可以加上如下配置,就能正常访问静态资源了。

@Configuration
public class ResourceConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//可以访问localhost:8095/static/images/image.jpg
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}

5. 总结

 本文讲解了如何处理捕获全局异常以及怎么自定义异常,顺便说明了统一结果的返回格式,并特殊处理的404,not found的异常,将其作为统一结果返回。如果你觉得本文有用,点个赞吧!

SpringBoot系列(十)优雅的处理统一异常处理与统一结果返回的更多相关文章

  1. SpringBoot系列(十二)过滤器配置详解

    SpringBoot(十二)过滤器详解 往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件 ...

  2. SpringBoot系列教程web篇之自定义异常处理HandlerExceptionResolver

    关于Web应用的全局异常处理,上一篇介绍了ControllerAdvice结合@ExceptionHandler的方式来实现web应用的全局异常管理: 本篇博文则带来另外一种并不常见的使用方式,通过实 ...

  3. SpringBoot系列教程web篇之全局异常处理

    当我们的后端应用出现异常时,通常会将异常状况包装之后再返回给调用方或者前端,在实际的项目中,不可能对每一个地方都做好异常处理,再优雅的代码也可能抛出异常,那么在 Spring 项目中,可以怎样优雅的处 ...

  4. SpringBoot系列——@Async优雅的异步调用

    前言 众所周知,java的代码是同步顺序执行,当我们需要执行异步操作时我们需要创建一个新线程去执行,以往我们是这样操作的: /** * 任务类 */ class Task implements Run ...

  5. Java 项目创建 -- 统一结果处理、统一异常处理、统一日志处理

    一.IDEA 插件使用 1.说明 此处使用 SpringBoot 2.2.6 .JDK 1.8 .mysql 8.0.18 作为演示. 使用 IDEA 作为开发工具. 2.IDEA 插件 -- Lom ...

  6. SpringBoot系列: 如何优雅停止服务

    ============================背景============================在系统生命周期中, 免不了要做升级部署, 对于关键服务, 我们应该能做到不停服务完成 ...

  7. SpringBoot系列十:SpringBoot整合Redis

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合 Redis 2.背景 Redis 的数据库的整合在 java 里面提供的官方工具包:jed ...

  8. springboot系列十四、自定义实现starter

    一.starter的作用 当我们实现了一个组建,希望尽可能降低它的介入成本,一般的组建写好了,只要添加spring扫描路径加载spring就能发挥作用.有个更简单的方式扫描路径都不用加,直接引入jar ...

  9. springboot系列十、springboot整合redis、多redis数据源配置

    一.简介 Redis 的数据库的整合在 java 里面提供的官方工具包:jedis,所以即便你现在使用的是 SpringBoot,那么也继续使用此开发包. 二.redidTemplate操作 在 Sp ...

随机推荐

  1. 干净直接安装+PS下载

    PS CS6 https://www.cr173.com/soft/247727.html 直接一键安装,很方便干净. 不要去华军软件下,广告浪费时间. 链接:https://pan.baidu.co ...

  2. 【Pytest01】全网最全最新的Pytest框架快速入门

    一.Pytest简介pytest是一个非常成熟的全功能的Python测试框架,主要有一下几个特点:1.简单灵活,容易上手,支持参数化2.能够支持简单的单元测试和复杂的功能测试,还可以用来做seleni ...

  3. coding++:Spring中的@Transactional(rollbackFor = Exception.class)属性详解

    异常: 如下图所示,我们都知道 Exception 分为 运行时异常 RuntimeException 和 非运行时异常. error 是一定会回滚的. 如果不对运行时异常进行处理,那么出现运行时异常 ...

  4. Python python 五种数据类型--数字

    一:Number 数字 不可变类型 整型(Int) - 通常被称为是整型或整数,是正或负整数,不带小数点. 长整型(long integers) - 无限大小的整数,整数最后是一个大写或小写的L.(P ...

  5. 题解 P2620 虫洞

    总体思路:离散化 + 建图 + 单源最短路(看见人少蒟蒻才敢发题解QAQ) 需要注意的是: 考虑到w范围较大,而实际虫洞数量较小,就只记录虫洞的起点与终点来建图. 建图时,虫洞起点可以去重. 在建图时 ...

  6. 角色移动优化【Unity2D自学之路】

    自学unity2D独立游戏开发,第一篇自学笔记.在场景中添加角色,并给角色添加Rigidbody2D刚体组件.collection2D碰撞体组件,c#脚本组件控制人物移动和跳跃.c#脚本组件内容如下, ...

  7. iOS 协议分发

    Github:AOMultiproxier.HJProtocolDispatcher 协议实现分发器,能够轻易实现将协议事件分发给多个实现者. 一.AOMultiproxier.h #define A ...

  8. mybatis 源码赏析(一)sql解析篇

    本系列主要分为三部分,前两部分主要分析mybatis的实现原理,最后一部分结合spring,来看看mybtais是如何与spring结合的就是就是mybatis-spring的源码. 相较于sprin ...

  9. mac 中使用git 和pycharm提交项目

    一.安装Git 1.验证git是否安装: 终端中输入: git 如果安装过出现: 2.安装git: 进入https://git-scm.com: 点击 Download 2.23.0 for Mac ...

  10. 3.用IntelliJ IDEA 创建Maven

    一.File→New→ Project (需要下载安装配置Maven等,这些步骤省略) 二.Maven→org.apache.maven.archetypes:maven-archetype-quic ...