iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot实战之实现结果的优雅响应案例详解
  • 457
分享到

SpringBoot实战之实现结果的优雅响应案例详解

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

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

摘要

今天说一下 Spring Boot 如何实现优雅的数据响应:统一的结果响应格式、简单的数据封装。 前提 无论系统规模大小,大部分 spring Boot 项目是提供 Restful

今天说一下 Spring Boot 如何实现优雅的数据响应:统一的结果响应格式、简单的数据封装。

前提

无论系统规模大小,大部分 spring Boot 项目是提供 Restful + JSON 接口,供前端或其他服务调用,格式统一规范,是程序猿彼此善待彼此的象征,也是减少联调挨骂的基本保障。

通常响应结果中需要包含业务状态码、响应描述、响应时间戳、响应内容,比如:

{
"code": 200,
"desc": "查询成功",
"timestamp": "2020-08-12 14:37:11",
"data": {
"uid": "1597242780874",
"name": "测试 1"
}
}

对于业务状态码分为两个派系:一个是推荐使用 Http 响应码作为接口业务返回;另一种是 HTTP 响应码全部返回 200,在响应体中通过单独的字段表示响应状态。两种方式各有优劣,个人推荐使用第二种,因为很多 WEB 服务器对 HTTP 状态码有拦截处理功能,而且状态码数量有限,不够灵活。比如返回 200 表示接口处理成功且正常响应,现在需要有一个状态码表示接口处理成功且正常响应,但是请求数据状态不对,可以返回 2001 表示。

自定义响应体

定义一个数据响应体是返回统一响应格式的第一步,无论接口正常返回,还是发生异常,返回给调用方的结构格式都应该不变。给出一个示例:


@apiModel
@Data
public class Response<T> {
    @ApiModelProperty(value = "返回码", example = "200")
    private Integer code;
    @ApiModelProperty(value = "返回码描述", example = "ok")
    private String desc;
    @ApiModelProperty(value = "响应时间戳", example = "2020-08-12 14:37:11")
    private Date timestamp = new Date();
    @ApiModelProperty(value = "返回结果")
    private T data;
}

这样,只要在 Controller 的方法返回Response就可以了,接口响应就一致了,但是这样会形成很多格式固定的代码模板,比如下面这种写法:


@RequestMapping("hello1")
public Response<String> hello1() {
    final Response<String> response = new Response<>();
    response.setCode(200);
    response.setDesc("返回成功");
    response.setData("Hello, World!");
    return response;
}

调用接口响应结果为:

{
"code": 200,
"desc": "返回成功",
"timestamp": "2020-08-12 14:37:11",

     "data": "Hello, World!"

}

这种重复且没有技术含量的代码,怎么能配得上程序猿这种优(lan)雅(duo)的生物呢?最好能在返回响应结果的前提下,减去那些重复的代码,比如:


@RequestMapping("hello2")
public String hello2() {
    return "Hello, World!";
}

这就需要借助 Spring 提供的ResponseBodyAdvice来实现了。

全局处理响应数据

先上代码:



@RestControllerAdvice
public class ResultResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
        return !returnType.getGenericParameterType().equals(Response.class);// 1
    }

    @Override
    public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType,
                                  final Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  final ServerHttpRequest request, final ServerHttpResponse response) {
        if (body == null || body instanceof Response) {
            return body;
        }
        final Response<Object> result = new Response<>();
        result.setCode(200);
        result.setDesc("查询成功");
        result.setData(body);
        if (returnType.getGenericParameterType().equals(String.class)) {// 2
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                return objectMapper.writeValueAsString(result);
            } catch (jsonProcessingException e) {
                throw new RuntimeException("将 Response 对象序列化为 json 字符串时发生异常", e);
            }
        }
        return result;
    }
}


@RestController
public class HelloWorldController {
    @RequestMapping("hello2")
    public String hello2() {
        return "Hello, World!";
    }

    @RequestMapping("user1")
    public User user1() {
        User u = new User();
        u.setUid(System.currentTimeMillis() + "");
        u.setName("测试1");
        return u;
    }
}

上面代码是实现了 Spring ResponseBodyAdvice类的模板方式,按照 Spring 的要求实现就行。只有两个需要特别注意的地方,也就是代码中标注 1 和 2 的地方。

首先说 1 这一行,也就是supports方法,这个方法是校验是否需要调用beforeBodyWrite方法的前置判断,返回true则执行beforeBodyWrite方法,这里根据 Controller 方法返回类型来判断是否需要执行beforeBodyWrite,也可以一律返回true,在后面判断是否需要进行类型转换。

