全局统一返回RESTful风格数据,主要是实现ResponseBodyAdvice接口的方法,对返回值在输出之前进行修改。
使用注解@RestControllerAdvice拦截异常并统一处理。

开发环境:
IntelliJ IDEA 2019.2.2
jdk1.8
Spring Boot 2.2.2

1、创建一个SpringBoot项目,pom.xml引用的依赖包如下

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>

2、定义一个返回类

package com.example.response.entity;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString; import java.io.Serializable; @Data
@NoArgsConstructor
@ToString
public class ResponseData<T> implements Serializable {
/**
* 状态码:0-成功,1-失败
* */
private int code; /**
* 错误消息,如果成功可为空或SUCCESS
* */
private String msg; /**
* 返回结果数据
* */
private T data; public static ResponseData success() {
return success(null);
} public static ResponseData success(Object data) {
ResponseData result = new ResponseData();
result.setCode(0);
result.setMsg("SUCCESS");
result.setData(data);
return result;
} public static ResponseData fail(String msg) {
return fail(msg,null);
} public static ResponseData fail(String msg, Object data) {
ResponseData result = new ResponseData();
result.setCode(1);
result.setMsg(msg);
result.setData(data);
return result;
}
}

3、统一拦截接口返回数据

新建一个类GlobalResponseHandler,用注解@RestControllerAdvice,并且实现ResponseBodyAdvice接口的方法,其中方法supports可以判断哪些需要拦截,方法beforeBodyWrite可以对返回值在输出之前进行修改,从而实现返回统一的接口数据。

package com.example.response.config;

import com.alibaba.fastjson.JSON;
import com.example.response.entity.ResponseData;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; /**
* 实现ResponseBodyAdvice接口,可以对返回值在输出之前进行修改
*/
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> { //判断支持的类型
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
// 检查注解是否存在,存在则忽略拦截
if (methodParameter.getDeclaringClass().isAnnotationPresent(IgnorReponseAdvice.class)) {
return false;
}
if (methodParameter.getMethod().isAnnotationPresent(IgnorReponseAdvice.class)) {
return false;
}
return true;
} @Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
// 判断为null构建ResponseData对象进行返回
if (o == null) {
return ResponseData.success();
}
// 判断是ResponseData子类或其本身就返回Object o本身,因为有可能是接口返回时创建了ResponseData,这里避免再次封装
if (o instanceof ResponseData) {
return (ResponseData<Object>) o;
}
// String特殊处理,否则会抛异常
if (o instanceof String) {
return JSON.toJSON(ResponseData.success(o)).toString();
}
return ResponseData.success(o);
}
}
新建自定义注解IgnorReponseAdvice
package com.example.response.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnorReponseAdvice {
}

4、统一异常处理

package com.example.response.exception;
import com.example.response.entity.ResponseData;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseData exceptionHandler(Exception e) {
e.printStackTrace();
return ResponseData.fail("服务器异常:" + e.getMessage());
}
}

5、新建一个测试用的实体类

package com.example.response.entity;

import lombok.Data;

@Data
public class User {
private Long userId;
private String userName;
public User(Long userId, String userName){
this.userId = userId;
this.userName = userName;
}
}

6、新建一个测试用的控制器类

package com.example.response.controller;

import com.example.response.config.IgnorReponseAdvice;
import com.example.response.entity.ResponseData;
import com.example.response.entity.User;
import org.springframework.web.bind.annotation.*; import java.util.ArrayList;
import java.util.List; @RestController
public class DemoController {
@GetMapping("user")
public User user() {
User u = new User(100L, "u1");
return u;
} @GetMapping("userList")
public List<User> userList(){
List<User> list = new ArrayList<User>();
list.add(new User(100L, "u1"));
list.add(new User(200L, "u2"));
return list;
} @GetMapping("test1")
public String test1(){
return "test1";
} @GetMapping("test2")
public ResponseData test2(){
return ResponseData.success("test2");
} @IgnorReponseAdvice
@GetMapping("test3")
public String test3() {
return "test3";
} @GetMapping("test4")
public String test4() {
Integer x = 1 / 0;
return x.toString();
} @GetMapping("test5")
public String test5() throws Exception {
throw new Exception("自定义异常信息");
}
}

7、用Postman测试

(1)请求http://localhost:8080/user,返回

{
"code": 0,
"msg": "SUCCESS",
"data": {
"userId": 100,
"userName": "u1"
}
}

(2)请求http://localhost:8080/userList,返回

{
"code": 0,
"msg": "SUCCESS",
"data": [
{
"userId": 100,
"userName": "u1"
},
{
"userId": 200,
"userName": "u2"
}
]
}

(3)请求http://localhost:8080/tes1,返回

{"msg":"SUCCESS","code":0,"data":"test1"}

(4)请求http://localhost:8080/test2,返回

{
"code": 0,
"msg": "SUCCESS",
"data": "test2"
}

