From eafab2a0c12583ce1afc9060e0054ee42b49b882 Mon Sep 17 00:00:00 2001 From: jay <75509151@qq.com> Date: Tue, 28 May 2024 17:30:30 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=99=A8=E6=A8=A1=E5=9D=97-=E5=90=8E=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iot-module/iot-generator/pom.xml | 119 +++++ .../cc/iotkit/generator/config/GenConfig.java | 73 +++ .../generator/config/MybatisPlusConfig.java | 102 ++++ .../generator/constant/GenConstants.java | 186 +++++++ .../generator/controller/GenController.java | 213 ++++++++ .../cc/iotkit/generator/core/BaseEntity.java | 70 +++ .../iotkit/generator/core/BaseMapperPlus.java | 198 +++++++ .../iotkit/generator/core/DataBaseHelper.java | 76 +++ .../iotkit/generator/core/DataBaseType.java | 51 ++ .../iotkit/generator/core/DbIdGenerator.java | 30 ++ .../cc/iotkit/generator/core/PageBuilder.java | 25 + .../cc/iotkit/generator/core/PageQuery.java | 113 ++++ .../cc/iotkit/generator/core/SqlUtil.java | 58 ++ .../cc/iotkit/generator/domain/GenTable.java | 196 +++++++ .../generator/domain/GenTableColumn.java | 222 ++++++++ .../generator/dto/bo/ImportTableBo.java | 24 + .../factory/YmlPropertySourceFactory.java | 32 ++ .../mapper/GenTableColumnMapper.java | 24 + .../generator/mapper/GenTableMapper.java | 63 +++ .../service/GenTableServiceImpl.java | 463 ++++++++++++++++ .../generator/service/IGenTableService.java | 134 +++++ .../cc/iotkit/generator/util/GenUtils.java | 233 ++++++++ .../generator/util/VelocityInitializer.java | 35 ++ .../iotkit/generator/util/VelocityUtils.java | 354 +++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../main/resources/application-generator.yml | 45 ++ .../src/main/resources/common-mybatis.yml | 33 ++ .../src/main/resources/generator.yml | 10 + .../mapper/generator/GenTableColumnMapper.xml | 105 ++++ .../mapper/generator/GenTableMapper.xml | 309 +++++++++++ .../src/main/resources/mapper/package-info.md | 3 + .../src/main/resources/vm/java/bo.java.vm | 52 ++ .../main/resources/vm/java/controller.java.vm | 113 ++++ .../src/main/resources/vm/java/idata.java.vm | 16 + .../main/resources/vm/java/idataimpl.java.vm | 135 +++++ .../src/main/resources/vm/java/mapper.java.vm | 15 + .../src/main/resources/vm/java/model.java.vm | 50 ++ .../main/resources/vm/java/repository.java.vm | 15 + .../main/resources/vm/java/service.java.vm | 53 ++ .../resources/vm/java/serviceImpl.java.vm | 109 ++++ .../main/resources/vm/java/tbmodel.java.vm | 71 +++ .../src/main/resources/vm/java/vo.java.vm | 61 +++ .../src/main/resources/vm/js/api.js.vm | 47 ++ .../src/main/resources/vm/sql/oracle/sql.vm | 19 + .../src/main/resources/vm/sql/postgres/sql.vm | 20 + .../src/main/resources/vm/sql/sql.vm | 19 + .../main/resources/vm/sql/sqlserver/sql.vm | 19 + .../src/main/resources/vm/ts/api.ts.vm | 48 ++ .../src/main/resources/vm/ts/types.ts.vm | 44 ++ .../main/resources/vm/vue/index-tree.vue.vm | 501 ++++++++++++++++++ .../src/main/resources/vm/vue/index.vue.vm | 467 ++++++++++++++++ .../src/main/resources/vm/xml/mapper.xml.vm | 7 + iot-module/pom.xml | 1 + .../src/main/resources/application.yml | 1 + .../src/main/resources/sql/schema-postgre.sql | 112 ++++ iot-starter/src/main/resources/sql/schema.sql | 60 +++ pom.xml | 20 + 57 files changed, 5675 insertions(+) create mode 100644 iot-module/iot-generator/pom.xml create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/GenConfig.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/MybatisPlusConfig.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/constant/GenConstants.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/controller/GenController.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseEntity.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseMapperPlus.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java create mode 100644 iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java create mode 100644 iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 iot-module/iot-generator/src/main/resources/application-generator.yml create mode 100644 iot-module/iot-generator/src/main/resources/common-mybatis.yml create mode 100644 iot-module/iot-generator/src/main/resources/generator.yml create mode 100644 iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml create mode 100644 iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml create mode 100644 iot-module/iot-generator/src/main/resources/mapper/package-info.md create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/model.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/service.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/js/api.js.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/sql/sql.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm create mode 100644 iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm create mode 100644 iot-starter/src/main/resources/sql/schema-postgre.sql create mode 100644 iot-starter/src/main/resources/sql/schema.sql diff --git a/iot-module/iot-generator/pom.xml b/iot-module/iot-generator/pom.xml new file mode 100644 index 00000000..8af739cd --- /dev/null +++ b/iot-module/iot-generator/pom.xml @@ -0,0 +1,119 @@ + + + + iot-module + cc.iotkit + 0.5.3 + + + 4.0.0 + + iot-generator + + + + generator 代码生成 + + + + 3.5.1 + 0.2.0 + 3.5.3.1 + + + + + + + + cc.iotkit + iot-common-core + + + + cc.iotkit + iot-common-doc + + + + + + cc.iotkit + iot-common-log + + + + + + + com.github.yitter + yitter-idgenerator + + + + + org.apache.velocity + velocity-engine-core + + + + + com.baomidou + dynamic-datasource-spring-boot-starter + ${dynamic-ds.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-annotation + ${mybatis-plus.version} + + + cc.iotkit + iot-common-web + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + utf8 + + + org.projectlombok + lombok + ${lombok.version} + + + io.github.linpeilie + mapstruct-plus-processor + ${mapstruct-plus.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + + + + + + + + diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/GenConfig.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/GenConfig.java new file mode 100644 index 00000000..e6c0103f --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/GenConfig.java @@ -0,0 +1,73 @@ +package cc.iotkit.generator.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * 读取代码生成相关配置 + * + * @author ruoyi + */ +@Component +@ConfigurationProperties(prefix = "gen") +@PropertySource(value = {"classpath:generator.yml"}, encoding = "UTF-8") +public class GenConfig { + + /** + * 作者 + */ + public static String author; + + /** + * 生成包路径 + */ + public static String packageName; + + /** + * 自动去除表前缀,默认是false + */ + public static boolean autoRemovePre; + + /** + * 表前缀(类名不会包含表前缀) + */ + public static String tablePrefix; + + public static String getAuthor() { + return author; + } + + @Value("${author}") + public void setAuthor(String author) { + GenConfig.author = author; + } + + public static String getPackageName() { + return packageName; + } + + @Value("${packageName}") + public void setPackageName(String packageName) { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() { + return autoRemovePre; + } + + @Value("${autoRemovePre}") + public void setAutoRemovePre(boolean autoRemovePre) { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() { + return tablePrefix; + } + + @Value("${tablePrefix}") + public void setTablePrefix(String tablePrefix) { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/MybatisPlusConfig.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/MybatisPlusConfig.java new file mode 100644 index 00000000..67e0bbe3 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/config/MybatisPlusConfig.java @@ -0,0 +1,102 @@ +package cc.iotkit.generator.config; + +import cc.iotkit.generator.core.DbIdGenerator; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * mybatis-plus配置类(下方注释有插件介绍) + * + * @author Lion Li + */ +@EnableTransactionManagement(proxyTargetClass = true) +@AutoConfiguration +//@MapperScan("${mybatis-plus.mapperPackage}") +@MapperScan("cc.iotkit.**.mapper") +//@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class) +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 数据权限处理 +// interceptor.addInnerInterceptor(dataPermissionInterceptor()); + // 分页插件 + interceptor.addInnerInterceptor(paginationInnerInterceptor()); + // 乐观锁插件 + interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); + return interceptor; + } + + /** + * 数据权限拦截器 + */ +// public PlusDataPermissionInterceptor dataPermissionInterceptor() { +// return new PlusDataPermissionInterceptor(); +// } + + /** + * 分页插件,自动识别数据库类型 + */ + public PaginationInnerInterceptor paginationInnerInterceptor() { + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + paginationInnerInterceptor.setMaxLimit(-1L); + // 分页合理化 + paginationInnerInterceptor.setOverflow(true); + return paginationInnerInterceptor; + } + + /** + * 乐观锁插件 + */ + public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { + return new OptimisticLockerInnerInterceptor(); + } + + /** + * 元对象字段填充控制器 + */ +// @Bean +// public MetaObjectHandler metaObjectHandler() { +// return new InjectionMetaObjectHandler(); +// } + + /** + * 使用网卡信息绑定雪花生成器 + * 防止集群雪花ID重复 + */ + @Bean + public IdentifierGenerator idGenerator() { +// String hostAddress = NetUtil.getLocalhost().getHostAddress(); + // TODO: 采用配置文件里的 + return new DbIdGenerator((short) 1); + } + + /** + * PaginationInnerInterceptor 分页插件,自动识别数据库类型 + * https://baomidou.com/pages/97710a/ + * OptimisticLockerInnerInterceptor 乐观锁插件 + * https://baomidou.com/pages/0d93c0/ + * MetaObjectHandler 元对象字段填充控制器 + * https://baomidou.com/pages/4c6bcf/ + * ISqlInjector sql注入器 + * https://baomidou.com/pages/42ea4a/ + * BlockAttackInnerInterceptor 如果是对全表的删除或更新操作,就会终止该操作 + * https://baomidou.com/pages/f9a237/ + * IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截) + * IdentifierGenerator 自定义主键策略 + * https://baomidou.com/pages/568eb2/ + * TenantLineInnerInterceptor 多租户插件 + * https://baomidou.com/pages/aef2f2/ + * DynamicTableNameInnerInterceptor 动态表名插件 + * https://baomidou.com/pages/2a45ff/ + */ + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/constant/GenConstants.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/constant/GenConstants.java new file mode 100644 index 00000000..7457336c --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/constant/GenConstants.java @@ -0,0 +1,186 @@ +package cc.iotkit.generator.constant; + +/** + * 代码生成通用常量 + * + * @author ruoyi + */ +public interface GenConstants { + /** + * 单表(增删改查) + */ + String TPL_CRUD = "crud"; + + /** + * 树表(增删改查) + */ + String TPL_TREE = "tree"; + + /** + * 树编码字段 + */ + String TREE_CODE = "treeCode"; + + /** + * 树父编码字段 + */ + String TREE_PARENT_CODE = "treeParentCode"; + + /** + * 树名称字段 + */ + String TREE_NAME = "treeName"; + + /** + * 上级菜单ID字段 + */ + String PARENT_MENU_ID = "parentMenuId"; + + /** + * 上级菜单名称字段 + */ + String PARENT_MENU_NAME = "parentMenuName"; + + /** + * 数据库字符串类型 + */ + String[] COLUMNTYPE_STR = {"char", "varchar", "enum", "set", "nchar", "nvarchar", "varchar2", "nvarchar2"}; + + /** + * 数据库文本类型 + */ + String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext", "binary", "varbinary", "blob", + "ntext", "image", "bytea"}; + + /** + * 数据库时间类型 + */ + String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval", + "smalldatetime", "datetime2", "datetimeoffset"}; + + /** + * 数据库数字类型 + */ + String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", + "bit", "bigint", "float", "double", "decimal", "numeric", "real", "double precision", + "smallserial", "serial", "bigserial", "money", "smallmoney"}; + + /** + * BO对象 不需要添加字段 + */ + String[] COLUMNNAME_NOT_ADD = {"create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "version", "tenant_id"}; + + /** + * BO对象 不需要编辑字段 + */ + String[] COLUMNNAME_NOT_EDIT = {"create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "version", "tenant_id"}; + + /** + * VO对象 不需要返回字段 + */ + String[] COLUMNNAME_NOT_LIST = {"create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "version", "tenant_id"}; + + /** + * BO对象 不需要查询字段 + */ + String[] COLUMNNAME_NOT_QUERY = {"id", "create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark", "version", "tenant_id"}; + + /** + * Entity基类字段 + */ + String[] BASE_ENTITY = {"createDept", "createBy", "createTime", "updateBy", "updateTime", "tenantId"}; + + /** + * 文本框 + */ + String HTML_INPUT = "input"; + + /** + * 文本域 + */ + String HTML_TEXTAREA = "textarea"; + + /** + * 下拉框 + */ + String HTML_SELECT = "select"; + + /** + * 单选框 + */ + String HTML_RADIO = "radio"; + + /** + * 复选框 + */ + String HTML_CHECKBOX = "checkbox"; + + /** + * 日期控件 + */ + String HTML_DATETIME = "datetime"; + + /** + * 图片上传控件 + */ + String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** + * 文件上传控件 + */ + String HTML_FILE_UPLOAD = "fileUpload"; + + /** + * 富文本控件 + */ + String HTML_EDITOR = "editor"; + + /** + * 字符串类型 + */ + String TYPE_STRING = "String"; + + /** + * 整型 + */ + String TYPE_INTEGER = "Integer"; + + /** + * 长整型 + */ + String TYPE_LONG = "Long"; + + /** + * 浮点型 + */ + String TYPE_DOUBLE = "Double"; + + /** + * 高精度计算类型 + */ + String TYPE_BIGDECIMAL = "BigDecimal"; + + /** + * 时间类型 + */ + String TYPE_DATE = "Date"; + + /** + * 模糊查询 + */ + String QUERY_LIKE = "LIKE"; + + /** + * 相等查询 + */ + String QUERY_EQ = "EQ"; + + /** + * 需要 + */ + String REQUIRE = "1"; +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/controller/GenController.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/controller/GenController.java new file mode 100644 index 00000000..4ac50bff --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/controller/GenController.java @@ -0,0 +1,213 @@ +package cc.iotkit.generator.controller; + +import cc.iotkit.common.api.PageRequest; +import cc.iotkit.common.api.Paging; +import cc.iotkit.common.api.Request; +import cc.iotkit.common.log.annotation.Log; +import cc.iotkit.common.log.enums.BusinessType; +import cc.iotkit.common.web.core.BaseController; +import cc.iotkit.generator.domain.GenTable; +import cc.iotkit.generator.domain.GenTableColumn; +import cc.iotkit.generator.dto.bo.ImportTableBo; +import cc.iotkit.generator.service.IGenTableService; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 代码生成 操作处理 + * + * @author Lion Li + */ +@Validated +@RestController +@RequiredArgsConstructor + +@RequestMapping("/tool/gen") +public class GenController extends BaseController { + + private final IGenTableService genTableService; + + /** + * 查询代码生成列表 + */ +// @SaCheckPermission("tool:gen:list") + @ApiOperation(value = "查询代码生成列表", notes = "查询代码生成列表,根据查询条件分页") + @PostMapping("/list") + public Paging genList(@RequestBody @Validated PageRequest query) { + return genTableService.selectPageGenTableList(query ); + } + + /** + * 修改代码生成业务 + * + */ +// @SaCheckPermission("tool:gen:query") + @ApiOperation(value = "修改代码生成业务", notes = "修改代码生成业务详情") + @PostMapping(value = "/getDetail") + public Map getInfo(@Validated @RequestBody Request bo) { + Long tableId = bo.getData(); + GenTable table = genTableService.selectGenTableById(tableId); + List tables = genTableService.selectGenTableAll(); + List list = genTableService.selectGenTableColumnListByTableId(tableId); + Map map = new HashMap<>(); + map.put("info", table); + map.put("rows", list); + map.put("tables", tables); + return map; + } + + /** + * 查询数据库列表 + */ +// @SaCheckPermission("tool:gen:list") + @ApiOperation(value = "查询数据库列表", notes = "查询数据库列表") + @PostMapping("/db/list") + public Paging dataList(@RequestBody @Validated PageRequest pageQuery) { + return genTableService.selectPageDbTableList( pageQuery); + } + + /** + * 查询数据表字段列表 + * + * @param tableId 表ID + */ +// @SaCheckPermission("tool:gen:list") + @ApiOperation(value = "查询数据表字段列表", notes = "查询数据表字段列表") + @PostMapping(value = "/column/{tableId}") + public Paging columnList(Long tableId) { + + List list = genTableService.selectGenTableColumnListByTableId(tableId); + + return new Paging<>(); + } + + /** + * 导入表结构(保存) + * + */ +// @SaCheckPermission("tool:gen:import") + @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + @ApiOperation(value = "导入表结构(保存)", notes = "导入表结构(保存)") + public void importTableSave(@Validated @RequestBody Request bo) { + List tables = bo.getData().getTables(); + + // 查询表信息 + List tableList = genTableService.selectDbTableListByNames(tables); + genTableService.importGenTable(tableList); + } + + /** + * 修改保存代码生成业务 + */ +// @SaCheckPermission("tool:gen:edit") + @ApiOperation(value = "修改保存代码生成业务", notes = "修改保存代码生成业务") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + public void editSave(@Validated @RequestBody Request bo) { + GenTable genTable = bo.getData(); + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + } + + /** + * 删除代码生成 + * + + */ +// @SaCheckPermission("tool:gen:remove") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @PostMapping("/delete") + @ApiOperation(value = "删除代码生成", notes = "删除代码生成") + public void remove(@Validated @RequestBody Request> bo) { + genTableService.deleteGenTableByIds(bo.getData()); + } + + /** + * 预览代码 + * + */ +// @SaCheckPermission("tool:gen:preview") + @ApiOperation(value = "预览代码", notes = "预览代码") + @PostMapping("/preview") + public Map preview(@Validated @RequestBody Request bo) throws IOException { + Map dataMap = genTableService.previewCode(bo.getData()); + return dataMap; + } + + /** + * 生成代码(下载方式) + * + * @param tableName 表名 + */ +// @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @PostMapping("/download/{tableName}") + public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException { + byte[] data = genTableService.downloadCode(tableName); + genCode(response, data); + } + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名 + */ +// @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @ApiOperation(value = "生成代码(自定义路径)", notes = "生成代码(自定义路径)") + @PostMapping("/genCode/{tableName}") + public void genCode(@PathVariable("tableName") String tableName) { + genTableService.generatorCode(tableName); + } + + /** + * 同步数据库 + * + */ +// @SaCheckPermission("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @ApiOperation(value = "同步数据库", notes = "同步数据库") + @PostMapping("/synchDb") + public void synchDb(@Validated @RequestBody Request bo) { + genTableService.synchDb(bo.getData()); + } + + /** + * 批量生成代码 + * + * @param tables 表名串 + */ +// @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @ApiOperation(value = "批量生成代码", notes = "批量生成代码") + @PostMapping("/batchGenCode") + public void batchGenCode(HttpServletResponse response, String tables) throws IOException { + String[] tableNames = Convert.toStrArray(tables); + byte[] data = genTableService.downloadCode(tableNames); + genCode(response, data); + } + + /** + * 生成zip文件 + */ + private void genCode(HttpServletResponse response, byte[] data) throws IOException { + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\""); + response.addHeader("Content-Length", "" + data.length); + response.setContentType("application/octet-stream; charset=UTF-8"); + IoUtil.write(response.getOutputStream(), false, data); + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseEntity.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseEntity.java new file mode 100644 index 00000000..8e2109c0 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseEntity.java @@ -0,0 +1,70 @@ +package cc.iotkit.generator.core; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Entity基类 + * + * @author Lion Li + */ + +@Data +public class BaseEntity implements Serializable { + + + private static final long serialVersionUID = 1L; + + /** + * 搜索值 + */ + @JsonIgnore + @TableField(exist = false) + private String searchValue; + + /** + * 创建部门 + */ + @TableField(fill = FieldFill.INSERT) + private Long createDept; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @TableField(exist = false) + private Map params = new HashMap<>(); + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseMapperPlus.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseMapperPlus.java new file mode 100644 index 00000000..378813e7 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/BaseMapperPlus.java @@ -0,0 +1,198 @@ +package cc.iotkit.generator.core; + +import cc.iotkit.common.utils.MapstructUtils; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.ReflectionKit; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.toolkit.Db; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param table 泛型 + * @param vo 泛型 + * @author Lion Li + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperPlus extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperPlus.class); + + default Class currentVoClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1); + } + + default Class currentModelClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0); + } + + default List selectList() { + return this.selectList(new QueryWrapper<>()); + } + + /** + * 批量插入 + */ + default boolean insertBatch(Collection entityList) { + return Db.saveBatch(entityList); + } + + /** + * 批量更新 + */ + default boolean updateBatchById(Collection entityList) { + return Db.updateBatchById(entityList); + } + + /** + * 批量插入或更新 + */ + default boolean insertOrUpdateBatch(Collection entityList) { + return Db.saveOrUpdateBatch(entityList); + } + + /** + * 批量插入(包含限制条数) + */ + default boolean insertBatch(Collection entityList, int batchSize) { + return Db.saveBatch(entityList, batchSize); + } + + /** + * 批量更新(包含限制条数) + */ + default boolean updateBatchById(Collection entityList, int batchSize) { + return Db.updateBatchById(entityList, batchSize); + } + + /** + * 批量插入或更新(包含限制条数) + */ + default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { + return Db.saveOrUpdateBatch(entityList, batchSize); + } + + /** + * 插入或更新(包含限制条数) + */ + default boolean insertOrUpdate(T entity) { + return Db.saveOrUpdate(entity); + } + + default V selectVoById(Serializable id) { + return selectVoById(id, this.currentVoClass()); + } + + /** + * 根据 ID 查询 + */ + default C selectVoById(Serializable id, Class voClass) { + T obj = this.selectById(id); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + default List selectVoBatchIds(Collection idList) { + return selectVoBatchIds(idList, this.currentVoClass()); + } + + /** + * 查询(根据ID 批量查询) + */ + default List selectVoBatchIds(Collection idList, Class voClass) { + List list = this.selectBatchIds(idList); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + default List selectVoByMap(Map map) { + return selectVoByMap(map, this.currentVoClass()); + } + + /** + * 查询(根据 columnMap 条件) + */ + default List selectVoByMap(Map map, Class voClass) { + List list = this.selectByMap(map); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + default V selectVoOne(Wrapper wrapper) { + return selectVoOne(wrapper, this.currentVoClass()); + } + + /** + * 根据 entity 条件,查询一条记录 + */ + default C selectVoOne(Wrapper wrapper, Class voClass) { + T obj = this.selectOne(wrapper); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + default List selectVoList() { + return selectVoList(new QueryWrapper<>(), this.currentVoClass()); + } + + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + /** + * 根据 entity 条件,查询全部记录 + */ + default List selectVoList(Wrapper wrapper, Class voClass) { + List list = this.selectList(wrapper); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + /** + * 分页查询VO + */ + default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { + IPage pageData = this.selectPage(page, wrapper); + IPage voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()); + if (CollUtil.isEmpty(pageData.getRecords())) { + return (P) voPage; + } + voPage.setRecords(MapstructUtils.convert(pageData.getRecords(), voClass)); + return (P) voPage; + } + + default List selectObjs(Wrapper wrapper, Function mapper) { + return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList()); + } + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java new file mode 100644 index 00000000..22243391 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java @@ -0,0 +1,76 @@ +package cc.iotkit.generator.core; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.SpringUtils; +import cn.hutool.core.convert.Convert; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +/** + * 数据库助手 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DataBaseHelper { + + private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + + /** + * 获取当前数据库类型 + */ + public static DataBaseType getDataBaseType() { + DataSource dataSource = DS.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return DataBaseType.find(databaseProductName); + } catch (SQLException e) { + throw new BizException(e.getMessage()); + } + } + + public static boolean isMySql() { + return DataBaseType.MY_SQL == getDataBaseType(); + } + + public static boolean isH2() { + return DataBaseType.H2 == getDataBaseType(); + } + + + public static boolean isOracle() { + return DataBaseType.ORACLE == getDataBaseType(); + } + + public static boolean isPostgerSql() { + return DataBaseType.POSTGRE_SQL == getDataBaseType(); + } + + public static boolean isSqlServer() { + return DataBaseType.SQL_SERVER == getDataBaseType(); + } + + public static String findInSet(Object var1, String var2) { + DataBaseType dataBasyType = getDataBaseType(); + String var = Convert.toStr(var1); + if (dataBasyType == DataBaseType.SQL_SERVER) { + // charindex(',100,' , ',0,100,101,') <> 0 + return String.format("charindex(',%s,' , ','+%s+',') <> 0",var, var2 ); + } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { + // (select position(',100,' in ',0,100,101,')) <> 0 + return String.format("(select position(',%s,' in ','||%s||',')) <> 0", var, var2); + } else if (dataBasyType == DataBaseType.ORACLE) { + // instr(',0,100,101,' , ',100,') <> 0 + return String.format("instr(','||%s||',' , ',%s,') <> 0",var2, var ); + } + // find_in_set(100 , '0,100,101') + return String.format("find_in_set('%s' , %s) <> 0", var, var2); + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java new file mode 100644 index 00000000..06168643 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java @@ -0,0 +1,51 @@ +package cc.iotkit.generator.core; + +import cc.iotkit.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + + +/** + * 数据库类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DataBaseType { + + /** + * MySQL + */ + MY_SQL("MySQL"), + + H2("H2"), + /** + * Oracle + */ + ORACLE("Oracle"), + + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL"), + + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server"); + + private final String type; + + public static DataBaseType find(String databaseProductName) { + if (StringUtils.isBlank(databaseProductName)) { + return null; + } + for (DataBaseType type : values()) { + if (type.getType().equals(databaseProductName)) { + return type; + } + } + return null; + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java new file mode 100644 index 00000000..f1c748e8 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java @@ -0,0 +1,30 @@ +package cc.iotkit.generator.core; + +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.github.yitter.contract.IdGeneratorOptions; +import com.github.yitter.idgen.YitIdHelper; + +/** + * @author: Jay + * @description: + * @date:created in 2023/5/18 10:20 + * @modificed by: + */ +public class DbIdGenerator implements IdentifierGenerator { + + + public DbIdGenerator(Short workerId) { +// 使用网卡信息绑定雪花生成器 +// 防止集群雪花ID重复 + + IdGeneratorOptions options = new IdGeneratorOptions(workerId); + YitIdHelper.setIdGenerator(options); + } + + + + @Override + public Number nextId(Object entity) { + return YitIdHelper.nextId(); + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java new file mode 100644 index 00000000..0d5d7510 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java @@ -0,0 +1,25 @@ +package cc.iotkit.generator.core; + +import cc.iotkit.common.api.PageRequest; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.io.Serializable; + +/** + * 分页查询实体类 + * + * @author Lion Li + */ + + +public class PageBuilder implements Serializable { + + + public static Page build(PageRequest pageRequest) { + Integer pageNum = ObjectUtil.defaultIfNull(pageRequest.getPageNum(), PageQuery.DEFAULT_PAGE_NUM); + Integer pageSize = ObjectUtil.defaultIfNull(pageRequest.getPageSize(), PageQuery.DEFAULT_PAGE_SIZE); + return new Page(pageNum, pageSize); + } + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java new file mode 100644 index 00000000..efab0216 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java @@ -0,0 +1,113 @@ +package cc.iotkit.generator.core; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.StringUtils; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 分页查询实体类 + * + * @author Lion Li + */ + +@Data +public class PageQuery implements Serializable { + + + private static final long serialVersionUID = 1L; + + /** + * 分页大小 + */ + private Integer pageSize; + + /** + * 当前页数 + */ + private Integer pageNum; + + /** + * 排序列 + */ + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + private String isAsc; + + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + + /** + * 每页显示记录数 默认值 默认查全部 + */ + public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + + public Page build() { + Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); + Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + Page page = new Page<>(pageNum, pageSize); + List orderItems = buildOrderItem(); + if (CollUtil.isNotEmpty(orderItems)) { + page.addOrder(orderItems); + } + return page; + } + + /** + * 构建排序 + * + * 支持的用法如下: + * {isAsc:"asc",orderByColumn:"id"} order by id asc + * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc + * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc + * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc + */ + private List buildOrderItem() { + if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { + return Collections.emptyList(); + } + String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); + orderBy = StringUtils.toUnderScoreCase(orderBy); + + // 兼容前端排序类型 + isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); + + String[] orderByArr = orderBy.split(StringUtils.SEPARATOR); + String[] isAscArr = isAsc.split(StringUtils.SEPARATOR); + if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { + throw new BizException("排序参数有误"); + } + + List list = new ArrayList<>(); + // 每个字段各自排序 + for (int i = 0; i < orderByArr.length; i++) { + String orderByStr = orderByArr[i]; + String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; + if ("asc".equals(isAscStr)) { + list.add(OrderItem.asc(orderByStr)); + } else if ("desc".equals(isAscStr)) { + list.add(OrderItem.desc(orderByStr)); + } else { + throw new BizException("排序参数有误"); + } + } + return list; + } + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java new file mode 100644 index 00000000..c4fb2979 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java @@ -0,0 +1,58 @@ +package cc.iotkit.generator.core; + +import cc.iotkit.common.utils.StringUtils; +import cn.hutool.core.exceptions.UtilException; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + + +/** + * sql操作工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SqlUtil { + + /** + * 定义常用的 sql关键字 + */ + public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare "; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new UtilException("参数不符合规范,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new UtilException("参数存在SQL注入风险"); + } + } + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java new file mode 100644 index 00000000..16c1a903 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java @@ -0,0 +1,196 @@ +package cc.iotkit.generator.domain; + +import cc.iotkit.common.utils.StringUtils; +import cc.iotkit.generator.constant.GenConstants; +import cc.iotkit.generator.core.BaseEntity; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 业务表 gen_table + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gen_table") +public class GenTable extends BaseEntity { + + /** + * 编号 + */ + @TableId(value = "table_id") + private Long tableId; + + /** + * 数据源名称 + */ + @NotBlank(message = "数据源名称不能为空") + private String dataName; + + /** + * 表名称 + */ + @NotBlank(message = "表名称不能为空") + private String tableName; + + /** + * 表描述 + */ + @NotBlank(message = "表描述不能为空") + private String tableComment; + + /** + * 关联父表的表名 + */ + private String subTableName; + + /** + * 本表关联父表的外键名 + */ + private String subTableFkName; + + /** + * 实体类名称(首字母大写) + */ + @NotBlank(message = "实体类名称不能为空") + private String className; + + /** + * 使用的模板(crud单表操作 tree树表操作 sub主子表操作) + */ + private String tplCategory; + + /** + * 生成包路径 + */ + @NotBlank(message = "生成包路径不能为空") + private String packageName; + + /** + * 生成模块名 + */ + @NotBlank(message = "生成模块名不能为空") + private String moduleName; + + /** + * 生成业务名 + */ + @NotBlank(message = "生成业务名不能为空") + private String businessName; + + /** + * 生成功能名 + */ + @NotBlank(message = "生成功能名不能为空") + private String functionName; + + /** + * 生成作者 + */ + @NotBlank(message = "作者不能为空") + private String functionAuthor; + + /** + * 生成代码方式(0zip压缩包 1自定义路径) + */ + private String genType; + + /** + * 生成路径(不填默认项目路径) + */ + @TableField(updateStrategy = FieldStrategy.NOT_EMPTY) + private String genPath; + + /** + * 主键信息 + */ + @TableField(exist = false) + private GenTableColumn pkColumn; + + /** + * 表列信息 + */ + @Valid + @TableField(exist = false) + private List columns; + + /** + * 其它生成选项 + */ + private String options; + + /** + * 备注 + */ + private String remark; + + /** + * 树编码字段 + */ + @TableField(exist = false) + private String treeCode; + + /** + * 树父编码字段 + */ + @TableField(exist = false) + private String treeParentCode; + + /** + * 树名称字段 + */ + @TableField(exist = false) + private String treeName; + + /* + * 菜单id列表 + */ + @TableField(exist = false) + private List menuIds; + + /** + * 上级菜单ID字段 + */ + @TableField(exist = false) + private String parentMenuId; + + /** + * 上级菜单名称字段 + */ + @TableField(exist = false) + private String parentMenuName; + + public boolean isTree() { + return isTree(this.tplCategory); + } + + public static boolean isTree(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); + } + + public boolean isCrud() { + return isCrud(this.tplCategory); + } + + public static boolean isCrud(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); + } + + public boolean isSuperColumn(String javaField) { + return isSuperColumn(this.tplCategory, javaField); + } + + public static boolean isSuperColumn(String tplCategory, String javaField) { + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java new file mode 100644 index 00000000..6535f28f --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java @@ -0,0 +1,222 @@ +package cc.iotkit.generator.domain; + +import cc.iotkit.common.utils.StringUtils; +import cc.iotkit.generator.core.BaseEntity; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.ibatis.type.JdbcType; + +/** + * 代码生成业务字段表 gen_table_column + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gen_table_column") +public class GenTableColumn extends BaseEntity { + + /** + * 编号 + */ + @TableId(value = "column_id") + private Long columnId; + + /** + * 归属表编号 + */ + private Long tableId; + + /** + * 列名称 + */ + private String columnName; + + /** + * 列描述 + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String columnComment; + + /** + * 列类型 + */ + private String columnType; + + /** + * JAVA类型 + */ + private String javaType; + + /** + * JAVA字段名 + */ + @NotBlank(message = "Java属性不能为空") + private String javaField; + + /** + * 是否主键(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isPk; + + /** + * 是否自增(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isIncrement; + + /** + * 是否必填(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isRequired; + + /** + * 是否为插入字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isInsert; + + /** + * 是否编辑字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isEdit; + + /** + * 是否列表字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isList; + + /** + * 是否查询字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + private String isQuery; + + /** + * 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) + */ + private String queryType; + + /** + * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) + */ + private String htmlType; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 排序 + */ + private Integer sort; + + public String getCapJavaField() { + return StringUtils.capitalize(javaField); + } + + public boolean isPk() { + return isPk(this.isPk); + } + + public boolean isPk(String isPk) { + return isPk != null && StringUtils.equals("1", isPk); + } + + public boolean isIncrement() { + return isIncrement(this.isIncrement); + } + + public boolean isIncrement(String isIncrement) { + return isIncrement != null && StringUtils.equals("1", isIncrement); + } + + public boolean isRequired() { + return isRequired(this.isRequired); + } + + public boolean isRequired(String isRequired) { + return isRequired != null && StringUtils.equals("1", isRequired); + } + + public boolean isInsert() { + return isInsert(this.isInsert); + } + + public boolean isInsert(String isInsert) { + return isInsert != null && StringUtils.equals("1", isInsert); + } + + public boolean isEdit() { + return isInsert(this.isEdit); + } + + public boolean isEdit(String isEdit) { + return isEdit != null && StringUtils.equals("1", isEdit); + } + + public boolean isList() { + return isList(this.isList); + } + + public boolean isList(String isList) { + return isList != null && StringUtils.equals("1", isList); + } + + public boolean isQuery() { + return isQuery(this.isQuery); + } + + public boolean isQuery(String isQuery) { + return isQuery != null && StringUtils.equals("1", isQuery); + } + + public boolean isSuperColumn() { + return isSuperColumn(this.javaField); + } + + public static boolean isSuperColumn(String javaField) { + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", + // TreeEntity + "parentName", "parentId"); + } + + public boolean isUsableColumn() { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); + } + + public String readConverterExp() { + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotEmpty(remarks)) { + for (String value : remarks.split(" ")) { + if (StringUtils.isNotEmpty(value)) { + Object startStr = value.subSequence(0, 1); + String endStr = value.substring(1); + sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR); + } + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } else { + return this.columnComment; + } + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java new file mode 100644 index 00000000..19544e38 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java @@ -0,0 +1,24 @@ +package cc.iotkit.generator.dto.bo; + +import cc.iotkit.common.api.BaseDto; +import io.swagger.annotations.ApiModelProperty; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import java.util.List; + +/** + * @Author: jay + * @Date: 2023/6/24 16:47 + * @Version: V1.0 + * @Description: 导入表Bo + */ +@Data +public class ImportTableBo extends BaseDto { + + @ApiModelProperty(value = "表名列表", notes = "表名列表") + @NotEmpty(message = "表名列表不能为空") + private List tables; + + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java new file mode 100644 index 00000000..cd5933b8 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java @@ -0,0 +1,32 @@ +package cc.iotkit.generator.factory; + + +import cc.iotkit.common.utils.StringUtils; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.DefaultPropertySourceFactory; +import org.springframework.core.io.support.EncodedResource; + +import java.io.IOException; + +/** + * yml 配置源工厂 + * + * @author Lion Li + */ +public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + String sourceName = resource.getResource().getFilename(); + if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resource.getResource()); + factory.afterPropertiesSet(); + return new PropertiesPropertySource(sourceName, factory.getObject()); + } + return super.createPropertySource(name, resource); + } + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java new file mode 100644 index 00000000..ad5a4a53 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java @@ -0,0 +1,24 @@ +package cc.iotkit.generator.mapper; + +import cc.iotkit.generator.core.BaseMapperPlus; +import cc.iotkit.generator.domain.GenTableColumn; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; + +import java.util.List; + +/** + * 业务字段 数据层 + * + * @author Lion Li + */ +@InterceptorIgnore(dataPermission = "true", tenantLine = "true") +public interface GenTableColumnMapper extends BaseMapperPlus { + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + List selectDbTableColumnsByName(String tableName); + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java new file mode 100644 index 00000000..42f8f9bd --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java @@ -0,0 +1,63 @@ +package cc.iotkit.generator.mapper; + +import cc.iotkit.generator.core.BaseMapperPlus; +import cc.iotkit.generator.domain.GenTable; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; +import java.util.List; + +/** + * 业务 数据层 + * + * @author Lion Li + */ +@InterceptorIgnore( tenantLine = "true") +public interface GenTableMapper extends BaseMapperPlus { + + /** + * 查询据库列表 + * + * @param genTable 查询条件 + * @return 数据库表集合 + */ + @InterceptorIgnore( tenantLine = "true") + Page selectPageDbTableList(@Param("page") Page page, @Param("genTable") GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + List selectDbTableListByNames(Collection tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + List selectGenTableAll(); + + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + GenTable selectGenTableById(Long id); + + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + GenTable selectGenTableByName(String tableName); + + List selectTableNameList(String dataName); + + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java new file mode 100644 index 00000000..7887ca3e --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java @@ -0,0 +1,463 @@ +package cc.iotkit.generator.service; + +import cc.iotkit.common.api.PageRequest; +import cc.iotkit.common.api.Paging; +import cc.iotkit.common.constant.Constants; +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.satoken.utils.LoginHelper; +import cc.iotkit.common.utils.JsonUtils; +import cc.iotkit.common.utils.StreamUtils; +import cc.iotkit.common.utils.StringUtils; +import cc.iotkit.common.utils.file.FileUtils; +import cc.iotkit.generator.constant.GenConstants; +import cc.iotkit.generator.core.DbIdGenerator; +import cc.iotkit.generator.core.PageBuilder; +import cc.iotkit.generator.domain.GenTable; +import cc.iotkit.generator.domain.GenTableColumn; +import cc.iotkit.generator.mapper.GenTableColumnMapper; +import cc.iotkit.generator.mapper.GenTableMapper; +import cc.iotkit.generator.util.GenUtils; +import cc.iotkit.generator.util.VelocityInitializer; +import cc.iotkit.generator.util.VelocityUtils; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 业务 服务层实现 + * + * @author Lion Li + */ +@DS("#header.datasource") +@Slf4j +@RequiredArgsConstructor +@Service +public class GenTableServiceImpl implements IGenTableService { + + private final GenTableMapper baseMapper; + private final GenTableColumnMapper genTableColumnMapper; + private final DbIdGenerator identifierGenerator; + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + @Override + public List selectGenTableColumnListByTableId(Long tableId) { + return genTableColumnMapper.selectList(new LambdaQueryWrapper() + .eq(GenTableColumn::getTableId, tableId) + .orderByAsc(GenTableColumn::getSort)); + } + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + @Override + public GenTable selectGenTableById(Long id) { + GenTable genTable = baseMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + @Override + public Paging selectPageGenTableList( PageRequest pageQuery) { + Page page = baseMapper.selectPage(PageBuilder.build(pageQuery), this.buildGenTableQueryWrapper(pageQuery.getData())); + return new Paging<>(page.getTotal(), page.getRecords()); + } + + private QueryWrapper buildGenTableQueryWrapper(GenTable genTable) { + Map params = genTable.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName())) + .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment())) + .between(StringUtils.isNotBlank((CharSequence) params.get("beginTime")) && StringUtils.isNotBlank((CharSequence) params.get("endTime")), + "create_time", params.get("beginTime"), params.get("endTime")); + return wrapper; + } + + + @Override + public Paging selectPageDbTableList(PageRequest pageQuery) { + GenTable genTable = pageQuery.getData(); + genTable.getParams().put("genTableNames",baseMapper.selectTableNameList(genTable.getDataName())); + + Page page = baseMapper.selectPageDbTableList(PageBuilder.build(pageQuery), genTable); + return new Paging<>(page.getTotal(), page.getRecords()); + } + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + @Override + public List selectDbTableListByNames(Collection tableNames) { + return baseMapper.selectDbTableListByNames(tableNames); + } + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() { + return baseMapper.selectGenTableAll(); + } + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void updateGenTable(GenTable genTable) { + String options = JsonUtils.toJsonString(genTable.getParams()); + genTable.setOptions(options); + int row = baseMapper.updateById(genTable); + if (row > 0) { + for (GenTableColumn cenTableColumn : genTable.getColumns()) { + genTableColumnMapper.updateById(cenTableColumn); + } + } + } + + /** + * 删除业务对象 + * + * @param tableIds 需要删除的数据ID + * @return 结果 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void deleteGenTableByIds(Collection tableIds) { + + baseMapper.deleteBatchIds(tableIds); + genTableColumnMapper.delete(new LambdaQueryWrapper().in(GenTableColumn::getTableId, tableIds)); + } + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void importGenTable(List tableList) { + String operName = LoginHelper.getUsername(); + try { + for (GenTable table : tableList) { + String tableName = table.getTableName(); + GenUtils.initTable(table, operName); + int row = baseMapper.insert(table); + if (row > 0) { + // 保存列信息 + List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + List saveColumns = new ArrayList<>(); + for (GenTableColumn column : genTableColumns) { + GenUtils.initColumnField(column, table); + saveColumns.add(column); + } + if (CollUtil.isNotEmpty(saveColumns)) { + genTableColumnMapper.insertBatch(saveColumns); + } + } + } + } catch (Exception e) { + throw new BizException("导入失败:" + e.getMessage()); + } + } + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + @Override + public Map previewCode(Long tableId) { + Map dataMap = new LinkedHashMap<>(); + // 查询表信息 + GenTable table = baseMapper.selectGenTableById(tableId); + List menuIds = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + menuIds.add((Long) identifierGenerator.nextId(null)); + } + table.setMenuIds(menuIds); + // 设置主键列信息 + setPkColumn(table); + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + dataMap.put(template, sw.toString()); + } + return dataMap; + } + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + @Override + public byte[] downloadCode(String tableName) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + generatorCode(tableName, zip); + IoUtil.close(zip); + return outputStream.toByteArray(); + } + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + @Override + public void generatorCode(String tableName) { + // 查询表信息 + GenTable table = baseMapper.selectGenTableByName(tableName); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + String path = getGenPath(table, template); + FileUtils.writeUtf8String(sw.toString(), path); + } catch (Exception e) { + throw new BizException("渲染模板失败,表名:" + table.getTableName()); + } + } + } + } + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void synchDb(String tableName) { + GenTable table = baseMapper.selectGenTableByName(tableName); + List tableColumns = table.getColumns(); + Map tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName); + + List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + if (CollUtil.isEmpty(dbTableColumns)) { + throw new BizException("同步数据失败,原表结构不存在"); + } + List dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName); + + List saveColumns = new ArrayList<>(); + dbTableColumns.forEach(column -> { + GenUtils.initColumnField(column, table); + if (tableColumnMap.containsKey(column.getColumnName())) { + GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName()); + column.setColumnId(prevColumn.getColumnId()); + if (column.isList()) { + // 如果是列表,继续保留查询方式/字典类型选项 + column.setDictType(prevColumn.getDictType()); + column.setQueryType(prevColumn.getQueryType()); + } + if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() + && (column.isInsert() || column.isEdit()) + && ((column.isUsableColumn()) || (!column.isSuperColumn()))) { + // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项 + column.setIsRequired(prevColumn.getIsRequired()); + column.setHtmlType(prevColumn.getHtmlType()); + } + } + saveColumns.add(column); + }); + if (CollUtil.isNotEmpty(saveColumns)) { + genTableColumnMapper.insertOrUpdateBatch(saveColumns); + } + List delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName())); + if (CollUtil.isNotEmpty(delColumns)) { + List ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId); + genTableColumnMapper.deleteBatchIds(ids); + } + } + + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + @Override + public byte[] downloadCode(String[] tableNames) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + for (String tableName : tableNames) { + generatorCode(tableName, zip); + } + IoUtil.close(zip); + return outputStream.toByteArray(); + } + + /** + * 查询表信息并生成代码 + */ + private void generatorCode(String tableName, ZipOutputStream zip) { + // 查询表信息 + GenTable table = baseMapper.selectGenTableByName(tableName); + List menuIds = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + menuIds.add((Long) identifierGenerator.nextId(null)); + } + table.setMenuIds(menuIds); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + // 添加到zip + zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table))); + IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString()); + IoUtil.close(sw); + zip.flush(); + zip.closeEntry(); + } catch (IOException e) { + log.error("渲染模板失败,表名:" + table.getTableName(), e); + } + } + } + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + @Override + public void validateEdit(GenTable genTable) { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) { + String options = JsonUtils.toJsonString(genTable.getParams()); + Dict paramsObj = JsonUtils.parseMap(options); + if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) { + throw new BizException("树编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) { + throw new BizException("树父编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) { + throw new BizException("树名称字段不能为空"); + } + } + } + + /** + * 设置主键列信息 + * + * @param table 业务表信息 + */ + public void setPkColumn(GenTable table) { + for (GenTableColumn column : table.getColumns()) { + if (column.isPk()) { + table.setPkColumn(column); + break; + } + } + if (ObjectUtil.isNull(table.getPkColumn())) { + table.setPkColumn(table.getColumns().get(0)); + } + + } + + /** + * 设置代码生成其他选项值 + * + * @param genTable 设置后的生成对象 + */ + public void setTableFromOptions(GenTable genTable) { + Dict paramsObj = JsonUtils.parseMap(genTable.getOptions()); + if (ObjectUtil.isNotNull(paramsObj)) { + String treeCode = paramsObj.getStr(GenConstants.TREE_CODE); + String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE); + String treeName = paramsObj.getStr(GenConstants.TREE_NAME); + String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME); + + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); + } + } + + /** + * 获取代码生成地址 + * + * @param table 业务表信息 + * @param template 模板文件路径 + * @return 生成地址 + */ + public static String getGenPath(GenTable table, String template) { + String genPath = table.getGenPath(); + if (StringUtils.equals(genPath, "/")) { + return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table); + } + return genPath + File.separator + VelocityUtils.getFileName(template, table); + } +} + diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java new file mode 100644 index 00000000..7b53f199 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java @@ -0,0 +1,134 @@ +package cc.iotkit.generator.service; + + +import cc.iotkit.common.api.PageRequest; +import cc.iotkit.common.api.Paging; +import cc.iotkit.generator.domain.GenTable; +import cc.iotkit.generator.domain.GenTableColumn; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 业务 服务层 + * + * @author Lion Li + */ +public interface IGenTableService { + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + List selectGenTableColumnListByTableId(Long tableId); + + /** + * 查询业务列表 + * + * + * @return 业务集合 + */ + Paging selectPageGenTableList(PageRequest pageQuery); + + /** + * 查询据库列表 + * + * @return 数据库表集合 + */ + Paging selectPageDbTableList(PageRequest pageQuery); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + List selectDbTableListByNames(Collection tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + List selectGenTableAll(); + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + GenTable selectGenTableById(Long id); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + void updateGenTable(GenTable genTable); + + /** + * 删除业务信息 + * + * @param tableIds 需要删除的表数据ID + * @return 结果 + */ + void deleteGenTableByIds(Collection tableIds); + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + void importGenTable(List tableList); + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + Map previewCode(Long tableId); + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + byte[] downloadCode(String tableName); + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + * @return 数据 + */ + void generatorCode(String tableName); + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + void synchDb(String tableName); + + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + byte[] downloadCode(String[] tableNames); + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + void validateEdit(GenTable genTable); +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java new file mode 100644 index 00000000..4659c5e7 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java @@ -0,0 +1,233 @@ +package cc.iotkit.generator.util; + +import cc.iotkit.common.satoken.utils.LoginHelper; +import cc.iotkit.common.utils.StringUtils; +import cc.iotkit.generator.config.GenConfig; +import cc.iotkit.generator.constant.GenConstants; +import cc.iotkit.generator.domain.GenTable; +import cc.iotkit.generator.domain.GenTableColumn; +import cn.hutool.core.util.ReUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Arrays; + +/** + * 代码生成器 工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class GenUtils { + + /** + * 初始化表信息 + */ + public static void initTable(GenTable genTable, String operName) { + genTable.setClassName(convertClassName(genTable.getTableName())); + genTable.setPackageName(GenConfig.getPackageName()); + genTable.setModuleName(getModuleName(GenConfig.getPackageName())); + genTable.setBusinessName(getBusinessName(genTable.getTableName())); + genTable.setFunctionName(replaceText(genTable.getTableComment())); + genTable.setFunctionAuthor(GenConfig.getAuthor()); + genTable.setCreateBy(LoginHelper.getUserId()); + } + + /** + * 初始化列属性字段 + */ + public static void initColumnField(GenTableColumn column, GenTable table) { + String dataType = getDbType(column.getColumnType()); + String columnName = column.getColumnName(); + column.setTableId(table.getTableId()); + column.setCreateBy(table.getCreateBy()); + // 设置java字段名 + column.setJavaField(StringUtils.toCamelCase(columnName)); + // 设置默认类型 + column.setJavaType(GenConstants.TYPE_STRING); + column.setQueryType(GenConstants.QUERY_EQ); + + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) { + // 字符串长度超过500设置为文本域 + Integer columnLength = getColumnLength(column.getColumnType()); + String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + column.setHtmlType(htmlType); + } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) { + column.setJavaType(GenConstants.TYPE_DATE); + column.setHtmlType(GenConstants.HTML_DATETIME); + } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) { + column.setHtmlType(GenConstants.HTML_INPUT); + + // 如果是浮点型 统一用BigDecimal + String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) { + column.setJavaType(GenConstants.TYPE_BIGDECIMAL); + } + // 如果是整形 + else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) { + column.setJavaType(GenConstants.TYPE_INTEGER); + } + // 长整形 + else { + column.setJavaType(GenConstants.TYPE_LONG); + } + } + + // BO对象 默认插入勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) { + column.setIsInsert(GenConstants.REQUIRE); + } + // BO对象 默认编辑勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) { + column.setIsEdit(GenConstants.REQUIRE); + } + // BO对象 默认是否必填勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) { + column.setIsRequired(GenConstants.REQUIRE); + } + // VO对象 默认返回勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) { + column.setIsList(GenConstants.REQUIRE); + } + // BO对象 默认查询勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) { + column.setIsQuery(GenConstants.REQUIRE); + } + + // 查询字段类型 + if (StringUtils.endsWithIgnoreCase(columnName, "name")) { + column.setQueryType(GenConstants.QUERY_LIKE); + } + // 状态字段设置单选框 + if (StringUtils.endsWithIgnoreCase(columnName, "status")) { + column.setHtmlType(GenConstants.HTML_RADIO); + } + // 类型&性别字段设置下拉框 + else if (StringUtils.endsWithIgnoreCase(columnName, "type") + || StringUtils.endsWithIgnoreCase(columnName, "sex")) { + column.setHtmlType(GenConstants.HTML_SELECT); + } + // 图片字段设置图片上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) { + column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); + } + // 文件字段设置文件上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) { + column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) { + column.setHtmlType(GenConstants.HTML_EDITOR); + } + } + + /** + * 校验数组是否包含指定值 + * + * @param arr 数组 + * @param targetValue 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) { + return Arrays.asList(arr).contains(targetValue); + } + + /** + * 获取模块名 + * + * @param packageName 包名 + * @return 模块名 + */ + public static String getModuleName(String packageName) { + int lastIndex = packageName.lastIndexOf("."); + int nameLength = packageName.length(); + return StringUtils.substring(packageName, lastIndex + 1, nameLength); + } + + /** + * 获取业务名 + * + * @param tableName 表名 + * @return 业务名 + */ + public static String getBusinessName(String tableName) { + int firstIndex = tableName.indexOf("_"); + int nameLength = tableName.length(); + String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength); + businessName = StringUtils.toCamelCase(businessName); + return businessName; + } + + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) { + String[] searchList = StringUtils.split(tablePrefix, StringUtils.SEPARATOR); + tableName = replaceFirst(tableName, searchList); + } + return StringUtils.convertToCamelCase(tableName); + } + + /** + * 批量替换前缀 + * + * @param replacementm 替换值 + * @param searchList 替换列表 + * @return + */ + public static String replaceFirst(String replacementm, String[] searchList) { + String text = replacementm; + for (String searchString : searchList) { + if (replacementm.startsWith(searchString)) { + text = replacementm.replaceFirst(searchString, ""); + break; + } + } + return text; + } + + /** + * 关键字替换 + * + * @param text 需要被替换的名字 + * @return 替换后的名字 + */ + public static String replaceText(String text) { + return ReUtil.replaceAll(text, "(?:表|若依)", ""); + } + + /** + * 获取数据库类型字段 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) { + if (StringUtils.indexOf(columnType, '(') > 0) { + return StringUtils.substringBefore(columnType, "("); + } else { + return columnType; + } + } + + /** + * 获取字段长度 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) { + if (StringUtils.indexOf(columnType, '(') > 0) { + String length = StringUtils.substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } else { + return 0; + } + } +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java new file mode 100644 index 00000000..a47b7595 --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java @@ -0,0 +1,35 @@ +package cc.iotkit.generator.util; + +import cc.iotkit.common.constant.Constants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.velocity.app.Velocity; + +import java.util.Properties; + +/** + * VelocityEngine工厂 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class VelocityInitializer { + + /** + * 初始化vm方法 + */ + public static void initVelocity() { + Properties p = new Properties(); + try { + // 加载classpath目录下的vm文件 + p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + // 定义字符集 + p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8); + // 初始化Velocity引擎,指定配置Properties + Velocity.init(p); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java new file mode 100644 index 00000000..88b2768d --- /dev/null +++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java @@ -0,0 +1,354 @@ +package cc.iotkit.generator.util; + +import cc.iotkit.common.utils.DateUtils; +import cc.iotkit.common.utils.JsonUtils; +import cc.iotkit.common.utils.StringUtils; +import cc.iotkit.generator.constant.GenConstants; +import cc.iotkit.generator.core.DataBaseHelper; +import cc.iotkit.generator.domain.GenTable; +import cc.iotkit.generator.domain.GenTableColumn; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.velocity.VelocityContext; + +import java.util.*; + +/** + * 模板处理工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class VelocityUtils { + + /** + * 项目空间路径 + */ + private static final String PROJECT_PATH = "main/java"; + + /** + * mybatis空间路径 + */ + private static final String MYBATIS_PATH = "main/resources/mapper"; + + /** + * 默认上级菜单,系统工具 + */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; + + /** + * 设置模板变量信息 + * + * @return 模板列表 + */ + public static VelocityContext prepareContext(GenTable genTable) { + String moduleName = genTable.getModuleName(); + String businessName = genTable.getBusinessName(); + String packageName = genTable.getPackageName(); + String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("tplCategory", genTable.getTplCategory()); + velocityContext.put("tableName", genTable.getTableName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("ClassName", genTable.getClassName()); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); + velocityContext.put("moduleName", genTable.getModuleName()); + velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); + velocityContext.put("businessName", genTable.getBusinessName()); + velocityContext.put("basePackage", getPackagePrefix(packageName)); + velocityContext.put("packageName", packageName); + velocityContext.put("author", genTable.getFunctionAuthor()); + velocityContext.put("datetime", DateUtils.getDate()); + velocityContext.put("pkColumn", genTable.getPkColumn()); + velocityContext.put("importList", getImportList(genTable)); + velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); + velocityContext.put("columns", genTable.getColumns()); + velocityContext.put("table", genTable); + velocityContext.put("dicts", getDicts(genTable)); + setMenuVelocityContext(velocityContext, genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) { + setTreeVelocityContext(velocityContext, genTable); + } + return velocityContext; + } + + public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String treeCode = getTreecode(paramsObj); + String treeParentCode = getTreeParentCode(paramsObj); + String treeName = getTreeName(paramsObj); + + context.put("treeCode", treeCode); + context.put("treeParentCode", treeParentCode); + context.put("treeName", treeName); + context.put("expandColumn", getExpandColumn(genTable)); + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + context.put("tree_parent_code", paramsObj.get(GenConstants.TREE_PARENT_CODE)); + } + if (paramsObj.containsKey(GenConstants.TREE_NAME)) { + context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME)); + } + } + + /** + * 获取模板信息 + * + * @return 模板列表 + */ + public static List getTemplateList(String tplCategory) { + List templates = new ArrayList(); + templates.add("vm/java/model.java.vm"); + templates.add("vm/java/vo.java.vm"); + templates.add("vm/java/bo.java.vm"); +// templates.add("vm/java/mapper.java.vm"); + templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); + templates.add("vm/java/controller.java.vm"); + templates.add("vm/java/idata.java.vm"); + templates.add("vm/java/idataimpl.java.vm"); + templates.add("vm/java/tbmodel.java.vm"); + templates.add("vm/java/repository.java.vm"); + if (DataBaseHelper.isOracle()) { + templates.add("vm/sql/oracle/sql.vm"); + } else if (DataBaseHelper.isPostgerSql()) { + templates.add("vm/sql/postgres/sql.vm"); + } else if (DataBaseHelper.isSqlServer()) { + templates.add("vm/sql/sqlserver/sql.vm"); + } else { + templates.add("vm/sql/sql.vm"); + } + templates.add("vm/ts/api.ts.vm"); + templates.add("vm/ts/types.ts.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) { + templates.add("vm/vue/index.vue.vm"); + } else if (GenConstants.TPL_TREE.equals(tplCategory)) { + templates.add("vm/vue/index-tree.vue.vm"); + } + return templates; + } + + /** + * 获取文件名 + */ + public static String getFileName(String template, GenTable genTable) { + // 文件名称 + String fileName = ""; + // 包路径 + String packageName = genTable.getPackageName(); + // 模块名 + String moduleName = genTable.getModuleName(); + // 大写类名 + String className = genTable.getClassName(); + // 业务名称 + String businessName = genTable.getBusinessName(); + + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); + String mybatisPath = MYBATIS_PATH + "/" + moduleName; + String vuePath = "vue"; + + if (template.contains("domain.java.vm")) { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); + } + if (template.endsWith("tbmodel.java.vm")) { + fileName = StringUtils.format("{}/data/model/Tb{}.java", javaPath, className); + } else if (template.endsWith("model.java.vm")) { + fileName = StringUtils.format("{}/model/{}.java", javaPath, className); + } + if (template.endsWith("repository.java.vm")) { + fileName = StringUtils.format("{}/repository/{}Repository.java", javaPath, className); + } + if (template.endsWith("idata.java.vm")) { + fileName = StringUtils.format("{}/data/I{}Data.java", javaPath, className); + } else if (template.endsWith("idataimpl.java.vm")) { + fileName = StringUtils.format("{}/data/impl/{}DataImpl.java", javaPath, className); + } + if (template.contains("vo.java.vm")) { + fileName = StringUtils.format("{}/dto/vo/{}Vo.java", javaPath, className); + } + if (template.contains("bo.java.vm")) { + fileName = StringUtils.format("{}/dto/bo/{}Bo.java", javaPath, className); + } + if (template.contains("mapper.java.vm")) { + fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); + } else if (template.contains("service.java.vm")) { + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); + } else if (template.contains("serviceImpl.java.vm")) { + fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); + } else if (template.contains("controller.java.vm")) { + fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); + } else if (template.contains("mapper.xml.vm")) { + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + } else if (template.contains("sql.vm")) { + fileName = businessName + "Menu.sql"; + } else if (template.contains("api.ts.vm")) { + fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName); + } else if (template.contains("types.ts.vm")) { + fileName = StringUtils.format("{}/api/{}/{}/types.ts", vuePath, moduleName, businessName); + } else if (template.contains("index.vue.vm")) { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } else if (template.contains("index-tree.vue.vm")) { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + return fileName; + } + + /** + * 获取包前缀 + * + * @param packageName 包名称 + * @return 包前缀名称 + */ + public static String getPackagePrefix(String packageName) { + int lastIndex = packageName.lastIndexOf("."); + return StringUtils.substring(packageName, 0, lastIndex); + } + + /** + * 根据列类型获取导入包 + * + * @param genTable 业务表对象 + * @return 返回需要导入的包列表 + */ + public static HashSet getImportList(GenTable genTable) { + List columns = genTable.getColumns(); + HashSet importList = new HashSet<>(); + for (GenTableColumn column : columns) { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) { + importList.add("java.util.Date"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) { + importList.add("java.math.BigDecimal"); + } + } + return importList; + } + + /** + * 根据列类型获取字典组 + * + * @param genTable 业务表对象 + * @return 返回字典组 + */ + public static String getDicts(GenTable genTable) { + List columns = genTable.getColumns(); + Set dicts = new HashSet<>(); + addDicts(dicts, columns); + return StringUtils.join(dicts, ", "); + } + + /** + * 添加字典列表 + * + * @param dicts 字典列表 + * @param columns 列集合 + */ + public static void addDicts(Set dicts, List columns) { + for (GenTableColumn column : columns) { + if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( + column.getHtmlType(), + new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) { + dicts.add("'" + column.getDictType() + "'"); + } + } + } + + /** + * 获取权限前缀 + * + * @param moduleName 模块名称 + * @param businessName 业务名称 + * @return 返回权限前缀 + */ + public static String getPermissionPrefix(String moduleName, String businessName) { + return StringUtils.format("{}:{}", moduleName, businessName); + } + + /** + * 获取上级菜单ID字段 + * + * @param paramsObj 生成其他选项 + * @return 上级菜单ID字段 + */ + public static String getParentMenuId(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID) + && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) { + return paramsObj.getStr(GenConstants.PARENT_MENU_ID); + } + return DEFAULT_PARENT_MENU_ID; + } + + /** + * 获取树编码 + * + * @param paramsObj 生成其他选项 + * @return 树编码 + */ + public static String getTreecode(Map paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) { + return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE))); + } + return StringUtils.EMPTY; + } + + /** + * 获取树父编码 + * + * @param paramsObj 生成其他选项 + * @return 树父编码 + */ + public static String getTreeParentCode(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE)); + } + return StringUtils.EMPTY; + } + + /** + * 获取树名称 + * + * @param paramsObj 生成其他选项 + * @return 树名称 + */ + public static String getTreeName(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) { + return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME)); + } + return StringUtils.EMPTY; + } + + /** + * 获取需要在哪一列上面显示展开按钮 + * + * @param genTable 业务表对象 + * @return 展开按钮列序号 + */ + public static int getExpandColumn(GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String treeName = paramsObj.getStr(GenConstants.TREE_NAME); + int num = 0; + for (GenTableColumn column : genTable.getColumns()) { + if (column.isList()) { + num++; + String columnName = column.getColumnName(); + if (columnName.equals(treeName)) { + break; + } + } + } + return num; + } +} diff --git a/iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..6919707b --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cc.iotkit.generator.config.MybatisPlusConfig \ No newline at end of file diff --git a/iot-module/iot-generator/src/main/resources/application-generator.yml b/iot-module/iot-generator/src/main/resources/application-generator.yml new file mode 100644 index 00000000..19ea3641 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/application-generator.yml @@ -0,0 +1,45 @@ +spring: + + + jpa: + show-sql: true + hibernate: + ddl-auto: update + properties: + hibernate: + format_sql: true + + sql: + init: + # mysql 初始化 + # schema-locations: classpath:sql/schema.sql + # postgrep 初始化 + schema-locations: classpath:sql/schema-postgre.sql + mode: ALWAYS + + datasource: + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + primary: master #设置默认的数据源或者数据源组,默认值即为master + strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: ${spring.datasource.driverClassName} + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: ${spring.datasource.url} + username: ${spring.datasource.url} + password: ${spring.datasource.password} + + # 从库数据源 + slave: + lazy: true + type: ${spring.datasource.type} + driverClassName: ${spring.datasource.driverClassName} + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: ${spring.datasource.url} + username: ${spring.datasource.username} + password: ${spring.datasource.password} \ No newline at end of file diff --git a/iot-module/iot-generator/src/main/resources/common-mybatis.yml b/iot-module/iot-generator/src/main/resources/common-mybatis.yml new file mode 100644 index 00000000..f5dc6375 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/common-mybatis.yml @@ -0,0 +1,33 @@ +# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖 +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 启动时是否检查 MyBatis XML 文件的存在,默认不检查 + checkConfigLocation: false + configuration: + # 自动驼峰命名规则(camel case)映射 + mapUnderscoreToCamelCase: true + # MyBatis 自动映射策略 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 + autoMappingBehavior: FULL + # MyBatis 自动映射时未知列或未知属性处理策 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 + autoMappingUnknownColumnBehavior: NONE + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl + global-config: + # 是否打印 Logo banner + banner: true + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + idType: ASSIGN_ID + # 逻辑已删除值(框架表均使用此值 禁止随意修改) + logicDeleteValue: 2 + # 逻辑未删除值 + logicNotDeleteValue: 0 + insertStrategy: NOT_NULL + updateStrategy: NOT_NULL + whereStrategy: NOT_NULL diff --git a/iot-module/iot-generator/src/main/resources/generator.yml b/iot-module/iot-generator/src/main/resources/generator.yml new file mode 100644 index 00000000..aa8b9def --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/generator.yml @@ -0,0 +1,10 @@ +# 代码生成 +gen: + # 作者 + author: iita + # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool + packageName: cc.iotkit.system + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) + tablePrefix: sys_ diff --git a/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml new file mode 100644 index 00000000..14f2d97b --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -0,0 +1,105 @@ + + + + + + + + + + diff --git a/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml new file mode 100644 index 00000000..57ff7958 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iot-module/iot-generator/src/main/resources/mapper/package-info.md b/iot-module/iot-generator/src/main/resources/mapper/package-info.md new file mode 100644 index 00000000..c938b1e5 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm new file mode 100644 index 00000000..400b821a --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm @@ -0,0 +1,52 @@ +package ${packageName}.dto.bo; + +import ${packageName}.model.${ClassName}; +import cc.iotkit.common.api.BaseDto; +import cc.iotkit.common.validate.AddGroup; +import cc.iotkit.common.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +#foreach ($import in $importList) +import ${import}; +#end + +/** + * ${functionName}业务对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false) +public class ${ClassName}Bo extends BaseDto { + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit)) + /** + * $column.columnComment + */ +#if($column.insert && $column.edit) +#set($Group="AddGroup.class, EditGroup.class") +#elseif($column.insert) +#set($Group="AddGroup.class") +#elseif($column.edit) +#set($Group="EditGroup.class") +#end +#if($column.required) +#if($column.javaType == 'String') + @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) +#else + @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) +#end +#end + @ApiModelProperty(value = "$column.columnComment", required = ${column.required}) + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 00000000..566b9517 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,113 @@ +package ${packageName}.controller; + +import java.util.List; + + +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import cc.iotkit.common.log.annotation.Log; +import cc.iotkit.common.web.core.BaseController; +import cc.iotkit.common.api.PageRequest; +import cc.iotkit.common.api.Paging; +import cc.iotkit.common.api.Request; +import cc.iotkit.common.validate.AddGroup; +import cc.iotkit.common.validate.EditGroup; +import cc.iotkit.common.log.enums.BusinessType; +import cc.iotkit.common.excel.utils.ExcelUtil; +import ${packageName}.dto.vo.${ClassName}Vo; +import ${packageName}.dto.bo.${ClassName}Bo; +import ${packageName}.service.I${ClassName}Service; + + +/** + * ${functionName} + * + * @author ${author} + * @date ${datetime} + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/${moduleName}/${businessName}") +public class ${ClassName}Controller extends BaseController { + + private final I${ClassName}Service ${className}Service; + + /** + * 查询${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:list") + @PostMapping("/list") + @ApiOperation("查询${functionName}列表") +#if($table.crud || $table.sub) + public Paging<${ClassName}Vo> list( PageRequest<${ClassName}Bo> pageQuery) { + return ${className}Service.queryPageList(pageQuery); + } +#elseif($table.tree) + public List<${ClassName}Vo> list(@RequestBody Request<${ClassName}Bo> query) { + List<${ClassName}Vo> list = ${className}Service.queryList(query.getData()); + return list; + } +#end + + /** + * 导出${functionName}列表 + */ + @ApiOperation("导出${functionName}列表") + @SaCheckPermission("${permissionPrefix}:export") + @Log(title = "${functionName}", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(${ClassName}Bo bo, HttpServletResponse response) { + List<${ClassName}Vo> list = ${className}Service.queryList(bo); + ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response); + } + + /** + * 获取${functionName}详细信息 + * + */ + @SaCheckPermission("${permissionPrefix}:query") + @PostMapping("/getDetail") + @ApiOperation("获取${functionName}详细信息") + public ${ClassName}Vo getDetail(@Validated @RequestBody Request request) { + return ${className}Service.queryById(request.getData()); + } + + /** + * 新增${functionName} + */ + @SaCheckPermission("${permissionPrefix}:add") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @PostMapping(value = "/add") + @ApiOperation("新增${functionName}") + public Long add(@Validated(AddGroup.class) @RequestBody Request<${ClassName}Bo> request) { + return ${className}Service.insertByBo(request.getData()); + } + + /** + * 修改${functionName} + */ + @SaCheckPermission("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ApiOperation("修改${functionName}") + public boolean edit(@Validated(EditGroup.class) @RequestBody Request<${ClassName}Bo> request) { + return ${className}Service.updateByBo(request.getData()); + } + + /** + * 删除${functionName} + * + */ + @SaCheckPermission("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @PostMapping("/delete") + @ApiOperation("删除${functionName}") + public boolean remove(@Validated @RequestBody Request> query) { + return ${className}Service.deleteWithValidByIds(query.getData(), true); + } +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm new file mode 100644 index 00000000..9dcec7e3 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm @@ -0,0 +1,16 @@ +package ${packageName}.data; + +import cc.iotkit.data.ICommonData; +import ${packageName}.model.${ClassName}; +import java.util.List; + +/** + * 数据接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Data extends ICommonData<${ClassName}, Long> { + + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm new file mode 100644 index 00000000..aa20bb48 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm @@ -0,0 +1,135 @@ +package ${packageName}.data; + +import ${packageName}.repository.${ClassName}Repository; +import ${packageName}.data.I${ClassName}Data; +import ${packageName}.data.model.Tb${ClassName}; +import ${packageName}.model.${ClassName}; +import java.util.List; +import com.querydsl.core.types.Predicate; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; +import cc.iotkit.data.util.PredicateBuilder; + +import cc.iotkit.common.api.PageRequest; +import cc.iotkit.common.api.Paging; +import cc.iotkit.common.utils.StringUtils; +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import com.google.common.collect.Lists; + + +import cc.iotkit.common.utils.MapstructUtils; +import cc.iotkit.data.util.PageBuilder; + + +import static ${packageName}.data.model.QTb${ClassName}.tb${ClassName}; +/** + * 数据实现接口 + * + * @author ${author} + * @date ${datetime} + */ +@Primary +@Service +@RequiredArgsConstructor +public class ${ClassName}DataImpl implements I${ClassName}Data { + + private final ${ClassName}Repository baseRepository; + + private final JPAQueryFactory jpaQueryFactory; + + @Override + public Paging<${ClassName}> findAll(PageRequest<${ClassName}> pageRequest) { + return PageBuilder.toPaging(baseRepository.findAll(buildQueryCondition(pageRequest.getData()), PageBuilder.toPageable(pageRequest))).to(${ClassName}.class); + } + + private Predicate buildQueryCondition(${ClassName} bo) { + PredicateBuilder builder = PredicateBuilder.instance(); + if(Objects.nonNull(bo)) { + + #foreach($column in $columns) + #if($column.query) + #set($queryType=$column.queryType) + #set($javaField=$column.javaField) + #set($javaType=$column.javaType) + #set($columnName=$column.columnName) + #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #if($queryType != 'BETWEEN') + #if($javaType == 'String') + #set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())') + #else + #set($condition='bo.get'+$AttrName+'() != null') + #end + builder.and($condition, () -> tb${ClassName}.${javaField}.eq(bo.get${AttrName}())); + #else + builder.and(params.get("begin$AttrName") != null && params.get("end$AttrName") != null, + () -> tb${ClassName}.${javaField}.bettwen(params.get("begin$AttrName"), params.get("end$AttrName"))); + #end + #end + #end + } + return builder.build(); + } + + @Override + public List<${ClassName}> findByIds(Collection ids) { + List allById = baseRepository.findAllById(ids); + return MapstructUtils.convert(allById, ${ClassName}.class); + } + + @Override + public ${ClassName} save(${ClassName} data) { + Object o = baseRepository.save(MapstructUtils.convert(data, Tb${ClassName}.class)); + return MapstructUtils.convert(o, ${ClassName}.class); + } + + @Override + public void batchSave(List<${ClassName}> data) { + baseRepository.saveAll(MapstructUtils.convert(data, Tb${ClassName}.class)); + } + + @Override + public void deleteById(Long id) { + baseRepository.deleteById(id); + } + + @Override + public void deleteByIds(Collection ids) { + baseRepository.deleteAllById(ids); + } + + @Override + public ${ClassName} findById(Long id) { + Tb${ClassName} ret = jpaQueryFactory.select(tb${ClassName}).from(tb${ClassName}).where(tb${ClassName}.id.eq(id)).fetchOne(); + return MapstructUtils.convert(ret, ${ClassName}.class); + } + + @Override + public long count() { + return baseRepository.count(); + } + + @Override + public List findAll() { + return MapstructUtils.convert(baseRepository.findAll(), IotContributor.class); + } + + @Override + public List findAllByCondition(IotContributor data) { + Iterable all = baseRepository.findAll(buildQueryCondition(data)); + return MapstructUtils.convert(Lists.newArrayList(all), IotContributor.class); + } + + @Override + public IotContributor findOneByCondition(IotContributor data) { + Optional one = baseRepository.findOne(buildQueryCondition(data)); + + if(one.isPresent()){ + return MapstructUtils.convert(one.get(), IotContributor.class); + } + return null; + } +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 00000000..a367317d --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,15 @@ +package ${packageName}.mapper; + +import ${packageName}.domain.${ClassName}; +import ${packageName}.domain.vo.${ClassName}Vo; +import cc.iotkit.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> { + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/model.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/model.java.vm new file mode 100644 index 00000000..6b75cdbb --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/model.java.vm @@ -0,0 +1,50 @@ +package ${packageName}.model; + +import cc.iotkit.model.Id; +#foreach ($column in $columns) +#if($column.javaField=='tenantId') +#set($IsTenant=1) +#end +#end +#if($IsTenant==1) +import cc.iotkit.model.TenantModel; +#else +import cc.iotkit.model.BaseModel; +#end +import lombok.Data; +import lombok.EqualsAndHashCode; +#foreach ($import in $importList) +import ${import}; +#end + +import java.io.Serializable; + + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($IsTenant==1) +#set($Entity="TenantModel") +#else +#set($Entity="BaseModel") +#end +@Data +@EqualsAndHashCode(callSuper = true) +public class ${ClassName} extends ${Entity} implements Id, Serializable{ + + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** + * $column.columnComment + */ + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm new file mode 100644 index 00000000..e008721e --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm @@ -0,0 +1,15 @@ +package ${packageName}.data.dao; + +import ${packageName}.data.model.Tb${ClassName}; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Repository extends JpaRepository, QuerydslPredicateExecutor { + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/service.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/service.java.vm new file mode 100644 index 00000000..d789b777 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,53 @@ +package ${packageName}.service; + +import ${packageName}.dto.vo.${ClassName}Vo; +import ${packageName}.dto.bo.${ClassName}Bo; +#if($table.crud || $table.sub) + +#end +import cc.iotkit.common.api.Paging; +import cc.iotkit.common.api.PageRequest; + +import java.util.Collection; +import java.util.List; + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service { + + /** + * 查询${functionName} + */ + ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}); + +#if($table.crud || $table.sub) + /** + * 查询${functionName}列表 + */ + Paging<${ClassName}Vo> queryPageList(PageRequest<${ClassName}Bo> pageQuery); +#end + + /** + * 查询${functionName}列表 + */ + List<${ClassName}Vo> queryList(${ClassName}Bo bo); + + /** + * 新增${functionName} + */ + Long insertByBo(${ClassName}Bo bo); + + /** + * 修改${functionName} + */ + Boolean updateByBo(${ClassName}Bo bo); + + /** + * 校验并批量删除${functionName}信息 + */ + Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 00000000..995d4b62 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,109 @@ +package ${packageName}.service.impl; + +import cc.iotkit.common.utils.MapstructUtils; +import cc.iotkit.common.utils.StringUtils; +#if($table.crud || $table.sub) +import cc.iotkit.common.api.PageRequest; +import cc.iotkit.common.api.Paging; +#end +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ${packageName}.dto.bo.${ClassName}Bo; +import ${packageName}.dto.vo.${ClassName}Vo; +import ${packageName}.model.${ClassName}; +import ${packageName}.service.I${ClassName}Service; +import ${packageName}.data.I${ClassName}Data; + +import java.util.List; +import java.util.Collection; +import cc.iotkit.common.exception.BizException; + + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@RequiredArgsConstructor +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service { + + private final I${ClassName}Data baseData; + + /** + * 查询${functionName} + */ + @Override + public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){ + return MapstructUtils.convert(baseData.findById(${pkColumn.javaField}), ${ClassName}Vo.class); + } + +#if($table.crud || $table.sub) + /** + * 查询${functionName}列表 + */ + @Override + public Paging<${ClassName}Vo> queryPageList(PageRequest<${ClassName}Bo> pageQuery) { + Paging<${ClassName}Vo> result = baseData.findAll(pageQuery.to(${ClassName}.class)).to(${ClassName}Vo.class); + return result; + } +#end + + /** + * 查询${functionName}列表 + */ + @Override + public List<${ClassName}Vo> queryList(${ClassName}Bo bo) { + + return MapstructUtils.convert(baseData.findAllByCondition(bo.to(${ClassName}.class)), ${ClassName}Vo.class); + } + + /** + * 新增${functionName} + */ + @Override + public Long insertByBo(${ClassName}Bo bo) { + ${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class); + validEntityBeforeSave(add); + baseData.save(add); + if (add == null) { + throw new BizException("新增失败"); + } + #set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)}) + return add.get$pk(); + } + + /** + * 修改${functionName} + */ + @Override + public Boolean updateByBo(${ClassName}Bo bo) { + ${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class); + validEntityBeforeSave(update); + ${ClassName} ret = baseData.save(update); + if(ret == null){ + return false; + } + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(${ClassName} entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除${functionName} + */ + @Override + public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + baseData.deleteByIds(ids); + return true; + } +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm new file mode 100644 index 00000000..0f03e08f --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm @@ -0,0 +1,71 @@ +package ${packageName}.data.model; + +import ${packageName}.model.IotContributor; +import io.github.linpeilie.annotations.AutoMapper; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +#foreach ($column in $columns) +#if($column.javaField=='tenantId') +#set($IsTenant=1) +#end +#end +#if($IsTenant==1) +import cc.iotkit.model.TenantModel; +#else +import cc.iotkit.data.model.BaseEntity; +#end +import lombok.Data; +import lombok.EqualsAndHashCode; +#foreach ($import in $importList) +import ${import}; +#end +import javax.persistence.Table; +import javax.persistence.Entity; + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($IsTenant==1) +#set($Entity="TenantEntity") +#else +#set($Entity="BaseEntity") +#end +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Entity +@Table(name = "${tableName}") +@AutoMapper(target = ${ClassName}.class) +public class Tb${ClassName} extends ${Entity} { + + + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** + * $column.columnComment + */ +#if($column.javaField=='delFlag') +#end +#if($column.javaField=='version') +#end +#if($column.isPk==1) + @Id + @GeneratedValue(generator = "SnowflakeIdGenerator") + @GenericGenerator(name = "SnowflakeIdGenerator", strategy = "cc.iotkit.data.config.id.SnowflakeIdGenerator") +#end + @ApiModelProperty(value = "$column.columnComment") + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm new file mode 100644 index 00000000..06da2d21 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm @@ -0,0 +1,61 @@ +package ${packageName}.dto.vo; + +#foreach ($import in $importList) +import ${import}; +#end +import ${packageName}.model.${ClassName}; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import cc.iotkit.common.excel.annotation.ExcelDictFormat; +import cc.iotkit.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import io.swagger.annotations.ApiModelProperty; + + +import java.io.Serializable; +import java.util.Date; + + + +/** + * ${functionName}视图对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ${ClassName}.class) +public class ${ClassName}Vo implements Serializable { + + + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if(${column.dictType} && ${column.dictType} != '') + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "${column.dictType}") +#elseif($parentheseIndex != -1) + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") +#else + @ExcelProperty(value = "${comment}") +#end + @ApiModelProperty(value = "${comment}") + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/iot-module/iot-generator/src/main/resources/vm/js/api.js.vm b/iot-module/iot-generator/src/main/resources/vm/js/api.js.vm new file mode 100644 index 00000000..1df6ef37 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/js/api.js.vm @@ -0,0 +1,47 @@ +import request from '@/utils/request' +import { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types' + +// 查询${functionName}列表 +export function list${BusinessName}(query: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'post', + params: query + }) +} + +// 查询${functionName}详细 +export function get${BusinessName}(${pkColumn.javaField}: string | number) : AxiosPromise<${BusinessName}VO> { + return request({ + url: '/${moduleName}/${businessName}/getDetail', + method: 'post', + data: ${pkColumn.javaField} + }) +} + +// 新增${functionName} +export function add${BusinessName}(data: ${BusinessName}Form) { + return request({ + url: '/${moduleName}/${businessName}/add', + method: 'post', + data, + }) +} + +// 修改${functionName} +export function update${BusinessName}(data: ${BusinessName}Form) { + return request({ + url: '/${moduleName}/${businessName}/edit', + method: 'post', + data, + }) +} + +// 删除${functionName} +export function del${BusinessName}(${pkColumn.javaField}: Array) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'post', + data: ${pkColumn.javaField} + }) +} diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm new file mode 100644 index 00000000..f6638be5 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate, null, null, ''); diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm new file mode 100644 index 00000000..09233923 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm @@ -0,0 +1,20 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, now(), null, null, ''); + diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/sql.vm new file mode 100644 index 00000000..01824c27 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm new file mode 100644 index 00000000..bdf166e5 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, getdate(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, getdate(), null, null, ''); diff --git a/iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm b/iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm new file mode 100644 index 00000000..ee309bc7 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm @@ -0,0 +1,48 @@ +import request from '@/utils/request'; +import {AxiosPromise} from 'axios'; +import {${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO} from './types'; + +// 查询${functionName}列表 +export const list${BusinessName}(query: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'post', + params: query + }) +} + +// 查询${functionName}详细 +export const get${BusinessName}(${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> { + return request({ + url: '/${moduleName}/${businessName}/getDetail', + method: 'post', + data: ${pkColumn.javaField} + }) +} + +// 新增${functionName} +export const add${BusinessName}(data: ${BusinessName}Form) { + return request({ + url: '/${moduleName}/${businessName}/add', + method: 'post', + data + }) +} + +// 修改${functionName} +export const update${BusinessName}(data: ${BusinessName}Form) { + return request({ + url: '/${moduleName}/${businessName}/edit', + method: 'post', + data: data + }) +} + +// 删除${functionName} +export const del${BusinessName}(${pkColumn.javaField}: Array) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'post', + data: ${pkColumn.javaField} + }) +} diff --git a/iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm b/iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm new file mode 100644 index 00000000..99359e02 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm @@ -0,0 +1,44 @@ +export interface ${BusinessName}VO { +#foreach ($column in $columns) +#if($column.insert || $column.edit) + /** + * $column.columnComment + */ + $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end +} + +export interface ${BusinessName}Form extends BaseEntity { +#foreach ($column in $columns) +#if($column.insert || $column.edit) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end +} + +export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{ +#foreach ($column in $columns) +#if($column.query) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end +} diff --git a/iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm b/iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm new file mode 100644 index 00000000..dbfa4b98 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -0,0 +1,501 @@ + + + diff --git a/iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm b/iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm new file mode 100644 index 00000000..ace3446b --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm @@ -0,0 +1,467 @@ + + + diff --git a/iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm b/iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 00000000..9fb48d99 --- /dev/null +++ b/iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,7 @@ + + + + + diff --git a/iot-module/pom.xml b/iot-module/pom.xml index a0b4d164..2fda6a31 100644 --- a/iot-module/pom.xml +++ b/iot-module/pom.xml @@ -20,6 +20,7 @@ iot-plugin iot-manager iot-modbus + iot-generator \ No newline at end of file diff --git a/iot-starter/src/main/resources/application.yml b/iot-starter/src/main/resources/application.yml index b57eaa77..59d903bd 100644 --- a/iot-starter/src/main/resources/application.yml +++ b/iot-starter/src/main/resources/application.yml @@ -1,5 +1,6 @@ spring: profiles: +# active: dev,generator # 使用application-dev.yml和代码生成器模块application-generator.yml配置 active: dev # 使用application-dev.yml 配置 # active: prd # 使用application-prd.yml 配置 # active: test # 使用application-test.yml 配置 diff --git a/iot-starter/src/main/resources/sql/schema-postgre.sql b/iot-starter/src/main/resources/sql/schema-postgre.sql new file mode 100644 index 00000000..c593d651 --- /dev/null +++ b/iot-starter/src/main/resources/sql/schema-postgre.sql @@ -0,0 +1,112 @@ + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +drop table if exists gen_table; +create table if not exists gen_table +( + table_id int8, + data_name varchar(200) default ''::varchar, + table_name varchar(200) default ''::varchar, + table_comment varchar(500) default ''::varchar, + sub_table_name varchar(64) default ''::varchar, + sub_table_fk_name varchar(64) default ''::varchar, + class_name varchar(100) default ''::varchar, + tpl_category varchar(200) default 'crud'::varchar, + package_name varchar(100) default null::varchar, + module_name varchar(30) default null::varchar, + business_name varchar(30) default null::varchar, + function_name varchar(50) default null::varchar, + function_author varchar(50) default null::varchar, + gen_type char default '0'::bpchar not null, + gen_path varchar(200) default '/'::varchar, + options varchar(1000) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint gen_table_pk primary key (table_id) + ); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.sub_table_name is '关联子表的表名'; +comment on column gen_table.sub_table_fk_name is '子表关联的外键名'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(CRUD单表操作 TREE树表操作)'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +drop table if exists gen_table_column; +create table if not exists gen_table_column +( + column_id int8, + table_id int8, + column_name varchar(200) default null::varchar, + column_comment varchar(500) default null::varchar, + column_type varchar(100) default null::varchar, + java_type varchar(500) default null::varchar, + java_field varchar(200) default null::varchar, + is_pk char default null::bpchar, + is_increment char default null::bpchar, + is_required char default null::bpchar, + is_insert char default null::bpchar, + is_edit char default null::bpchar, + is_list char default null::bpchar, + is_query char default null::bpchar, + query_type varchar(200) default 'EQ'::varchar, + html_type varchar(200) default null::varchar, + dict_type varchar(200) default ''::varchar, + sort int4, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint gen_table_column_pk primary key (column_id) + ); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; diff --git a/iot-starter/src/main/resources/sql/schema.sql b/iot-starter/src/main/resources/sql/schema.sql new file mode 100644 index 00000000..b9ea000a --- /dev/null +++ b/iot-starter/src/main/resources/sql/schema.sql @@ -0,0 +1,60 @@ +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table if not exists gen_table ( + table_id bigint(20) not null comment '编号', + data_name varchar(200) default '' comment '数据源名称', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- + +create table if not exists gen_table_column ( + column_id bigint(20) not null comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb comment = '代码生成业务表字段'; \ No newline at end of file diff --git a/pom.xml b/pom.xml index 39b40b60..028750a7 100755 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,9 @@ 5.8.18 1.3.1 3.1.4 + 1.0.6 + 2.3 + @@ -340,6 +343,12 @@ ${project.version} + + cc.iotkit + iot-generator + ${project.version} + + cc.iotkit iot-message-notify @@ -406,6 +415,17 @@ ${iot-iita-core.version} + + com.github.yitter + yitter-idgenerator + ${yitter.version} + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} +