一二三应用开发平台应用开发示例(3)——生成库表及后端代码

生成库表

前端页面的配置,也就是视图功能,我们先放一放,来看看生成库表和后端代码。
关闭实体配置界面,回到实体列表,勾选“文件夹”实体,点击“生成库表”,并确定。
image.png
系统提示成功后,使用数据库客户端图形化工具查看,如下:
image.png
库表创建完成了,库表的名称和注释、字段的名称、编码、类型、注释都是完整的,来源于数据模型的配置。
注意:配置中的是否必填,平台在生成库表环节特意去除了数据库层面的不能为空的处理,改由应用层的前端与后端去做逻辑验证。

生成代码

在实体列表页面,勾选“文件夹”实体,点击“生成代码”按钮,提示成功后,到idea的项目根目录下,找到output目录,生成的代码会按照前面的配置,结合代码模板,生成各层的代码,如下图所示:
image.png
注意上图中,包路径出现了两次edoc,实际上含义不同,第一个edoc是应用的编码,第二个edoc是模块的编码,如果要避免这种情况,也简单,模块可以命名为main或core等其他不重复的名字,这里我就不调整了。

复制后端代码

复制输出的代码,到我们新建的模块对应包下,如下图所示:
image.png

查看后端代码

以下完全是基于配置和代码模板一次性生成的各层代码,无任何手工调整的地方,包括注释,均为自动生成。

实体类

package tech.abc.edoc.edoc.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 2024-01-29**/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("ed_folder")
public class Folder extends BaseEntity {/*** 上级*/@TableField("parent_id")private String parentId;/*** 名称*/@TableField("name")private String name;/********非库表存储属性*****/
}

mapper类及xml

package tech.abc.edoc.edoc.mapper;import tech.abc.edoc.edoc.entity.Folder;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** 文件夹 Mapper 接口** @author wqliu* @date 2024-01-29*/
public interface FolderMapper extends BaseMapper<Folder> {}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tech.abc.edoc.edoc.mapper.FolderMapper"></mapper>

保留了MybatisPlus(或者说Mybatis)的xml和mapper接口类,如需要使用sql语句扩展功能,如多表关联查询,在当前文件上追加即可,非常方便。

服务接口

package tech.abc.edoc.edoc.service;import tech.abc.edoc.edoc.entity.Folder;
import tech.abc.platform.common.base.BaseService;
import java.util.List;
import java.util.Map;/*** 文件夹 服务接口类** @author wqliu* @date 2024-01-29*/
public interface FolderService extends BaseService<Folder> {/*** 获取标识与名称的Map集合** @param idList 标识列表* @return 集合*/Map<String,String> getNameMap(List<String> idList);
}

公用操作如增删改查,都放到了父接口中BaseService,并内置了一个获取标识与名称的Map集合,用于处理列表页面转换显示数据时产生的经典1+N问题。

服务实现类

