1 抛砖引玉

先来看一段十分基础的业务代码

  Map<String, Object> map = service.getDataByName("悟空GoKu");Long userId = (Long)map.get("userId");String phone = (String)map.get("phone");

每次我写这种map获取返回数据总是感觉十分别扭

  1. map就像个无底洞,你不看服务提供方代码的话就不知道里面到底放了什么key
  2. 拿到数据之后都要自己强转一下,有点麻烦。
  3. 这玩意有潜在的类型转换异常发生

2 请求参数Request

首先要肯定的是用map来传输参数(前端http请求后端接口)真的是方便,不需要额外去定义一个类,想往里面塞什么数据就塞什么,就如下面的例子,不需要为每个接口都定义一个RequestVo类,统一map接收

@PostMapping(value = "/map")
public ApiResponse testMap(@RequestBody Map<String, Object> map) {//获取map中的数据Long userId = (Long)map.get("userId");String phone = (String)map.get("phone");//业务代码...return ApiResponse.ok();
}

上面说了我不喜欢这样获取数据,但也不喜欢定义一个类来接收,因为这样会造成类数量激增,可能一个请求接口就得对应创建一个请求类。

有人说不定义成类,有些额外的功能就无法使用:

  1. swagger这种文档注解无法完美兼容。

不想用swagger,代码侵入性太强,样式、目录展示也一般,接口文档推荐开源yapi

swagger有时确实方便,增加参数时,代码跟文档同时更新,不必额外维护文档,但我还是不喜欢将文档跟代码耦合在一起。

  1. validator验证注解无法使用。

验证逻辑我还是喜欢写在controller,逻辑更清晰。

原来的注解不一定适合某些复杂验证,那岂不是要自定义注解,又回到了类激增的问题

说回了map,map.get(key)这样获取数据确实别扭,但我们可以封装请求啊,
例如上一篇文章<<当技术leader说要把接口设计成RESTful,我拒绝了>>提到的ApiRequest。

public class ApiRequest implements Serializable {//....省略部分代码    private Map<String, Object> data;  //通过拦截器处理后请求参数已存放在这里public Long getDataParamAsLong(String name, Long defaultValue) {Long i = defaultValue;try{i = StringUtils.isNotEmpty(getDataParamAsString(name)) ? Long.valueOf(getDataParamAsString(name)) : defaultValue;}catch (Exception e){e.printStackTrace();}return i;}
}
@PostMapping(value = "/test")
public ApiResponse test(ApiRequest apiRequest) {Long userId = apiRequest.getDataParamAsLong("userId", 0L);//省略部分代码....ApiResponse response = ApiResponse.ok()return response;
}

这里已经是面向json编程了,而不是以往的面向对象。

3 响应参数Response

对于返回数据,我一般会在controller层拿到service的数据后再根据业务需求来处理数据(结构修改,数据整合),最终用map整合再response,给前端一个合适的结构, 而不是数据库查到什么就整个类对象返回

当前有些返回数据我也会定义一个类ReponseVo封装,最后return给前端

你这前后矛盾啊,之前还说不要面向对象。

这里主要考虑的有些场景下,多个接口返回的数据完全一样,可以共用。
对于部分app开发者来说,他们会依赖后台的接口来定义自己的model,相似的数据会要求后台返回的字段命名和结构一样,以便他们能共用model。

这…,其实他们可以自己定义属于他们的model,而不是完全依赖后台字段命名。

4 service层数据传输

前面说的是前端/移动端http请求我们的网关接口,这里是说我们服务端之间的远程方法调用/本地方法调用,也可以理解成service层方法调用。如果是多个参数的话,需要封装一个DTO,这里最好不用map。

  1. 这种接口我们不可能去写一份文档来维护。
  2. 数据反序列化问题(划重点)

如果某个方法内部使用了缓存,且通过json反序列化后才返回,容易引发调用方发生异常

@PostMapping(value = "/setData")
public ApiResponse setData(ApiRequest request) {//省略部分代码...Map<String, Object> map = new HashMap<>();map.put("id", 123L);map.put("name", "悟空GoKu");stringRedisTemplate.set("KEY_GOKU", JsonUtil.toJsonString(map));return ApiResponse.ok();
}@PostMapping(value = "/getData")
public ApiResponse getData(ApiRequest request) {Map<String, Object> map = stringRedisTemplate.get("KEY_GOKU", Map.class);Long id = (Long)map.get("id");  //会发生异常ClassCastExceptionreturn ApiResponse.ok();
}

json 反序列化 map 时如果原来的整数值小于 int 最大值,反序列化后原本为 Long 类型的字段,会变为 Integer 类型

json 序列化的优势在于可读性更强。但没有携带类型信息,只有提供了准确的类型信息才能准确地进行反序列化,这点也特别容易引发线上问题。

5 总结

最后来几句总结阐述下本文的观点,仅代表个人看法

  1. 前端请求接口,面向json编程,用map来传输数据,部分接口的返回数据可定义成VO类。
  2. 服务端之间的方法调用,多个参数的话需要定义DTO类来传输数据。
  3. 前后端联调,有一份清晰可见的接口文档极为重要,写好代码的同时不要忘记也要写好文档。

特别想diss那些字段不写注释、代码加了字段又不同步到文档的后端开发者hhh

