diff --git a/application/Dockerfile b/application/Dockerfile
new file mode 100644
index 0000000..06a3b8b
--- /dev/null
+++ b/application/Dockerfile
@@ -0,0 +1,11 @@
+FROM java:17
+
+ENV LANG C.UTF-8
+ENV LC_ALL C.UTF-8 en_US.UTF-8
+
+EXPOSE 2020
+
+VOLUME /tmp
+ADD appliction.jar /app.jar
+RUN bash -c 'touch /app.jar'
+ENTRYPOINT ["java","-jar","/app.jar"]
diff --git a/application/pom.xml b/application/pom.xml
new file mode 100644
index 0000000..37ada59
--- /dev/null
+++ b/application/pom.xml
@@ -0,0 +1,148 @@
+
+
+ 4.0.0
+
+ com.thing
+ thingbi
+ 5.1
+
+ application
+ ThingBI Application
+
+
+
+ UTF-8
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ com.google.guava
+ guava
+ provided
+
+
+ org.mybatis
+ mybatis-spring
+
+
+
+ com.thing.common
+ data
+
+
+ com.thing.common
+ orm
+
+
+ com.thing.common
+ queue
+
+
+ com.thing.common
+ script
+
+
+ com.thing.common
+ security
+
+
+ com.thing.common
+ transport
+
+
+ com.thing.common
+ tskv
+
+
+ com.thing.common
+ util
+
+
+
+
+ com.thing.modules
+ alarm
+
+
+ com.thing.modules
+ calculation
+
+
+ com.thing.modules
+ mock
+
+
+ com.thing.modules
+ report-analysis
+
+
+ com.thing.modules
+ configuration
+
+
+ com.thing.modules
+ dequeue
+
+
+ com.thing.modules
+ msg
+
+
+ com.thing.modules
+ quartz
+
+
+ com.thing.modules
+ carbon-track
+
+
+ com.thing.modules
+ carbon-public
+
+
+ com.thing.modules
+ equipment
+
+
+ com.thing.modules
+ thing
+
+
+ com.thing.tools
+ system-monitor
+
+
+ com.thing.tools
+ code-generator
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+
+
diff --git a/application/src/main/java/com/thing/ThingBiApplication.java b/application/src/main/java/com/thing/ThingBiApplication.java
new file mode 100644
index 0000000..5ec17f5
--- /dev/null
+++ b/application/src/main/java/com/thing/ThingBiApplication.java
@@ -0,0 +1,16 @@
+package com.thing;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+
+@EnableAsync
+@SpringBootApplication
+public class ThingBiApplication {
+
+
+ public static void main(String[] args) {
+ SpringApplication.run(ThingBiApplication.class, args);
+ }
+}
diff --git a/application/src/main/java/com/thing/listener/QueueCacheEventListener.java b/application/src/main/java/com/thing/listener/QueueCacheEventListener.java
new file mode 100644
index 0000000..9991f9e
--- /dev/null
+++ b/application/src/main/java/com/thing/listener/QueueCacheEventListener.java
@@ -0,0 +1,78 @@
+package com.thing.listener;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.thing.common.core.enumeration.QueueOriginType;
+import com.thing.common.core.event.QueueCacheEvent;
+import com.thing.common.data.dto.QueueMsgDTO;
+import com.thing.common.data.event.QueueConsumerEvent;
+import com.thing.common.data.proto.QueueProto;
+import com.thing.queue.util.Topics;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author zhenghh. 2022-10-13
+ **/
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class QueueCacheEventListener {
+
+// private final DynamicCacheTsKvService tsKvService;
+// private final CacheTsKvLastestService tsKvLastService;
+// @Resource
+// private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+// private DateTime dateTime = new DateTime();
+
+
+ private final ApplicationEventPublisher eventPublisher;
+
+
+ @EventListener(QueueCacheEvent.class)
+ public void onCacheEvent(QueueCacheEvent event) {
+ List list = event.getList();
+ if (CollectionUtil.isEmpty(list)) {
+ return;
+ }
+ // 去除来源为TB的数据,否则在ClickHouse的视图中会有重复数据
+ List nonTbList =
+ list.stream()
+ .filter(
+ e ->
+ !Objects.equals(
+ QueueOriginType.TB.name(), e.getOrigin()))
+ .toList();
+ List protoList = new ArrayList<>();
+
+ //新版本,将数据send到遥测数据全局监听器中
+ nonTbList.forEach(temp->{
+ QueueProto.TsKvProto tsKvProto =QueueProto.TsKvProto.newBuilder().setThingCode(temp.getThingCode()).setKey(temp.getAttrKey()).setTs(temp.getTs()).setVal(temp.getVal()).build();
+ protoList.add(QueueProto.DataProto.newBuilder().setTskvProto(tsKvProto).build());
+ });
+ //JSON.toJSONString(protoList)
+ eventPublisher.publishEvent(new QueueConsumerEvent(Topics.V1_TSKV_HISTORY.getValue(), protoList));
+ }
+
+//
+// //保存历史值
+// threadPoolTaskExecutor.execute(() -> tsKvService.saveList(nonTbList));
+//
+// if ((new DateTime().getMillis() - dateTime.getMillis()) > 3000) {
+// //保存最新值
+// List deduplicatedList = new ArrayList<>(nonTbList.stream()
+// .collect(Collectors.toMap(queueMsgDTO -> queueMsgDTO.getThingCode() + "_" + queueMsgDTO.getAttrKey() + "_" + queueMsgDTO.getTs(),
+// Function.identity(),
+// (a, b) -> a, LinkedHashMap::new))
+// .values());
+// tsKvLastService.saveList(deduplicatedList);
+// dateTime = new DateTime();
+// }
+
+}
diff --git a/application/src/main/java/com/thing/mock/IpCommandLineRunner.java b/application/src/main/java/com/thing/mock/IpCommandLineRunner.java
new file mode 100644
index 0000000..f10ab2f
--- /dev/null
+++ b/application/src/main/java/com/thing/mock/IpCommandLineRunner.java
@@ -0,0 +1,15 @@
+package com.thing.mock;
+
+import com.thing.common.core.annotation.LogOperation;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IpCommandLineRunner implements CommandLineRunner {
+
+ @LogOperation(value = "项目启动", type = "1")
+ @Override
+ public void run(String... args) throws Exception {
+
+ }
+}
diff --git a/application/src/main/java/com/thing/mock/MockDataController.java b/application/src/main/java/com/thing/mock/MockDataController.java
new file mode 100644
index 0000000..e23cc19
--- /dev/null
+++ b/application/src/main/java/com/thing/mock/MockDataController.java
@@ -0,0 +1,102 @@
+package com.thing.mock;
+
+import com.github.jsonzou.jmockdata.JMockData;
+import com.thing.common.core.web.response.Result;
+import com.thing.common.data.event.QueueConsumerEvent;
+import com.thing.common.data.proto.QueueProto.DataProto;
+import com.thing.common.data.proto.QueueProto.TsKvProto;
+import com.thing.common.data.tskv.TsKvDTO;
+import com.thing.queue.util.Topics;
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author siyang
+ * @date 2024-03-08
+ * @description mock数据服务(仅用作内部测试)不对外开放
+ */
+@RestController
+@RequestMapping("v2/mock/data")
+@RequiredArgsConstructor
+public class MockDataController {
+
+ @Value("${calculate.am_total.keys}")
+ private String keys;
+
+ private final ApplicationEventPublisher eventPublisher;
+
+ private static final List mockThings = new ArrayList<>(10);
+
+ static {
+ for (int i = 0; i < 10; i++) {
+ mockThings.add(JMockData.mock(String.class));
+ }
+ }
+
+ /** mock数据推送,随机数据 */
+ @RequestMapping("push/random")
+ public Result> randomPush() {
+ List list = new ArrayList<>();
+ long ts = System.currentTimeMillis();
+ List keyList = Arrays.stream(this.keys.split(",")).toList();
+ Random random = new Random();
+ for (int i = 0; i < 100; i++) {
+ TsKvProto mockTskv =
+ TsKvProto.newBuilder()
+ .setThingCode(mockThings.get(i % 10))
+ .setKey(keyList.get(random.nextInt(keyList.size())))
+ .setTs(ts)
+ .setVal(String.valueOf(JMockData.mock(Integer.class)))
+ .build();
+ list.add(DataProto.newBuilder().setTskvProto(mockTskv).build());
+ }
+
+ eventPublisher.publishEvent(
+ new QueueConsumerEvent(Topics.V1_TSKV_HISTORY.getValue(), list));
+ List tsKvList =
+ list.stream()
+ .map(DataProto::getTskvProto)
+ .map(e -> new TsKvDTO(e.getThingCode(), e.getKey(), e.getTs(), e.getVal()))
+ .collect(Collectors.toList());
+
+ return new Result>().ok(tsKvList);
+ }
+
+ /** mock数据推送,指定数据 */
+ @PostMapping("push/specify")
+ public Result specifyPush(@RequestBody TskvVO[] tskvVOList) {
+ List tsKvDTOList = new ArrayList<>();
+ for (TskvVO tskvVO : tskvVOList) {
+ TsKvDTO tsKvDTO =
+ new TsKvDTO(
+ tskvVO.getThingCode(),
+ tskvVO.getAttrKey(),
+ Optional.ofNullable(tskvVO.getTs()).orElse(System.currentTimeMillis()),
+ Optional.ofNullable(tskvVO.getVal()).orElse(String.valueOf(JMockData.mock(Integer.class))));
+ tsKvDTOList.add(tsKvDTO);
+ }
+ List dataList =
+ tsKvDTOList.stream().map(TsKvDTO::toDataProto).collect(Collectors.toList());
+
+ eventPublisher.publishEvent(
+ new QueueConsumerEvent(Topics.V1_TSKV_HISTORY.getValue(), dataList));
+
+ return new Result<>();
+ }
+
+ @Data
+ public static class TskvVO {
+ private String thingCode;
+ private String attrKey;
+ private Long ts;
+ private String val;
+ }
+}
diff --git a/application/src/main/java/com/thing/queue/DataTransferListener.java b/application/src/main/java/com/thing/queue/DataTransferListener.java
new file mode 100644
index 0000000..28955dc
--- /dev/null
+++ b/application/src/main/java/com/thing/queue/DataTransferListener.java
@@ -0,0 +1,69 @@
+package com.thing.queue;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import com.thing.queue.util.Topics;
+import com.thing.common.tskv.event.TsKvEvent;
+import org.springframework.stereotype.Component;
+import com.thing.common.data.event.QueueConsumerEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.context.ApplicationEventPublisher;
+
+import java.util.Map;
+import java.util.Arrays;
+import java.util.HashMap;
+import javax.annotation.PreDestroy;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Executors;
+import javax.annotation.PostConstruct;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * @description 数据传输监听,范围:
+ * 1. tskv入库事件
+ * 2. todo
+ */
+@Slf4j
+@Component
+public class DataTransferListener {
+
+ private final ApplicationEventPublisher publisher;
+ private final Map total = new HashMap<>();
+ private final ScheduledExecutorService schedule = Executors.newSingleThreadScheduledExecutor();
+
+ public DataTransferListener(ApplicationEventPublisher eventPublisher) {
+ this.publisher = eventPublisher;
+ }
+
+ //数据统一消费中转
+ @EventListener(QueueConsumerEvent.class)
+ void dataListener(QueueConsumerEvent consumerEvent) {
+ if (!consumerEvent.getList().isEmpty()) {
+ String topic = consumerEvent.getSource().toString();
+ if (topic.contains(Topics.V1_TSKV.getValue())) {
+ publisher.publishEvent(new TsKvEvent(topic, consumerEvent.getList()));
+ } else {
+ log.info("-----QueueConsumerEvent--其它数据-----{}----->{}", consumerEvent.getSource(), consumerEvent.getList());
+ }
+ String t = String.join("/", Arrays.copyOfRange(topic.split("/"), 0, 3));
+ if (total.get(t) != null) {
+ total.put(t, total.get(t) + consumerEvent.getList().size());
+ } else {
+ total.put(t, (long) consumerEvent.getList().size());
+ }
+ }
+ }
+
+ @PostConstruct
+ void dataTotalPrint() {
+ schedule.scheduleAtFixedRate(() -> {
+ log.info("------------数据累计处理--------->{}", total);
+ }, 1, 1, TimeUnit.MINUTES);
+ }
+
+ @PreDestroy
+ void stopActorSystem() {
+ schedule.shutdown();
+ }
+
+}
diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml
new file mode 100644
index 0000000..3042094
--- /dev/null
+++ b/application/src/main/resources/application.yml
@@ -0,0 +1,271 @@
+server:
+ port: 18080
+ servlet:
+ context-path: /thing
+spring:
+ cache:
+ type: caffeine # 支持 redis/caffeine, 当选择redis时,要在application.yml中配置redis连接信息
+ main:
+ allow-bean-definition-overriding: true
+ allow-circular-references: true
+ servlet:
+ multipart:
+ max-file-size: 100MB
+ max-request-size: 100MB
+ enabled: true
+ messages:
+ encoding: UTF-8
+ basename: i18n/messages
+ data:
+ redis:
+ host: 192.168.188.185
+ port: 7963
+ password: Sddt8888!
+ database: 5
+ #项目入口签名
+ title:
+ sign: ck #企业签名
+ technical:
+ phone:
+ map-bucket: geojson #地图文件路径
+
+queue:
+ type: in-memory # 队列类型: inMemory / disruptor
+ inMemory:
+ maxSize: 500
+ pollInterval: 100
+ disruptor:
+ maximumPoolSize: 8
+ bufferSize: 256 # 指定ringbuffer字节大小,当前值将乘1024
+ partitions:
+ hash_function_name: murmur3_128 # murmur3_32, murmur3_128 or sha256
+ core:
+ topic: queue_core
+ poll-interval: 1000
+ partitions: 30
+ debug: false
+ log-interval: 300
+ rabbitmq:
+ exchange_name:
+ host: localhost
+ port: 5673
+ virtual_host: /
+ username: guest
+ password: guest
+ automatic_recovery_enabled: false
+ connection_timeout: 60000
+ handshake_timeout: 10000
+ queue-properties:
+ core: x-max-length-bytes:1048576000;x-message-ttl:604800000
+#数据源配置
+database:
+ ts_kv:
+ type: postgresql # 时序数据存储类型 clickhouse/timescale/postgresql/tidb/mysql
+ latest:
+ type: postgresql # 最新数据存储类型 postgresql/timescale/mysql/tidb/clickhouse
+ save_maximumPoolSize: 12
+# 数据源及mybatis、mybatis-flex配置
+mybatis-flex:
+ typeAliasesPackage: com.thing.**.mapper
+ mapperLocations: classpath*:/mapper/**/*.xml
+ #本部分(Configuration)的配置都为 MyBatis 原生支持的配置,有关配置请参考:https://mybatis.org/mybatis-3/zh/configuration.html#%E8%AE%BE%E7%BD%AE%EF%BC%88settings%EF%BC%89
+ configuration:
+ mapUnderscoreToCamelCase: true
+ autoMappingBehavior: FULL
+ autoMappingUnknownColumnBehavior: NONE
+ cacheEnabled: true
+ global-config:
+ print-banner: true
+ normal-value-of-logic-delete: 0
+ deleted-value-of-logic-delete: 1
+ datasource:
+ pg:
+ type: com.zaxxer.hikari.HikariDataSource
+ url: jdbc:postgresql://192.168.188.185:5432/thing_v2
+ driver-class-name: org.postgresql.Driver
+ username: postgres
+ password: sddt8888
+ postgresql:
+ type: com.zaxxer.hikari.HikariDataSource
+ url: jdbc:postgresql://192.168.188.185:5432/thing_v2
+ driver-class-name: org.postgresql.Driver
+ username: postgres
+ password: sddt8888
+ sqlServer:
+ type: com.zaxxer.hikari.HikariDataSource
+ url: jdbc:sqlserver://127.0.0.1:1433;databaseName=销售生产其他
+ driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
+ username: czj
+ password: 1234
+
+# 区间统计计算相关配置
+calculate:
+ am_total:
+ offset: 24 #当数据出现断点时,向后偏移查询多少小时
+ interval: 15 # 分区间统计,间隔时长(分)1/3/5/10/15/20/30/60
+ keys: A29,B2,C2,C6,D2,D4,E3,E4,F4,G2,G4,H2,I2,I4,K2,N2,N4,P4,Q2,R2,R4,S2,S4,F2,T2,T4,U2,U4,J2,J4,L2,A30,P2,Q4,V2,V4,A29_rush,A29_peak,A29_valley,A29_normal,A29_generate,A30_rush,A30_peak,A30_valley,A30_normal,tce_C6,tce_A29,tce_E3,CO2_A29,CO2_C6,CO2_E3,CO2_run,tce_run,tce_E3,A201,A202,A204,tce_J2
+ ddmmyy: #例如:每月1号0时0分 开始统计年/月/日用量
+ start_hh: 0 #小时/天/月/年 用量统计开始的分钟数(0-59)
+ start_dd: 0 #天/月/年 用量统计开始的小时(0-23)
+ start_mm: 1 #月/年 用量统计开始的天(1-30)
+ start_yy: 1 #年 用量统计开始的月份(1-12)
+ maximumPoolSize: 12
+
+# 产品碳足迹 相关配置
+carbon:
+ syncButton: false
+ pub:
+ # 公共服务侧租户标识
+ tenantTag: 公共服务
+ api:
+ secret: nba!w^0@01
+
+#物管理相关配置
+thing:
+ # token 过期时间 30天
+ token:
+ expire: 2592000
+
+##数据解析配置
+nashorn:
+ # JS Eval max request timeout. 0 - no timeout
+ max_requests_timeout: 0
+ # Specify thread pool size for javascript executor service
+ js_thread_pool_size: 120
+ # Specify thread pool size for JavaScript sandbox resource monitor
+ monitor_thread_pool_size: 12
+ # Maximum CPU time in milliseconds allowed for script execution
+ max_cpu_time: 8000
+tbel:
+ # JS Eval max request timeout. 0 - no timeout
+ max_requests_timeout: 0
+ # Specify thread pool size for javascript executor service
+ thread_pool_size: 100
+ # Maximum allowed TBEL script execution memory
+ max_memory_limit_mb: 8
+ compiled_scripts_cache_size: 1000
+aviator:
+ # JS Eval max request timeout. 0 - no timeout
+ max_requests_timeout: 0
+ # Specify thread pool size for javascript executor service
+ js_thread_pool_size: 100
+ # Whether to put capturing groups into passed-in env map
+ # when regular-expression pattern matches
+ put_capturing_groups_into_env: false
+ # Max loop count to prevent too much CPU consumption. If it's value is zero or negative, it means
+ # no limitation on loop count.Default is zero.
+ max_loop_count: 1000
+#队列相关配置
+transport:
+ # Enable/disable http/mqtt/... transport protocols (has higher priority than certain protocol's 'enabled' property)
+ api_enabled: true
+ sessions:
+ inactivity_timeout: 300000
+ report_timeout: 30000
+ rate_limits:
+ enabled: false
+ # 1s 10次,60s 300次
+ device: 10:1,300:60
+ # Local HTTP transport parameters
+ http:
+ # Enable/disable http transport protocol.
+ enabled: false
+ request_timeout: 60000
+ # Local MQTT transport parameters
+ mqtt:
+ # Enable/disable mqtt transport protocol.
+ enabled: false
+ bind_address: 0.0.0.0
+ bind_port: 1883
+ timeout: 10000
+ netty:
+ leak_detector_level: DISABLED
+ boss_group_thread_count: 1
+ worker_group_thread_count: 12
+ max_payload_size: 65536
+ so_keep_alive: false
+#告警模块 配置
+alarm:
+ event_bus:
+ queue_size: 50
+ core_pool_size: 5
+ max_pool_size: 20
+
+#swagger 文档配置
+springdoc:
+ swagger-ui:
+ path: /swagger-ui.html
+ packages-to-scan: com.thing
+ api-docs:
+ enabled: true
+# knife4j的增强配置,不需要增强可以不配
+knife4j:
+ enable: true
+ setting:
+ language: zh_cn
+#数据过滤配置
+filter:
+ rule:
+ enable: false
+#项目状态
+management:
+ health:
+ redis:
+ enabled: false
+ endpoints:
+ enabled-by-default: true #暴露所有端点信息
+ web:
+ exposure:
+ include: '*' #以web方式暴露
+
+# 缓存管理
+cache-manager:
+ specs:
+ security:
+ timeToLiveInMinutes: 10
+ maxSize: 50
+ thingModel:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ authThingCodes:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ thingEntity:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ thingDict:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ thingDictRelation:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ thingDetailRelation:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ thingRootRelation:
+ timeToLiveInMinutes: 1440
+ maxSize: 10000
+ thingCalcConfig:
+ timeToLiveInMinutes: 525600
+ maxSize: 10000
+ filterRule:
+ timeToLiveInMinutes: 525600
+ maxSize: 10000
+ alarmRule:
+ timeToLiveInMinutes: 525600
+ maxSize: 1000
+ alarmRuleEntity:
+ timeToLiveInMinutes: 525600
+ maxSize: 1000
+ alarmRuleAction:
+ timeToLiveInMinutes: 525600
+ maxSize: 1000
+ scriptInfo:
+ timeToLiveInMinutes: 525600
+ maxSize: 1000
+ mockDataConfig:
+ timeToLiveInMinutes: 525600
+ maxSize: 1000
+ mockDataLatestTime:
+ timeToLiveInMinutes: 525600
+ maxSize: 1000
diff --git a/application/src/main/resources/logback.xml b/application/src/main/resources/logback.xml
new file mode 100644
index 0000000..b3fe325
--- /dev/null
+++ b/application/src/main/resources/logback.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+ logback
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ info
+
+
+ ${CONSOLE_LOG_PATTERN}
+
+ UTF-8
+
+
+
+
+
+
+
+
+
+ ${log.path}/debug.log
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+ UTF-8
+
+
+
+
+ ${log.path}/debug/debug-%d{yyyy-MM-dd}.%i.log
+
+ 100MB
+
+
+ 15
+
+
+
+ debug
+ ACCEPT
+ DENY
+
+
+
+
+
+
+ ${log.path}/info.log
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+ UTF-8
+
+
+
+
+ ${log.path}/info/info-%d{yyyy-MM-dd}.%i.log
+
+ 2048MB
+
+
+ 90
+
+
+
+ info
+ ACCEPT
+ DENY
+
+
+
+
+
+
+ ${log.path}/warn.log
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+ UTF-8
+
+
+
+ ${log.path}/warn/warn-%d{yyyy-MM-dd}.%i.log
+
+ 1024MB
+
+
+ 365
+
+
+
+ warn
+ ACCEPT
+ DENY
+
+
+
+
+
+
+
+ ${log.path}/error.log
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+ UTF-8
+
+
+
+ ${log.path}/error/error-%d{yyyy-MM-dd}.%i.log
+
+ 1024MB
+
+
+ 365
+
+
+
+ ERROR
+ ACCEPT
+ DENY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/resources/static/favicon.ico b/application/src/main/resources/static/favicon.ico
new file mode 100644
index 0000000..dea688e
Binary files /dev/null and b/application/src/main/resources/static/favicon.ico differ
diff --git a/tools/code-generator/pom.xml b/tools/code-generator/pom.xml
new file mode 100644
index 0000000..96e6a99
--- /dev/null
+++ b/tools/code-generator/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ com.thing
+ tools
+ 5.1
+ ../pom.xml
+
+
+ com.thing.tools
+ code-generator
+ jar
+ ThingBI Server Modules code-generator
+
+ UTF-8
+
+
+
+
+ com.thing.modules
+ thing
+
+
+
+ org.freemarker
+ freemarker
+ 2.3.31
+
+
+
+
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/DataSourceInfo.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/DataSourceInfo.java
new file mode 100644
index 0000000..bf4d4f8
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/DataSourceInfo.java
@@ -0,0 +1,71 @@
+package com.thing.tools.codegenerator.config;
+
+import com.thing.tools.codegenerator.config.query.*;
+import com.thing.tools.codegenerator.entity.DataSourceEntity;
+import com.thing.tools.codegenerator.utils.DbType;
+import com.thing.tools.codegenerator.utils.DbUtils;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * 数据源信息
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Slf4j
+public class DataSourceInfo {
+ /** 数据源ID */
+ private Long id;
+ /** 数据库类型 */
+ private DbType dbType;
+ /** 数据库URL */
+ private String connUrl;
+ /** 用户名 */
+ private String username;
+ /** 密码 */
+ private String password;
+
+ private AbstractQuery dbQuery;
+
+ private Connection connection;
+
+ public DataSourceInfo(DataSourceEntity entity) {
+ this.id = entity.getId();
+ this.dbType = DbType.valueOf(entity.getDbType());
+ this.connUrl = entity.getConnUrl();
+ this.username = entity.getUsername();
+ this.password = entity.getPassword();
+
+ switch (dbType) {
+ case MySQL -> this.dbQuery = new MySqlQuery();
+ case Oracle -> this.dbQuery = new OracleQuery();
+ case SQLServer -> this.dbQuery = new SqlServerQuery();
+ case PostgreSQL -> this.dbQuery = new PostgreSqlQuery();
+ }
+
+ try {
+ this.connection = DbUtils.getConnection(this);
+ } catch (Exception e) {
+ log.error("connect error: ", e);
+ }
+ }
+
+ public DataSourceInfo(Connection connection) throws SQLException {
+ this.id = 0L;
+ this.dbType = DbType.valueOf(connection.getMetaData().getDatabaseProductName());
+
+ switch (dbType) {
+ case MySQL -> this.dbQuery = new MySqlQuery();
+ case Oracle -> this.dbQuery = new OracleQuery();
+ case SQLServer -> this.dbQuery = new SqlServerQuery();
+ case PostgreSQL -> this.dbQuery = new PostgreSqlQuery();
+ }
+
+ this.connection = connection;
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/AbstractQuery.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/AbstractQuery.java
new file mode 100644
index 0000000..8c3f81a
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/AbstractQuery.java
@@ -0,0 +1,59 @@
+package com.thing.tools.codegenerator.config.query;
+
+
+import com.thing.tools.codegenerator.utils.DbType;
+
+/**
+ * Query
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface AbstractQuery {
+
+ /**
+ * 数据库类型
+ */
+ DbType dbType();
+
+ /**
+ * 表信息查询 SQL
+ */
+ String tablesSql(String tableName);
+
+ /**
+ * 表名称
+ */
+ String tableName();
+
+ /**
+ * 表注释
+ */
+ String tableComment();
+
+ /**
+ * 表字段信息查询 SQL
+ */
+ String tableFieldsSql();
+
+ /**
+ * 字段名称
+ */
+ String fieldName();
+
+
+ /**
+ * 字段类型
+ */
+ String fieldType();
+
+
+ /**
+ * 字段注释
+ */
+ String fieldComment();
+
+ /**
+ * 主键字段
+ */
+ String fieldKey();
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/MySqlQuery.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/MySqlQuery.java
new file mode 100644
index 0000000..7b66a29
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/MySqlQuery.java
@@ -0,0 +1,68 @@
+package com.thing.tools.codegenerator.config.query;
+
+import com.thing.tools.codegenerator.utils.DbType;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * MySQL查询
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class MySqlQuery implements AbstractQuery {
+
+ @Override
+ public DbType dbType() {
+ return DbType.MySQL;
+ }
+
+ @Override
+ public String tablesSql(String tableName) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("select table_name, table_comment from information_schema.tables ");
+ sql.append("where table_schema = (select database()) ");
+ // 表名查询
+ if (StringUtils.isNotBlank(tableName)) {
+ sql.append("and table_name = '").append(tableName).append("' ");
+ }
+ sql.append("order by table_name asc");
+
+ return sql.toString();
+ }
+
+ @Override
+ public String tableName() {
+ return "table_name";
+ }
+
+ @Override
+ public String tableComment() {
+ return "table_comment";
+ }
+
+ @Override
+ public String tableFieldsSql() {
+ return "select column_name, data_type, column_comment, column_key from information_schema.columns "
+ + "where table_name = '%s' and table_schema = (select database()) order by ordinal_position";
+ }
+
+ @Override
+ public String fieldName() {
+ return "column_name";
+ }
+
+ @Override
+ public String fieldType() {
+ return "data_type";
+ }
+
+ @Override
+ public String fieldComment() {
+ return "column_comment";
+ }
+
+ @Override
+ public String fieldKey() {
+ return "column_key";
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/OracleQuery.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/OracleQuery.java
new file mode 100644
index 0000000..d83c007
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/OracleQuery.java
@@ -0,0 +1,73 @@
+package com.thing.tools.codegenerator.config.query;
+
+import com.thing.tools.codegenerator.utils.DbType;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Oracle查询
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class OracleQuery implements AbstractQuery {
+
+ @Override
+ public DbType dbType() {
+ return DbType.Oracle;
+ }
+
+ @Override
+ public String tablesSql(String tableName) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("select dt.table_name, dtc.comments from user_tables dt,user_tab_comments dtc ");
+ sql.append("where dt.table_name = dtc.table_name ");
+ //表名查询
+ if(StringUtils.isNotBlank(tableName)){
+ sql.append("and dt.table_name = '").append(tableName).append("' ");
+ }
+ sql.append("order by dt.table_name asc");
+
+ return sql.toString();
+ }
+
+ @Override
+ public String tableName() {
+ return "table_name";
+ }
+
+ @Override
+ public String tableComment() {
+ return "comments";
+ }
+
+ @Override
+ public String tableFieldsSql() {
+ return "SELECT A.COLUMN_NAME, A.DATA_TYPE, B.COMMENTS,DECODE(C.POSITION, '1', 'PRI') KEY FROM ALL_TAB_COLUMNS A "
+ + " INNER JOIN ALL_COL_COMMENTS B ON A.TABLE_NAME = B.TABLE_NAME AND A.COLUMN_NAME = B.COLUMN_NAME AND B.OWNER = '#schema'"
+ + " LEFT JOIN ALL_CONSTRAINTS D ON D.TABLE_NAME = A.TABLE_NAME AND D.CONSTRAINT_TYPE = 'P' AND D.OWNER = '#schema'"
+ + " LEFT JOIN ALL_CONS_COLUMNS C ON C.CONSTRAINT_NAME = D.CONSTRAINT_NAME AND C.COLUMN_NAME=A.COLUMN_NAME AND C.OWNER = '#schema'"
+ + "WHERE A.OWNER = '#schema' AND A.TABLE_NAME = '%s' ORDER BY A.COLUMN_ID ";
+ }
+
+ @Override
+ public String fieldName() {
+ return "COLUMN_NAME";
+ }
+
+
+ @Override
+ public String fieldType() {
+ return "DATA_TYPE";
+ }
+
+
+ @Override
+ public String fieldComment() {
+ return "COMMENTS";
+ }
+
+
+ @Override
+ public String fieldKey() {
+ return "KEY";
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/PostgreSqlQuery.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/PostgreSqlQuery.java
new file mode 100644
index 0000000..bee784e
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/PostgreSqlQuery.java
@@ -0,0 +1,72 @@
+package com.thing.tools.codegenerator.config.query;
+
+import com.thing.tools.codegenerator.utils.DbType;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * PostgreSql查询
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class PostgreSqlQuery implements AbstractQuery {
+
+ @Override
+ public DbType dbType() {
+ return DbType.PostgreSQL;
+ }
+
+ @Override
+ public String tablesSql(String tableName) {
+ StringBuilder sql = new StringBuilder();
+ sql.append(
+ "select t1.tablename, obj_description(relfilenode, 'pg_class') as comments from pg_tables t1, pg_class t2 ");
+ sql.append(
+ "where t1.tablename not like 'pg%' and t1.tablename not like 'sql_%' and t1.tablename = t2.relname ");
+ // 表名查询
+ if (StringUtils.isNotBlank(tableName)) {
+ sql.append("and t1.tablename = '").append(tableName).append("' ");
+ }
+
+ return sql.toString();
+ }
+
+ @Override
+ public String tableFieldsSql() {
+ return "select t2.attname as columnName, pg_type.typname as dataType, col_description(t2.attrelid,t2.attnum) as columnComment,"
+ + "(CASE t3.contype WHEN 'p' THEN 'PRI' ELSE '' END) as columnKey "
+ + "from pg_class as t1, pg_attribute as t2 inner join pg_type on pg_type.oid = t2.atttypid "
+ + "left join pg_constraint t3 on t2.attnum = t3.conkey[1] and t2.attrelid = t3.conrelid "
+ + "where t1.relname = '%s' and t2.attrelid = t1.oid and t2.attnum>0";
+ }
+
+ @Override
+ public String tableName() {
+ return "tablename";
+ }
+
+ @Override
+ public String tableComment() {
+ return "comments";
+ }
+
+ @Override
+ public String fieldName() {
+ return "columnName";
+ }
+
+ @Override
+ public String fieldType() {
+ return "dataType";
+ }
+
+ @Override
+ public String fieldComment() {
+ return "columnComment";
+ }
+
+ @Override
+ public String fieldKey() {
+ return "columnKey";
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/SqlServerQuery.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/SqlServerQuery.java
new file mode 100644
index 0000000..b6d123c
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/config/query/SqlServerQuery.java
@@ -0,0 +1,83 @@
+package com.thing.tools.codegenerator.config.query;
+
+import com.thing.tools.codegenerator.utils.DbType;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * SqlServer查询
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class SqlServerQuery implements AbstractQuery {
+
+ @Override
+ public DbType dbType() {
+ return DbType.SQLServer;
+ }
+
+ @Override
+ public String tablesSql(String tableName) {
+ StringBuilder sql = new StringBuilder();
+ sql.append(
+ "select cast(so.name as varchar(500)) as TABLE_NAME, cast(sep.value as varchar(500)) as COMMENTS from sysobjects so ");
+ sql.append(
+ "left JOIN sys.extended_properties sep on sep.major_id=so.id and sep.minor_id=0 where (xtype='U' or xtype='V') ");
+
+ // 表名查询
+ if (StringUtils.isNotBlank(tableName)) {
+ sql.append("and cast(so.name as varchar(500)) = '").append(tableName).append("' ");
+ }
+ sql.append(" order by cast(so.name as varchar(500))");
+
+ return sql.toString();
+ }
+
+ @Override
+ public String tableFieldsSql() {
+ return "SELECT cast(a.name AS VARCHAR(500)) AS TABLE_NAME,cast(b.name AS VARCHAR(500)) AS COLUMN_NAME, "
+ + "cast(c.VALUE AS NVARCHAR(500)) AS COMMENTS,cast(sys.types.name AS VARCHAR (500)) AS DATA_TYPE,"
+ + "(SELECT CASE count(1) WHEN 1 then 'PRI' ELSE '' END"
+ + " FROM syscolumns,sysobjects,sysindexes,sysindexkeys,systypes "
+ + " WHERE syscolumns.xusertype = systypes.xusertype AND syscolumns.id = object_id (a.name) AND sysobjects.xtype = 'PK'"
+ + " AND sysobjects.parent_obj = syscolumns.id AND sysindexes.id = syscolumns.id "
+ + " AND sysobjects.name = sysindexes.name AND sysindexkeys.id = syscolumns.id "
+ + " AND sysindexkeys.indid = sysindexes.indid "
+ + " AND syscolumns.colid = sysindexkeys.colid AND syscolumns.name = b.name) as 'KEY',"
+ + " b.is_identity isIdentity "
+ + " FROM ( select name,object_id from sys.tables UNION all select name,object_id from sys.views ) a "
+ + " INNER JOIN sys.columns b ON b.object_id = a.object_id "
+ + " LEFT JOIN sys.types ON b.user_type_id = sys.types.user_type_id "
+ + " LEFT JOIN sys.extended_properties c ON c.major_id = b.object_id AND c.minor_id = b.column_id "
+ + " WHERE a.name = '%s' and sys.types.name !='sysname' ";
+ }
+
+ @Override
+ public String tableName() {
+ return "TABLE_NAME";
+ }
+
+ @Override
+ public String tableComment() {
+ return "COMMENTS";
+ }
+
+ @Override
+ public String fieldName() {
+ return "COLUMN_NAME";
+ }
+
+ @Override
+ public String fieldType() {
+ return "DATA_TYPE";
+ }
+
+ @Override
+ public String fieldComment() {
+ return "COMMENTS";
+ }
+
+ @Override
+ public String fieldKey() {
+ return "KEY";
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/BaseClassController.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/BaseClassController.java
new file mode 100644
index 0000000..7a39fa8
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/BaseClassController.java
@@ -0,0 +1,65 @@
+package com.thing.tools.codegenerator.controller;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.core.web.response.Result;
+import com.thing.tools.codegenerator.entity.BaseClassEntity;
+import com.thing.tools.codegenerator.service.BaseClassService;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 基类管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@RestController
+@RequestMapping("devtools/baseclass")
+@RequiredArgsConstructor
+public class BaseClassController {
+ private final BaseClassService baseClassService;
+
+ @GetMapping("page")
+ public Result> page(@RequestParam Map params) {
+ PageData page = baseClassService.page(params);
+
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("list")
+ public Result> list() {
+ List list = baseClassService.list();
+
+ return new Result>().ok(list);
+ }
+
+ @GetMapping("{id}")
+ public Result get(@PathVariable("id") Long id) {
+ BaseClassEntity data = baseClassService.getById(id);
+
+ return new Result().ok(data);
+ }
+
+ @PostMapping
+ public Result save(@RequestBody BaseClassEntity entity) {
+ baseClassService.save(entity);
+ return new Result<>();
+ }
+
+ @PutMapping
+ public Result update(@RequestBody BaseClassEntity entity) {
+ baseClassService.updateById(entity);
+
+ return new Result<>();
+ }
+
+ @DeleteMapping
+ public Result delete(@RequestBody Long[] ids) {
+ baseClassService.batchDelete(ids);
+ return new Result<>();
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/DataSourceController.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/DataSourceController.java
new file mode 100644
index 0000000..dc906e5
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/DataSourceController.java
@@ -0,0 +1,74 @@
+package com.thing.tools.codegenerator.controller;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.core.web.response.Result;
+import com.thing.tools.codegenerator.config.DataSourceInfo;
+import com.thing.tools.codegenerator.entity.DataSourceEntity;
+import com.thing.tools.codegenerator.service.DataSourceService;
+import com.thing.tools.codegenerator.utils.DbUtils;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 数据源管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@RestController
+@RequestMapping("devtools/datasource")
+@RequiredArgsConstructor
+public class DataSourceController {
+ private final DataSourceService datasourceService;
+
+ @GetMapping("page")
+ public Result> page(@RequestParam Map params){
+ PageData page = datasourceService.page(params);
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("list")
+ public Result> list(){
+ List list = datasourceService.list();
+ return new Result>().ok(list);
+ }
+
+ @GetMapping("{id}")
+ public Result get(@PathVariable("id") Long id){
+ DataSourceEntity data = datasourceService.getById(id);
+ return new Result().ok(data);
+ }
+
+ @GetMapping("test/{id}")
+ public Result test(@PathVariable("id") Long id){
+ try {
+ DataSourceEntity entity = datasourceService.getById(id);
+ DbUtils.getConnection(new DataSourceInfo(entity));
+ return new Result().ok("连接成功");
+ } catch (Exception e) {
+ return new Result().error("连接失败,请检查配置信息");
+ }
+ }
+
+ @PostMapping
+ public Result save(@RequestBody DataSourceEntity entity){
+ datasourceService.save(entity);
+ return new Result<>();
+ }
+
+ @PutMapping
+ public Result update(@RequestBody DataSourceEntity entity){
+ datasourceService.updateById(entity);
+ return new Result<>();
+ }
+
+ @DeleteMapping
+ public Result delete(@RequestBody Long[] ids){
+ datasourceService.batchDelete(ids);
+ return new Result<>();
+ }
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/FieldTypeController.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/FieldTypeController.java
new file mode 100644
index 0000000..d61e0d7
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/FieldTypeController.java
@@ -0,0 +1,65 @@
+package com.thing.tools.codegenerator.controller;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.core.web.response.Result;
+import com.thing.tools.codegenerator.entity.FieldTypeEntity;
+import com.thing.tools.codegenerator.service.FieldTypeService;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 字段类型管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@RestController
+@RequestMapping("devtools/fieldtype")
+@RequiredArgsConstructor
+public class FieldTypeController {
+ private final FieldTypeService fieldTypeService;
+
+ @GetMapping("page")
+ public Result> page(@RequestParam Map params) {
+ PageData page = fieldTypeService.page(params);
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("{id}")
+ public Result get(@PathVariable("id") Long id) {
+ FieldTypeEntity data = fieldTypeService.getById(id);
+ return new Result().ok(data);
+ }
+
+ @GetMapping("list")
+ public Result> list() {
+ List list = fieldTypeService.list();
+ Set set =
+ list.stream().map(FieldTypeEntity::getAttrType).collect(Collectors.toSet());
+ return new Result>().ok(set);
+ }
+
+ @PostMapping
+ public Result save(@RequestBody FieldTypeEntity entity) {
+ fieldTypeService.save(entity);
+ return new Result<>();
+ }
+
+ @PutMapping
+ public Result update(@RequestBody FieldTypeEntity entity) {
+ fieldTypeService.updateById(entity);
+ return new Result<>();
+ }
+
+ @DeleteMapping
+ public Result delete(@RequestBody Long[] ids) {
+ fieldTypeService.batchDelete(ids);
+ return new Result<>();
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/GenParamController.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/GenParamController.java
new file mode 100644
index 0000000..9268d8f
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/GenParamController.java
@@ -0,0 +1,36 @@
+package com.thing.tools.codegenerator.controller;
+
+import com.google.gson.Gson;
+import com.thing.common.core.constants.Constant;
+import com.thing.common.core.web.response.Result;
+import com.thing.sys.biz.service.SysParamsService;
+import com.thing.tools.codegenerator.entity.GenParam;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 代码生成参数配置
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@RestController
+@RequestMapping("devtools/param")
+@RequiredArgsConstructor
+public class GenParamController {
+ private final SysParamsService sysParamsService;
+
+ @GetMapping("info")
+ public Result info() {
+ GenParam param =
+ sysParamsService.getValueObject(Constant.DEV_TOOLS_PARAM_KEY, GenParam.class);
+ return new Result().ok(param);
+ }
+
+ @PostMapping
+ public Result saveConfig(@RequestBody GenParam param) {
+ sysParamsService.updateValueByCode(Constant.DEV_TOOLS_PARAM_KEY, new Gson().toJson(param));
+ return new Result<>();
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/GeneratorController.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/GeneratorController.java
new file mode 100644
index 0000000..0a61bd2
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/GeneratorController.java
@@ -0,0 +1,118 @@
+package com.thing.tools.codegenerator.controller;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.core.web.response.Result;
+import com.thing.sys.biz.entity.DictType;
+import com.thing.sys.biz.service.SysDictTypeService;
+import com.thing.tools.codegenerator.config.DataSourceInfo;
+import com.thing.tools.codegenerator.entity.MenuEntity;
+import com.thing.tools.codegenerator.entity.TableFieldEntity;
+import com.thing.tools.codegenerator.entity.TableInfoEntity;
+import com.thing.tools.codegenerator.service.GeneratorService;
+import com.thing.tools.codegenerator.service.TableFieldService;
+import com.thing.tools.codegenerator.service.TableInfoService;
+import com.thing.tools.codegenerator.utils.DbUtils;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 代码生成
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@RestController
+@RequestMapping("devtools")
+@RequiredArgsConstructor
+public class GeneratorController {
+ private final GeneratorService generatorService;
+ private final TableInfoService tableInfoService;
+ private final TableFieldService tableFieldService;
+ private final SysDictTypeService sysDictTypeService;
+
+ @GetMapping("table/page")
+ public Result> pageTable(@RequestParam Map params) {
+ PageData page = tableInfoService.getPageData(params);
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("table/{id}")
+ public Result getTable(@PathVariable("id") Long id) {
+ TableInfoEntity table = tableInfoService.getById(id);
+ List fieldList = tableFieldService.getByTableName(table.getTableName());
+ table.setFields(fieldList);
+ return new Result().ok(table);
+ }
+
+ @PutMapping("table")
+ public Result updateTable(@RequestBody TableInfoEntity tableInfo) {
+ tableInfoService.updateById(tableInfo);
+ return new Result<>();
+ }
+
+ @DeleteMapping("table")
+ public Result deleteTable(@RequestBody Long[] ids) {
+ tableInfoService.deleteBatchIds(ids);
+ return new Result<>();
+ }
+
+ /** 获取数据源中所有表 */
+ @GetMapping("datasource/table/list/{id}")
+ public Result> getDataSourceTableList(@PathVariable("id") Long id) {
+ try {
+ // 初始化配置信息
+ DataSourceInfo info = generatorService.getDataSourceInfo(id);
+ List tableInfoList = DbUtils.getTablesInfoList(info);
+ return new Result>().ok(tableInfoList);
+ } catch (Exception e) {
+ return new Result>().error("数据源配置错误,请检查数据源配置!");
+ }
+ }
+
+ /** 导入数据源中的表 */
+ @PostMapping("datasource/table")
+ public Result datasourceTable(@RequestBody TableInfoEntity tableInfo) {
+ generatorService.datasourceTable(tableInfo);
+ return new Result<>();
+ }
+
+ /** 更新列数据 */
+ @PutMapping("table/field/{tableId}")
+ public Result updateTableField(
+ @PathVariable("tableId") Long tableId,
+ @RequestBody List tableFieldList) {
+ generatorService.updateTableField(tableId, tableFieldList);
+ return new Result<>();
+ }
+
+ @GetMapping("dict")
+ public Result> dict() {
+ List list = sysDictTypeService.getDictTypeList();
+ return new Result>().ok(list);
+ }
+
+ /** 生成代码 */
+ @PostMapping("generator")
+ public Result generator(@RequestBody TableInfoEntity tableInfo) {
+ // 保存表信息
+ tableInfoService.updateById(tableInfo);
+
+ // 生成代码
+ generatorService.generatorCode(tableInfo);
+
+ return new Result<>();
+ }
+
+ /** 创建菜单 */
+ @PostMapping("menu")
+ public Result menu(@RequestBody MenuEntity menu) {
+ // 创建菜单
+ generatorService.generatorMenu(menu);
+
+ return new Result<>();
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/TemplateController.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/TemplateController.java
new file mode 100644
index 0000000..2771044
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/controller/TemplateController.java
@@ -0,0 +1,83 @@
+package com.thing.tools.codegenerator.controller;
+
+import com.google.common.collect.Maps;
+import com.thing.common.core.exception.SysException;
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.core.web.response.Result;
+import com.thing.tools.codegenerator.entity.TemplateEntity;
+import com.thing.tools.codegenerator.service.TemplateService;
+import com.thing.tools.codegenerator.utils.GenUtils;
+
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * 模板管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@RestController
+@RequestMapping("devtools/template")
+@RequiredArgsConstructor
+public class TemplateController {
+ private final TemplateService templateService;
+
+ @GetMapping("page")
+ public Result> page(@RequestParam Map params) {
+ PageData page = templateService.page(params);
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("{id}")
+ public Result get(@PathVariable("id") Long id) {
+ TemplateEntity data = templateService.getById(id);
+ return new Result().ok(data);
+ }
+
+ @PostMapping
+ public Result save(@RequestBody TemplateEntity entity) {
+ try {
+ // 检查模板语法是否正确
+ GenUtils.getTemplateContent(entity.getContent(), Maps.newHashMap());
+ } catch (Exception e) {
+ throw new SysException("模板语法错误,请查看控制台报错信息!", e);
+ }
+ templateService.save(entity);
+ return new Result<>();
+ }
+
+ @PutMapping
+ public Result update(@RequestBody TemplateEntity entity) {
+ try {
+ // 检查模板语法是否正确
+ GenUtils.getTemplateContent(entity.getContent(), Maps.newHashMap());
+ } catch (Exception e) {
+ throw new SysException("模板语法错误,请查看控制台报错信息!", e);
+ }
+ templateService.updateById(entity);
+ return new Result<>();
+ }
+
+ @DeleteMapping
+ public Result delete(@RequestBody Long[] ids) {
+ templateService.batchDelete(ids);
+ return new Result<>();
+ }
+
+ /** 启用 */
+ @PutMapping("enabled")
+ public Result enabled(@RequestBody Long[] ids) {
+ templateService.updateStatusBatch(ids, 0);
+ return new Result<>();
+ }
+
+ /** 禁用 */
+ @PutMapping("disabled")
+ public Result disabled(@RequestBody Long[] ids) {
+ templateService.updateStatusBatch(ids, 1);
+ return new Result<>();
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/BaseClassEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/BaseClassEntity.java
new file mode 100644
index 0000000..0b992a6
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/BaseClassEntity.java
@@ -0,0 +1,39 @@
+package com.thing.tools.codegenerator.entity;
+
+import com.mybatisflex.annotation.Table;
+
+import lombok.Data;
+
+/**
+ * 基类管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Table("gen_base_class")
+public class BaseClassEntity {
+ /**
+ * id
+ */
+ private Long id;
+ /**
+ * 基类包名
+ */
+ private String packageName;
+ /**
+ * 基类编码
+ */
+ private String code;
+ /**
+ * 公共字段,多个用英文逗号分隔
+ */
+ private String fields;
+ /**
+ * 备注
+ */
+ private String remark;
+ /**
+ * 创建时间
+ */
+ private Long createDate;
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/DataSourceEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/DataSourceEntity.java
new file mode 100644
index 0000000..b1e83e7
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/DataSourceEntity.java
@@ -0,0 +1,49 @@
+package com.thing.tools.codegenerator.entity;
+
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.Table;
+
+import lombok.Data;
+
+/**
+ * 数据源管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Table("gen_datasource")
+public class DataSourceEntity {
+ /**
+ * id
+ */
+ @Id
+ private Long id;
+ /**
+ * 数据库类型 MySQL、Oracle、SQLServer、PostgreSQL
+ */
+ private String dbType;
+ /**
+ * 连接名
+ */
+ private String connName;
+ /**
+ * URL
+ */
+ private String connUrl;
+ /**
+ * 用户名
+ */
+ private String username;
+ /**
+ * 密码
+ */
+ private String password;
+ /**
+ * 状态 0:启用 1:禁用
+ */
+ private Integer status;
+ /**
+ * 创建时间
+ */
+ private Long createDate;
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/FieldTypeEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/FieldTypeEntity.java
new file mode 100644
index 0000000..55666c0
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/FieldTypeEntity.java
@@ -0,0 +1,38 @@
+package com.thing.tools.codegenerator.entity;
+
+
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.Table;
+
+import lombok.Data;
+
+/**
+ * 字段类型管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Table("gen_field_type")
+public class FieldTypeEntity {
+ /**
+ * id
+ */
+ @Id
+ private Long id;
+ /**
+ * 字段类型
+ */
+ private String columnType;
+ /**
+ * 属性类型
+ */
+ private String attrType;
+ /**
+ * 属性包名
+ */
+ private String packageName;
+ /**
+ * 创建时间
+ */
+ private Long createDate;
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/GenParam.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/GenParam.java
new file mode 100644
index 0000000..a30f231
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/GenParam.java
@@ -0,0 +1,25 @@
+
+package com.thing.tools.codegenerator.entity;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 代码生成参数配置
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+public class GenParam implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ private String packageName;
+ private String version;
+ private String author;
+ private String email;
+ private String backendPath;
+ private String frontendPath;
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/MenuEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/MenuEntity.java
new file mode 100644
index 0000000..12bea95
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/MenuEntity.java
@@ -0,0 +1,19 @@
+
+package com.thing.tools.codegenerator.entity;
+
+import lombok.Data;
+
+/**
+ * 创建菜单
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+public class MenuEntity {
+ private Long pid;
+ private String name;
+ private String icon;
+ private String moduleName;
+ private String className;
+
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TableFieldEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TableFieldEntity.java
new file mode 100644
index 0000000..cd9489f
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TableFieldEntity.java
@@ -0,0 +1,102 @@
+package com.thing.tools.codegenerator.entity;
+
+
+import com.mybatisflex.annotation.Column;
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.Table;
+
+import lombok.Data;
+
+/**
+ * 表字段信息
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Table("gen_table_field")
+public class TableFieldEntity {
+ @Id
+ private Long id;
+ /**
+ * 表ID
+ */
+ private Long tableId;
+ /**
+ * 表名
+ */
+ private String tableName;
+ /**
+ * 列名
+ */
+ private String columnName;
+ /**
+ * 类型
+ */
+ private String columnType;
+ /**
+ * 列说明
+ */
+ private String columnComment;
+ /**
+ * 列说明
+ */
+ @Column(ignore = true)
+ private String comment;
+
+ public String getComment() {
+ return this.columnComment;
+ }
+
+ /**
+ * 属性名
+ */
+ private String attrName;
+ /**
+ * 属性类型
+ */
+ private String attrType;
+ /**
+ * 属性包名
+ */
+ private String packageName;
+ /**
+ * 是否主键 0:否 1:是
+ */
+ private boolean isPk;
+ /**
+ * 是否必填 0:否 1:是
+ */
+ private boolean isRequired;
+ /**
+ * 是否表单字段 0:否 1:是
+ */
+ private boolean isForm;
+ /**
+ * 是否列表字段 0:否 1:是
+ */
+ private boolean isList;
+ /**
+ * 是否查询字段 0:否 1:是
+ */
+ private boolean isQuery;
+ /**
+ * 查询方式
+ */
+ private String queryType;
+ /**
+ * 表单类型
+ */
+ private String formType;
+ /**
+ * 字典名称
+ */
+ private String dictName;
+ /**
+ * 效验方式
+ */
+ private String validatorType;
+ /**
+ * 排序
+ */
+ private Integer sort;
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TableInfoEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TableInfoEntity.java
new file mode 100644
index 0000000..88d7f68
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TableInfoEntity.java
@@ -0,0 +1,83 @@
+package com.thing.tools.codegenerator.entity;
+
+import com.mybatisflex.annotation.Column;
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.Table;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 表信息
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Table("gen_table_info")
+public class TableInfoEntity {
+ @Id
+ private Long id;
+ /**
+ * 表名
+ */
+ private String tableName;
+ /**
+ * 实体类名称
+ */
+ private String className;
+ /**
+ * 功能名
+ */
+ private String tableComment;
+ /**
+ * 项目包名
+ */
+ private String packageName;
+ /**
+ * 项目版本号
+ */
+ private String version;
+ /**
+ * 作者
+ */
+ private String author;
+ /**
+ * 邮箱
+ */
+ private String email;
+ /**
+ * 后端生成路径
+ */
+ private String backendPath;
+ /**
+ * 前端生成路径
+ */
+ private String frontendPath;
+ /**
+ * 模块名
+ */
+ private String moduleName;
+ /**
+ * 子模块名
+ */
+ private String subModuleName;
+ /**
+ * 数据源ID
+ */
+ private Long datasourceId;
+ /**
+ * 基类ID
+ */
+ private Long baseclassId;
+ /**
+ * 时间
+ */
+ private Long createDate;
+ /**
+ * 表字段
+ */
+ @Column(ignore = true)
+ private List fields;
+
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TemplateEntity.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TemplateEntity.java
new file mode 100644
index 0000000..f8082ff
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/entity/TemplateEntity.java
@@ -0,0 +1,46 @@
+package com.thing.tools.codegenerator.entity;
+
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.Table;
+
+import lombok.Data;
+
+/**
+ * 模板管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Data
+@Table("gen_template")
+public class TemplateEntity {
+ /**
+ * id
+ */
+ @Id
+ private Long id;
+ /**
+ * 名称
+ */
+ private String name;
+ /**
+ * 内容
+ */
+ private String content;
+ /**
+ * 文件名
+ */
+ private String fileName;
+ /**
+ * 生成路径
+ */
+ private String path;
+ /**
+ * 状态 0:启用 1:禁用
+ */
+ private Integer status;
+ /**
+ * 创建时间
+ */
+ private Long createDate;
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/BaseClassMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/BaseClassMapper.java
new file mode 100644
index 0000000..9bc7b12
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/BaseClassMapper.java
@@ -0,0 +1,15 @@
+package com.thing.tools.codegenerator.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.thing.tools.codegenerator.entity.BaseClassEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 基类管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface BaseClassMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/DataSourceMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/DataSourceMapper.java
new file mode 100644
index 0000000..c63553a
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/DataSourceMapper.java
@@ -0,0 +1,15 @@
+package com.thing.tools.codegenerator.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.thing.tools.codegenerator.entity.DataSourceEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 数据源管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface DataSourceMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/FieldTypeMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/FieldTypeMapper.java
new file mode 100644
index 0000000..4fbbbfc
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/FieldTypeMapper.java
@@ -0,0 +1,26 @@
+package com.thing.tools.codegenerator.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.thing.tools.codegenerator.entity.FieldTypeEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Set;
+
+/**
+ * 字段类型管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface FieldTypeMapper extends BaseMapper {
+
+ /**
+ * 根据tableId,获取包列表
+ */
+ Set getPackageListByTableId(Long tableId);
+
+ /**
+ * 获取全部字段类型
+ */
+ Set list();
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/GeneratorMenuMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/GeneratorMenuMapper.java
new file mode 100644
index 0000000..65e542e
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/GeneratorMenuMapper.java
@@ -0,0 +1,18 @@
+package com.thing.tools.codegenerator.mapper;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Map;
+
+/**
+ * 创建菜单
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface GeneratorMenuMapper {
+
+ void generatorMenu(Map params);
+
+ void generatorMenuLanguage(Map params);
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TableFieldMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TableFieldMapper.java
new file mode 100644
index 0000000..f068056
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TableFieldMapper.java
@@ -0,0 +1,22 @@
+package com.thing.tools.codegenerator.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.thing.tools.codegenerator.entity.TableFieldEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 表
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface TableFieldMapper extends BaseMapper {
+
+ List getByTableName(String tableName);
+
+ void deleteByTableName(String tableName);
+
+ void deleteBatchTableIds(Long[] tableIds);
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TableInfoMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TableInfoMapper.java
new file mode 100644
index 0000000..8a222de
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TableInfoMapper.java
@@ -0,0 +1,17 @@
+package com.thing.tools.codegenerator.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.thing.tools.codegenerator.entity.TableInfoEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 列
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface TableInfoMapper extends BaseMapper {
+ TableInfoEntity getByTableName(String tableName);
+
+ void deleteByTableName(String tableName);
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TemplateMapper.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TemplateMapper.java
new file mode 100644
index 0000000..b8576a2
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/mapper/TemplateMapper.java
@@ -0,0 +1,18 @@
+package com.thing.tools.codegenerator.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.thing.tools.codegenerator.entity.TemplateEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Map;
+
+/**
+ * 模板管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Mapper
+public interface TemplateMapper extends BaseMapper {
+
+ int updateStatusBatch(Map map);
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/BaseClassService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/BaseClassService.java
new file mode 100644
index 0000000..fe342c3
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/BaseClassService.java
@@ -0,0 +1,20 @@
+package com.thing.tools.codegenerator.service;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.IBaseService;
+import com.thing.tools.codegenerator.entity.BaseClassEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 基类管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface BaseClassService extends IBaseService {
+
+ PageData page(Map params);
+
+ List list();
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/DataSourceService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/DataSourceService.java
new file mode 100644
index 0000000..d58ddc0
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/DataSourceService.java
@@ -0,0 +1,20 @@
+package com.thing.tools.codegenerator.service;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.IBaseService;
+import com.thing.tools.codegenerator.entity.DataSourceEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 数据源管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface DataSourceService extends IBaseService {
+
+ PageData page(Map params);
+
+ List list();
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/FieldTypeService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/FieldTypeService.java
new file mode 100644
index 0000000..ba9cba0
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/FieldTypeService.java
@@ -0,0 +1,26 @@
+
+
+package com.thing.tools.codegenerator.service;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.IBaseService;
+import com.thing.tools.codegenerator.entity.FieldTypeEntity;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 字段类型管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface FieldTypeService extends IBaseService {
+ PageData page(Map params);
+
+ Map getMap();
+
+ /**
+ * 根据tableId,获取包列表
+ */
+ Set getPackageListByTableId(Long tableId);
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/GeneratorService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/GeneratorService.java
new file mode 100644
index 0000000..3cf3b2b
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/GeneratorService.java
@@ -0,0 +1,26 @@
+package com.thing.tools.codegenerator.service;
+
+import com.thing.tools.codegenerator.config.DataSourceInfo;
+import com.thing.tools.codegenerator.entity.MenuEntity;
+import com.thing.tools.codegenerator.entity.TableFieldEntity;
+import com.thing.tools.codegenerator.entity.TableInfoEntity;
+
+import java.util.List;
+
+/**
+ * 代码生成
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface GeneratorService {
+
+ DataSourceInfo getDataSourceInfo(Long datasourceId);
+
+ void datasourceTable(TableInfoEntity tableInfo);
+
+ void updateTableField(Long tableId, List tableFieldList);
+
+ void generatorCode(TableInfoEntity tableInfo);
+
+ void generatorMenu(MenuEntity menu);
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TableFieldService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TableFieldService.java
new file mode 100644
index 0000000..c5dd8cf
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TableFieldService.java
@@ -0,0 +1,20 @@
+package com.thing.tools.codegenerator.service;
+
+import com.thing.common.orm.service.IBaseService;
+import com.thing.tools.codegenerator.entity.TableFieldEntity;
+
+import java.util.List;
+
+/**
+ * 列
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface TableFieldService extends IBaseService {
+
+ List getByTableName(String tableName);
+
+ void deleteByTableName(String tableName);
+
+ void deleteBatchTableIds(Long[] tableIds);
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TableInfoService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TableInfoService.java
new file mode 100644
index 0000000..52332d9
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TableInfoService.java
@@ -0,0 +1,23 @@
+package com.thing.tools.codegenerator.service;
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.IBaseService;
+import com.thing.tools.codegenerator.entity.TableInfoEntity;
+
+import java.util.Map;
+
+/**
+ * 表
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface TableInfoService extends IBaseService {
+
+ PageData page(Map params);
+
+ TableInfoEntity getByTableName(String tableName);
+
+ void deleteByTableName(String tableName);
+
+ void deleteBatchIds(Long[] ids);
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TemplateService.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TemplateService.java
new file mode 100644
index 0000000..a2f6f83
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/TemplateService.java
@@ -0,0 +1,24 @@
+package com.thing.tools.codegenerator.service;
+
+
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.IBaseService;
+import com.thing.tools.codegenerator.entity.TemplateEntity;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 模板管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public interface TemplateService extends IBaseService {
+
+ PageData page(Map params);
+
+ List list();
+
+ void updateStatusBatch(Long[] ids, int status);
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/BaseClassServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/BaseClassServiceImpl.java
new file mode 100644
index 0000000..e2e8052
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/BaseClassServiceImpl.java
@@ -0,0 +1,43 @@
+package com.thing.tools.codegenerator.service.impl;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.impl.BaseServiceImpl;
+import com.thing.tools.codegenerator.mapper.BaseClassMapper;
+import com.thing.tools.codegenerator.entity.BaseClassEntity;
+import com.thing.tools.codegenerator.service.BaseClassService;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 基类管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Service
+public class BaseClassServiceImpl extends BaseServiceImpl implements BaseClassService {
+
+ @Override
+ public QueryWrapper getWrapper(Map params){
+ String code = (String)params.get("code");
+ QueryWrapper wrapper = new QueryWrapper();
+ wrapper.like("code", code, StringUtils.isNotEmpty(code));
+ return wrapper;
+ }
+
+ @Override
+ public PageData page(Map params) {
+ return getPageData(params);
+ }
+
+ @Override
+ public List list() {
+ return mapper.selectAll();
+ }
+
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/DataSourceServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/DataSourceServiceImpl.java
new file mode 100644
index 0000000..7e1615e
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/DataSourceServiceImpl.java
@@ -0,0 +1,43 @@
+package com.thing.tools.codegenerator.service.impl;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.impl.BaseServiceImpl;
+import com.thing.tools.codegenerator.mapper.DataSourceMapper;
+import com.thing.tools.codegenerator.entity.DataSourceEntity;
+import com.thing.tools.codegenerator.service.DataSourceService;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 数据源管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Service
+public class DataSourceServiceImpl extends BaseServiceImpl implements DataSourceService {
+
+ public QueryWrapper getWrapper(Map params){
+ String connName = (String)params.get("connName");
+ String dbType = (String)params.get("dbType");
+ QueryWrapper wrapper = new QueryWrapper();
+ wrapper.like("conn_name", connName, StringUtils.isNotEmpty(connName));
+ wrapper.eq("db_type", dbType, StringUtils.isNotEmpty(dbType));
+ return wrapper;
+ }
+
+ @Override
+ public PageData page(Map params) {
+ return getPageData(params);
+ }
+
+ @Override
+ public List list() {
+ return mapper.selectListByQuery(QueryWrapper.create().eq(DataSourceEntity::getStatus, 0));
+ }
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/FieldTypeServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/FieldTypeServiceImpl.java
new file mode 100644
index 0000000..c0e161b
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/FieldTypeServiceImpl.java
@@ -0,0 +1,57 @@
+package com.thing.tools.codegenerator.service.impl;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.impl.BaseServiceImpl;
+import com.thing.tools.codegenerator.mapper.FieldTypeMapper;
+import com.thing.tools.codegenerator.entity.FieldTypeEntity;
+import com.thing.tools.codegenerator.service.FieldTypeService;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 字段类型管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Service
+public class FieldTypeServiceImpl extends BaseServiceImpl implements FieldTypeService {
+
+ public QueryWrapper getWrapper(Map params){
+ String attrType = (String)params.get("attrType");
+ String columnType = (String)params.get("columnType");
+
+ QueryWrapper wrapper = new QueryWrapper();
+ wrapper.like("attr_type", attrType, StringUtils.isNotEmpty(attrType));
+ wrapper.like("column_type", columnType, StringUtils.isNotEmpty(columnType));
+
+ return wrapper;
+ }
+
+ @Override
+ public PageData page(Map params) {
+ return getPageData(params);
+ }
+
+ @Override
+ public Map getMap() {
+ List list = mapper.selectAll();
+ Map map = new LinkedHashMap<>(list.size());
+ for(FieldTypeEntity entity : list){
+ map.put(entity.getColumnType().toLowerCase(), entity);
+ }
+ return map;
+ }
+
+ @Override
+ public Set getPackageListByTableId(Long tableId) {
+ return mapper.getPackageListByTableId(tableId);
+ }
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/GeneratorServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/GeneratorServiceImpl.java
new file mode 100644
index 0000000..aef0271
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/GeneratorServiceImpl.java
@@ -0,0 +1,342 @@
+package com.thing.tools.codegenerator.service.impl;
+
+import cn.hutool.core.io.FileUtil;
+import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.core.constants.Constant;
+import com.thing.common.core.exception.SysException;
+import com.thing.common.core.utils.DateTimeUtils;
+import com.thing.sys.biz.service.SysParamsService;
+import com.thing.tools.codegenerator.config.DataSourceInfo;
+import com.thing.tools.codegenerator.mapper.GeneratorMenuMapper;
+import com.thing.tools.codegenerator.entity.*;
+import com.thing.tools.codegenerator.service.*;
+import com.thing.tools.codegenerator.utils.DbUtils;
+import com.thing.tools.codegenerator.utils.GenUtils;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.File;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import javax.sql.DataSource;
+
+/**
+ * 代码生成
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GeneratorServiceImpl implements GeneratorService {
+ private final TableInfoService tableInfoService;
+ private final TableFieldService tableFieldService;
+ private final DataSourceService datasourceService;
+ private final FieldTypeService fieldTypeService;
+ private final BaseClassService baseClassService;
+ private final TemplateService templateService;
+ private final SysParamsService sysParamsService;
+ private final GeneratorMenuMapper generatorMenuMapper;
+ private final DataSource dataSource;
+
+ @Override
+ public DataSourceInfo getDataSourceInfo(Long datasourceId) {
+ //初始化配置信息
+ DataSourceInfo info = null;
+ if (datasourceId.intValue() == 0) {
+ try {
+ info = new DataSourceInfo(dataSource.getConnection());
+ } catch (SQLException e) {
+ log.error("connect error: ", e);
+ }
+ } else {
+ info = new DataSourceInfo(datasourceService.getById(datasourceId));
+ }
+
+ return info;
+ }
+
+
+ @Override
+ public void datasourceTable(TableInfoEntity tableInfo) {
+ //初始化配置信息
+ DataSourceInfo info = getDataSourceInfo(tableInfo.getDatasourceId());
+
+ TableInfoEntity table = tableInfoService.getByTableName(tableInfo.getTableName());
+ //表存在
+ if(table != null){
+ throw new SysException(tableInfo.getTableName() + "数据表已存在");
+ }
+
+ table = DbUtils.getTablesInfo(info, tableInfo.getTableName());
+
+ //代码生成器参数
+ GenParam param = sysParamsService.getValueObject(Constant.DEV_TOOLS_PARAM_KEY, GenParam.class);
+
+ //保存表信息
+ assert table != null;
+ table.setPackageName(param.getPackageName());
+ table.setVersion(param.getVersion());
+ table.setAuthor(param.getAuthor());
+ table.setEmail(param.getEmail());
+ table.setBackendPath(param.getBackendPath());
+ table.setFrontendPath(param.getFrontendPath());
+ table.setCreateDate(System.currentTimeMillis());
+ tableInfoService.save(table);
+
+ //获取原生列数据
+ List tableFieldList = DbUtils.getTableColumns(info, table.getId(), tableInfo.getTableName());
+ //初始化列数据
+ initFieldList(tableFieldList);
+ //批量保存列数据
+ tableFieldService.saveBatch(tableFieldList);
+
+ try {
+ //释放数据源
+ info.getConnection().close();
+ }catch (SQLException e){
+ log.error(e.getMessage());
+ }
+ }
+
+ @Override
+ public void updateTableField(Long tableId, List tableFieldList){
+ //删除旧列信息
+ tableFieldService.deleteBatchTableIds(new Long[]{tableId});
+
+ //保存新列数据
+ int sort = 0;
+ for(TableFieldEntity tableField : tableFieldList){
+ tableField.setSort(sort++);
+ tableFieldService.save(tableField);
+ }
+
+ }
+
+ /**
+ * 初始化列数据
+ */
+ private void initFieldList(List tableFieldList){
+ //字段类型、属性类型映射
+ Map fieldTypeMap = fieldTypeService.getMap();
+ int index = 0;
+ for(TableFieldEntity tableField : tableFieldList){
+ tableField.setAttrName(StringUtils.uncapitalize(GenUtils.columnToJava(tableField.getColumnName())));
+ //获取字段对应的类型
+ FieldTypeEntity fieldTypeMapping = fieldTypeMap.get(tableField.getColumnType().toLowerCase());
+ if(fieldTypeMapping == null){
+ //没找到对应的类型,则为Object类型
+ tableField.setAttrType("Object");
+ }else {
+ tableField.setAttrType(fieldTypeMapping.getAttrType());
+ tableField.setPackageName(fieldTypeMapping.getPackageName());
+ }
+
+ tableField.setList(true);
+ tableField.setForm(true);
+
+ tableField.setQueryType("=");
+ tableField.setFormType("text");
+
+ tableField.setSort(index++);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void generatorCode(TableInfoEntity tableInfo) {
+ //删除旧表信息
+ tableInfoService.deleteByTableName(tableInfo.getTableName());
+ //删除旧列信息
+ tableFieldService.deleteByTableName(tableInfo.getTableName());
+
+ //保存新表信息
+ tableInfoService.save(tableInfo);
+ //保存新列信息
+ tableFieldService.saveBatch(tableInfo.getFields());
+
+ //数据模型
+ Map dataModel = new HashMap<>();
+ //项目信息
+ dataModel.put("package", tableInfo.getPackageName());
+ dataModel.put("packagePath", tableInfo.getPackageName().replace(".", File.separator));
+ dataModel.put("version", tableInfo.getVersion());
+ dataModel.put("moduleName", tableInfo.getModuleName());
+
+ String subModuleName = tableInfo.getSubModuleName();
+ if(StringUtils.isBlank(subModuleName)){
+ subModuleName = null;
+ }
+ dataModel.put("subModuleName", subModuleName);
+ dataModel.put("backendPath", tableInfo.getBackendPath());
+ dataModel.put("frontendPath", tableInfo.getFrontendPath());
+ //开发者信息
+ dataModel.put("author", tableInfo.getAuthor());
+ dataModel.put("email", tableInfo.getEmail());
+ dataModel.put("datetime", DateTimeUtils.format(new Date(), DateTimeUtils.DATE_TIME_PATTERN_STR));
+ dataModel.put("date", DateTimeUtils.format(new Date(), DateTimeUtils.DATE_PATTERN_STR));
+ //表信息
+ dataModel.put("tableName", tableInfo.getTableName());
+ dataModel.put("tableComment", tableInfo.getTableComment());
+ dataModel.put("ClassName", tableInfo.getClassName());
+ dataModel.put("className", StringUtils.uncapitalize(tableInfo.getClassName()));
+ dataModel.put("classname", tableInfo.getClassName().toLowerCase());
+ dataModel.put("columnList", tableInfo.getFields());
+ //是否包含tenant_code,用于模板判断是否需要@DataFilter
+ dataModel.put("needDataFilter", tableInfo.getFields() != null && tableInfo.getFields().stream().anyMatch(item -> StringUtils.equals(item.getColumnName(), "tenant_code")));
+
+ //主键
+ for(TableFieldEntity tableField : tableInfo.getFields()){
+ if(tableField.isPk()){
+ dataModel.put("pk", tableField);
+ break;
+ }
+ }
+
+ //导入的包列表
+ Set imports = fieldTypeService.getPackageListByTableId(tableInfo.getId());
+ //过滤为空的数据
+ imports = imports.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet());
+ dataModel.put("imports", imports);
+
+ //基类
+ if(tableInfo.getBaseclassId() != null){
+ QueryWrapper queryWrapper = QueryWrapper.create().eq(BaseClassEntity::getId, tableInfo.getBaseclassId());
+ BaseClassEntity baseClassEntity = baseClassService.getMapper().selectOneByQuery(queryWrapper);
+ baseClassEntity.setPackageName(GenUtils.getTemplateContent(baseClassEntity.getPackageName(), dataModel));
+ dataModel.put("baseClassEntity", baseClassEntity);
+ }
+
+ //获取模板
+ List templateList = templateService.list();
+
+ //渲染模板并输出
+ for(TemplateEntity template : templateList){
+ dataModel.put("templateName", template.getName());
+ String content = GenUtils.getTemplateContent(template.getContent(), dataModel);
+ String path = GenUtils.getTemplateContent(template.getPath(), dataModel) + File.separator +
+ GenUtils.getTemplateContent(template.getFileName(), dataModel);
+ FileUtil.writeUtf8String(content, path);
+ System.out.println(path);
+ }
+ }
+
+ @Override
+ public void generatorMenu(MenuEntity menu) {
+ Map params = new HashMap<>();
+ params.put("pid", menu.getPid());
+ params.put("name", menu.getName());
+ params.put("icon", menu.getIcon());
+ params.put("type", 0);
+ int sort = 0;
+ params.put("sort", sort);
+ params.put("url", menu.getModuleName() + "/" + menu.getClassName().toLowerCase());
+ params.put("now", new Date());
+ //权限标识
+ String permission = menu.getModuleName() + ":" + menu.getClassName().toLowerCase();
+ //菜单id
+ Long menuId = new SnowFlakeIDKeyGenerator().nextId();
+
+ //菜单
+ params.put("id", menuId);
+ generatorMenuMapper.generatorMenu(params);
+ params.put("language", "en-US");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("language", "zh-CN");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("language", "zh-TW");
+ generatorMenuMapper.generatorMenuLanguage(params);
+
+ //查看
+ params.put("id", new SnowFlakeIDKeyGenerator().nextId());
+ params.put("pid", menuId);
+ params.put("permissions", permission + ":page," + permission + ":info");
+ params.put("icon", null);
+ params.put("type", 1);
+ params.put("sort", sort);
+ generatorMenuMapper.generatorMenu(params);
+ params.put("name", "View");
+ params.put("language", "en-US");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "查看");
+ params.put("language", "zh-CN");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "查看");
+ params.put("language", "zh-TW");
+ generatorMenuMapper.generatorMenuLanguage(params);
+
+ //新增
+ params.put("id", new SnowFlakeIDKeyGenerator().nextId());
+ params.put("pid", menuId);
+ params.put("permissions", permission + ":save");
+ params.put("sort", ++sort);
+ generatorMenuMapper.generatorMenu(params);
+ params.put("name", "Add");
+ params.put("language", "en-US");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "新增");
+ params.put("language", "zh-CN");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "新增");
+ params.put("language", "zh-TW");
+ generatorMenuMapper.generatorMenuLanguage(params);
+
+ //修改
+ params.put("id", new SnowFlakeIDKeyGenerator().nextId());
+ params.put("pid", menuId);
+ params.put("permissions", permission + ":update");
+ params.put("sort", ++sort);
+ generatorMenuMapper.generatorMenu(params);
+ params.put("name", "Edit");
+ params.put("language", "en-US");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "修改");
+ params.put("language", "zh-CN");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "修改");
+ params.put("language", "zh-TW");
+ generatorMenuMapper.generatorMenuLanguage(params);
+
+ //删除
+ params.put("id", new SnowFlakeIDKeyGenerator().nextId());
+ params.put("pid", menuId);
+ params.put("permissions", permission + ":delete");
+ params.put("sort", ++sort);
+ generatorMenuMapper.generatorMenu(params);
+ params.put("name", "Delete");
+ params.put("language", "en-US");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "删除");
+ params.put("language", "zh-CN");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "删除");
+ params.put("language", "zh-TW");
+ generatorMenuMapper.generatorMenuLanguage(params);
+
+ //导出
+ params.put("id", new SnowFlakeIDKeyGenerator().nextId());
+ params.put("pid", menuId);
+ params.put("permissions", permission + ":export");
+ params.put("sort", ++sort);
+ generatorMenuMapper.generatorMenu(params);
+ params.put("name", "Export");
+ params.put("language", "en-US");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "导出");
+ params.put("language", "zh-CN");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ params.put("name", "導出");
+ params.put("language", "zh-TW");
+ generatorMenuMapper.generatorMenuLanguage(params);
+ }
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TableFieldServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TableFieldServiceImpl.java
new file mode 100644
index 0000000..7901026
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TableFieldServiceImpl.java
@@ -0,0 +1,43 @@
+
+
+package com.thing.tools.codegenerator.service.impl;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.orm.service.impl.BaseServiceImpl;
+import com.thing.tools.codegenerator.mapper.TableFieldMapper;
+import com.thing.tools.codegenerator.entity.TableFieldEntity;
+import com.thing.tools.codegenerator.service.TableFieldService;
+
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 表
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Service
+public class TableFieldServiceImpl extends BaseServiceImpl implements TableFieldService {
+
+ @Override
+ public QueryWrapper getWrapper(Map params) {
+ return null;
+ }
+
+ @Override
+ public List getByTableName(String tableName) {
+ return mapper.getByTableName(tableName);
+ }
+
+ @Override
+ public void deleteByTableName(String tableName) {
+ mapper.deleteByTableName(tableName);
+ }
+
+ @Override
+ public void deleteBatchTableIds(Long[] tableIds) {
+ mapper.deleteBatchTableIds(tableIds);
+ }
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TableInfoServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TableInfoServiceImpl.java
new file mode 100644
index 0000000..3ba55c1
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TableInfoServiceImpl.java
@@ -0,0 +1,58 @@
+package com.thing.tools.codegenerator.service.impl;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.impl.BaseServiceImpl;
+import com.thing.tools.codegenerator.mapper.TableInfoMapper;
+import com.thing.tools.codegenerator.entity.TableInfoEntity;
+import com.thing.tools.codegenerator.service.TableFieldService;
+import com.thing.tools.codegenerator.service.TableInfoService;
+
+import lombok.RequiredArgsConstructor;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * 表
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Service
+@RequiredArgsConstructor
+public class TableInfoServiceImpl extends BaseServiceImpl implements TableInfoService {
+ private final TableFieldService tableFieldService;
+
+ @Override
+ public PageData page(Map params) {
+ return getPageData(params);
+ }
+
+ public QueryWrapper getWrapper(Map params){
+ String tableName = (String)params.get("tableName");
+ QueryWrapper wrapper = new QueryWrapper();
+ wrapper.like( "table_name", tableName, StringUtils.isNotEmpty(tableName));
+ return wrapper;
+ }
+
+ @Override
+ public TableInfoEntity getByTableName(String tableName) {
+ return mapper.getByTableName(tableName);
+ }
+
+ @Override
+ public void deleteByTableName(String tableName) {
+ mapper.deleteByTableName(tableName);
+ }
+
+ @Override
+ public void deleteBatchIds(Long[] ids) {
+ //删除表
+ batchDelete(ids);
+
+ //删除列
+ tableFieldService.deleteBatchTableIds(ids);
+ }
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TemplateServiceImpl.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TemplateServiceImpl.java
new file mode 100644
index 0000000..01525e1
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/service/impl/TemplateServiceImpl.java
@@ -0,0 +1,51 @@
+package com.thing.tools.codegenerator.service.impl;
+
+import com.mybatisflex.core.query.QueryWrapper;
+import com.thing.common.core.web.response.PageData;
+import com.thing.common.orm.service.impl.BaseServiceImpl;
+import com.thing.tools.codegenerator.mapper.TemplateMapper;
+import com.thing.tools.codegenerator.entity.TemplateEntity;
+import com.thing.tools.codegenerator.service.TemplateService;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 模板管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Service
+public class TemplateServiceImpl extends BaseServiceImpl
+ implements TemplateService {
+
+ @Override
+ public QueryWrapper getWrapper(Map params) {
+ String name = (String) params.get("name");
+ QueryWrapper wrapper = new QueryWrapper();
+ wrapper.like("name", name, StringUtils.isNotEmpty(name));
+ return wrapper;
+ }
+
+ @Override
+ public PageData page(Map params) {
+ return getPageData(params);
+ }
+
+ @Override
+ public List list() {
+ return mapper.selectListByQuery(QueryWrapper.create().eq(TemplateEntity::getStatus, 0));
+ }
+
+ @Override
+ public void updateStatusBatch(Long[] ids, int status) {
+ Map map = new HashMap<>(2);
+ map.put("ids", ids);
+ map.put("status", status);
+ mapper.updateStatusBatch(map);
+ }
+}
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/DbType.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/DbType.java
new file mode 100644
index 0000000..f00105f
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/DbType.java
@@ -0,0 +1,28 @@
+
+
+package com.thing.tools.codegenerator.utils;
+
+/**
+ * 数据库类型
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public enum DbType {
+ /**
+ * 支持MySQL、Oracle、SQLServer、PostgreSQL
+ */
+ MySQL("com.mysql.cj.jdbc.Driver"),
+ Oracle("oracle.jdbc.driver.OracleDriver"),
+ SQLServer("com.microsoft.sqlserver.jdbc.SQLServerDriver"),
+ PostgreSQL("org.postgresql.Driver");
+
+ private final String driverClass;
+
+ DbType(String driverClass) {
+ this.driverClass = driverClass;
+ }
+
+ public String getDriverClass() {
+ return driverClass;
+ }
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/DbUtils.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/DbUtils.java
new file mode 100644
index 0000000..f47d711
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/DbUtils.java
@@ -0,0 +1,148 @@
+
+
+package com.thing.tools.codegenerator.utils;
+
+import com.thing.tools.codegenerator.config.DataSourceInfo;
+import com.thing.tools.codegenerator.config.query.AbstractQuery;
+import com.thing.tools.codegenerator.entity.TableFieldEntity;
+import com.thing.tools.codegenerator.entity.TableInfoEntity;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DB工具类
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+@Slf4j
+public class DbUtils {
+ private static final int CONNECTION_TIMEOUTS_SECONDS = 6;
+
+ /**
+ * 获得数据库连接
+ *
+ * @param info
+ * @return
+ * @throws ClassNotFoundException
+ * @throws SQLException
+ */
+ public static Connection getConnection(DataSourceInfo info) throws ClassNotFoundException, SQLException {
+ DriverManager.setLoginTimeout(CONNECTION_TIMEOUTS_SECONDS);
+
+ Class.forName(info.getDbType().getDriverClass());
+
+ return DriverManager.getConnection(info.getConnUrl(), info.getUsername(), info.getPassword());
+ /* 使用oracle时放开
+ Connection connection = DriverManager.getConnection(info.getConnUrl(), info.getUsername(), info.getPassword());
+ if(info.getDbType() == DbType.Oracle){
+ ((OracleConnection)connection).setRemarksReporting(true);
+ }
+
+ return connection;*/
+ }
+
+
+ /**
+ * 获取数据库表信息
+ */
+ public static TableInfoEntity getTablesInfo(DataSourceInfo info, String tableName) {
+ try {
+ AbstractQuery dbQuery = info.getDbQuery();
+
+ //查询数据
+ PreparedStatement preparedStatement = info.getConnection().prepareStatement(dbQuery.tablesSql(tableName));
+ ResultSet rs = preparedStatement.executeQuery();
+ if (rs.next()) {
+ TableInfoEntity tableInfo = new TableInfoEntity();
+ tableInfo.setTableName(rs.getString(dbQuery.tableName()));
+ tableInfo.setClassName(GenUtils.columnToJava(tableInfo.getTableName()));
+ tableInfo.setTableComment(rs.getString(dbQuery.tableComment()));
+ tableInfo.setDatasourceId(info.getId());
+ return tableInfo;
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * 获取所有的数据库表
+ */
+ public static List getTablesInfoList(DataSourceInfo info) {
+ List tableInfoList = new ArrayList<>();
+ try {
+ AbstractQuery dbQuery = info.getDbQuery();
+
+ //查询数据
+ PreparedStatement preparedStatement = info.getConnection().prepareStatement(dbQuery.tablesSql(null));
+ ResultSet rs = preparedStatement.executeQuery();
+ while (rs.next()) {
+ TableInfoEntity tableInfo = new TableInfoEntity();
+ tableInfo.setTableName(rs.getString(dbQuery.tableName()));
+ tableInfo.setClassName(GenUtils.columnToJava(tableInfo.getTableName()));
+ tableInfo.setTableComment(rs.getString(dbQuery.tableComment()));
+ tableInfo.setDatasourceId(info.getId());
+ tableInfoList.add(tableInfo);
+ }
+
+ info.getConnection().close();
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+
+ return tableInfoList;
+ }
+
+
+ /**
+ * 获取表的列属性
+ *
+ * @param info 数据库配置文件
+ * @param tableName 表名
+ */
+ public static List getTableColumns(DataSourceInfo info, Long tableId, String tableName) {
+ List tableFieldList = new ArrayList<>();
+
+ try {
+ AbstractQuery dbQuery = info.getDbQuery();
+ String tableFieldsSql = dbQuery.tableFieldsSql();
+ if (info.getDbType() == DbType.Oracle) {
+ DatabaseMetaData md = info.getConnection().getMetaData();
+ tableFieldsSql = String.format(tableFieldsSql.replace("#schema", md.getUserName()), tableName);
+ } else {
+ tableFieldsSql = String.format(tableFieldsSql, tableName);
+ }
+ PreparedStatement preparedStatement = info.getConnection().prepareStatement(tableFieldsSql);
+ ResultSet rs = preparedStatement.executeQuery();
+ while (rs.next()) {
+ TableFieldEntity field = new TableFieldEntity();
+ field.setTableId(tableId);
+ field.setTableName(tableName);
+ field.setColumnName(rs.getString(dbQuery.fieldName()));
+ String columnType = rs.getString(dbQuery.fieldType());
+ if(columnType.indexOf(" ") != -1){
+ columnType = columnType.substring(0, columnType.indexOf(" "));
+ }
+ field.setColumnType(columnType);
+ field.setColumnComment(rs.getString(dbQuery.fieldComment()));
+ String key = rs.getString(dbQuery.fieldKey());
+ field.setPk(StringUtils.isNotBlank(key) && "PRI".equals(key.toUpperCase()));
+
+ tableFieldList.add(field);
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+
+ return tableFieldList;
+ }
+
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/GenUtils.java b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/GenUtils.java
new file mode 100644
index 0000000..c77e696
--- /dev/null
+++ b/tools/code-generator/src/main/java/com/thing/tools/codegenerator/utils/GenUtils.java
@@ -0,0 +1,56 @@
+
+
+package com.thing.tools.codegenerator.utils;
+
+import cn.hutool.core.map.MapUtil;
+
+import com.thing.common.core.exception.SysException;
+
+import freemarker.template.Template;
+
+import org.apache.commons.lang3.text.WordUtils;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Map;
+
+/**
+ * 代码生成器工具类
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class GenUtils {
+
+ /**
+ * 列名转换成Java属性名
+ */
+ public static String columnToJava(String columnName) {
+ return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
+ }
+
+ /**
+ * 获取模板渲染后的内容
+ * @param content 模板内容
+ * @param dataModel 数据模型
+ */
+ public static String getTemplateContent(String content, Map dataModel) {
+ if(MapUtil.isEmpty(dataModel)){
+ return content;
+ }
+ StringReader reader = new StringReader(content);
+ StringWriter sw = new StringWriter();
+ try {
+ //渲染模板
+ String templateName = dataModel.getOrDefault("templateName", "generator").toString();
+ Template template = new Template(templateName, reader, null, "utf-8");
+ template.process(dataModel, sw);
+ } catch (Exception e) {
+ throw new SysException("渲染模板失败,请检查模板语法", e);
+ }
+ content = sw.toString();
+ IOUtils.closeQuietly(reader);
+ IOUtils.closeQuietly(sw);
+ return content;
+ }
+}
\ No newline at end of file
diff --git a/tools/code-generator/src/main/resources/mapper/codegenerator/FieldTypeMapper.xml b/tools/code-generator/src/main/resources/mapper/codegenerator/FieldTypeMapper.xml
new file mode 100644
index 0000000..bb61919
--- /dev/null
+++ b/tools/code-generator/src/main/resources/mapper/codegenerator/FieldTypeMapper.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tools/code-generator/src/main/resources/mapper/codegenerator/GeneratorMenuMapper.xml b/tools/code-generator/src/main/resources/mapper/codegenerator/GeneratorMenuMapper.xml
new file mode 100644
index 0000000..365dda1
--- /dev/null
+++ b/tools/code-generator/src/main/resources/mapper/codegenerator/GeneratorMenuMapper.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tools/code-generator/src/main/resources/mapper/codegenerator/TableFieldMapper.xml b/tools/code-generator/src/main/resources/mapper/codegenerator/TableFieldMapper.xml
new file mode 100644
index 0000000..9932134
--- /dev/null
+++ b/tools/code-generator/src/main/resources/mapper/codegenerator/TableFieldMapper.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+ delete from gen_table_field where table_name = #{value}
+
+
+
+ delete from gen_table_field where table_id in
+
+ #{tableId}
+
+
+
\ No newline at end of file
diff --git a/tools/code-generator/src/main/resources/mapper/codegenerator/TableInfoMapper.xml b/tools/code-generator/src/main/resources/mapper/codegenerator/TableInfoMapper.xml
new file mode 100644
index 0000000..5a1af5a
--- /dev/null
+++ b/tools/code-generator/src/main/resources/mapper/codegenerator/TableInfoMapper.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ delete from gen_table_info where table_name = #{value}
+
+
+
\ No newline at end of file
diff --git a/tools/code-generator/src/main/resources/mapper/codegenerator/TemplateMapper.xml b/tools/code-generator/src/main/resources/mapper/codegenerator/TemplateMapper.xml
new file mode 100644
index 0000000..302072f
--- /dev/null
+++ b/tools/code-generator/src/main/resources/mapper/codegenerator/TemplateMapper.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ update gen_template set status = #{status} where id in
+
+ #{id}
+
+
+
+
\ No newline at end of file
diff --git a/tools/pom.xml b/tools/pom.xml
new file mode 100644
index 0000000..fa0144c
--- /dev/null
+++ b/tools/pom.xml
@@ -0,0 +1,23 @@
+
+
+ 4.0.0
+
+ com.thing
+ thingbi
+ 5.1
+
+ pom
+
+
+ code-generator
+ system-monitor
+
+
+ tools
+ ThingBI Server tools
+
+ ${basedir}/..
+
+
diff --git a/tools/system-monitor/pom.xml b/tools/system-monitor/pom.xml
new file mode 100644
index 0000000..2484cd8
--- /dev/null
+++ b/tools/system-monitor/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+
+ com.thing
+ tools
+ 5.1
+ ../pom.xml
+
+
+ com.thing.tools
+ system-monitor
+ jar
+ ThingBI Server Modules system-monitor
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ io.micrometer
+ micrometer-core
+
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+
+
+
\ No newline at end of file
diff --git a/tools/system-monitor/src/main/java/com/thing/tools/monitor/config/.gitkeep b/tools/system-monitor/src/main/java/com/thing/tools/monitor/config/.gitkeep
new file mode 100644
index 0000000..e69de29