服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 详解SpringBoot如何实现统一后端返回格式

详解SpringBoot如何实现统一后端返回格式

2022-11-23 11:21北根娃 Java教程

在前后端分离的项目中后端返回的格式一定要友好,不然会对前端的开发人员带来很多的工作量。那么SpringBoot如何做到统一的后端返回格式呢?本文将为大家详细讲讲

在前后端分离的项目中后端返回的格式一定要友好,不然会对前端的开发人员带来很多的工作量。那么SpringBoot如何做到统一的后端返回格式呢?今天我们一起来看看。

1.为什么要对SpringBoot返回统一的标准格式

在默认情况下,SpringBoot的返回格式常见的有三种:

1.1 返回String

?
1
2
3
4
@GetMapping("/hello")
public String hello() {
    return  "hello";
}

此时调用接口获取到的返回值是这样:

hello

1.2 返回自定义对象

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@GetMapping("/student")
public Student getStudent() {
        Student student = new Student();
        student.setId(1);
        student.setName("didiplus");
        return  student;
}
 
 
//student的类
@Data
public class Student {
    private Integer id;
    private String name;
}

此时调用接口获取到的返回值是这样:

{"id":1,"name":"didiplus"}

1.3 接口异常

?
1
2
3
4
5
@GetMapping("/error")
public int error(){
    int i = 9/0;
    return i;
}

此时调用接口获取到的返回值是这样

SpringBoot的版本是v2.6.7,

2.定义返回对象

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package com.didiplus.common.web.response;
 
import lombok.Data;
 
import java.io.Serializable;
 
/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/24
 * Desc: Ajax 返 回 JSON 结 果 封 装 数 据
 */
 
@Data
public class Result<T> implements Serializable {
 
    /**
     * 是否返回成功
     */
    private boolean success;
 
    /**
     * 错误状态
     */
    private int code;
 
    /***
     * 错误信息
     */
    private String msg;
 
    /**
     * 返回数据
     */
    private T data;
 
    /**
     * 时间戳
     */
    private long timestamp ;
 
 
    public Result (){
        this.timestamp = System.currentTimeMillis();
    }
    /**
     * 成功的操作
     */
    public static <T> Result<T> success() {
        return  success(null);
    }
 
    /**
     * 成 功 操 作 , 携 带 数 据
     */
    public static <T> Result<T> success(T data){
        return success(ResultCode.RC100.getMessage(),data);
    }
 
    /**
     * 成 功 操 作, 携 带 消 息
     */
    public static <T> Result<T> success(String message) {
        return success(message, null);
    }
 
        /**
         * 成 功 操 作, 携 带 消 息 和 携 带 数 据
         */
    public static <T> Result<T> success(String message, T data) {
        return success(ResultCode.RC100.getCode(), message, data);
    }
 
    /**
     * 成 功 操 作, 携 带 自 定 义 状 态 码 和 消 息
     */
    public static <T> Result<T> success(int code, String message) {
        return success(code, message, null);
    }
 
    public static <T> Result<T> success(int code,String message,T data) {
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setMsg(message);
        result.setSuccess(true);
        result.setData(data);
        return result;
    }
 
    /**
     * 失 败 操 作, 默 认 数 据
     */
    public static <T> Result<T> failure() {
        return failure(ResultCode.RC100.getMessage());
    }
 
    /**
     * 失 败 操 作, 携 带 自 定 义 消 息
     */
    public static <T> Result<T> failure(String message) {
        return failure(message, null);
    }
 
    /**
     * 失 败 操 作, 携 带 自 定 义 消 息 和 数 据
     */
    public static <T> Result<T> failure(String message, T data) {
        return failure(ResultCode.RC999.getCode(), message, data);
    }
 
    /**
     * 失 败 操 作, 携 带 自 定 义 状 态 码 和 自 定 义 消 息
     */
    public static <T> Result<T> failure(int code, String message) {
        return failure(ResultCode.RC999.getCode(), message, null);
    }
 
    /**
     * 失 败 操 作, 携 带 自 定 义 状 态 码 , 消 息 和 数 据
     */
    public static <T> Result<T> failure(int code, String message, T data) {
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setMsg(message);
        result.setSuccess(false);
        result.setData(data);
        return result;
    }
 
    /**
     * Boolean 返 回 操 作, 携 带 默 认 返 回 值
     */
    public static <T> Result<T> decide(boolean b) {
        return decide(b, ResultCode.RC100.getMessage(), ResultCode.RC999.getMessage());
    }
 
    /**
     * Boolean 返 回 操 作, 携 带 自 定 义 消 息
     */
    public static <T> Result<T> decide(boolean b, String success, String failure) {
        if (b) {
            return success(success);
        } else {
            return failure(failure);
        }
    }
}

3.定义状态码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.didiplus.common.web.response;
 
import lombok.Getter;
 
/**
 * Author: didiplus
 * Email: 972479352@qq.com
 * CreateTime: 2022/4/24
 * Desc: 统 一 返 回 状 态 码
 */
public enum ResultCode {
    /**操作成功**/
    RC100(100,"操作成功"),
    /**操作失败**/
    RC999(999,"操作失败"),
    /**服务限流**/
    RC200(200,"服务开启限流保护,请稍后再试!"),
    /**服务降级**/
    RC201(201,"服务开启降级保护,请稍后再试!"),
    /**热点参数限流**/
    RC202(202,"热点参数限流,请稍后再试!"),
    /**系统规则不满足**/
    RC203(203,"系统规则不满足要求,请稍后再试!"),
    /**授权规则不通过**/
    RC204(204,"授权规则不通过,请稍后再试!"),
    /**access_denied**/
    RC403(403,"无访问权限,请联系管理员授予权限"),
    /**access_denied**/
    RC401(401,"匿名用户访问无权限资源时的异常"),
    /**服务异常**/
    RC500(500,"系统异常,请稍后重试"),
 