package tech.abc.edoc.edoc.service.impl;import tech.abc.edoc.edoc.entity.Folder;
import tech.abc.edoc.edoc.mapper.FolderMapper;
import tech.abc.edoc.edoc.service.FolderService;
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;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
/**
* 文件夹 服务实现类
*
* @author wqliu
* @date 2024-01-29
*/
@Service
@Slf4j
public class FolderServiceImpl extends BaseServiceImpl<FolderMapper, Folder> implements FolderService {@Overridepublic Folder init() {Folder entity=new Folder();// 预先分配标识entity.setId(IdWorker.getIdStr());//默认值处理return entity;}@Overridepublic void beforeAdd(Folder entity) {//唯一性验证//验证 名称 同节点下唯一if (StringUtils.isNotBlank(entity.getName())) {long countName = this.lambdaQuery().eq(Folder::getName, entity.getName()).eq(Folder::getParentId, entity.getParentId()).count();if (countName > 0) {throw new CustomException(CommonException.PROPERTY_EXIST_IN_SAME_NODE,"【名称】");}}}@Overridepublic void beforeModify(Folder entity) {//唯一性验证//验证 名称 同节点下唯一if (StringUtils.isNotBlank(entity.getName())) {long countName = this.lambdaQuery().eq(Folder::getName, entity.getName()).eq(Folder::getParentId, entity.getParentId()).ne(Folder::getId, entity.getId()).count();if (countName > 0) {throw new CustomException(CommonException.PROPERTY_EXIST_IN_SAME_NODE,"【名称】");}}}@Overridepublic Map<String, String> getNameMap(List<String> idList) {Map<String, String> result = new HashMap<>(5);if (CollectionUtils.isNotEmpty(idList)) {List<Folder> list = this.lambdaQuery().in(Folder::getId, idList).list();if (CollectionUtils.isNotEmpty(list)) {list.stream().forEach(x -> {result.put(x.getId(), x.getName());});}}return result;}@Overrideprotected void copyPropertyHandle(Folder entity, String... value) {// 主属性后附加“副本”用于区分entity.setName (entity.getName() + " 副本");}}

模型属性配置时的唯一性配置,平台处理时,会自动在新增和修改操作前生成验证代码;默认值配置,会在初始化方法init中体现。

控制器

package tech.abc.edoc.edoc.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.constant.TreeDefaultConstant;
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.edoc.edoc.entity.Folder;
import tech.abc.edoc.edoc.service.FolderService;
import tech.abc.edoc.edoc.vo.FolderVO;
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;
import java.util.stream.Collectors;import tech.abc.platform.common.utils.TreeUtil;
import tech.abc.platform.common.vo.TreeVO;/**
* 文件夹 前端控制器类
*
* @author wqliu
* @date 2024-01-29
*/
@RestController
@RequestMapping("/edoc/folder")
@Slf4j
public class FolderController extends BaseController {@Autowiredprivate FolderService folderService;//region 基本操作/*** 初始化*/@GetMapping("/init")public ResponseEntity<Result> init() {Folder entity=folderService.init();FolderVO vo = convert2VO(entity);return ResultUtil.success(vo);}/*** 新增*/@PostMapping("/")@SystemLog(value = "文件夹-新增")@PreAuthorize("hasPermission(null,'edoc:folder:add')")public ResponseEntity<Result> add(@Validated @RequestBody FolderVO vo) {Folder entity=convert2Entity(vo);folderService.add(entity);FolderVO newVO = convert2VO(entity);return ResultUtil.success(newVO);}/*** 修改*/@PutMapping("/")@SystemLog(value = "文件夹-修改")@PreAuthorize("hasPermission(null,'edoc:folder:modify')")public ResponseEntity<Result> modify(@Validated @RequestBody FolderVO vo) {Folder entity=convert2Entity(vo);folderService.modify(entity);FolderVO newVO = convert2VO(entity);return ResultUtil.success(newVO);}/*** 删除数据,单条数据标识,或多条数据标识用逗号间隔拼成的字符串*/@DeleteMapping("/{id}")@SystemLog(value = "文件夹-删除")@PreAuthorize("hasPermission(null,'edoc:folder:remove')")public ResponseEntity<Result> remove(@PathVariable("id") String id) {folderService.remove(id);return ResultUtil.success();}/*** 分页*/@GetMapping("/page")@SystemLog(value = "文件夹-分页")@PreAuthorize("hasPermission(null,'edoc:folder:query')")public ResponseEntity<Result> page(FolderVO queryVO, PageInfo pageInfo, SortInfo sortInfo) {//构造分页对象IPage<Folder> page = new Page<Folder>(pageInfo.getPageNum(), pageInfo.getPageSize());// 当勾选查询所有复选框时,查询所有数据if (queryVO.getIgnoreParent() != null && queryVO.getIgnoreParent()) {queryVO.setParentId(null);}//构造查询条件QueryWrapper<Folder> queryWrapper = QueryGenerator.generateQueryWrapper(Folder.class,queryVO,sortInfo);//查询数据folderService.page(page, queryWrapper);//转换voIPage<FolderVO> pageVO = mapperFacade.map(page, IPage.class);List<FolderVO>  folderVOList=convert2VO(page.getRecords());pageVO.setRecords(folderVOList);return ResultUtil.success(pageVO);}/*** 列表*/@GetMapping("/list")@SystemLog(value = "文件夹-列表")@PreAuthorize("hasPermission(null,'edoc:folder:query')")public ResponseEntity<Result> list(FolderVO queryVO, SortInfo sortInfo) {//构造查询条件QueryWrapper<Folder> queryWrapper = QueryGenerator.generateQueryWrapper(Folder.class, queryVO,sortInfo);List<Folder> list= folderService.list(queryWrapper);//转换voList<FolderVO>  folderVOList=convert2VO(list);return ResultUtil.success(folderVOList);}/*** 获取单条数据*/@GetMapping("/{id}")@SystemLog(value = "文件夹-详情")@PreAuthorize("hasPermission(null,'edoc:folder:view')")public ResponseEntity<Result> get(@PathVariable("id") String id) {Folder entity = folderService.query(id);FolderVO vo = convert2VO(entity);return ResultUtil.success(vo);}/*** 复制新增数据,单条数据标识,或多条数据标识用逗号间隔拼成的字符串*/@PostMapping("/{id}")@SystemLog(value = "文件夹-复制新增")@PreAuthorize("hasPermission(null,'edoc:folder:addByCopy')")public ResponseEntity<Result> addByCopy(@PathVariable("id") String id) {folderService.addByCopy(id);return ResultUtil.success();}//endregion//region 扩展操作//endregion//region 树操作/*** 获取树数据** @return*/@GetMapping("/tree")@PreAuthorize("hasPermission(null,'edoc:folder:query')")public ResponseEntity<Result> tree() {QueryWrapper<Folder> queryWrapper = new QueryWrapper<>();List<Folder> list = folderService.list(queryWrapper);// 转化成树结构数据List<TreeVO> treeList = list.stream().map(e -> convert2TreeVO(e)).collect(Collectors.toList());List<TreeVO> tree = TreeUtil.buildTree(treeList, TreeDefaultConstant.DEFAULT_TREE_ROOT_PARENT_ID);return ResultUtil.success(tree);}/*** 转换为树视图对象*/private TreeVO convert2TreeVO(Folder entity) {TreeVO tree = new TreeVO();tree.setId(entity.getId());tree.setParentId(entity.getParentId());tree.setLabel(entity.getName());return tree;}//endregion//region 辅助操作/*** 将单条实体转换为视图对象** @param entity 实体* @return {@link EntityVO} 视图对象*/protected FolderVO convert2VO(Folder entity){FolderVO vo=mapperFacade.map(entity,FolderVO.class);return vo;}/*** 将实体列表转换为视图对象列表** @param entityList 实体列表* @return {@link List}<{@link EntityVO}> 视图对象列表*/protected List<FolderVO> convert2VO(List<Folder> entityList) {List<FolderVO> voList = new ArrayList<>(entityList.size());entityList.stream().forEach(x -> {FolderVO vo = convert2VO(x);voList.add(vo);});return voList;}private Folder convert2Entity(FolderVO vo){Folder entity=mapperFacade.map(vo,Folder.class);return entity;}//endregion}

控制器类作为与前端交互的最后一个层,不能像服务层那样,通过泛型基类来提取公共代码复用,平台生成全量的增删改查基本操作,根据实际业务需求进行删除,比如某些实体只能删除不能修改。

除了基本的初始化、新增、删除、修改外,平台内置了分页操作、列表操作、复制新增操作以及实体类与视图对象类的转换操作,且转换时数据字典类型与实体关联类可自动化转换。如果该实体是自关联,同时还会附加树形数据的处理方法。

同时考虑到该类的方法比较多,使用region注释的方式进行了分组。
image.png

视图对象类

package tech.abc.edoc.edoc.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 2024-01-29
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class FolderVO extends BaseVO {/*** 上级*/private String parentId;/*** 名称*/@NotBlank(message = "【名称】不能为空")private String name;/********非库表存储属性*****//********字典类*****//********实体类、用户单选、组织机构单选*****//********范围查询*****//********自定义扩展*****//*** 忽略上级*/private Boolean ignoreParent;/********子对象*****/}

这里平台自动附加了一个忽略上级的属性,是对于树形结构的实体,默认查询是只查询选中节点下的数据,有时候不确定在哪个节点下,总不能逐个点击去查找,而是提供了这么一个额外属性,来忽略选中节点,查询所有数据。

编译代码

使用maven,clean并install该模块。
image.png
一次性编译成功,无需任何改动。

开发平台资料

平台名称:一二三应用开发平台
平台简介:企业级通用低代码应用开发平台,免费全开源可商用
设计资料:csdn专栏
开源地址:Gitee
开源协议:MIT

应用系统资料

应用名称:一二三文档管理系统
应用简介: 企事业单位一站式文档管理系统,让组织内文档管理有序,协作高效、安全可控
设计文档:csdn专栏
开源地址:Gitee
开源协议:MIT

如果您在阅读本文时获得了帮助或受到了启发,希望您能够喜欢并收藏这篇文章,为它点赞~
请在评论区与我分享您的想法和心得,一起交流学习,不断进步,遇见更加优秀的自己!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/854092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【每天学会一个渗透测试工具】dirsearch安装及使用指南

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 ✨dirsearch介绍 dirsearch安装包百度网盘 disearch是基于Python开发的&#xff0c;因此需要确保你的系统中已经安装了pyth…

flstudio怎么调中文

FL Studio设置中文的步骤如下&#xff1a; 打开FL Studio&#xff1a;首先&#xff0c;需要打开FL Studio编曲软件。 进入常规设置&#xff1a;在软件顶部菜单栏中&#xff0c;选择“OPTIONS”&#xff0c;然后点击“General setting”&#xff0c;进入常规设置窗口。 切换语言…

经典电源电路基础(变压-整流-滤波-稳压)

1.电源电路的功能和组成 电子电路中的电源一般是低压直流电&#xff0c;先把220v交流电变换成低压直流电&#xff0c;再用整流电路变成脉动的直流电&#xff0c;最后用滤波电路滤除掉脉动直流中的交流成分后才能得到直流电。有的电子设备对电源的质量要求很高&#xff0c;所以…

JavaWeb之初识Tomcat

Tomcat 轻量级应用服务器、JSP、Servlet Tomcat目录结构 在IDEA中创建web项目 在这里不使用maven构建项目&#xff0c;这种方式后面会更新 新建一个java项目File -> Project Settings -> Facets -> -> Web -> OK ( 此时src目录下有一个web目录 )Edit ->…

[个人感悟] 缓存应该考察哪些问题?

前言 缓存, 根据冯诺依曼计算机模型, 无非是为了更高效的交互, 使用内存IO替换本地磁盘IO. 又因为内存的稀缺性, 其必然存储的是热点数据, 且较小的数据. [虽然直至今日, 已有使用缓存作为数据库的使用, 但是与磁盘IO相比, 其价格仍是数倍之多.] 当涉及缓存问题时, 又分为本地…

调用第三方系统的签名设计与校验实例讲解与实践

在现代软件开发中&#xff0c;调用第三方系统API已经成为常见需求。为了保证数据传输的安全性和完整性&#xff0c;许多API采用了签名机制。本文将详细讲解如何设计与校验调用第三方系统的签名&#xff0c;以确保双方通信的安全和可靠。 #### 一、签名机制的意义 签名机制主要…

C语言之顺序结构以及程序调试的debug宏

一&#xff1a;C语言中的顺序结构 1:最浅显的顺序结构理解&#xff1a;三种结构之一 &#xff08;1&#xff09;代码执行的时候没有遇到判断跳转或者循环&#xff0c;默认是顺序执行的。执行完上一句则开始执行下一句。 &#xff08;2&#xff09;顺序结构说明cpu的工作状态&a…

类Copy方法:BeanUtils.copyProperties

类Copy方法&#xff1a;BeanUtils.copyProperties 需求场景 比如有时候我们想要把数据库里面的数据导出到excel表中&#xff0c;比如想要把数据库中的用户数据导出到excel表格中&#xff1b; 假设我们程序代码中与数据库对接的实体类是User&#xff0c;用于展示到前端的实体类…

Fiddler抓包工具介绍

下载 下载:Web Debugging Proxy and Troubleshooting Tools|Fiddler 进去要填一个表 汉化版 百度网盘 请输入提取码 提取码&#xff1a;xq9t 下载过附件之后分别把两个文件 点开fiddler就ok了 配置https fiddler要想抓到https包(解密的),点击tools->options勾选三个对…

总结之Docker(四)——镜像修改非ROOT用户权限后生成新镜像并发布

Docker拉去目标镜像 docker pull redis:6.2.5如果出现拉去过程超时&#xff0c;或者连接失败。 添加镜像加速器&#xff0c;以阿里云为例&#xff0c;阿里云目前推广提供镜像加速器&#xff0c;需要登录。 https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 生成…

HMI(人机交互)应用的15大领域,欢迎补充。

HMI&#xff08;Human-Machine Interface&#xff0c;人机界面&#xff09;可以应用于许多不同的场景和行业&#xff0c;包括但不限于以下几个方面&#xff1a; 工业控制系统&#xff1a;HMI在工业生产中广泛应用&#xff0c;用于监控和控制生产过程。例如&#xff0c;工厂中的…

NewStarCTF_RE(week1,2)

[NewStarCTF 2023 公开赛道]easy_RE ida 可能会把 一个数组或字符串拆开&#xff0c;可以通过计算地址&#xff0c;知道是一起的 也有的会藏在汇编窗口 Segments IDA的Segments窗口 &#xff1a;shiftf7 https://www.cnblogs.com/sch01ar/p/9477697.html ida 各种窗口也是需要…

AMD平台,5600X+6650XT,虚拟机安装macOS 14(2024年6月)

AMD平台安装macOS 14的麻烦&#xff0c;要比Intel平台多的多&#xff0c;由于macOS从13开始&#xff0c;对CPU寄存器的读取进行了改变&#xff0c;导致AMD平台只要安装完macOS 13及以后版本&#xff0c;开机后就报五国语言错误&#xff0c;不断重启。改vmx文件&#xff0c;被证…

mongodb command

1. start and stop ./mongod --dbpath -dbpath /data/shard1/db --logpath -dbpath /data/shard1/db/logs/mongodb.log --fork mongod --shutdown --dbpath /data/shard1/db MongoDB基础篇-03-启动与关闭_mongodb启动和关闭-CSDN博客 2. 查看分片数据分布 mongo mongo01.c…

用React编写一个密码组件表单

theme: condensed-night-purple highlight: atelier-cave-light 背景介绍 我们在使用网站或者应用程序的登录界面或创建帐户界面时&#xff0c;往往避免不了需要用户输入密码这一步骤&#xff0c;而用户是否可以选择看见他们输入的密码是十分重要的一项功能。尤其是在当输入的…

Java面向对象-final关键字

Java面向对象-final关键字 一、final1、修饰变量2、修饰方法3、修饰类4、案例 一、final 可以修饰变量、方法、类 1、修饰变量 final修饰一个变量&#xff0c;变量的值不可以改变&#xff0c;这个变量就变成一个字符常量&#xff0c;约定俗称的规定&#xff1a;名字大写。 f…

【flink实战】flink-connector-mysql-cdc导致mysql连接器报类型转换错误

文章目录 一. 报错现象二. 方案二&#xff1a;重新编译打包flink-connector-cdc1. 排查脚本2. 重新编译打包flink-sql-connector-mysql-cdc-2.4.0.jar3. 测试flink环境 三. 方案一&#xff1a;改造flink连接器 一. 报错现象 flink sql任务是&#xff1a;mysql到hdfs的离线任务&…

IPTCP知识

1. IP&#xff1a; IP地址是一个32位的二进制数&#xff0c;通常被分割为4个“8位二进制数”IP地址分类&#xff1a;A类地址、B类地址、C类地址、D类地址、E类地址 A类地址分配给规模特别大的网络使用&#xff0c;B类地址分配给一般的中型网络&#xff0c;C类地址分配给小型网…

短URL服务设计

引言 在营销系统里&#xff0c;为了增加系统的活跃用户数&#xff0c;经常会有各种各样的营销活动。这类活动几乎都是为了充分利用存量用户的价值&#xff0c;促使他们分享产品或App以达到触达到更多用户的目的。又或者是出于营销目的&#xff0c;群发优惠券触达短信这种场景。…