广告
返回顶部
首页 > 资讯 > 后端开发 > Python >详解SpringBoot如何统一后端返回格式
  • 771
分享到

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

2024-04-02 19:04:59 771人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录为什么要对SpringBoot返回统一的标准格式第一种:返回 String第二种:返回自定义对象第三种:接口异常定义返回标准格式高级实现方式接口异常问题springBoot为什么

今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常。

首先我们来看看为什么要返回统一的标准格式?

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

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

第一种:返回 String


@GetMapping("/hello")
public String getStr(){
  return "hello,javadaily";
}

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

hello,javadaily

第二种:返回自定义对象


@GetMapping("/aniaml")
public Aniaml getAniaml(){
  Aniaml aniaml = new Aniaml(1,"pig");
  return aniaml;
}

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


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

第三种:接口异常


@GetMapping("/error")
public int error(){
    int i = 9/0;
    return i;
}

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


{
  "timestamp": "2021-07-08T08:05:15.423+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/wrong"
}

基于以上种种情况,如果你和前端开发人员联调接口她们就会很懵逼,由于我们没有给他一个统一的格式,前端人员不知道如何处理返回值。

还有甚者,有的同学比如小张喜欢对结果进行封装,他使用了Result对象,小王也喜欢对结果进行包装,但是他却使用的是Response对象,当出现这种情况时我相信前端人员一定会抓狂的。

所以我们项目中是需要定义一个统一的标准返回格式的。

定义返回标准格式

一个标准的返回格式至少包含3部分:

  • status 状态值:由后端统一定义各种返回结果的状态码
  • message 描述:本次接口调用的结果描述
  • data 数据:本次返回的数据

{
  "status":"100",
  "message":"操作成功",
  "data":"hello,javadaily"
}

当然也可以按需加入其他扩展值,比如我们就在返回对象中添加了接口调用时间

timestamp: 接口调用时间

定义返回对象


@Data
public class ResultData<t> {
  
  private int status;
  private String message;
  private T data;
  private long timestamp ;


  public ResultData (){
    this.timestamp = System.currentTimeMillis();
  }


  public static <t> ResultData<t> success(T data) {
    ResultData<t> resultData = new ResultData<>();
    resultData.setStatus(ReturnCode.RC100.getCode());
    resultData.setMessage(ReturnCode.RC100.getMessage());
    resultData.setData(data);
    return resultData;
  }

  public static <t> ResultData<t> fail(int code, String message) {
    ResultData<t> resultData = new ResultData<>();
    resultData.setStatus(code);
    resultData.setMessage(message);
    return resultData;
  }

}

定义状态码


public enum ReturnCode {
    
    RC100(100,"操作成功"),
    
    RC999(999,"操作失败"),
    
    RC200(200,"服务开启限流保护,请稍后再试!"),
    
    RC201(201,"服务开启降级保护,请稍后再试!"),
    
    RC202(202,"热点参数限流,请稍后再试!"),
    
    RC203(203,"系统规则不满足要求,请稍后再试!"),
    
    RC204(204,"授权规则不通过,请稍后再试!"),
    
    RC403(403,"无访问权限,请联系管理员授予权限"),
    
    RC401(401,"匿名用户访问无权限资源时的异常"),
    
    RC500(500,"系统异常,请稍后重试"),

    INVALID_TOKEN(2001,"访问令牌不合法"),
    ACCESS_DENIED(2003,"没有权限访问该资源"),
    CLIENT_AUTHENTICATioN_FAILED(1001,"客户端认证失败"),
    USERNAME_OR_PASSWord_ERROR(1002,"用户名或密码错误"),
    UNSUPPORTED_GRANT_TYPE(1003, "不支持的认证模式");



    
    private final int code;
    
    private final String message;