(5)请求http://localhost:8080/test3,返回

test3

(6)请求http://localhost:8080/test4,返回

{
"code": 1,
"msg": "服务器异常:/ by zero",
"data": null
}

(7)请求http://localhost:8080/test5,返回

{
"code": 1,
"msg": "服务器异常:自定义异常信息",
"data": null
}

参考文章:
https://blog.csdn.net/lrt890424/article/details/83624761
https://www.cnblogs.com/Purgeyao/p/11599810.html

spring boot 2 全局统一返回RESTful风格数据、统一异常处理的更多相关文章

  1. Spring Boot 无侵入式 实现RESTful API接口统一JSON格式返回

    前言 现在我们做项目基本上中大型项目都是选择前后端分离,前后端分离已经成了一个趋势了,所以总这样·我们就要和前端约定统一的api 接口返回json 格式, 这样我们需要封装一个统一通用全局 模版api ...

  2. Spring Boot中使用Swagger2构建RESTful APIs

    关于 Swagger Swagger能成为最受欢迎的REST APIs文档生成工具之一,有以下几个原因: Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速学习和尝试API. S ...

  3. Spring Boot中使用Swagger2构建RESTful API文档

    在开发rest api的时候,为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题: 1.由于接口众多,并且细 ...

  4. Spring Boot 中全局异常处理器

    Spring Boot 中全局异常处理器,就是把错误异常统一处理的方法.等价于Springmvc中的异常处理器. 步骤一:基于前面的springBoot入门小demo修改 步骤二:修改HelloCon ...

  5. Spring Boot中使用Swagger2构建RESTful APIs介绍

    1.添加相关依赖 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <depen ...

  6. Spring Boot中使用Swagger2生成RESTful API文档(转)

    效果如下图所示: 添加Swagger2依赖 在pom.xml中加入Swagger2的依赖 <!-- https://mvnrepository.com/artifact/io.springfox ...

  7. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  8. spring jpa 实体互相引用返回restful数据循环引用报错的问题

    spring jpa 实体互相引用返回restful数据循环引用报错的问题 Java实体里两个对象有关联关系,互相引用,比如,在一对多的关联关系里 Problem对象,引用了标签列表ProblemLa ...

  9. Spring Boot 揭秘与实战(二) 数据缓存篇 - 快速入门

    文章目录 1. 声明式缓存 2. Spring Boot默认集成CacheManager 3. 默认的 ConcurrenMapCacheManager 4. 实战演练5. 扩展阅读 4.1. Mav ...

随机推荐

  1. ubuntu windows mutual remote control

    Win10 remote control Ubuntu18 Part1.ubuntu settings 1.安装所需组件 sudo apt-get update //若没有desktop sharin ...

  2. 多进程使用同一log4j配置导致的日志丢失与覆盖问题

    最近接手了一个流传很多手的魔性古早代码,追日志时发现有明显缺失.对log4j不熟,不过可以猜测日志出问题肯定和多进程使用同一个log4j配置有关.经多次排查,终于捋清了其中逻辑.本文对排查过程进行复盘 ...

  3. altium designer 20.0.8

    altium designer 20.0.8 download : http://dl3.downloadly.ir/Files/Software/Altium_Designer_20.0.8_Bet ...

  4. Java8 Stream终端操作使用详解

    话不多说,自己挖的坑自己要填完,今天就给大家讲完Java8中Stream的终端操作使用详解.Stream流的终端操作主要有以下几种,我们来一一讲解. forEach() forEachOrdered( ...

  5. java switch语句 要点注意

    1.格式 switch(表达式){ case 常量1:语句1:break: case 常量2:语句2:break: case 常量3:语句3:break: .... case 常量n:语句n:brea ...

  6. python函数-函数对象

    python函数-函数对象 实验室 当函数定义时,就类似a=1,以函数名为变量名 def zx(): pass print(zx) zx=21 print(zx) <function zx at ...

  7. Hudi基本概念

    Apache Hudi(发音为"Hoodie")在DFS的数据集上提供以下流原语 插入更新 (如何改变数据集?) 增量拉取 (如何获取变更的数据?) 在本节中,我们将讨论重要的概念 ...

  8. 这是一个测试 hello world

    第一次写博客,冒着生命危险尝试一下,发说说 搞了半天,发现原创文章在随笔发,我以为在文章目录发,白白在文章那里建了分类,太难了吧我

  9. luogu P4065 [JXOI2017]颜色 |随机化+前缀和

    题目描述 可怜有一个长度为 n 的正整数序列 Ai,其中相同的正整数代表着相同的颜色. 现在可怜觉得这个序列太长了,于是她决定选择一些颜色把这些颜色的所有位置都删去. 删除颜色 i 可以定义为把所有满 ...

  10. hdu3999 The order of a Tree

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3999 题意:给一序列,按该序列插入二叉树,给出字典序最小的插入方法建相同的一棵树出来.即求二叉树的先序 ...