快速生成应用程序的开发平台
低代码开发平台(LCDP)是无需编码(0代码)或通过少量代码就可以快速生成应用程序的开发平台。通过可视化进行应用程序开发的方法(参考可视编程语言),使具有不同经验水平的开发人员可以通过图形化的用户界面,使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程序。 [1] 低代码开发平台(LCDP)的正式名称直到2014年6月才正式确定,整个低代码开发领域却可以追溯到更早前第四代编程语言和快速应用开发工具。
模型和数据库表是一对一的关系
列表页:
数据录入页面:
列表页:
数据录入页面:
项目代码已提交到github上面,请自行拉起代码查看
项目基于下面实现:
核心的两张表设计
关键代码类 | 描述 |
---|---|
enums包下的ConditionTypeEnum类 | 定义通用列表页面查询类型 |
enums包下的DataTypeEnum类 | 定义数据库字段类型 |
model包下的MetaInfo类 | 存储元数据信息 |
model包下的MetaColumn类 | 存型元数据拥有的字段信息 |
model.dto包下的类 | 存储通用数据查询修改删除用的类 |
service.impl包下的MetaServiceImpl类 | 元数据模型业务实现类 |
service.impl包下的UniversalServiceImpl类 | 元数据模型对应表的通用CRUD业务实现类 |
util包下的NativeQueryUtil类 | 执行sql的工具类 |
由于篇幅有限只贴了一个通用数据的CRUD类,可下载源代码自行预览。
public class UniversalServiceImpl implements UniversalService {
@Autowired
private MetaInfoRepository metaInfoRepository;
@Autowired
private NativeQueryUtil nativeQueryUtil;
@Override
public JsonResult query(UniversalQueryParamDTO universalQueryParam) {
MetaInfo metaInfo = metaInfoRepository.getOne(universalQueryParam.getMetaId());
//组装查询的sql
StringBuilder querySql = new StringBuilder("select id,");
for (MetaColumn metaColumn : metaInfo.getMetaColumnList()) {
if (metaColumn.isViewShow()) {
querySql.append(metaColumn.getColumnCode()).append(",");
}
}
querySql.deleteCharAt(querySql.length() - 1);
querySql.append(" from ").append(metaInfo.getTableCode()).append(" where 1=1");
List<UniversalQueryParamDTO.ConditionFiled> conditionFiledList = universalQueryParam.getConditionList();
//对查询条件排序 优化查询性能
conditionFiledList = conditionFiledList.stream().sorted().collect(Collectors.toList());
List<Object> condition = new ArrayList<>();
Integer index = 1;
//拼接查询条件
for (UniversalQueryParamDTO.ConditionFiled conditionFiled : conditionFiledList) {
if (StringUtils.hasText(conditionFiled.getValue())) {
if (conditionFiled.getType() == ConditionTypeEnum.EQUALS) {
//等值查询
querySql.append(" and ").append(conditionFiled.getCode());
querySql.append(" =?").append(index);
condition.add(conditionFiled.getValue());
index++;
} else {
//模糊查询
querySql.append(" and ").append(conditionFiled.getCode());
querySql.append(" like CONCAT('%',?").append(index).append(",'%')");
condition.add(conditionFiled.getValue());
index++;
}
}else if(!Collections.isEmpty(conditionFiled.getBetweenValue())){
//日期范围查询
querySql.append(" and ").append(conditionFiled.getCode()).append(">=?").append(index);
condition.add(conditionFiled.getBetweenValue().get(0));
index++;
querySql.append(" and ").append(conditionFiled.getCode()).append("<=?").append(index);
condition.add(DateUtil.getDateStrIncrement(conditionFiled.getBetweenValue().get(1)));
index++;
}
}
String sql = querySql.toString();
//查询符合条件的记录数
String countSql = "select count(id) " + sql.substring(sql.indexOf("from"));
//拼接分页的条件
querySql.append(" limit ").append((universalQueryParam.getCurrentPage() - 1) * universalQueryParam.getPageSize()).append(",").append(universalQueryParam.getPageSize());
//执行查询sql获取执行结果
List<Object[]> result = nativeQueryUtil.query(querySql.toString(), condition);
//执行获取总记录数的sql结果用于分页使用
List<BigInteger> pageResult = nativeQueryUtil.query(countSql, condition);
//总记录数
Integer totalElements = pageResult.get(0).intValue();
//总页数
Integer totalPages = totalElements % universalQueryParam.getPageSize() == 0 ? totalElements / universalQueryParam.getPageSize() : totalElements / universalQueryParam.getPageSize() + 1;
//把结果和字段映射起来
List<JSONObject> tabel = new ArrayList<>();
JSONObject tr;
//列名称用于显示表格的title信息
List<String> shouColumnCode = metaInfo.getMetaColumnList().stream().filter(MetaColumn::isViewShow).map(MetaColumn::getColumnCode).collect(Collectors.toList());
for (Object[] objects : result) {
tr = new JSONObject();
tr.put("id", objects[0].toString());
for (int i = 1; i < objects.length; i++) {
tr.put(shouColumnCode.get(i - 1), objects[i]);
}
tabel.add(tr);
}
JSONObject jsonObject = new JSONObject();
if (universalQueryParam.isFirstInit()) {
//获取当前表的所有字段,用于在添加和修改页面进行使用
List<MetaColumnVO> metaColumnVOList = new ArrayList<>();
metaInfo.getMetaColumnList().forEach(metaColumn -> metaColumnVOList.add(new MetaColumnVO(metaColumn)));
jsonObject.put("metaColumnList", metaColumnVOList);
//组装列表页的查询条件
List<List<MetaColumnVO>> searchMetaColumnList = new ArrayList<>();
List<MetaColumnVO> allSearchMetaColumnList = metaColumnVOList.stream().filter(metaColumnVO -> metaColumnVO.isSearch()).collect(Collectors.toList());
int count = 0, size = allSearchMetaColumnList.size();
//一行显示3个查询条件,使用二维集合封装
while (count < size) {
searchMetaColumnList.add(allSearchMetaColumnList.subList(count, Math.min((count + 3), size)));
count += 3;
}
//封装查询条件对象用于页面上展示
List<List<UniversalQueryParamDTO.ConditionFiled>> conditionList = new ArrayList<>();
List<UniversalQueryParamDTO.ConditionFiled> conditionFileds;
for (List<MetaColumnVO> columnVOList : searchMetaColumnList) {
conditionFileds = new ArrayList<>();
conditionList.add(conditionFileds);
for (MetaColumnVO mc : columnVOList) {
conditionFileds.add(new UniversalQueryParamDTO.ConditionFiled(mc.getName(), mc.getCode(), mc.getDataType()));
}
}
jsonObject.put("searchMetaColumnList", conditionList);
}
jsonObject.put("metaName", metaInfo.getMetaName());
jsonObject.put("tabelData", tabel);
jsonObject.put("totalElements", totalElements);
jsonObject.put("totalPages", totalPages);
return JsonResult.successResult(jsonObject);
}
@Override
public JsonResult save(UniversalSaveDTO universalSaveDTO) {
MetaInfo metaInfo = metaInfoRepository.getOne(universalSaveDTO.getMetaId());
StringBuilder sql = new StringBuilder();
String title;
Optional<MetaColumnVO> metaColumnVOOptional = universalSaveDTO.getData().stream().filter(metaColumnVO1 -> metaColumnVO1.getCode().equals("id")).findFirst();
if (metaColumnVOOptional.isPresent()) {
title = "修改";
//修改
sql.append("update ").append(metaInfo.getTableCode()).append(" set ");
for (MetaColumnVO metaColumnVO : universalSaveDTO.getData()) {
sql.append(metaColumnVO.getCode()).append("='").append(metaColumnVO.getValue()).append("',");
}
sql.deleteCharAt(sql.length() - 1);
sql.append(" where id=").append(metaColumnVOOptional.get().getValue());
} else {
title = "新增";
//新增
sql.append("insert into ").append(metaInfo.getTableCode()).append("(");
if (!metaInfo.isIncrement()) {
sql.append("id,");
}
StringBuilder valueSb = new StringBuilder();
for (MetaColumnVO metaColumnVO : universalSaveDTO.getData()) {
sql.append(metaColumnVO.getCode()).append(",");
valueSb.append("'").append(metaColumnVO.getValue()).append("',");
}
sql.deleteCharAt(sql.length() - 1);
valueSb.deleteCharAt(valueSb.length() - 1);
sql.append(") values(");
if (!metaInfo.isIncrement()) {
sql.append("'").append(IdWorkerUtil.getId()).append("',");
}
sql.append(valueSb);
sql.append(")");
}
boolean flag = nativeQueryUtil.executeUpdate(sql.toString());
if (flag) {
return JsonResult.successResult(title + "成功");
}
return JsonResult.failureResult(title + "失败");
}
@Override
public JsonResult delete(UniversalDeleteDTO universalDeleteDTO) {
MetaInfo metaInfo = metaInfoRepository.getOne(universalDeleteDTO.getMetaId());
StringBuilder sb = new StringBuilder("delete from ");
sb.append(metaInfo.getTableCode()).append(" where id in (");
for (Object o : universalDeleteDTO.getIdList()) {
sb.append(o);
sb.append(",");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
boolean flag = nativeQueryUtil.executeUpdate(sb.toString());
if (flag) {
return JsonResult.successResult("删除成功");
}
return JsonResult.failureResult("删除失败");
}
}
组件 | 描述 |
---|---|
metadata.Index.vue | 模型列表页面 |
metadata.save.vue | 模型保存页面 |
universal.Index.vue | 通用列表页面 |
universal.save.vue | 通用数据录入页面 |
通用列表页面
created() {
let path = this.$route.path;
let arr=path.split("/");
this.condition.metaId=arr[arr.length-1];
this.condition.firstInit = true;
},
<div style="height:200px">
<el-form label-width="80px">
<el-row v-for="columnList in searchMetaColumnList" :key="columnList" >
<el-col
:span="8"
v-for="column in columnList"
:key="column.code"
>
<el-form-item :label="column.name+':'" :key="column.code" class="names">
<el-input
v-if="column.type=='0'"
type="number"
v-model="column.value"
>el-input>
<el-date-picker style="width:55%"
v-else-if="column.type=='1'"
v-model="column.betweenValue"
type="daterange"
value-format="yyyy-MM-dd"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
>
el-date-picker>
<el-input v-else v-model="column.value">el-input>
el-form-item>
el-col>
el-row>
el-form>
div>
<el-table
class="tableLimit"
:data="tabelData"
style="width: 100%; height: 100%"
@selection-change="selectAll"
:row-class-name="tableRowClassName"
>
<el-table-column type="selection" width="55">el-table-column>
<el-table-column
v-for="column in metaColumnList"
v-if="column.viewShow"
:key="column.code"
:prop="column.code"
:label="column.name"
>el-table-column>
<el-table-column label="操作" min-width="120">
<template slot-scope="scope">
<el-button @click="create(scope.row)" type="text" size="small"
>修改
el-button>
<el-button
:disabled="scope.row.builtIn == 1"
@click="deleteSelected(scope.row)"
type="text"
size="small"
>删除
el-button>
template>
el-table-column>
el-table>
通用数据录入页面
<el-form-item
v-for="metaColumn in metaColumnList"
:key="metaColumn.code"
:label="metaColumn.name"
>
<el-input
v-if="metaColumn.dataType.includes('int')"
type="number"
v-show="metaColumn.code!='id'"
v-model="metaColumn.value"
>el-input>
<el-date-picker
v-else-if="metaColumn.dataType.includes('date')"
v-model="metaColumn.value"
type="date"
placeholder="选择日期"
format="yyyy 年 MM 月 dd 日"
value-format="yyyy-MM-dd"
>
el-date-picker>
<el-input v-else v-model="metaColumn.value">el-input>
el-form-item>
创作不易,要是觉得我写的对你有点帮助的话,麻烦在github上帮我点下 Star
【SpringBoot框架篇】其它文章如下,后续会继续更新。