    ReturnCode(int code, String message){
        this.code = code;
        this.message = message;
    }


    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

统一返回格式


@GetMapping("/hello")
public ResultData<string> getStr(){
	return ResultData.success("hello,javadaily");
}

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


{
  "status": 100,
  "message": "hello,javadaily",
  "data": null,
  "timestamp": 1625736481648,
  "httpstatus": 0
}

这样确实已经实现了我们想要的结果,我在很多项目中看到的都是这种写法,在Controller层通过ResultData.success()对返回结果进行包装后返回给前端。

看到这里我们不妨停下来想想,这样做有什么弊端呢?

最大的弊端就是我们后面每写一个接口都需要调用ResultData.success()这行代码对结果进行包装,重复劳动,浪费体力;而且还很容易被其他老鸟给嘲笑。

所以呢我们需要对代码进行优化,目标就是不要每个接口都手工制定ResultData返回值。

高级实现方式

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

ResponseBodyAdvice的作用:拦截Controller方法的返回值,统一处理返回值/响应体,一般用来统一返回格式,加解密,签名等等。

先来看下ResponseBodyAdvice源码


public interface ResponseBodyAdvice<t> {
		
    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);
}

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



@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<object> {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<!--? extends HttpMessageConverter<?-->> aClass) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<!--? extends HttpMessageConverter<?-->> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if(o instanceof String){
            return objectMapper.writeValueAsString(ResultData.success(o));
        }        
        return ResultData.success(o);
    }
}

需要注意两个地方:

@RestControllerAdvice注解

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

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

String类型判断


if(o instanceof String){
  return objectMapper.writeValueAsString(ResultData.success(o));
} 

这段代码一定要加,如果Controller直接返回String的话,SpringBoot是直接返回,故我们需要手动转换成JSON

经过上面的处理我们就再也不需要通过ResultData.success()来进行转换了,直接返回原始数据格式,SpringBoot自动帮我们实现包装类的封装。


@GetMapping("/hello")
public String getStr(){
    return "hello,javadaily";
}

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


@GetMapping("/hello")
public String getStr(){
  return "hello,javadaily";
}

是不是感觉很完美,别急,还有个问题在等着你呢。

接口异常问题

此时有个问题,由于我们没对Controller的异常进行处理,当我们调用的方法一旦出现异常,就会出现问题,比如下面这个接口


@GetMapping("/wrong")
public int error(){
    int i = 9/0;
    return i;
}

返回的结果为:

这显然不是我们想要的结果,接口都报错了还返回操作成功的响应码,前端看了会打人的。

别急,接下来我们进入第二个议题,如何优雅的处理全局异常。

SpringBoot为什么需要全局异常处理器

不用手写try...catch,由全局异常处理器统一捕获

使用全局异常处理器最大的便利就是程序员在写代码时不再需要手写try...catch了,前面我们讲过,默认情况下SpringBoot出现异常时返回的结果是这样:


{
  "timestamp": "2021-07-08T08:05:15.423+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/wrong"
}

这种数据格式返回给前端,前端是看不懂的,所以这时候我们一般通过try...catch来处理异常


@GetMapping("/wrong")
public int error(){
    int i;
    try{
        i = 9/0;
    }catch (Exception e){
        log.error("error:{}",e);
        i = 0;
    }
    return i;
}

我们追求的目标肯定是不需要再手动写try...catch了,而是希望由全局异常处理器处理。

对于自定义异常,只能通过全局异常处理器来处理


@GetMapping("error1")
public void empty(){
	throw  new RuntimeException("自定义异常");
}

当我们引入Validator参数校验器的时候,参数校验不通过会抛出异常,此时是无法用try...catch捕获的,只能使用全局异常处理器。

SpringBoot集成参数校验请参考这篇文章SpringBoot开发秘籍 - 集成参数校验及高阶技巧

如何实现全局异常处理器


@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
    
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultData<string> exception(Exception e) {
        log.error("全局异常信息 ex={}", e.getMessage(), e);
        return ResultData.fail(ReturnCode.RC500.getCode(),e.getMessage());
    }

}

有三个细节需要说明一下:

  • @RestControllerAdvice,RestController的增强类,可用于实现全局异常处理器
  • @ExceptionHandler,统一处理某一类异常,从而减少代码重复率和复杂度,比如要获取自定义异常可以@ExceptionHandler(BusinessException.class)
  • @ResponseStatus指定客户端收到的http状态码

