惯例先描述业务场景:
产品拿到公司业务需求如下,给领导展示几个现有的业务线场景的具体信息,且指定人可见.
技术描述也就是用excel表格或者后台输入作为数据源,行字段灵活增加减少,且每一行控制可见人员的白名单信息.
技术思考:
作为技术开发听到产品给的泛泛的描述后,觉得一个宽表+excel作为数据源同步就可以搞定,那么如果产品频繁的增加字段我们该如何快速满足,每个字段的处理规则我们要如何满足,只有支持好了这两点才能快速支撑业务,那么我们就不能用传统的一张表就搞定了
实现过程:
本人java技术栈,仅用java分享过程
1、首先我们定义业务模型,例如目标对象TargetGroup
2、我们对目标对象的细节进行分析,也就属性以及属性所对应的业务关系:
id、name、等等一系列字段
3、定义数据源输入:
数据源我们为了快速实现采用表格上传作为数据源
4、表设计:
此处就不画关系了,object_field表最为对象模型的字段表,field_detail作为对象每个字段具体记录值表,通俗点理解关系就是我们把行表还为了列表存取kv+namespace的形式进行对业务数据的映射,以满足对数据模型的字段的灵活拓展,当然此处也有严重的缺点,就是我们做关联关系的时候一些必要的字段以及状态还是要存到主表的
此处的代码参考
public void insertTargetField(TargetGroupExcelDto dto, String namespase) {
ObjectField objectField = objectFieldMapper.findByNamespase(namespase);
if (Objects.isNull(objectField)) {
return;
}
List<String> fields = Arrays.asList(objectField.getObjectFields().split(","));
//处理单个字段与字段的规则为一组动作
Class<? extends TargetGroupExcelDto> aClass = dto.getClass();
List<Field> dtoFields = Arrays.asList(aClass.getDeclaredFields());
//删除之前的字段详情记录
fieldDetailMapper.deleteByObjectId(dto.getTargetId());
fields.stream().forEach(f -> {
WhiteInfoDto whiteInfoDto = new WhiteInfoDto();
whiteInfoDto.setTargetId(dto.getTargetId());
whiteInfoDto.setObjectNamespace(namespase);
Optional<Field> first = dtoFields.stream().filter(df -> df.getName().equals(f)).findFirst();
if (first.isPresent()) {
try {
Field field = first.get();
field.setAccessible(true);
String fValue = (String) field.get(dto);
whiteInfoDto.setFieldName(f);
whiteInfoDto.setFieldValue(fValue);
try {
Field wfield = aClass.getDeclaredField(f + "Whited");//开启白名单
wfield.setAccessible(true);
String wfieldValue = "否";
try {
wfieldValue = ((String) wfield.get(dto)).replaceAll(" ", "");
} catch (NullPointerException e) {
}
//此处为是否对全员可见在业务定义,不是是否开启白名单,擦了
whiteInfoDto.setStringWhited(StringUtils.isEmpty(wfieldValue) || wfieldValue.equals("否") ? false : true);
} catch (NoSuchFieldException e) {
log.warn("当前无白名单设置dto={},field={}", dto, f);
}
try {
Field ufield = aClass.getDeclaredField(f + "Users");//白名单
ufield.setAccessible(true);
String ufieldValue = "";
try {
ufieldValue = ((String) ufield.get(dto)).replaceAll(" ", "");
} catch (NullPointerException e) {
}
whiteInfoDto.setWhiteUsers(UserItcodeAnalysisUtil.getStringItcodes(ufieldValue));
} catch (NoSuchFieldException e) {
log.warn("当前无白名单人员dto={},field={}", dto, f);
}
//入库
saveFeild(whiteInfoDto);
} catch (IllegalAccessException e) {
log.warn("获取字段异常e={}", e, first);
}
}
});
}
private void saveFeild(WhiteInfoDto dto) {
FieldDetail fd = new FieldDetail();
String fieldDetailId = uidGenerator.getUID();
fd.setId(fieldDetailId);
//此处为事项id
fd.setObjectId(dto.getTargetId());
fd.setObjectNamespace(dto.getObjectNamespace());
fd.setFieldName(dto.getFieldName());
fd.setFieldType("String");//暂时写死后续有需要在迭代
fd.setFieldValue(dto.getFieldValue());
fd.setDeleted(false);
fieldDetailMapper.insertSelective(fd);
FieldWhiteItcode fw = new FieldWhiteItcode();
fw.setFieldId(fieldDetailId);
fw.setWhited(dto.getStringWhited());
fw.setWhiteItcodes(dto.getWhiteUsers());
fw.setDeleted(false);
fieldWhiteItcodeMapper.insertSelective(fw);
}
有遇到相同情况的可以找博主讨论哦,源码例子就不上传了,都是项目的,有空来个demo丢上来