一二三应用开发平台应用开发示例(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…

vscode连接ssh远程服务器

当使用Visual Studio Code (VSCode) 连接SSH远程服务器时&#xff0c;可以遵循以下步骤。这些步骤将帮助你设置并连接到远程服务器&#xff0c;包括免密登录的设置&#xff08;如果需要&#xff09;。 一、安装并配置Remote-SSH插件 下载并安装VSCode&#xff1a;确保你已经下…

flstudio怎么调中文

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

vue实现图片预览

在 Vue 中实现图片预览功能&#xff0c;通常涉及监听文件输入的变化&#xff0c;并在用户选择文件后&#xff0c;使用 FileReader API 来读取文件内容&#xff0c;然后显示这个内容作为图片的预览。以下是一个简单的 Vue 组件示例&#xff0c;它实现了图片预览功能&#xff1a;…

PostgreSQL 数据库选择指南

PostgreSQL 数据库选择指南 引言 PostgreSQL,作为一款开源的对象-关系型数据库管理系统,以其稳定性、功能丰富性和强大的扩展能力而闻名。在选择数据库时,PostgreSQL常常是企业和开发者的首选之一。本文将详细介绍PostgreSQL的特点,帮助您更好地理解为何选择PostgreSQL,…

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

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

编程C语言自学书:引领你深入编程世界的神秘之旅

编程C语言自学书&#xff1a;引领你深入编程世界的神秘之旅 在信息时代的浪潮中&#xff0c;编程技能已变得至关重要。而C语言&#xff0c;作为计算机编程的基石&#xff0c;其地位更是不可动摇。对于初学者来说&#xff0c;一本好的自学书籍是掌握C语言的关键。今天&#xff…

ant design vue table表格合并后每个单元格加点击事件并获取每个单元格的值

用 event.target.closest(.ant-table-row-cell-break-word).textContent 获取 {title: "ECP",dataIndex: "ecp",scopedSlots: { customRender: "ecp" },customRender(_, row) {return {child: row.ecp,attrs: {rowSpan: row.ecpRowSpan}}},custo…

Swift JSON

https://www.bilibili.com/read/cv32068675/ [ { "id": 32025753, "title": "【100天学习SwiftUI】第0天 如何成为一名iOS开发人员", "state": 0, "publish_time": 1708878554, "words": …

JavaWeb之初识Tomcat

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

对冲基金为什么叫做Hedge Fund?

中文版 对冲基金详细介绍 “对冲基金”名称的由来 “对冲基金”&#xff08;Hedge Fund&#xff09;这个名称源于最初采用的投资策略&#xff0c;即通过对冲&#xff08;hedging&#xff09;来减少风险。1949年&#xff0c;阿尔弗雷德温斯洛琼斯&#xff08;Alfred Winslow …

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

前言 缓存, 根据冯诺依曼计算机模型, 无非是为了更高效的交互, 使用内存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;用于展示到前端的实体类…

浔川画板v5.0——浔川python科技社

浔川画板v5.0 本代码由浔川python社、浔川python科技社联合创作 # -*- coding: utf-8 -*- import tkinter as tk import tkinter.messagebox import pickle import random# 窗口 window tk.Tk() window.title(欢迎进入python) window.geometry(450x200) # 画布放置图片 # canv…

iOS cell的复用以及自定义cell

自定义cell以及cell复用的内容 文章目录 自定义cell以及cell复用的内容前言cell的复用原理cell的复用的两种不同方式自定义cell的实现总结 前言 cell是我们开发中的一个重要的控件&#xff0c;下面来讲解一下这个内容 cell的复用原理 cell的复用是UITableView的最核心的内容…

Fiddler抓包工具介绍

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

速盾:高防服务器防御 DDoS 攻击的掩护技巧

在当今互联网环境下&#xff0c;DDoS 攻击已成为网络安全的一大威胁&#xff0c;而高防服务器则是对抗这种攻击的重要手段。速盾作为提供高防服务器服务的品牌&#xff0c;在防御 DDoS 攻击方面有着独特的技巧和策略。 首先&#xff0c;速盾高防服务器采用了智能流量分析技术。…