导读:本文主要围绕进行数据接口传值时JSON序列化对于空值问题的处理,通过里流式查降低内存使用。总结本篇文章希望对从事相关工作的同学能够有所帮助或者启发 。
作为后端开发在进行接口调试或者与其他部门日常对接工作的时候,至于数据接口都是一一对应,但是不免很多时候在进行业务针对数据接口有赋空值现象。<key,Null>类型这种现象,但是如果这样赋值在JSON序列化的时候通常会不参与序列到导致服务层无法解析对应的值。
当A服务调用服务数据包结构如下
当 type 和 extendData 两个字段赋值为Null时候的数据包,如果AB服务分开部署(不在同一个JVM)中,那么对于B服务而言在JSON序列化以后得到的数据包如下
两个对应数据相应丢失。
对于上诉场景后端面对的频率非常高,但是此类问题如何基础底层框架一次性解决能?
一、设计基础数据包
后端数据包中除了场景的VO、DO、DTO、BO之类,先前有文章整理过,不熟悉的朋友可以翻阅文章
我这里基于基类设计,对于数据对象而言通常可分为四大部分
/**
* 数据对象
*/
public interface IData {
/**
* 读-主键
*
* @return
*/
String getFdId();
/**
* 写-主键
*
* @param fdId
*/
void setFdId(String fdId);
/**
* 读-机制类数据
*
* @return
*/
Map<String, Object> getMechanisms();
/**
* 写-机制类数据
*
* @param mechanisms
*/
void setMechanisms(Map<String, Object> mechanisms);
/**
* 读-动态数据
*
* @return
*/
Map<String, Object> getDynamicProps();
/**
* 写-动态属性
*
* @param dynamicProps
*/
void setDynamicProps(Map<String, Object> dynamicProps);
/**
* 读-固定的扩展属性
*
* @return
*/
@JsonIgnore
Map<String, Object> getExtendProps();
}
为什么需要设计IViewObject 展示数据对象接口?
比如在使用Hibernate 时候我们将数据层分为几层数据,因此我们一下所有的数据层都需继承IData
而IViewObject就是展示数据对象和接受数据对象的暴露数据包,所以要想解决空值问题,需要再这一层设计完善
/**
* 界面展现对象接口
*/
public interface IViewObject extends IData {
/**
* 读-空值字段
*
* @return
*/
public List<String> getNullValueProps();
/**
* 写-空值字段
*
* @param props
*/
public void setNullValueProps(List<String> props);
/**
* 加-空值字段
* @param props
*/
public void addNullValueProps(String... props);
}
VO的字段为null表示不修改Entity,若要讲Entity字段设置为null,请调用addNullValueProps
封装基类数据自然想到了抽象类来实现,这里将继续延续上面的思路往下
AbstractVO 实现IViewObject 方便展示层封装的拓展属性可以继续给其他层级使用。
实现代码如下:
/**
* 展示对象基类
*/
public abstract class AbstractVO implements IViewObject {
private String fdId;
private transient final Map<String, Object> extendProps = new HashMap<>(16);
private Map<String, Object> dynamicProps;
private Map<String, Object> mechanisms;
private List<String> nullValueProps;
@Override
public String getFdId() {
return fdId;
}
@Override
public void setFdId(String fdId) {
if (fdId != null) {
IDGenerator.validate(fdId);
}
this.fdId = fdId;
}
@Override
public Map<String, Object> getExtendProps() {
return extendProps;
}
@Override
public Map<String, Object> getDynamicProps() {
return dynamicProps;
}
@Override
public void setDynamicProps(Map<String, Object> dynamicProps) {
this.dynamicProps = dynamicProps;
}
@Override
public Map<String, Object> getMechanisms() {
return mechanisms;
}
@Override
public void setMechanisms(Map<String, Object> mechanisms) {
this.mechanisms = mechanisms;
}
@Override
public List<String> getNullValueProps() {
return nullValueProps;
}
@Override
public void setNullValueProps(List<String> nullValueProps) {
this.nullValueProps = nullValueProps;
}
@Override
public void addNullValueProps(String... props) {
if (nullValueProps == null) {
nullValueProps = new ArrayList<>();
}
for (String prop : props) {
nullValueProps.add(prop);
}
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(getClass().getName())
.append(getFdId()).toHashCode();
}
@Override
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (!(other instanceof IViewObject)) {
return false;
}
if (!getFdId().equals(((IViewObject) other).getFdId())) {
return false;
}
return getClass().getName()
.equals(other.getClass().getName());
}
}
二、业务实现引用
我们举个实际例子。下面是一个 Mapper 类:
基础数据包完善后改如何对接业务场景呢?结合下面的案例来实现场景引用,记得先前写过一篇大文件分片上传的文章以及超大文件断点续传
在定义附件基础信息对象中我们可以这样依赖
写在最后
跬步至千里,小流成江海,开发工作有大小,业务需求有缓急,但终究要落到眼下,从一砖一瓦的基石开始,从一行一列的编码开始,希望本文中能帮助到更多的研发同学。
- END -