From 193c9d5a8dd107b7f72db3d2b84a1941c6905bac Mon Sep 17 00:00:00 2001 From: q1279335527 <1279335527@qq.com> Date: Wed, 26 Mar 2025 17:02:02 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D250326?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apis/client/controller/DataTypeApi.java | 15 ++++++++++++++- .../main/resources/static/html/pages/ApiInfo.json | 2 +- .../step/executor/SimpleQueryExecutor.java | 6 +++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/DataTypeApi.java b/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/DataTypeApi.java index db0adba..f41239c 100644 --- a/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/DataTypeApi.java +++ b/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/DataTypeApi.java @@ -1,16 +1,24 @@ package xyz.thoughtset.viewer.apis.client.controller; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import xyz.thoughtset.viewer.common.api.controller.BaseController; import xyz.thoughtset.viewer.common.connector.linker.LinkerHelper; +import xyz.thoughtset.viewer.modules.ds.core.entity.LinkerConfig; +import xyz.thoughtset.viewer.modules.ds.core.service.LinkerConfigService; import xyz.thoughtset.viewer.modules.step.constants.TypeConstants; import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; @RestController public class DataTypeApi extends BaseController { + @Autowired + private LinkerConfigService linkerConfigService; @GetMapping("/dataType") public Object dataType(){ @@ -19,8 +27,13 @@ public class DataTypeApi extends BaseController { @GetMapping("/linkers") public Object linkers(){ + List linkerConfigs = linkerConfigService.list(); // return Arrays.asList("mysql5","mysql8","pgsql"); - return LinkerHelper.getConnectorKeys(); +// return LinkerHelper.getConnectorKeys(); + return Stream.concat( + LinkerHelper.getConnectorKeys().stream(), + linkerConfigs.stream().map(LinkerConfig::getTitle) + ).distinct().collect(Collectors.toList()); } } diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/ApiInfo.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/ApiInfo.json index f782ef3..4bbbf42 100644 --- a/apis/viewer-apis-client/src/main/resources/static/html/pages/ApiInfo.json +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/ApiInfo.json @@ -1023,7 +1023,7 @@ "actionType": "setValue", "args": { "value": { - "paramMappings": "${setTimeout(() => ISEMPTY(paramMappings)?ISTYPE(paramMappings,'array')?paramMappings:ARRAYMAP(event.data.queryBodyRespResult.responseData.params,item => {\"qpId\":item.id}):paramMappings, 100)\n}" + "paramMappings": "${ISEMPTY(paramMappings)?ISTYPE(paramMappings,'array')?paramMappings:ARRAYMAP(event.data.queryBodyRespResult.responseData.params,item => {\"qpId\":item.id}):paramMappings\n}" } } }, diff --git a/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/executor/SimpleQueryExecutor.java b/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/executor/SimpleQueryExecutor.java index ab0aeb8..7ad91fd 100644 --- a/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/executor/SimpleQueryExecutor.java +++ b/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/executor/SimpleQueryExecutor.java @@ -45,7 +45,8 @@ public class SimpleQueryExecutor { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); List list= new ArrayList<>(); try( - PreparedStatement statement = prepareStatement(boundSql,ds,parameterObject); + Connection connection = ds.getConnection(); + PreparedStatement statement = prepareStatement(boundSql,connection,parameterObject); ResultSet rs = getFirstResultSet(statement); ){ ResultSetMetaData data = rs.getMetaData(); @@ -71,9 +72,8 @@ public class SimpleQueryExecutor { return list; } - private PreparedStatement prepareStatement(BoundSql boundSql,DataSource ds,Object parameterObject) throws SQLException { + private PreparedStatement prepareStatement(BoundSql boundSql,Connection connection,Object parameterObject) throws SQLException { PreparedStatement stmt; - Connection connection = ds.getConnection(); String sql = boundSql.getSql(); stmt = connection.prepareStatement(sql); setParameters(stmt,boundSql,parameterObject); -- Gitee From 6899ef1f485909630526e3740268616cc59378d7 Mon Sep 17 00:00:00 2001 From: q1279335527 <1279335527@qq.com> Date: Mon, 7 Apr 2025 11:24:14 +0800 Subject: [PATCH 2/2] excel export --- README.md | 104 +++-- apis/viewer-apis-client/pom.xml | 17 + .../apis/client/controller/FileApi.java | 32 ++ .../src/main/resources/application-h2.yml | 4 +- .../src/main/resources/db/schema.sql | 33 ++ .../static/html/pages/exportDataInfo.json | 363 ++++++++++++++++++ .../resources/static/html/pages/index.json | 5 + apis/viewer-apis-service/pom.xml | 17 + .../service/controller/HelloController.java | 19 + .../src/main/resources/application-h2.yml | 2 +- commons/pom.xml | 1 + .../common/connector/linker/LinkerHelper.java | 5 + .../core/constants/FolderNameConstant.java | 13 + commons/viewer-common-envvar/pom.xml | 20 + .../envvar/CommonEnvVarAutoConfiguration.java | 11 + .../common/envvar/annotation/EnvPropSign.java | 10 + .../common/envvar/entity/BaseEnvMeta.java | 7 + .../main/resources/META-INF/spring.factories | 1 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + db/v.mv.db | Bin 0 -> 32768 bytes db/v.trace.db | 116 ++++++ modules/pom.xml | 2 + modules/viewer-modules-api/pom.xml | 5 + .../api/controller/EasyQueryController.java | 61 ++- modules/viewer-modules-ds/pom.xml | 1 - .../jdbc/self/linker/ManualConnBuilder.java | 6 +- modules/viewer-modules-excel/pom.xml | 27 ++ .../excel/ModuleExcelAutoConfiguration.java | 13 + .../modules/excel/dao/ExportDataInfoDao.java | 10 + .../modules/excel/entity/ExportDataInfo.java | 20 + .../excel/service/ExportDataInfoService.java | 11 + .../service/ExportDataInfoServiceImpl.java | 30 ++ .../main/resources/META-INF/spring.factories | 1 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + modules/viewer-modules-setting/pom.xml | 28 ++ .../ModuleSettingAutoConfiguration.java | 13 + .../constants/EnvVarDataTypeConstant.java | 8 + .../modules/setting/dao/EnvVarsDao.java | 10 + .../modules/setting/entity/EnvVars.java | 26 ++ .../setting/factory/EnvPropSignFactory.java | 76 ++++ .../setting/service/EnvVarsService.java | 11 + .../setting/service/EnvVarsServiceImpl.java | 49 +++ .../main/resources/META-INF/spring.factories | 1 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + pom.xml | 63 ++- .../Text - \345\211\257\346\234\254.xlsx" | Bin 0 -> 8854 bytes template/Text.xlsx | Bin 0 -> 8854 bytes 47 files changed, 1199 insertions(+), 56 deletions(-) create mode 100644 apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/FileApi.java create mode 100644 apis/viewer-apis-client/src/main/resources/static/html/pages/exportDataInfo.json create mode 100644 apis/viewer-apis-service/src/main/java/xyz/thoughtset/viewer/apis/service/controller/HelloController.java create mode 100644 commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/constants/FolderNameConstant.java create mode 100644 commons/viewer-common-envvar/pom.xml create mode 100644 commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/CommonEnvVarAutoConfiguration.java create mode 100644 commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/annotation/EnvPropSign.java create mode 100644 commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/entity/BaseEnvMeta.java create mode 100644 commons/viewer-common-envvar/src/main/resources/META-INF/spring.factories create mode 100644 commons/viewer-common-envvar/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 db/v.mv.db create mode 100644 db/v.trace.db create mode 100644 modules/viewer-modules-excel/pom.xml create mode 100644 modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/ModuleExcelAutoConfiguration.java create mode 100644 modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/dao/ExportDataInfoDao.java create mode 100644 modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/entity/ExportDataInfo.java create mode 100644 modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoService.java create mode 100644 modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoServiceImpl.java create mode 100644 modules/viewer-modules-excel/src/main/resources/META-INF/spring.factories create mode 100644 modules/viewer-modules-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 modules/viewer-modules-setting/pom.xml create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/ModuleSettingAutoConfiguration.java create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/constants/EnvVarDataTypeConstant.java create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/dao/EnvVarsDao.java create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/entity/EnvVars.java create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/factory/EnvPropSignFactory.java create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsService.java create mode 100644 modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsServiceImpl.java create mode 100644 modules/viewer-modules-setting/src/main/resources/META-INF/spring.factories create mode 100644 modules/viewer-modules-setting/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 "template/Text - \345\211\257\346\234\254.xlsx" create mode 100644 template/Text.xlsx diff --git a/README.md b/README.md index 335c596..e18edd1 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,89 @@ -# Viewer +# Viewer - 零代码API开发平台 -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +![License](https://img.shields.io/badge/license-MIT-blue.svg) +![SpringBoot](https://img.shields.io/badge/SpringBoot-3.x-green.svg) +![MySQL](https://img.shields.io/badge/MySQL-5.7%2B-orange) -#### 软件架构 -软件架构说明 +## 🚀 项目简介 +Viewer 是一个基于SpringBoot的**零代码API开发平台**,开发者只需通过可视化界面编写MyBatis风格的标准SQL语句,即可快速生成完整的HTTP RESTful API接口,无需编写任何Java业务代码。 -#### 安装教程 +## ✨ 核心特性 -1. xxxx -2. xxxx -3. xxxx +- **零代码开发**:告别Controller/Service/Dao编写 +- **MyBatis SQL支持**:直接使用熟悉的SQL语法开发接口 +- **可视化操作**:通过Web界面完成API开发全流程 +- **自动生成**:根据SQL自动生成Swagger文档和参数校验 +- **多数据源**:支持MySQL/Oracle/PostgreSQL等主流数据库 +- **高性能**:基于SpringBoot的轻量级架构 +- **实时生效**:支持动态创建、修改API;动态创建、修改数据源。热部署全程无感。 -#### 使用说明 +## 🚀 5分钟快速体验 +### 1. 下载运行 +```bash +# 下载最新JAR包(约15MB) -1. xxxx -2. xxxx -3. xxxx +#Window启动命令: +java -jar viewer-apis-service.jar -#### 参与贡献 +#Linux下后台进程启动命令: +nohup java -jar viewer-apis-service.jar >catalina.out 2>&1 & -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +#关掉项目: +ps -ef|grep java +kill 进程号 +``` +## 📖 使用指南 -#### 特技 +### 创建第一个API +1. 访问 `http://localhost:11791` 登录管理界面 +2. 在"SQL工作台"编写MyBatis风格SQL: + ```sql + SELECT * FROM users + WHERE username = #{username} + AND status = #{status} + ``` +3. 设置API路径(如`/api/v1/users`) +4. 点击"生成API"即可通过Swagger测试 + +## 📌 示例展示 + +![API生成界面截图](docs/screenshots/sql-editor.png) + +## ⚙️ 生产环境配置 +创建 `application.yml` 文件: +```yaml +server: + port: 8080 +spring: + datasource: + url: jdbc:mysql://localhost:3306/your_db + username: db_user + password: db_pass +``` +然后运行: +```bash +java -jar viewer-apis-service.jar --spring.config.location=application.yml +``` + +## 🤝 参与贡献 +欢迎提交Issue和PR,贡献流程: +1. Fork本项目 +2. 创建分支(`git checkout -b feature/xxx`) +3. 提交修改(`git commit -m 'feat: xxx'`) +4. 推送到远程(`git push origin feature/xxx`) +5. 创建Pull Request + +## 📜 开源协议 +MIT License - 自由修改和商用,但需保留原始版权声明 + +## ☎ 联系我们 +- Email: your-email@example.com +- GitHub Issues: https://github.com/your-repo/viewer/issues + +## 分支命名规则 +- `feat/*`:新功能开发 +- `fix/*`:问题修复 +- `docs/*`:文档更新 -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/apis/viewer-apis-client/pom.xml b/apis/viewer-apis-client/pom.xml index aecc95f..682a91d 100644 --- a/apis/viewer-apis-client/pom.xml +++ b/apis/viewer-apis-client/pom.xml @@ -24,4 +24,21 @@ + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + \ No newline at end of file diff --git a/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/FileApi.java b/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/FileApi.java new file mode 100644 index 0000000..5556863 --- /dev/null +++ b/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/FileApi.java @@ -0,0 +1,32 @@ +package xyz.thoughtset.viewer.apis.client.controller; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import xyz.thoughtset.viewer.common.api.controller.BaseController; +import xyz.thoughtset.viewer.common.connector.linker.LinkerHelper; +import xyz.thoughtset.viewer.modules.ds.core.entity.LinkerConfig; +import xyz.thoughtset.viewer.modules.ds.core.service.LinkerConfigService; +import xyz.thoughtset.viewer.modules.excel.service.ExportDataInfoService; +import xyz.thoughtset.viewer.modules.step.constants.TypeConstants; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RestController +@RequestMapping("/file/") +public class FileApi extends BaseController { + @Autowired + private ExportDataInfoService exportDataInfoService; + + @GetMapping("/template") + public Object template(){ + return exportDataInfoService.templateFiles(); + } + + + +} diff --git a/apis/viewer-apis-client/src/main/resources/application-h2.yml b/apis/viewer-apis-client/src/main/resources/application-h2.yml index 0507902..c5fed42 100644 --- a/apis/viewer-apis-client/src/main/resources/application-h2.yml +++ b/apis/viewer-apis-client/src/main/resources/application-h2.yml @@ -8,10 +8,12 @@ spring: restart: enabled: false #设置开启热部署 datasource: - url: jdbc:h2:file:./db/q;MODE=MYSQL; + url: jdbc:h2:file:./db/v;MODE=MYSQL;AUTO_SERVER=TRUE; username: query password: Q@123 h2: console: enabled: true path: /h2-console + settings: + web-allow-others: true diff --git a/apis/viewer-apis-client/src/main/resources/db/schema.sql b/apis/viewer-apis-client/src/main/resources/db/schema.sql index 4c15875..b66ec7e 100644 --- a/apis/viewer-apis-client/src/main/resources/db/schema.sql +++ b/apis/viewer-apis-client/src/main/resources/db/schema.sql @@ -11,6 +11,7 @@ CREATE TABLE IF NOT EXISTS ApiInfo ( statesCode INT DEFAULT 200 , queryType INT, url varchar(256), + cacheTime INT, PRIMARY KEY (id) ) ; @@ -113,4 +114,36 @@ CREATE TABLE IF NOT EXISTS BlockParam ( PRIMARY KEY (id) ) ; +CREATE TABLE IF NOT EXISTS LinkerConfig ( + `id` varchar(32) NOT NULL, + `title` varchar(32) DEFAULT NULL, + `pid` varchar(32) DEFAULT NULL, + `groupId` varchar(32) DEFAULT NULL, + `remark` text, + `orderNum` int(11) DEFAULT 0, + `createdAt` datetime(0) NOT NULL, + `updatedAt` datetime(0) NOT NULL, + `statesCode` int(11) DEFAULT 200, + `driverClassName` varchar(64) DEFAULT NULL, + `jarFilePath` varchar(256) NOT NULL, + `linkerType` varchar(32) DEFAULT NULL, + `otherSettings` text NULL, + `reactive` BIT, + PRIMARY KEY (`id`) +) ; + +CREATE TABLE IF NOT EXISTS queryparam ( + `id` varchar(32) NOT NULL, + `title` varchar(32) DEFAULT NULL, + `pid` varchar(32) DEFAULT NULL, + `groupId` varchar(32) DEFAULT NULL, + `remark` text NULL, + `orderNum` int(11) DEFAULT 0, + `createdAt` datetime(0) NOT NULL, + `updatedAt` datetime(0) NOT NULL, + `statesCode` int(11) DEFAULT 200, + `dataType` varchar(32) NOT NULL, + `defaultVal` varchar(32) DEFAULT NULL, + PRIMARY KEY (`id`) +) diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/exportDataInfo.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/exportDataInfo.json new file mode 100644 index 0000000..b71f6fd --- /dev/null +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/exportDataInfo.json @@ -0,0 +1,363 @@ +{ + "type": "page", + "title": "ExportDataInfo Edit Page", + "regions": [ + "body" + ], + "body": [ + { + "id": "u:ae337865be36", + "type": "crud2", + "mode": "table2", + "dsType": "api", + "syncLocation": true, + "primaryField": "id", + "api": { + "url": "/q/findList/exportDataInfo", + "method": "get" + }, + "filter": { + "type": "form", + "title": "条件查询", + "mode": "inline", + "columnCount": 3, + "clearValueOnHidden": true, + "behavior": [ + "SimpleQuery" + ], + "body": [ + { + "name": "title", + "label": "title", + "type": "input-text", + "size": "full", + "required": false, + "behavior": "SimpleQuery", + "id": "u:ed2062d3e33f" + }, + { + "name": "bodyId", + "label": "内部接口", + "type": "input-text", + "size": "full", + "required": false, + "behavior": "SimpleQuery", + "id": "u:3a483d7f4dff" + }, + { + "type": "select", + "label": "模板文件", + "name": "templateId", + "id": "u:eea252d677ca", + "size": "full", + "multiple": false, + "source": "/file/templates" + } + ], + "actions": [ + { + "type": "button", + "label": "新增", + "onEvent": { + "click": { + "actions": [ + { + "ignoreError": false, + "actionType": "drawer", + "drawer": { + "$ref": "modal-ref-1" + } + } + ] + } + }, + "id": "u:495cbd1496ed" + }, + { + "type": "reset", + "label": "重置", + "id": "u:610663e9f6bf" + }, + { + "type": "submit", + "label": "查询", + "level": "primary", + "id": "u:f4f361c9616f" + } + ], + "id": "u:dedec97ee903", + "feat": "Insert" + }, + "headerToolbar": [], + "footerToolbar": [], + "columns": [ + { + "type": "tpl", + "title": "id", + "name": "id", + "id": "u:82de4381e80c", + "placeholder": "-", + "width": 1, + "visible": false + }, + { + "type": "tpl", + "title": "title", + "name": "title", + "id": "u:a91fafbe411f" + }, + { + "type": "tpl", + "title": "内部接口", + "name": "bodyId", + "id": "u:21fb081d55f8", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "模板文件", + "name": "templateId", + "id": "u:2b705c684fdc", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "文件名设定", + "name": "fileName", + "id": "u:1066fa85169e", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "更新时间", + "name": "updatedAt", + "id": "u:395ebc9fa7fa", + "placeholder": "-" + } + ], + "editorSetting": { + "mock": { + "enable": true, + "maxDisplayRows": 5 + } + }, + "showHeader": true, + "rowSelection": false, + "loadType": "", + "itemActions": [ + { + "type": "button", + "label": "编辑", + "id": "u:99a29cab900e", + "level": "link", + "behavior": "Edit", + "onEvent": { + "click": { + "actions": [ + { + "actionType": "drawer", + "drawer": { + "$ref": "modal-ref-1" + } + } + ] + } + } + }, + { + "type": "button", + "label": "删除", + "id": "u:8cfaa874cae5", + "behavior": "Delete", + "className": "m-r-xs text-danger", + "level": "link", + "confirmText": "确认要删除数据", + "onEvent": { + "click": { + "actions": [ + { + "actionType": "ajax", + "api": { + "url": "/c/delete/exportDataInfo", + "method": "post", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "data": { + "pkey": "${id}" + }, + "dataType": "form-data" + }, + { + "actionType": "search", + "groupType": "component", + "componentId": "u:ae337865be36" + } + ] + } + } + } + ] + } + ], + "id": "u:114370fd8d4e", + "pullRefresh": { + "disabled": true + }, + "definitions": { + "modal-ref-1": { + "type": "drawer", + "body": [ + { + "id": "u:d58be313daab", + "type": "form", + "title": "编辑数据", + "mode": "horizontal", + "labelAlign": "left", + "dsType": "api", + "feat": "Edit", + "body": [ + { + "name": "id", + "label": "id", + "type": "input-text", + "id": "u:5e6c099e564c", + "visible": false + }, + { + "name": "title", + "label": "标题", + "type": "input-text", + "id": "u:35bdd5b7f4a1" + }, + { + "name": "bodyId", + "label": "内部接口", + "type": "input-text", + "id": "u:2b16fabc9f5f" + }, + { + "name": "fileName", + "label": "文件名设定", + "type": "input-text", + "id": "u:b7035a5b4192" + }, + { + "type": "select", + "label": "模板文件", + "name": "templateId", + "id": "u:0010b139a63b", + "multiple": false, + "source": { + "method": "get", + "url": "/file/template", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "required": true + }, + { + "type": "textarea", + "label": "备注", + "name": "remark", + "id": "u:d21c32475118", + "minRows": 3, + "maxRows": 20 + } + ], + "api": { + "url": "/c/save/exportDataInfo", + "method": "post", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "dataType": "json" + }, + "resetAfterSubmit": true, + "actions": [ + { + "type": "button", + "actionType": "cancel", + "label": "取消" + }, + { + "type": "button", + "actionType": "submit", + "label": "提交", + "level": "primary" + } + ], + "onEvent": { + "submitSucc": { + "actions": [ + { + "actionType": "search", + "groupType": "component", + "componentId": "u:ae337865be36" + } + ] + } + }, + "initApi": { + "url": "/q/findOne/exportDataInfo", + "method": "get", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "data": { + "pkey": "${id}" + }, + "sendOn": "${!ISEMPTY(id)}" + }, + "themeCss": { + "itemLabelClassName": { + "padding-and-margin": { + "marginTop": "var(--sizes-size-1)", + "marginRight": "var(--sizes-size-1)", + "marginBottom": "var(--sizes-size-1)", + "marginLeft": "var(--sizes-size-1)" + } + }, + "itemClassName": { + "padding-and-margin": {} + }, + "actionsControlClassName": { + "padding-and-margin": {} + }, + "bodyControlClassName": { + "padding-and-margin": {} + } + } + } + ], + "title": "编辑数据", + "size": "md", + "actions": [ + { + "type": "button", + "actionType": "cancel", + "label": "取消", + "id": "u:619bd80615e9" + }, + { + "type": "button", + "actionType": "submit", + "label": "提交", + "level": "primary", + "id": "u:3919d958179f" + } + ], + "actionType": "drawer", + "id": "u:05bb830eb829", + "showCloseButton": false, + "closeOnOutside": false, + "closeOnEsc": false, + "showErrorMsg": true, + "showLoading": true, + "draggable": false, + "resizable": false + } + } +} \ No newline at end of file diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json index 98ac57d..c1d4557 100644 --- a/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json @@ -27,6 +27,11 @@ "label": "设定接口", "url": "ApiInfo", "schemaApi": "/html/pages/ApiInfo.json" + }, + { + "label": "导出数据", + "url": "ExportDataInfo", + "schemaApi": "/html/pages/exportDataInfo.json" } ] } diff --git a/apis/viewer-apis-service/pom.xml b/apis/viewer-apis-service/pom.xml index a918ea4..d54e8c7 100644 --- a/apis/viewer-apis-service/pom.xml +++ b/apis/viewer-apis-service/pom.xml @@ -17,4 +17,21 @@ UTF-8 + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + \ No newline at end of file diff --git a/apis/viewer-apis-service/src/main/java/xyz/thoughtset/viewer/apis/service/controller/HelloController.java b/apis/viewer-apis-service/src/main/java/xyz/thoughtset/viewer/apis/service/controller/HelloController.java new file mode 100644 index 0000000..f8f2f40 --- /dev/null +++ b/apis/viewer-apis-service/src/main/java/xyz/thoughtset/viewer/apis/service/controller/HelloController.java @@ -0,0 +1,19 @@ +package xyz.thoughtset.viewer.apis.service.controller; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import xyz.thoughtset.viewer.common.api.controller.BaseController; + +@Slf4j +@RestController +public class HelloController extends BaseController { + + @GetMapping(value = "hello") + public String hello(){ + log.info("*********OK*********"); + return "hello"; + } +} diff --git a/apis/viewer-apis-service/src/main/resources/application-h2.yml b/apis/viewer-apis-service/src/main/resources/application-h2.yml index 92d46d6..e9a1c25 100644 --- a/apis/viewer-apis-service/src/main/resources/application-h2.yml +++ b/apis/viewer-apis-service/src/main/resources/application-h2.yml @@ -4,6 +4,6 @@ spring: restart: enabled: false #设置开启热部署 datasource: - url: jdbc:h2:file:./db/q;MODE=MYSQL; + url: jdbc:h2:file:./db/v;MODE=MYSQL;AUTO_SERVER=TRUE; username: query password: Q@123 \ No newline at end of file diff --git a/commons/pom.xml b/commons/pom.xml index 8bdba8e..995bbd1 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -16,6 +16,7 @@ viewer-common-api viewer-common-crud viewer-common-connector + viewer-common-envvar diff --git a/commons/viewer-common-connector/src/main/java/xyz/thoughtset/viewer/common/connector/linker/LinkerHelper.java b/commons/viewer-common-connector/src/main/java/xyz/thoughtset/viewer/common/connector/linker/LinkerHelper.java index c958018..68cc9a3 100644 --- a/commons/viewer-common-connector/src/main/java/xyz/thoughtset/viewer/common/connector/linker/LinkerHelper.java +++ b/commons/viewer-common-connector/src/main/java/xyz/thoughtset/viewer/common/connector/linker/LinkerHelper.java @@ -3,16 +3,21 @@ package xyz.thoughtset.viewer.common.connector.linker; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import xyz.thoughtset.viewer.common.connector.entity.bo.ConnectorMeta; import xyz.thoughtset.viewer.common.connector.entity.bo.Linker; +import java.security.Security; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @Slf4j public class LinkerHelper{ + static { + Security.addProvider(new BouncyCastleProvider()); + } @Getter private static final List connectorKeys = new ArrayList<>(); private static final Map connectorCache = new ConcurrentHashMap<>(); diff --git a/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/constants/FolderNameConstant.java b/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/constants/FolderNameConstant.java new file mode 100644 index 0000000..4d4afeb --- /dev/null +++ b/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/constants/FolderNameConstant.java @@ -0,0 +1,13 @@ +package xyz.thoughtset.viewer.common.core.constants; + +import java.io.File; + +public class FolderNameConstant { + public static final String LINKER = "link"; + public static final String TEMPLATE = "template"; + + public static String folderWithSep(String folderName,String fileName) { + return folderName + File.separator + fileName; + } + +} diff --git a/commons/viewer-common-envvar/pom.xml b/commons/viewer-common-envvar/pom.xml new file mode 100644 index 0000000..94742b9 --- /dev/null +++ b/commons/viewer-common-envvar/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + commons + ${revision} + + + viewer-common-envvar + + + 17 + 17 + UTF-8 + + + \ No newline at end of file diff --git a/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/CommonEnvVarAutoConfiguration.java b/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/CommonEnvVarAutoConfiguration.java new file mode 100644 index 0000000..0506dce --- /dev/null +++ b/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/CommonEnvVarAutoConfiguration.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.common.envvar; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +public class CommonEnvVarAutoConfiguration { +} diff --git a/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/annotation/EnvPropSign.java b/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/annotation/EnvPropSign.java new file mode 100644 index 0000000..19a4b91 --- /dev/null +++ b/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/annotation/EnvPropSign.java @@ -0,0 +1,10 @@ +package xyz.thoughtset.viewer.common.envvar.annotation; + +import java.lang.annotation.*; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +public @interface EnvPropSign { + boolean single() default false; +} diff --git a/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/entity/BaseEnvMeta.java b/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/entity/BaseEnvMeta.java new file mode 100644 index 0000000..374af3b --- /dev/null +++ b/commons/viewer-common-envvar/src/main/java/xyz/thoughtset/viewer/common/envvar/entity/BaseEnvMeta.java @@ -0,0 +1,7 @@ +package xyz.thoughtset.viewer.common.envvar.entity; + +public class BaseEnvMeta { + + + +} diff --git a/commons/viewer-common-envvar/src/main/resources/META-INF/spring.factories b/commons/viewer-common-envvar/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..01cf435 --- /dev/null +++ b/commons/viewer-common-envvar/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=xyz.thoughtset.viewer.common.envvar \ No newline at end of file diff --git a/commons/viewer-common-envvar/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/commons/viewer-common-envvar/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..c0316e2 --- /dev/null +++ b/commons/viewer-common-envvar/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.common.envvar.CommonEnvVarAutoConfiguration \ No newline at end of file diff --git a/db/v.mv.db b/db/v.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..1742c9b8b1c2d3681c32c481fbdcf60d985e99d5 GIT binary patch literal 32768 zcmeHQ&2JmW72jP^5+hr(oy7TY+;qcOwv;l=&g>_7G9^+LZHiJz%CJwu?sDiDkw`(N z94oy9DbN&X4>|Ub9(pLyOD_d_Pf--ep$L*=(SM;W3KRi)3EHC(Q`P z&JOp@yxHHpH#_s@z43YhXPw=y`*y)#Y2*I8q<|Df$+~YHcHS52Sg9a!GrtV4&1eONzZ+Y929U1xu!*oIf4Ii1ULd50geDi zfFr;W;0SO8I0762jsQo1Bk)8KSm*2iCyGC3&Jo}Ua0EC490861M}Q;15#R`L1ULd5 zfo}o}kk1};yS;)2E&+v`L-6%(bcwvBbH zXlY_QM8T$(ZflyUXnE_^?!mp>TR6A(@IkM8Kyoc7S3BI@y>0Ivl9JuCn@9U3J3`ZY zl)KG58c2&0dPG;&Y!_-cS{xyU3hUi>f~o?l)HLhAQR*Jllv_FKk>bIDeH4_EN9v?h z)o$lrK!8UGfN8bsG@w1uXB+nZm6hGDQzvb5KsqkD;!bSRfcb{~c2X^NHfDWD|4_MKj?d+1Aa*mSp$lgAH z0L2$*{;<>PR=f9dh;l3J(25G96;awkpZ2O(wBXm9eVZH=0#V97w08@Eq%Bf1XgP2@ zP8G=7GOMiLuH%$}!1n8d7p7E!+)}QAptHvLc*R#HVlgioq9v-LE}EhSeR*^0S5rbt znB9Z^&E0R!cuEYw&;+wY7ttJ3Ys<+i{w=m#68wrS=yBmaL0I|}dj7f~y#GGrA^rJ> zkiy>=KV>Puas)U690861M}Q;15#R`L1ULdo5Ex#62VV4O;6(U}1Nxy%A!c?N*Iqq{D%0AQT&n*cB~0f21)OaRz)%|3^(e**@9 z>3>ge3(`d)jr5joD~Jp%0hqL1OI3`thFh*d+W9EkfMYp2c1YTCtQOW(o8IKDe4gIe zicW8c;|u;lhK};fcES} zw2~wxY{UEn^)5_6du{^Svs2Ra)by-4)*yBYGO%!NSj+_B6quYjJH+G^ILt2$aS(*B zU^|?sSxLs8iH(sznE4qPBSmRsW7FVieIkUCBQmw3Ja+%^*rBYkl%q-1$-_A^> zl#y50i}m7a6WV^eSif7T-B?obGJT2KcD0&igw0B`T8^VFmDh^f@PZ-wt@xTFsBhFa zwShVx8fAwe@{!?5<)V3aYe3{b*sfP2-f9W!#R7Ya`vmKWv4`G+8{08^awfV`FD)y-O? zSuesnhN>F;=y3@(Wr@}eh?L5ALiEGUx(ctc<-f)#WuY{+Ys zdZW2~4Jv&nL8VkmcDA=-!5N5AsQRp&2}wl>dY-C5L#`Hq_Y$b&rzxL#yh?6?25xYj zWTQx+A`G>Yl`RB)tkNb^NZ?as`WQJL`nuj+)v=nRsHrRr zjSNFnbIZ#h&+EQOg%m7Csf^>|>`NO}$k#yG--%UrMwv+4flsJ03AEkF{0Nle%Q4DP zf|0bgR=L5I<4Gz;A?!bi60&#sQ? zm0!nZbG=-Lt>z|7Y8nyhH@7SZ3%`C@oSMEMoSk1dcmBfD&pdnax#wSa@zP6|h3rIn zrjF>@Kyay^y&kV;eab|727D&dGc}U~J^Rm?c_BrTe}+O+!*AthXjF^Fevjss-vBYb znfP;oM#MNQ7gUf_=RuN>qQ4j+;zY6x%qEj%lu2CxVg5%FVP4rR-Q{16V+*rycvjVj zT?hJOblec$m-M;i)YB7*uv(0gVI~etgr5Nse)j|srnHG9*yA;s2t$d~vmnENOC-b9 z&DC36h@a%t$CHI|GTeaqg=ZaE+1#v_i#3qgiy*PLk`KD0lLx94E3EUG$UX-m`{R>D zmJ%nDSv2t!0!pNw2buju@?R-tB}-fU)g}>>S$`(C7d@_F@6Gsz21~^F)t+Y<^h^gJ zATLZLAjasB7Dk#0$cym;5+Y6{ARf2L1~n*=xZZ*f&5&!Qix?uGYYjr$nYPqBw zv%N+cIU>js+Bxc#+vWNySf?7bqGv-qws=~C_1uuj!GE8d#rj&MTHY!)*P}{#OSAq* z+b?qRx-rIFGH%u8*A3pot4(;9@UZ(5XjL`wu&a&C6NaUesnz9pwHhK%q*%akGQH9= zurrbQp_>x@y^7ht-llsMPZ=Lxx=fv)+pvLscCxqU zUx9djW^}o+{H*A568}Tj}S_FeO%oa_UgdZ?!KLtf4GpjfuM%4#UA= z@roJr!h>btLnUGf!9PtxhJ-8$*%ER^S8RzyLdqb}MM6kIs)Te2nG(uN$Ppc}?S;RH zHhh8qb#-x8m=}N5gc)-~5rKp4S9~?SR(=Jiji?e)cDp(izHi0cI$W2XBf${Dr3c z!V%yIa0EC49088NH-o^i|9vnIzytq(+W`N6Qyw{2Y|j@^#|P+1IsMdvVW$MC!tAJ-qm0L;8Q^SK~B9~lGC!nmb^gZ_6X z7$DuY;Qvt|t@cEYw#i({CyWY6;=Owct>lpd!D$o`hezlA`yWUjOQ&nzXIB0eO9(a6 zhmHNQ2d{7ge-3d2e<5mv1}8B2e%B2A!v^osoewQV;@rfq?U-~Bh;J?3P zOW;8W{J`X|4#MFBn?G`4GZwb;3lJMm?fyo5i2SIvANLo`xF0PaGWWL;nEUBc8@ZOH zvReh)$U0{3f9(Z$=j(#_$xm2HXC~LZnF-_tVe0q4pees_1ULd50geDifFr;W;0SO8 kI0762jsQo1Bk+U~VEg~U{(G?huZH&jZP@=ePi_DIe(MVStore.java:291) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2035) + at org.h2.mvstore.db.Store.(Store.java:133) + at org.h2.engine.Database.(Database.java:326) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:344) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:124) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:137) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:360) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:202) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:461) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:550) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:98) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111) + at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:269) + at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:532) + at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:405) + at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:639) + at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:374) + at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at xyz.thoughtset.viewer.modules.api.service.ApiInfoServiceImpl$$SpringCGLIB$$0.getById() + at xyz.thoughtset.viewer.modules.api.controller.EasyQueryController.doQuery(EasyQueryController.java:32) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at xyz.thoughtset.viewer.common.api.advice.SuccessResponseAdvice.handleControllerMethod(SuccessResponseAdvice.java:22) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at xyz.thoughtset.viewer.modules.api.controller.EasyQueryController$$SpringCGLIB$$0.doQuery() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:257) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:190) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) + at java.base/java.lang.Thread.run(Thread.java:833) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: D:/WorkPlace/Viewer/db/v.mv.db [2.3.232/7]" [50000-232] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:566) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + ... 103 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: D:/WorkPlace/Viewer/db/v.mv.db [2.3.232/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:996) + at org.h2.mvstore.SingleFileStore.lockFileChannel(SingleFileStore.java:143) + at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:117) + at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:81) + at org.h2.mvstore.MVStore.(MVStore.java:286) + ... 97 more diff --git a/modules/pom.xml b/modules/pom.xml index 80868da..33dbba3 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -15,6 +15,8 @@ viewer-modules-step viewer-modules-ds viewer-modules-api + viewer-modules-setting + viewer-modules-excel diff --git a/modules/viewer-modules-api/pom.xml b/modules/viewer-modules-api/pom.xml index af10601..52375d4 100644 --- a/modules/viewer-modules-api/pom.xml +++ b/modules/viewer-modules-api/pom.xml @@ -26,6 +26,11 @@ xyz.thoughtset.viewer viewer-common-api + + + xyz.thoughtset.viewer + viewer-modules-excel + \ No newline at end of file diff --git a/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java b/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java index 0e18eba..c8a6d40 100644 --- a/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java +++ b/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java @@ -1,20 +1,28 @@ package xyz.thoughtset.viewer.modules.api.controller; +import cn.idev.excel.ExcelWriter; +import cn.idev.excel.FastExcel; +import cn.idev.excel.write.metadata.WriteSheet; +import cn.idev.excel.write.metadata.fill.FillConfig; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; import xyz.thoughtset.viewer.common.api.controller.BaseController; +import xyz.thoughtset.viewer.common.core.constants.FolderNameConstant; import xyz.thoughtset.viewer.modules.api.constants.ApiParamTypeConstant; import xyz.thoughtset.viewer.modules.api.entity.ApiInfo; import xyz.thoughtset.viewer.modules.api.entity.ApiParam; import xyz.thoughtset.viewer.modules.api.service.ApiInfoService; +import xyz.thoughtset.viewer.modules.excel.entity.ExportDataInfo; +import xyz.thoughtset.viewer.modules.excel.service.ExportDataInfoService; import xyz.thoughtset.viewer.modules.step.executor.SimpleBlockExecutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.*; @RestController @RequestMapping("/eq/") @@ -24,6 +32,8 @@ public class EasyQueryController extends BaseController { private ApiInfoService apiInfoService; @Autowired private SimpleBlockExecutor simpleBlockExecutor; + @Autowired + private ExportDataInfoService exportDataService; @GetMapping(value = "{subject}") @ResponseBody @@ -66,5 +76,48 @@ public class EasyQueryController extends BaseController { } + @GetMapping(value = "e/{subject}") + @ResponseBody + public void excel(@RequestParam(required = false) LinkedHashMap searchMap + , @PathVariable("subject") String subject, HttpServletResponse response) { + ExportDataInfo exportDataInfo = exportDataService.getById(subject); + if (exportDataInfo == null) { + throw new NullPointerException("exportData not found"); + } + Map data = (Map) doQuery(searchMap, exportDataInfo.getBodyId()); + String fileName = exportDataInfo.getFileName(); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); +// String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + + try ( + InputStream templateStream = new FileInputStream( + FolderNameConstant.folderWithSep(FolderNameConstant.TEMPLATE,exportDataInfo.getTemplateId())); + ExcelWriter writer = + FastExcel.write(response.getOutputStream()) + .withTemplate(templateStream).build()) { + WriteSheet writeSheet = FastExcel.writerSheet().build(); + + for (Map.Entry entry : data.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + writer.fill(value, writeSheet); + } + // 填充列表数据,开启 forceNewRow +// FillConfig config = FillConfig.builder().forceNewRow(true).build(); +// writer.fill(data, config, writeSheet); + + // 填充普通变量 +// Map map = new HashMap<>(); +// map.put("date", "2024年11月20日"); +// map.put("total", 1000); +// writer.fill(map, writeSheet); + writer.finish(); + }catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } diff --git a/modules/viewer-modules-ds/pom.xml b/modules/viewer-modules-ds/pom.xml index c98255d..e001f9c 100644 --- a/modules/viewer-modules-ds/pom.xml +++ b/modules/viewer-modules-ds/pom.xml @@ -23,7 +23,6 @@ - xyz.thoughtset.viewer viewer-common-connector diff --git a/modules/viewer-modules-ds/viewer-modules-ds-jdbc/viewer-modules-ds-jdbc-self/src/main/java/xyz/thoughtset/viewer/modules/ds/jdbc/self/linker/ManualConnBuilder.java b/modules/viewer-modules-ds/viewer-modules-ds-jdbc/viewer-modules-ds-jdbc-self/src/main/java/xyz/thoughtset/viewer/modules/ds/jdbc/self/linker/ManualConnBuilder.java index ab7748f..78110ce 100644 --- a/modules/viewer-modules-ds/viewer-modules-ds-jdbc/viewer-modules-ds-jdbc-self/src/main/java/xyz/thoughtset/viewer/modules/ds/jdbc/self/linker/ManualConnBuilder.java +++ b/modules/viewer-modules-ds/viewer-modules-ds-jdbc/viewer-modules-ds-jdbc-self/src/main/java/xyz/thoughtset/viewer/modules/ds/jdbc/self/linker/ManualConnBuilder.java @@ -4,6 +4,7 @@ package xyz.thoughtset.viewer.modules.ds.jdbc.self.linker; import lombok.SneakyThrows; import xyz.thoughtset.viewer.common.connector.entity.bo.ConnectorMeta; import xyz.thoughtset.viewer.common.connector.entity.bo.Linker; +import xyz.thoughtset.viewer.common.core.constants.FolderNameConstant; import xyz.thoughtset.viewer.modules.ds.jdbc.core.linker.JdbcConnBuilder; import java.io.File; @@ -27,7 +28,7 @@ public class ManualConnBuilder extends JdbcConnBuilder { String appDir = System.getProperty("user.dir"); // 构建相对路径指向 JDBC 驱动所在的目录 - String jarFilePath = "link"+File.separator+dataLinker.getJarFilePath(); + String jarFilePath = FolderNameConstant.LINKER+File.separator+dataLinker.getJarFilePath(); // File jarFile = new File(appDir, jdbcJarRelativePath); File file = new File(jarFilePath); if (!jarFilePath.startsWith("jar:file:")) { @@ -49,9 +50,6 @@ public class ManualConnBuilder extends JdbcConnBuilder { if (!file.exists()) { throw new RuntimeException("JDBC JAR file not found at: " + file.getAbsolutePath()); } - Class mysqldriverClass = loader.loadClass("com.mysql.cj.jdbc.Driver"); - Class driverClass = loader.loadClass("org.postgresql.Driver"); - Class driverClass1 = Class.forName("org.postgresql.Driver", true, classLoader); return createDataSource(buildConfig(connectorMeta, properties)); } } diff --git a/modules/viewer-modules-excel/pom.xml b/modules/viewer-modules-excel/pom.xml new file mode 100644 index 0000000..03a404c --- /dev/null +++ b/modules/viewer-modules-excel/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + modules + ${revision} + + + viewer-modules-excel + + + 17 + 17 + UTF-8 + + + + + cn.idev.excel + fastexcel + + + + \ No newline at end of file diff --git a/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/ModuleExcelAutoConfiguration.java b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/ModuleExcelAutoConfiguration.java new file mode 100644 index 0000000..f8964a8 --- /dev/null +++ b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/ModuleExcelAutoConfiguration.java @@ -0,0 +1,13 @@ +package xyz.thoughtset.viewer.modules.excel; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +@MapperScan(basePackages = "xyz.thoughtset.viewer.modules.excel.dao") +public class ModuleExcelAutoConfiguration { +} diff --git a/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/dao/ExportDataInfoDao.java b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/dao/ExportDataInfoDao.java new file mode 100644 index 0000000..b31a10d --- /dev/null +++ b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/dao/ExportDataInfoDao.java @@ -0,0 +1,10 @@ +package xyz.thoughtset.viewer.modules.excel.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import xyz.thoughtset.viewer.modules.excel.entity.ExportDataInfo; + +@Mapper +public interface ExportDataInfoDao extends BaseMapper { +} diff --git a/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/entity/ExportDataInfo.java b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/entity/ExportDataInfo.java new file mode 100644 index 0000000..ca98529 --- /dev/null +++ b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/entity/ExportDataInfo.java @@ -0,0 +1,20 @@ +package xyz.thoughtset.viewer.modules.excel.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import xyz.thoughtset.viewer.common.core.entity.BaseMeta; +import xyz.thoughtset.viewer.common.crud.core.annotation.ApiCRUDPower; + +@TableName +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiCRUDPower(insert = false,save = true,update = false,list = true) +public class ExportDataInfo extends BaseMeta { + private String bodyId; + private String templateId; + private String fileName; + +} diff --git a/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoService.java b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoService.java new file mode 100644 index 0000000..2ae7623 --- /dev/null +++ b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoService.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.modules.excel.service; + + +import xyz.thoughtset.viewer.common.crud.core.service.BaseService; +import xyz.thoughtset.viewer.modules.excel.entity.ExportDataInfo; + +import java.util.List; + +public interface ExportDataInfoService extends BaseService { + List templateFiles(); +} diff --git a/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoServiceImpl.java b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoServiceImpl.java new file mode 100644 index 0000000..e88d9d6 --- /dev/null +++ b/modules/viewer-modules-excel/src/main/java/xyz/thoughtset/viewer/modules/excel/service/ExportDataInfoServiceImpl.java @@ -0,0 +1,30 @@ +package xyz.thoughtset.viewer.modules.excel.service; + +import cn.hutool.core.io.FileUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import xyz.thoughtset.viewer.common.core.constants.FolderNameConstant; +import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl; +import xyz.thoughtset.viewer.modules.excel.dao.ExportDataInfoDao; +import xyz.thoughtset.viewer.modules.excel.entity.ExportDataInfo; + +import java.io.File; +import java.util.List; + +@Service +@Transactional +public class ExportDataInfoServiceImpl extends BaseServiceImpl implements ExportDataInfoService { + private static final List EMPTY_LIST = List.of(); + @Override + public List templateFiles() { + File folder = new File(FolderNameConstant.TEMPLATE); + if (folder.exists() && folder.isDirectory() && folder.canRead() && folder.canWrite() && folder.listFiles() != null && folder.listFiles().length > 0) { + return FileUtil.loopFiles(folder).stream() + .map(file -> file.getName()) + .toList(); + } + return EMPTY_LIST; + } + + +} diff --git a/modules/viewer-modules-excel/src/main/resources/META-INF/spring.factories b/modules/viewer-modules-excel/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..409f13d --- /dev/null +++ b/modules/viewer-modules-excel/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=xyz.thoughtset.viewer.modules.excel \ No newline at end of file diff --git a/modules/viewer-modules-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/modules/viewer-modules-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..6a7d2dd --- /dev/null +++ b/modules/viewer-modules-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.modules.excel.ModuleExcelAutoConfiguration \ No newline at end of file diff --git a/modules/viewer-modules-setting/pom.xml b/modules/viewer-modules-setting/pom.xml new file mode 100644 index 0000000..66cfd0b --- /dev/null +++ b/modules/viewer-modules-setting/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + modules + ${revision} + + + viewer-modules-setting + + + 17 + 17 + UTF-8 + + + + + + xyz.thoughtset.viewer + viewer-common-envvar + + + + \ No newline at end of file diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/ModuleSettingAutoConfiguration.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/ModuleSettingAutoConfiguration.java new file mode 100644 index 0000000..fad95ca --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/ModuleSettingAutoConfiguration.java @@ -0,0 +1,13 @@ +package xyz.thoughtset.viewer.modules.setting; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +@MapperScan(basePackages = "xyz.thoughtset.viewer.modules.setting") +public class ModuleSettingAutoConfiguration { +} diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/constants/EnvVarDataTypeConstant.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/constants/EnvVarDataTypeConstant.java new file mode 100644 index 0000000..c74fc37 --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/constants/EnvVarDataTypeConstant.java @@ -0,0 +1,8 @@ +package xyz.thoughtset.viewer.modules.setting.constants; + +public class EnvVarDataTypeConstant { + public static final Integer OBJ = 0; + public static final Integer MAP = 1; + + +} diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/dao/EnvVarsDao.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/dao/EnvVarsDao.java new file mode 100644 index 0000000..983be90 --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/dao/EnvVarsDao.java @@ -0,0 +1,10 @@ +package xyz.thoughtset.viewer.modules.setting.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import xyz.thoughtset.viewer.modules.setting.entity.EnvVars; + +@Mapper +public interface EnvVarsDao extends BaseMapper { +} diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/entity/EnvVars.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/entity/EnvVars.java new file mode 100644 index 0000000..df83a70 --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/entity/EnvVars.java @@ -0,0 +1,26 @@ +package xyz.thoughtset.viewer.modules.setting.entity; + +import cn.zhxu.bs.bean.SearchBean; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.ibatis.type.Alias; +import xyz.thoughtset.viewer.common.core.entity.BaseMeta; +import xyz.thoughtset.viewer.common.crud.core.annotation.ApiCRUDPower; + +import java.util.Date; + + +@NoArgsConstructor +@AllArgsConstructor +@Data +@TableName +@ApiCRUDPower(insert = false,update = false,list = true) +public class EnvVars extends BaseMeta { + protected String type; + protected String topic; + protected String payload; + + +} diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/factory/EnvPropSignFactory.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/factory/EnvPropSignFactory.java new file mode 100644 index 0000000..97b9d8e --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/factory/EnvPropSignFactory.java @@ -0,0 +1,76 @@ +package xyz.thoughtset.viewer.modules.setting.factory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.crud.core.annotation.ApiCRUDPower; +import xyz.thoughtset.viewer.common.crud.core.service.BaseService; +import xyz.thoughtset.viewer.common.envvar.annotation.EnvPropSign; +import xyz.thoughtset.viewer.modules.setting.constants.EnvVarDataTypeConstant; +import xyz.thoughtset.viewer.modules.setting.entity.EnvVars; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +@Component +public class EnvPropSignFactory { + @Value("${scan.package}") + private String scanPackage; + @Autowired + protected ObjectMapper objectMapper; + @Autowired + protected ApplicationContext applicationContext; + + private Map signMap = new HashMap<>(); + + @PostConstruct + public void init() { + // 创建扫描器,false 表示不检查父类 + ClassPathScanningCandidateComponentProvider scanner = + new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(EnvPropSign.class)); + // 扫描指定包 + Set beanDefinitions = scanner.findCandidateComponents(scanPackage); + for (BeanDefinition beanDefinition : beanDefinitions) { + try { + Class clazz = Class.forName(beanDefinition.getBeanClassName()); + String key = StringUtils.uncapitalize(clazz.getSimpleName()); + signMap.put(key,clazz); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + + public Class getSignType(String key) { + return signMap.get(key); + } + + public EnvPropSign getSignInfo(String key) { + return (EnvPropSign) signMap.get(key).getAnnotation(EnvPropSign.class); + } + + public Object getTargetData(String key,Object payload) { + Class clazz = getSignType(key); + return objectMapper.convertValue(payload,clazz); + } + + public Object loadData(EnvVars data) { + if (!(EnvVarDataTypeConstant.OBJ.equals(data.getType()))) { + return data.getPayload(); + } + return objectMapper.convertValue(data.getPayload(),getSignType(data.getTopic())); + } + + + +} diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsService.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsService.java new file mode 100644 index 0000000..51109fc --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsService.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.modules.setting.service; + + +import xyz.thoughtset.viewer.common.crud.core.service.BaseService; +import xyz.thoughtset.viewer.modules.setting.entity.EnvVars; + +public interface EnvVarsService extends BaseService { + + Object loadData(String varId); + +} diff --git a/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsServiceImpl.java b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsServiceImpl.java new file mode 100644 index 0000000..1909766 --- /dev/null +++ b/modules/viewer-modules-setting/src/main/java/xyz/thoughtset/viewer/modules/setting/service/EnvVarsServiceImpl.java @@ -0,0 +1,49 @@ +package xyz.thoughtset.viewer.modules.setting.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl; +import xyz.thoughtset.viewer.modules.setting.constants.EnvVarDataTypeConstant; +import xyz.thoughtset.viewer.modules.setting.dao.EnvVarsDao; +import xyz.thoughtset.viewer.modules.setting.entity.EnvVars; +import xyz.thoughtset.viewer.modules.setting.factory.EnvPropSignFactory; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Transactional +public class EnvVarsServiceImpl extends BaseServiceImpl implements EnvVarsService { + private static final String TARGET_DATA_KEY = "payload"; + + @Autowired + private EnvPropSignFactory signFactory; + + @SneakyThrows + @Override + public Object saveData(LinkedHashMap baseMap) { + Object targetData = baseMap.remove(TARGET_DATA_KEY); + EnvVars data = convertValue(baseMap); + String topic = data.getTopic(); + if (EnvVarDataTypeConstant.OBJ.equals(data.getType())) { + targetData = signFactory.getTargetData(topic, targetData); + } + data.setPayload(mapper.writeValueAsString(targetData)); + saveOrUpdate(data); + return data; + } + + @Override + public Object loadData(String varId) { + EnvVars vars = baseMapper.selectById(varId); + return signFactory.loadData(vars); + } +} diff --git a/modules/viewer-modules-setting/src/main/resources/META-INF/spring.factories b/modules/viewer-modules-setting/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..2dc0ba9 --- /dev/null +++ b/modules/viewer-modules-setting/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=xyz.thoughtset.viewer.modules.setting \ No newline at end of file diff --git a/modules/viewer-modules-setting/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/modules/viewer-modules-setting/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..720d49b --- /dev/null +++ b/modules/viewer-modules-setting/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.modules.setting.ModuleSettingAutoConfiguration \ No newline at end of file diff --git a/pom.xml b/pom.xml index b381e61..bf67d1a 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,8 @@ 2.3.1 5.4.1 33.1.0-jre + 1.76 + 1.1.0 @@ -116,6 +118,11 @@ spring-boot-starter-test test + + org.bouncycastle + bcprov-jdk18on + ${bouncycastle.version} + @@ -127,6 +134,11 @@ pom import + + cn.idev.excel + fastexcel + ${fastexcel.version} + xyz.thoughtset.viewer viewer-common-core @@ -167,6 +179,16 @@ viewer-modules-api ${revision} + + xyz.thoughtset.viewer + viewer-modules-excel + ${revision} + + + xyz.thoughtset.viewer + viewer-modules-setting + ${revision} + xyz.thoughtset.viewer viewer-modules-ds-jdbc-core @@ -182,6 +204,11 @@ viewer-modules-ds-jdbc-self ${revision} + + xyz.thoughtset.viewer + viewer-common-envvar + ${revision} + @@ -191,27 +218,27 @@ org.apache.maven.plugins maven-compiler-plugin - - - org.projectlombok - lombok - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + diff --git "a/template/Text - \345\211\257\346\234\254.xlsx" "b/template/Text - \345\211\257\346\234\254.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..96319d93c860dac2c54e3bb0bbdb7f31c4c09d5e GIT binary patch literal 8854 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