通过前面的步骤,我们完成了实体的配置,主要包括实体、实体模型、视图,接下来的工作主要是三项,一是生成数据库表,二是生成前后端源码,三是配置权限项(菜单及按钮),完成这几步工作后,配置的功能就能运转起来了,下面继续以接口平台模块中的应用这个实体为例来具体说说。
不少低代码平台,都是先通过数据库模型开发工具,如PowerDesigner,设计数据库表,然后生成库表,平台再连接数据库,进行逆向工程,生成源码。这种方式,还是需要开发人员去了解库表设计工具的使用,以及数据库相应的知识,如不同种类的数据库,字符串、整形、日期各有不同。这种模式本质上还是传统意义上的数据驱动。
我设计的这套低代码平台,是先设计模型,然后由平台根据模型配置来自动创建库表,开发人员只需要在平台内做配置就可以了。这种模式相当于模型驱动,开发人员不再需要关注数据库的类型和细节了,平台已经接管了。
通过菜单进入实体管理列表,勾选要生成库表的一个或多个实体,然后点击“生成库表”按钮,系统会根据模型配置信息,自动生成数据库表创建语句,并连接数据库创建。
同生成库表操作类似,通过菜单进入实体管理列表,勾选要生成库表的一个或多个实体,然后点击“生成代码”按钮,系统会根据实体配置信息,自动生成源码,包括后端的实体类、DAO层的Mapper接口及xml配置文件、服务层(接口及实现类)、控制器层、视图对象类,以及前端的视图(列表、新增、修改、查看、参照以及可能的树、树表等,取决于视图配置环节的设置)。
前端:将view目录下的vue视图文件,拷贝到前端src\modules\cip\view目录下
后端:其他目录下文件,拷贝到后端manage项目下
package tech.abc.platform.cip.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import tech.abc.platform.common.base.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 应用 实体类
*
* @author wqliu
* @date 2023-05-02
*
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("cip_app")
public class App extends BaseEntity {
/**
* 名称
*/
@TableField("name")
private String name;
/**
* 编码
*/
@TableField("code")
private String code;
/**
* 密钥
*/
@TableField("secret_key")
private String secretKey;
/**
* 对接模式
*/
@TableField("integration_model")
private String integrationModel;
/**
* 状态
*/
@TableField("status")
private String status;
/**
* 排序
*/
@TableField("order_no")
private String orderNo;
}
package tech.abc.platform.cip.mapper;
import tech.abc.platform.cip.entity.App;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 应用 Mapper 接口
*
* @author wqliu
* @date 2023-05-02
*/
public interface AppMapper extends BaseMapper<App> {
}
package tech.abc.platform.cip.service;
import tech.abc.platform.cip.entity.App;
import tech.abc.platform.common.base.BaseService;
import java.util.List;
import java.util.Map;
/**
* 应用 服务接口类
*
* @author wqliu
* @date 2023-05-27
*/
public interface AppService extends BaseService<App> {
/**
* 获取标识与名称的Map集合
*
* @param idList 标识列表
* @return 集合
*/
Map<String,String> getNameMap(List<String> idList);
}
package tech.abc.platform.cip.service.impl;
import tech.abc.platform.cip.entity.App;
import tech.abc.platform.cip.mapper.AppMapper;
import tech.abc.platform.cip.service.AppService;
import tech.abc.platform.common.base.BaseServiceImpl;
import org.springframework.stereotype.Service;
import tech.abc.platform.common.exception.CommonException;
import tech.abc.platform.common.exception.CustomException;
import java.math.BigDecimal;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
/**
* 应用 服务实现类
*
* @author wqliu
* @date 2023-05-27
*/
@Service
@Slf4j
public class AppServiceImpl extends BaseServiceImpl<AppMapper, App> implements AppService {
@Override
public App init() {
App entity=new App();
//默认值处理
entity.setIntegrationModel("CLIENT");
entity.setStatus("NORMAL");
return entity;
}
@Override
public void beforeAdd(App entity) {
//唯一性验证
//验证 名称 全局唯一
if (StringUtils.isNotBlank(entity.getName())) {
long countName = this.lambdaQuery().eq(App::getName, entity.getName()).count();
if (countName > 0) {
throw new CustomException(CommonException.PROPERTY_EXIST,"【名称】");
}
}
//验证 编码 全局唯一
if (StringUtils.isNotBlank(entity.getCode())) {
long countCode = this.lambdaQuery().eq(App::getCode, entity.getCode()).count();
if (countCode > 0) {
throw new CustomException(CommonException.PROPERTY_EXIST,"【编码】");
}
}
}
@Override
public void beforeModify(App entity) {
//唯一性验证
//验证 名称 全局唯一
if (StringUtils.isNotBlank(entity.getName())) {
long countName = this.lambdaQuery().eq(App::getName, entity.getName())
.ne(App::getId, entity.getId()).count();
if (countName > 0) {
throw new CustomException(CommonException.PROPERTY_EXIST,"【名称】");
}
}
//验证 编码 全局唯一
if (StringUtils.isNotBlank(entity.getCode())) {
long countCode = this.lambdaQuery().eq(App::getCode, entity.getCode())
.ne(App::getId, entity.getId()).count();
if (countCode > 0) {
throw new CustomException(CommonException.PROPERTY_EXIST,"【编码】");
}
}
}
@Override
public Map<String, String> getNameMap(List<String> idList) {
Map<String, String> result = new HashMap<>(5);
if (CollectionUtils.isNotEmpty(idList)) {
List<App> list = this.lambdaQuery().in(App::getId, idList).list();
if (CollectionUtils.isNotEmpty(list)) {
list.stream().forEach(x -> {
result.put(x.getId(), x.getName());
});
}
}
return result;
}
@Override
protected void copyPropertyHandle(App entity, String... value) {
// 主属性后附加“副本”用于区分
entity.setName (entity.getName() + " 副本");
}
}
package tech.abc.platform.cip.controller;
import org.springframework.web.bind.annotation.RestController;
import tech.abc.platform.common.base.BaseController;
import org.springframework.web.bind.annotation.RequestMapping;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import tech.abc.platform.common.annotation.SystemLog;
import tech.abc.platform.common.query.QueryGenerator;
import tech.abc.platform.common.utils.ResultUtil;
import tech.abc.platform.common.vo.PageInfo;
import tech.abc.platform.common.vo.Result;
import tech.abc.platform.common.vo.SortInfo;
import tech.abc.platform.cip.entity.App;
import tech.abc.platform.cip.service.AppService;
import tech.abc.platform.cip.vo.AppVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 应用 前端控制器类
*
* @author wqliu
* @date 2023-05-27
*/
@RestController
@RequestMapping("/cip/app")
@Slf4j
public class AppController extends BaseController {
@Autowired
private AppService appService;
//region 基本操作
/**
* 初始化
*/
@GetMapping("/init")
public ResponseEntity<Result> init() {
App entity=appService.init();
AppVO vo = convert2VO(entity);
return ResultUtil.success(vo);
}
/**
* 新增
*/
@PostMapping("/")
@SystemLog(value = "应用-新增")
@PreAuthorize("hasPermission(null,'cip:app:add')")
public ResponseEntity<Result> add(@Validated @RequestBody AppVO vo) {
App entity=convert2Entity(vo);
appService.add(entity);
AppVO newVO = convert2VO(entity);
return ResultUtil.success(newVO);
}
/**
* 修改
*/
@PutMapping("/")
@SystemLog(value = "应用-修改")
@PreAuthorize("hasPermission(null,'cip:app:modify')")
public ResponseEntity<Result> modify(@Validated @RequestBody AppVO vo) {
App entity=convert2Entity(vo);
appService.modify(entity);
AppVO newVO = convert2VO(entity);
return ResultUtil.success(newVO);
}
/**
* 删除数据,单条数据标识,或多条数据标识用逗号间隔拼成的字符串
*/
@DeleteMapping("/{id}")
@SystemLog(value = "应用-删除")
@PreAuthorize("hasPermission(null,'cip:app:remove')")
public ResponseEntity<Result> remove(@PathVariable("id") String id) {
appService.remove(id);
return ResultUtil.success();
}
/**
* 分页
*/
@GetMapping("/page")
@SystemLog(value = "应用-分页")
@PreAuthorize("hasPermission(null,'cip:app:query')")
public ResponseEntity<Result> page(AppVO queryVO, PageInfo pageInfo, SortInfo sortInfo) {
//构造分页对象
IPage<App> page = new Page<App>(pageInfo.getPageNum(), pageInfo.getPageSize());
//构造查询条件
QueryWrapper<App> queryWrapper = QueryGenerator.generateQueryWrapper(App.class,queryVO,sortInfo);
//查询数据
appService.page(page, queryWrapper);
//转换vo
IPage<AppVO> pageVO = mapperFacade.map(page, IPage.class);
List<AppVO> appVOList=convert2VO(page.getRecords());
pageVO.setRecords(appVOList);
return ResultUtil.success(pageVO);
}
/**
* 列表
*/
@GetMapping("/list")
@SystemLog(value = "应用-列表")
@PreAuthorize("hasPermission(null,'cip:app:query')")
public ResponseEntity<Result> list(AppVO queryVO, SortInfo sortInfo) {
//构造查询条件
QueryWrapper<App> queryWrapper = QueryGenerator.generateQueryWrapper(App.class, queryVO,sortInfo);
List<App> list= appService.list(queryWrapper);
//转换vo
List<AppVO> appVOList=convert2VO(list);
return ResultUtil.success(appVOList);
}
/**
* 获取单条数据
*/
@GetMapping("/{id}")
@SystemLog(value = "应用-详情")
@PreAuthorize("hasPermission(null,'cip:app:view')")
public ResponseEntity<Result> get(@PathVariable("id") String id) {
App entity = appService.query(id);
AppVO vo = convert2VO(entity);
return ResultUtil.success(vo);
}
/**
* 复制新增数据,单条数据标识,或多条数据标识用逗号间隔拼成的字符串
*/
@PostMapping("/{id}")
@SystemLog(value = "应用-复制新增")
@PreAuthorize("hasPermission(null,'cip:app:addByCopy')")
public ResponseEntity<Result> addByCopy(@PathVariable("id") String id) {
appService.addByCopy(id);
return ResultUtil.success();
}
//endregion
//region 扩展操作
//endregion
//region 辅助操作
/**
* 将单条实体转换为视图对象
*
* @param entity 实体
* @return {@link EntityVO} 视图对象
*/
private AppVO convert2VO(App entity){
AppVO vo=mapperFacade.map(entity,AppVO.class);
vo.setIntegrationModelName(dictionaryUtil.getNameByCode("IntegrationModel", entity.getIntegrationModel()));
vo.setStatusName(dictionaryUtil.getNameByCode("Status", entity.getStatus()));
return vo;
}
/**
* 将实体列表转换为视图对象列表
*
* @param entityList 实体列表
* @return {@link List}<{@link EntityVO}> 视图对象列表
*/
private List<AppVO> convert2VO(List<App> entityList) {
List<AppVO> voList = new ArrayList<>(entityList.size());
entityList.stream().forEach(x -> {
AppVO vo = convert2VO(x);
voList.add(vo);
});
return voList;
}
private App convert2Entity(AppVO vo){
App entity=mapperFacade.map(vo,App.class);
return entity;
}
//endregion
}
package tech.abc.platform.cip.vo;
import tech.abc.platform.common.base.BaseVO;
import java.time.LocalDateTime;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 应用 视图对象类
*
* @author wqliu
* @date 2023-05-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class AppVO extends BaseVO {
/**
* 名称
*/
@NotBlank(message = "【名称】不能为空")
private String name;
/**
* 编码
*/
@NotBlank(message = "【编码】不能为空")
private String code;
/**
* 密钥
*/
@NotBlank(message = "【密钥】不能为空")
private String secretKey;
/**
* 对接模式
*/
@NotBlank(message = "【对接模式】不能为空")
private String integrationModel;
/**
* 状态
*/
@NotBlank(message = "【状态】不能为空")
private String status;
/**
* 排序
*/
private String orderNo;
/********字典类*****/
/**
* 对接模式
*/
private String integrationModelName;
/**
* 状态
*/
private String statusName;
/********实体类*****/
/********范围查询*****/
/********自定义扩展*****/
/********子对象*****/
}
刷新
新增
删除
复制新增
API权限
消息权限
更多
修改
删除
启用
停用
重置密钥
平台根据配置实现的是一些模式化的工作,还是需要开发人员根据业务需求进行一些调整工作,主要在后端方面,例如,编写启动、停用和重设密钥的服务。
低代码并不意味无代码,配置人员和开发人员需要协作才能发挥最大的作用。
至此,平台低代码整体配置流程介绍完毕,下篇我们介绍下平台如何通过优化来提升配置效率。
平台名称:一二三开发平台
简介: 企业级通用开发平台
设计资料:csdn专栏
开源地址:Gitee
开源协议:MIT
欢迎收藏、点赞、评论,你的支持是我前行的动力。