    INVALID_TOKEN(2001,"访问令牌不合法"),
    ACCESS_DENIED(2003,"没有权限访问该资源"),
    CLIENT_AUTHENTICATION_FAILED(1001,"客户端认证失败"),
    USERNAME_OR_PASSWORD_ERROR(1002,"用户名或密码错误"),
    UNSUPPORTED_GRANT_TYPE(1003, "不支持的认证模式");
 
    /**自定义状态码**/
    @Getter
    private final int code;
 
    /**
     * 携 带 消 息
     */
    @Getter
    private final String message;
    /**
     * 构 造 方 法
     */
    ResultCode(int code, String message) {
 
        this.code = code;
 
        this.message = message;
    }
}

4.统一返回格式

?
1
2
3
4
@GetMapping("/hello")
public Result<String> hello() {
    return  Result.success("操作成功","hello");
}

此时调用接口获取到的返回值是这样:

{"success":true,"code":100,"msg":"操作成功","data":"hello","timestamp":1650785058049}

这样确实已经实现了我们想要的结果,我在很多项目中看到的都是这种写法,在Controller层通过Result.success()对返回结果进行包装后返回给前端。这样显得不够专业而且不够优雅。 所以呢我们需要对代码进行优化,目标就是不要每个接口都手工制定Result返回值。

5.高级实现方式

要优化这段代码很简单,我们只需要借助SpringBoot提供的ResponseBodyAdvice即可。

5.1 ResponseBodyAdvice的源码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public interface ResponseBodyAdvice<T> {
        /**
        * 是否支持advice功能
        * true 支持,false 不支持
        */
    boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);
 
      /**
        * 对返回的数据进行处理
        */
    @Nullable
    T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}

只需要编写一个具体实现类即可

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RestControllerAdvice
public class ResponseAdvice  implements ResponseBodyAdvice<Object> {
 
 
    @Autowired
    ObjectMapper objectMapper;
 
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
 
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response)  {
        if (body instanceof  String){
            return objectMapper.writeValueAsString(Result.success(ResultCode.RC100.getMessage(),body));
        }
        return Result.success(ResultCode.RC100.getMessage(),body);
    }
}

需要注意两个地方:

@RestControllerAdvice注解 @RestControllerAdvice是@RestController注解的增强,可以实现三个方面的功能:

  • 全局异常处理
  • 全局数据绑定
  • 全局数据预处理

5.2 String类型判断

?
1
2
3
if (body instanceof  String){
    return objectMapper.writeValueAsString(Result.success(ResultCode.RC100.getMessage(),body));
}

这段代码一定要加,如果Controller直接返回String的话,SpringBoot是直接返回,故我们需要手动转换成json。 经过上面的处理我们就再也不需要通过ResultData.success()来进行转换了,直接返回原始数据格式,SpringBoot自动帮我们实现包装类的封装。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@GetMapping("/hello")
public String hello() {
    return "hello,didiplus";
}
 
 
@GetMapping("/student")
public Student getStudent() {
    Student student = new Student();
    student.setId(1);
    student.setName("didiplus");
    return student;
}

此时我们调用接口返回的数据结果为:

{ "success": true, "code": 100, "msg": "操作成功", "data": "hello,didiplus", "timestamp": 1650786993454 }

以上就是详解SpringBoot如何实现统一后端返回格式的详细内容,更多关于SpringBoot统一后端返回格式的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/alanlin/p/16191008.html

延伸 · 阅读

精彩推荐
  • Java教程MyBatis insert操作插入数据之后返回插入记录的id

    MyBatis insert操作插入数据之后返回插入记录的id

    今天小编就为大家分享一篇关于MyBatis插入数据之后返回插入记录的id,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟...

    徐刘根7592021-07-26
  • Java教程全面了解Java中的内部类和匿名类

    全面了解Java中的内部类和匿名类

    下面小编就为大家带来一篇全面了解Java中的内部类和匿名类。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    jingxian4572020-05-29
  • Java教程详解Java多线程编程中的线程同步方法

    详解Java多线程编程中的线程同步方法

    这篇文章主要介绍了Java多线程编程中的线程同步方法,使用synchronized关键字创建线程同步方法是实现线程同步的关键,需要的朋友可以参考下 ...

    arthinking2542020-04-27
  • Java教程Java Web使用POI导出Excel的方法详解

    Java Web使用POI导出Excel的方法详解

    这篇文章主要介绍了Java Web使用POI导出Excel的方法,结合实例形式详细分析了Java Web使用POI导出Excel的具体操作步骤、实现技巧与相关注意事项,需要的朋友可以...

    qq73422725542020-11-04
  • Java教程Java开发可应用于什么领域?

    Java开发可应用于什么领域?

    Java开发可应用于什么领域?Java的应用非常的广泛,可以用来在开发软件工具、嵌入式领域、交易系统、Android应用、大数据技术、服务器程序、网站开发、...

    博学谷4952020-12-21
  • Java教程浅谈Java生命周期管理机制

    浅谈Java生命周期管理机制

    最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明...

    hebedich3322020-03-22
  • Java教程Springboot文件上传出现找不到指定系统路径的解决

    Springboot文件上传出现找不到指定系统路径的解决

    这篇文章主要介绍了Springboot文件上传出现找不到指定系统路径的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    带着希望活下去8502021-12-11
  • Java教程Springboot jpa @Column命名大小写问题及解决

    Springboot jpa @Column命名大小写问题及解决

    这篇文章主要介绍了Springboot jpa @Column命名大小写问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    这个人在加班10982022-02-27