先来看一段十分基础的业务代码前端
Map<String, Object> map = service.getDataByName("悟空GoKu");
Long userId = (Long)map.get("userId");
String phone = (String)map.get("phone");
复制代码
每次我写这种map获取返回数据老是感受十分别扭web
放了什么key
。
强转
一下,有点麻烦。
类型转换异常发生
。
首先要确定的是用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();
}
复制代码
上面说了我不喜欢这样获取数据,但也不喜欢定义一个类来接收,由于这样会形成类数量激增
,可能一个请求接口就得对应建立一个请求类。编程
有人说不定义成类,有些额外的功能就没法使用:json
不想用swagger,代码侵入性太强,样式、目录展现也通常,接口文档推荐开源yapi后端
swagger有时确实方便,增长参数时,代码跟文档同时更新,没必要额外维护文档,但我仍是不喜欢将文档跟代码耦合在一块儿。api
验证逻辑我仍是喜欢写在controller,逻辑更清晰。缓存
原来的注解不必定适合某些复杂验证,那岂不是要自定义注解,又回到了类激增的问题app
说回了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编程
了,而不是以往的面向对象。
对于返回数据,我通常会在controller层拿到service的数据后再根据业务需求来处理数据(结构修改,数据整合),最终用map整合再response,给前端一个合适的结构, 而不是数据库查到什么就整个类对象返回
。
当前有些返回数据我也会定义一个类ReponseVo封装,最后return给前端
你这先后矛盾啊,以前还说不要面向对象。
这里主要考虑的有些场景下,多个接口返回的数据彻底同样,能够共用。 对于部分app开发者来讲,他们会依赖后台的接口来定义本身的model,类似的数据会要求后台返回的字段命名和结构同样,以便他们能共用model。
这.......其实他们能够本身定义属于他们的model,而不是
彻底依赖
后台字段命名。
前面说的是前端/移动端http请求咱们的网关接口,这里是说咱们服务端之间
的远程方法调用/本地方法调用,也能够理解成service层方法调用。若是是多个参数的话,须要封装一个DTO,这里最好不用map。
数据反序列化问题(划重点)
。
若是某个方法内部使用了缓存,且经过json反序列化后才返回,容易引起调用方发生异常
//set
@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();
}
//get
@PostMapping(value = "/getData")
public ApiResponse getData(ApiRequest request) {
Map<String, Object> map = stringRedisTemplate.get("KEY_GOKU", Map.class);
Long id = (Long)map.get("id"); //会发生异常ClassCastException
return ApiResponse.ok();
}
复制代码
json 反序列化 map 时若是原来的整数值小于 int 最大值,
反序列化后本来为 Long 类型的字段,会变为 Integer 类型
。
json 序列化的优点在于可读性更强。但
没有携带类型信息
,只有提供了准确的类型信息才能准确地进行反序列化,这点也特别容易引起线上问题。
最后来几句总结阐述下本文的观点,仅表明我的见解
特别想diss那些字段不写注释、代码加了字段又不一样步到文档的后端开发者hhh