体验效果

这时候我们调用如下接口:


@GetMapping("error1")
public void empty(){
    throw  new RuntimeException("自定义异常");
}

返回的结果如下:


{
  "status": 500,
  "message": "自定义异常",
  "data": null,
  "timestamp": 1625795902556
}

基本满足我们的需求了。

但是当我们同时启用统一标准格式封装功能ResponseAdviceRestExceptionHandler全局异常处理器时又出现了新的问题:


{
  "status": 100,
  "message": "操作成功",
  "data": {
    "status": 500,
    "message": "自定义异常",
    "data": null,
    "timestamp": 1625796167986
  },
  "timestamp": 1625796168008
}

此时返回的结果是这样,统一格式增强功能会给返回的异常结果再次封装,所以接下来我们需要解决这个问题。

全局异常接入返回的标准格式

要让全局异常接入标准格式很简单,因为全局异常处理器已经帮我们封装好了标准格式,我们只需要直接返回给客户端即可。


@SneakyThrows
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<!--? extends HttpMessageConverter<?-->> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
  if(o instanceof String){
    return objectMapper.writeValueAsString(ResultData.success(o));
  }
  if(o instanceof ResultData){
    return o;
  }
  return ResultData.success(o);
}

关键代码:


if(o instanceof ResultData){
  return o;
}

如果返回的结果是ResultData对象,直接返回即可。

这时候我们再调用上面的错误方法,返回的结果就符合我们的要求了。


{
  "status": 500,
  "message": "自定义异常",
  "data": null,
  "timestamp": 1625796580778
}

好了,今天的文章就到这里了,希望通过这篇文章你能掌握如何在你项目中友好实现统一标准格式到返回并且可以优雅的处理全局异常。

GitHub地址:https://github.com/jianzh5/cloud-blog/

到此这篇关于详解SpringBoot如何统一后端返回格式的文章就介绍到这了,更多相关SpringBoot 统一后端返回格式内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 详解SpringBoot如何统一后端返回格式