然后重点说下 2 这一行,这行是坑,是大坑,如果对 Spring 结构不熟悉的,绝对会在这徘徊许久,不得妙法。

代码 2 这一行是判断Controller的方法是否返回的是String类型的结果,如果是,将返回的对象序列化之后返回。

这是因为SpringString类型的响应类型单独处理了,使用StringHttpMessageConverter类进行数据转换。在处理响应结果的时候,会在方法getContentLength中计算响应体大小,其父类方法定义是protected Long getContentLength(T t, @Nullable MediaType contentType),而StringHttpMessageConverter将方法重写为protected Long getContentLength(String str, @Nullable MediaType contentType),第一个参数是响应对象,固定写死是String类型,如果我们强制返回Response对象,就会报ClassCastException

当然,直接返回String的场景不多,这个坑可能会在某天特殊接口中突然出现。

补充说明

上面只是展示了ResponseBodyAdvice类最简单的应用,我们还可以实现更多的扩展使用。比如:

  1. 返回请求ID:这个需要与与RequestBodyAdvice联动,获取到请求ID后,在响应是放在响应体中;
  2. 结果数据加密:通过ResponseBodyAdvice实现响应数据加密,不会侵入业务代码,而且可以通过注解方式灵活处理接口的加密等级;
  3. 有选择的包装响应体:比如定义注解IgnoreResponseWrap,在不需要包装响应体的接口上定义,然后在supports方法上判断方法的注解即可,比如:

@Override
public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
    final IgnoreResponseWrap[] declaredAnnotationsByType = returnType.getExecutable().getDeclaredAnnotationsByType(IgnoreResponseWrap.class);
    return !(declaredAnnotationsByType.length > 0 || returnType.getGenericParameterType().equals(Response.class));
}

很多其他玩法就不一一列举了。

总结

上面说了正常响应的数据,只做到了一点优雅,想要完整,还需要考虑接口异常情况,总不能来个大大的try/catch/finally包住业务逻辑吧,那也太丑了。后面会再来一篇,重点说说接口如何在出现异常时,也能返回统一的结果响应。

本文只是抛出一块砖,玉还得自己去找。

推荐阅读

  • SpringBoot 实战:一招实现结果的优雅响应
  • SpringBoot 实战:如何优雅的处理异常
  • SpringBoot 实战:通过 BeanPostProcessor 动态注入 ID 生成器
  • SpringBoot 实战:自定义 Filter 优雅获取请求参数和响应结果
  • SpringBoot 实战:优雅的使用枚举参数
  • SpringBoot 实战:优雅的使用枚举参数(原理篇)
  • SpringBoot 实战:在 RequestBody 中优雅的使用枚举参数
  • SpringBoot 实战:在 RequestBody 中优雅的使用枚举参数(原理篇)

到此这篇关于SpringBoot实战之实现结果的优雅响应案例详解的文章就介绍到这了,更多相关SpringBoot实战之实现结果的优雅响应内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringBoot实战之实现结果的优雅响应案例详解

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

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

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

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