我为什么既支持又反对接口用Map来传输数据?相关推荐

  1. 转usb驱动cmw500 ni_支持USB Type-C接口的外置蓝光驱动器IO Data BRP-UT6 / MC2本月发售...

    IO Data以其非正统的数据设备闻名,最近IO Data新推出了一款支持USB Type-C接口的外置超薄蓝光驱动器设备 BRP-UT6 / MC2,除了支持USB-C接口,其配置是非常标准的超薄外 ...

  2. 企业微信H5_网页jssdk调用 判断当前客户端版本是否支持指定JS接口

    接上一篇:企业微信H5_网页jssdk调用,ticket签名config及示例https://gblfy.blog.csdn.net/article/details/123170569 文章目录 一. ...

  3. 微信 SDK 升级,全面支持异步缓存接口, .NET 3.5/4.0版本5月1日起停止更新

    简介 Senparc.Weixin SDK 是目前使用率最高的微信 .NET SDK,也是国内最受欢迎的 .NET 开源项目之一. 使用 Senparc.Weixin,您可以方便快速地开发微信全平台的 ...

  4. 科学美国人》如何评价转基因?支持与反对之外的第三条道路

    提要 近日,农业部首次主动召开了一场有关转基因的新闻发布会,引发高度关注.也再度引发舆论对于转基因利弊的争论. 转基因的利与弊一向是学界的热点话题.这篇刊登在美国著名大众化学术科普刊物<科学美国 ...

  5. IDL中提供的[source]属性,是为了让实现类宣扬它支持哪几个对外接口注册。

    IDL中提供的[source]属性,是为了让实现类宣扬它支持哪几个对外接口注册. 主要表达的意思的是--组件内部在某种条件下将调用该接口,向外界传递信息.如果你对此信息感兴趣,就要自己实现这个接口,并 ...

  6. AI绘画,我们究竟该支持还是反对?

    随着科技的突飞猛进,人工智能开始与我们的生活变得越来越密集,人工智能绘画,简称AI绘画,是我们大多数普通人最近距离接触到的一个人工智能产品. 虽然AI绘画很早以前就已经有了,但开始让人们注意到它,频繁 ...

  7. 写给支持和反对完全用Linux工作的人们(王垠)

    完全用Linux工作,抛弃windows 我已经半年没有使用 Windows 的方式工作了.Linux 高效的完成了我所有的工作. GNU/Linux 不是每个人都想用的.如果你只需要处理一般的事务, ...

  8. 分享-RK3399支持多种屏幕接口如何进行屏幕切换控制

    本文硬件平台以飞凌嵌入式OK3399-C开发板为基础进行讲解,其它RK3399产品,由于各个厂家设置不同会有所差异,请参考使用.本文详细介绍了RK3399开发板屏幕切换控制的两种方式,uboot菜单动 ...

  9. java.util (Collection接口和Map接口)

    1:Collection和Map接口的几个主要继承和实现类                  1.1  Collection接口 Collection是最基本的集合接口,一个Collection代表一 ...

  10. Java集合篇:Map接口、Map接口的实现类、Collections集合工具类

    目录 一.Map接口 1.1 Map接口概述 1.2 Map接口常用功能 二.Map接口的实现类 2.1 Map实现类之一:HashMap 2.1.1 HashMap概述 2.1.2 HashMap的 ...

最新文章

  1. C语言-用gcc指令体验C语言编译过程
  2. 数据中心建设模式变革-- 如何采用EPC模式实现快速交付?
  3. c# combobox集合数据不显示_VBA与数据库解决方案:Recordset记录集合的动态查询,并显示结果...
  4. python eel 多线程_Python 基础
  5. 优雅的嵌套滑动解决方式-NestedScroll
  6. Parallels中使用加密狗读取文件出现错误
  7. python划分train val test
  8. 人力资源HR管理系统源码
  9. sql server的linux版命令行,Linux配置SQLServer
  10. Uniapp引入和使用阿里矢量图
  11. 上海是怎么错失这些年的互联网机遇的?——写的很好,转
  12. mac删除的文件还能找回吗
  13. avformat_seek_file使用
  14. 单片机c语言拟合二次曲线y=a0+a1x+a2x^2
  15. MINIS FORUM U820黑苹果安装教程
  16. 视频服务器信号转换器,DVI转换器
  17. 腾讯,迅雷,完美等公司的一些笔试题整理
  18. Unity Cinemachine Timeline 制作镜头动画
  19. 阿里的1001个错误:盲目相信空降兵,做死雅虎中国
  20. 让超级高铁黯然失色,概念机Antipode一小时内可达全球各地

热门文章

  1. net域名和com域名在属性和价值上有什么不同?
  2. 论用户体验测试:牛逼的功能千篇一律,好的用户体验万里挑一
  3. matlab三维地形显示,三维地形可视化的MATLAB实现_张林泉
  4. 项目一 认识Linux操作系统
  5. 传感器 | 密度测量系列:1.密度测量的基础知识
  6. 策略路由(本地策略和接口策略)
  7. 基于word2vec的word相似度
  8. PDF文件中电子签名(安全性、有效性、合法性)验证指南
  9. JavaScript脚本编写的两个创意时钟
  10. python画图函数