本文链接: https://www.lsjlt.com/news/130632.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 详解SpringBoot如何统一后端返回格式
    目录为什么要对SpringBoot返回统一的标准格式第一种:返回 String第二种:返回自定义对象第三种:接口异常定义返回标准格式高级实现方式接口异常问题SpringBoot为什么...
    99+
    2022-11-12
  • 详解SpringBoot如何实现统一后端返回格式
    目录1.为什么要对SpringBoot返回统一的标准格式1.1 返回String1.2 返回自定义对象1.3 接口异常2.定义返回对象3.定义状态码4.统一返回格式5.高级实现方式5...
    99+
    2022-11-13
  • SpringBoot如何统一后端返回格式
    这篇文章主要讲解了“SpringBoot如何统一后端返回格式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot如何统一后端返回格式”吧!目录为什么要对SpringBoot返回...
    99+
    2023-06-20
  • 详解SpringBoot 统一后端返回格式的方法
    目录为什么要对SpringBoot返回统一的标准格式定义返回标准格式定义返回对象定义状态码统一返回格式高级实现方式接口异常问题SpringBoot为什么需要全局异常处理器如何实现全局...
    99+
    2022-11-13
  • SpringBoot怎么实现统一后端返回格式
    这篇文章主要介绍“SpringBoot怎么实现统一后端返回格式”,在日常操作中,相信很多人在SpringBoot怎么实现统一后端返回格式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot怎么实...
    99+
    2023-06-30
  • SpringBoot统一返回格式的方法详解
    目录前言1. 直接返回结果2. 约定返回格式3. 返回统一格式结果4. 切片封装统一格式编写注解编写ControllerAdvice见证奇迹的时刻到了5. 自定义返回格式场景1:返回...
    99+
    2022-11-13
  • SpringBoot统一返回JSON格式实现方法详解
    目录定义JSON格式定义JavaBean字段定义返回体类Result实体返回测试统一返回JSON格式进阶全局处理(@RestControllerAdvice)@ResponseBod...
    99+
    2023-02-03
    SpringBoot返回JSON格式 SpringBoot无侵入式返回JSON格式
  • SpringBoot全局Controller返回值格式统一
    目录一、返回值格式统一1.返回值介绍2.基础类功能3.基础实现二、附录说明一、返回值格式统一 1.返回值介绍 在使用controller对外提供服务的时候,很多时候都需要统一返回值格...
    99+
    2022-11-12
  • 一文学会处理SpringBoot统一返回格式
    目录背景SpringBoot Controller 常见的返回格式String自定义对象正常返回错误返回定义返回对象定义状态枚举统一处理返回值及异常void 无返回值有返回值背景 相...
    99+
    2022-11-13
    SpringBoot统一返回格式  统一返回格式
  • SpringBoot中怎么统一全局Controller返回值格式
    这期内容当中小编将会给大家带来有关SpringBoot中怎么统一全局Controller返回值格式,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、返回值格式统一1.返回值介绍在使用controller对...
    99+
    2023-06-20
  • SpringBoot如何返回Json数据格式
    目录一、@RestController 注解二、Jackson1、对象、List、Map 转换为Json格式2、Jackson 的配置类三、FastjsonFastjson 配置类四...
    99+
    2023-03-22
    SpringBoot返回Json 返回Json数据格式 SpringBoot返回Json数据
  • 关于springboot的接口返回值统一标准格式
    目录一、目标二、为什么要对springboot的接口返回值统一标准格式第一种格式:response为String第二种格式:response为Objct第三种格式:response为...
    99+
    2022-11-13
  • SpringBoot返回统一的JSON标准格式实现步骤
    期望返回的JSON格式如下 { "code": 200, "msg": "操作成功", "data": "hello jenkins" } 实现步骤如下 1.自定义...
    99+
    2022-11-12
  • 详解如何在SpringBoot项目中使用统一返回结果
    目录1.创建Spring Boot项目2.返回结果的封装3.后端接口实现3.1 创建实体类3.2 创建dao层3.3 创建Controller层4.前端部分5.验证在一个完整的项目中...
    99+
    2022-11-13
    SpringBoot使用统一返回结果 SpringBoot 统一返回结果 SpringBoot 返回结果
  • Springboot配置返回日期格式化五种方法详解
    目录格式化全局时间字段1.前端时间格式化(不做无情人)2.SimpleDateFormat格式化(不推荐)3.DateTimeFormatter格式化(不推荐)4.全局时间格式化(推荐)实现原理分析5.部分时间格式化(推荐)总结应急就这样格...
    99+
    2022-11-13
  • 一文详解如何根据后端返回的url下载json文件
    目录需求场景描述实现思路分析完整的 demo 示例总结需求场景描述 有时候会遇到异步接口会返回一个 url 地址,然后前端需要根据这个 url 地址去下载文件资源的需求场景。 而这个...
    99+
    2022-11-13
  • SpringBoot如何实现统一封装返回前端结果集
    这篇文章主要介绍了SpringBoot如何实现统一封装返回前端结果集的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot如何实现统一封装返回前端结果集文章都会有所收获,下面我们一起来看看吧。我们如...
    99+
    2023-07-02
  • 如何设计API接口实现统一格式返回
    这篇文章给大家介绍如何设计API接口实现统一格式返回,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。前言在移动互联网,分布式、微服务盛行的今天,现在项目绝大部分都采用的微服务框架,前后端分离方式,(题外话:前后端的工作职...
    99+
    2023-06-05
  • SpringBoot中如何统一接口返回与全局异常处理详解
    目录背景 统一接口返回 定义API返回码枚举类 定义正常响应的API统一返回体定义异常响应的API统一返回体编写包装返回结果的自定义注解定义返回结果拦截器WebMvc配置类拦截器注册...
    99+
    2022-11-12
  • 如何解决处理后台返回json数据格式的问题
    小编给大家分享一下如何解决处理后台返回json数据格式的问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!最近在做一个移动端前端...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作