1. 背景
因为项目上的需求,客户想实现对元字段的新增和删除,以达到一个台账支持多种类型数据的目的。于是去查阅了多放资料,综合了各位大佬的现有成果,在短时间把这个功能实现了。在这里吧参考链接贴出来:
Java实现表单的自定义字段功能(动态管理不同类型的字段数据)_javaweb表单的字段和数据库定义字段类型不同如何处理-CSDN博客
自定义字段的设计与实现(Java实用版)_自定义字段设计模型-CSDN博客
下面是我自己实现的过程中的一些笔记,在这里规整一下。
2. 开放模型
2.1. 定义
自定义字段又叫做“开放模型”,用户可以根据自已的需求,添加需要的字段,实现个性化定制。
2.2. 优点
- 无需再处理后台逻辑
- 线上直接完成
- 灵活、扩展性强
- 可同时扩展多个表
- 支持多种数据类型的字段
3. 表结构说明
3.1 表设计
- 自定义字段模板表
type:配置用来扩展不同的数据表(如多种表都要扩展,便可以用type来区分)
template: 使用json格式的数据存储自定义字段模板(会配置字段的各属性)
- 模板数据表
field_date:保存自定义模板中的字段具体值,存储格式为map(key:value)形式的json串
3.2. E-R图
4. 核心代码示例
- 新增自定义元数据字段
public boolean addField(FieldTemplateVO templateVo) throws Exception {
List<FieldTemplateDTO> fieldList = templateVo.getFieldTemplateList();
Integer type = templateVo.getType();
List<String> label = fieldList.stream().map(FieldTemplateDTO::getLabel).collect(Collectors.toList());
List<String> field = fieldList.stream().map(FieldTemplateDTO::getField).collect(Collectors.toList());
Set<String>fieldSet=new HashSet<>(field);
if(field.size()!=fieldSet.size()){
log.error("字段名称存在重复");
throw new Exception("字段名称存在重复");
}
Set<String>labelSet=new HashSet<>(label);
if(label.size()!=labelSet.size()){
throw new Exception("显示名称存在重复");
}
FieldTemplate fieldTemplate = baseMapper.queryByType(type);
if(fieldTemplate==null){
fieldTemplate=new FieldTemplate();
fieldTemplate.setTemplate(JSON.toJSONString(fieldList));
fieldTemplate.setType(type);
baseMapper.insert(fieldTemplate);
}else {
fieldTemplate.setTemplate(JSON.toJSONString(fieldList));
baseMapper.updateById(fieldTemplate);
}
return true;
}
2. 删除自定义元数据字段
public boolean deletedField(String field,Integer type) throws Exception {
FieldTemplate fieldTemplate = baseMapper.queryByType(type);
if(fieldTemplate!=null){
List<FieldTemplateDTO>fieldList=JSON.parseArray(fieldTemplate.getTemplate(),FieldTemplateDTO.class);
int initial=fieldList.size();
for (FieldTemplateDTO fieldTemplateDTO : fieldList) {
String fieldName=fieldTemplateDTO.getField();
if(fieldName.equals(field)){
fieldList.remove(fieldTemplateDTO);
break;
}
}if(initial !=fieldList.size()){
fieldTemplate.setTemplate(JSON.toJSONString(fieldList));
}
int i = baseMapper.updateById(fieldTemplate);
if(i==0){
throw new Exception("删除数据失败");
}
return true;
}
return false;
}
3. 根据type查看相应自定义元数据信息
public List<FieldTemplateDTO> getFieldTemplate(Integer type) {
FieldTemplate fieldTemplate=baseMapper.queryByType(type);
if(fieldTemplate==null){
return new ArrayList<>();
}
List<FieldTemplateDTO>fieldTemplateDTOS= JSON.parseArray(baseMapper.queryByType(type).getTemplate(),FieldTemplateDTO.class);
if(fieldTemplateDTOS==null){
return new ArrayList<>();
}
return fieldTemplateDTOS;
}