下载Word文档
猜你喜欢
  • SpringBoot实战之实现结果的优雅响应案例详解
    今天说一下 Spring Boot 如何实现优雅的数据响应:统一的结果响应格式、简单的数据封装。 前提 无论系统规模大小,大部分 Spring Boot 项目是提供 Restful ...
    99+
    2024-04-02
  • SpringBoot实战之处理异常案例详解
    前段时间写了一篇关于实现统一响应信息的博文,根据文中实战操作,能够解决正常响应的一致性,但想要实现优雅响应,还需要优雅的处理异常响应,所以有了这篇内容。 作为后台服务,能够正确的处理...
    99+
    2024-04-02
  • SpringBoot之自定义Filter获取请求参数与响应结果案例详解
    一个系统上线,肯定会或多或少的存在异常情况。为了更快更好的排雷,记录请求参数和响应结果是非常必要的。所以,Nginx 和 Tomcat 之类的 web 服务器,都提供了访问日志,可以...
    99+
    2024-04-02
  • Templates实战之更优雅实现自定义View构造方法详解
    目录问题场景瞧瞧Live TemplatesLive Templates自定义customView指令Edit variables进一步优化总结问题场景 之前写过一篇文章: 2.@J...
    99+
    2024-04-02
  • SpringBoot + WebSocket 实现答题对战匹配机制案例详解
    概要设计 类似竞技问答游戏:用户随机匹配一名对手,双方同时开始答题,直到双方都完成答题,对局结束。基本的逻辑就是这样,如果有其他需求,可以在其基础上进行扩展 明确了这一点,下面介绍开...
    99+
    2024-04-02
  • Ajax解决跨域之设置CORS响应头实现跨域案例详解
    1.设置CORS响应头实现跨域 跨源资源共享(CORS) 1.1 什么是CORS CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官...
    99+
    2024-04-02
  • SpringBoot响应处理实现流程详解
    目录1、相关依赖2、ReturnValueHandlers—返回值处理器3、HttpMessageConvert—消息转换器4、开启浏览器参数方式内容协商功能...
    99+
    2024-04-02
  • java实现飞机大战案例详解
    前言 飞机大战是一个非常经典的案例,因为它包含了多种新手需要掌握的概念,是一个非常契合面向对象思想的入门练习案例 程序分析: 在此游戏中共有六个对象: 小敌机Airplane,大敌机...
    99+
    2024-04-02
  • OpenCV实战案例之车道线识别详解
    目录一、首先进行canny边缘检测,为获取车道线边缘做准备二、进行ROI提取获取确切的车道线边缘(红色线内部)三、利用概率霍夫变换获取直线,并将斜率正数和复数的线段给分割开来四、离群...
    99+
    2024-04-02
  • SpringBoot实战之高效使用枚举参数(原理篇)案例详解
    找入口 对 Spring 有一定基础的同学一定知道,请求入口是DispatcherServlet,所有的请求最终都会落到doDispatch方法中的ha.handle(process...
    99+
    2024-04-02
  • java实战小技巧之优雅的实现字符串拼接
    目录前言String底层原理1. 普通写法2. StringJoiner3. guava joiner4. 小结总结前言 字符串拼接不管是在业务上,还是写算法时都会频繁使用到。 相信...
    99+
    2024-04-02
  • SpringBoot + WebSocket如何实现答题对战匹配机制案例详解
    小编给大家分享一下SpringBoot + WebSocket如何实现答题对战匹配机制案例详解,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!概要设计类似竞技问答游戏:用户随机匹配一名对手,双方同时开始答题,直到双方都完成答...
    99+
    2023-06-15
  • SpringBoot实现WEB的常用功能案例详解
    目录前言SpringMVC整合支持Spring MVC自动配置项目基础环境搭建功能扩展实现Spring MVC功能扩展实现Spring整合Servlet三大组件使用注册方式整合使用组...
    99+
    2024-04-02
  • 一文详解SpringBoot如何优雅地实现异步调用
    目录前言实现步骤自定义异步任务执行器和异常处理@Async如何工作的总结前言 SpringBoot想必大家都用过,但是大家平时使用发布的接口大都是同步的,那么你知道如何优雅的实现异步...
    99+
    2023-03-19
    SpringBoot实现异步调用 SpringBoot异步调用 SpringBoot调用
  • SpringBoot封装响应数据实现过程详解
    目录业务处理封装响应值传值容器ModelModelMapHttpServletRequest重定向传值业务处理 这是通过 Spring 在 Controller中注入Service模...
    99+
    2023-05-20
    SpringBoot封装响应数据 SpringBoot响应数据的封装
  • SpringBoot接口返回结果封装方法实例详解
    rest接口会返回各种各样的数据,如果对接口的格式不加约束,很容易造成混乱。 在实际项目中,一般会把结果放在一个封装类中,封装类中包含http状态值,状态消息,以及实际的数据。这里主...
    99+
    2024-04-02
  • asp.net core 中优雅的进行响应包装的实现方法
    目录摘要正常响应包装实现按需禁用包装总结摘要 在 asp.net core 中提供了 Filter 机制,可以在 Action 执行前后进行一些特定的处理,例如模型验证,响应包装等功...
    99+
    2024-04-02
  • Java之单例模式实现方案详解
      单例模式是最常用到的设计模式之一,熟悉设计模式的朋友对单例模式都不会陌生。一般介绍单例模式的书籍都会提到 饿汉式 和 懒汉式 这两种实现方式。但是除了这两种方式,本文还会介绍其他...
    99+
    2024-04-02
  • Java实战之实现物流配送系统示例详解
    目录介绍效果图展示主要实现代码介绍 系统分普通用户、企业、超级管理员等角色,除基础脚手架外,实现的功能有: 超级管理员:系统管理、用户管理、企业用户管理、普通用户管理、货物类型管理、...
    99+
    2024-04-02
  • 实例详解SpringBoot默认的JSON解析方案
    目录一、什么是JSON二、如何在SpringBoot中使用JSON三、举例四、拓展总结一、什么是JSON JSON(JavaScript Object Notation)是一种基于J...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作