From f0e4c1b12ea96ac742ccf32871349d50b18ea960 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 17:47:11 +0800 Subject: [PATCH 01/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B7=A5=E5=85=B7=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E7=9A=84readme=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- initdatabse-component/README.md | 354 ++++++++++++++++++++++++++++++++ 1 file changed, 354 insertions(+) create mode 100644 initdatabse-component/README.md diff --git a/initdatabse-component/README.md b/initdatabse-component/README.md new file mode 100644 index 0000000..3d04a68 --- /dev/null +++ b/initdatabse-component/README.md @@ -0,0 +1,354 @@ +# Conscript 数据库初始化工具 + +> Conscript基于Spring-boot-starter的方式提供数据库初始化功能,可以随项目初次启动,自动创建相关数据库,后续系统升级所引发的数据库变化及升级也可由此完成,拆箱即用,随系统程序代码运行,省去额外的数据库升级操作, +> +> `支持数据库种类可扩展,目前支持通用mysql、postgreSQL、 国产数据库达梦和金仓` +> +> `支持执行失败回滚机制` + +## 1.支持数据库类型 + +| 数据库类型 | 是否支持 | db-driver参数 | +| ---------- | ---- | ----------- | +| mysql | 是 | mysql | +| mariadb | 是 | mariadb | +| PostgreSQL | 是 | pgsql | +| 达梦数据库 | 是 | dm | +| 人大金仓8 | 是 | kingbase8 | + +## 2.实现设计 + +核心代码结构: + +```shell ++---action #基础功能包 +| +---mysql #mysql数据库实现 +----initDataBase #数据库初始化接口 +----DataBaseInitorFactory #数据库初始器工厂 +----AbstractInitDataBase #数据库初始器基类 +``` + +| 类 | 介绍 | +| --------------------- | -------------- | +| initDataBase | 初始化接口 | +| AbstractInitDataBase | 初始化基类,定义核心逻辑 | +| MySqlDataBase | Mysql实现,具体执行方式 | +| DataBaseInitorFactory | 工厂类 | + +```mermaid +classDiagram +direction TD +class initDataBase{ + <> + isInitEd() + startCoreJob() + createConnection() + databaseIsExitd() + getCurrenDbVersion() + excuteSQL(Map sqlcontent) + close() +} +class AbstractInitDataBase { + <> + +void : startCoreJob() + } +class MySqlDataBase { + +void : createConnection() + +boolean:databaseIsExitd() + +Float:getCurrenDbVersion() + +void:excuteSQL(Map sqlcontent) + } +class DataBaseInitorFactory { + +InitDataBase : createInitiator(DbConConfiguration config) + +String:getClassUrlValue(DbType dbType) + } + class DbConConfiguration { + +DbConConfiguration : builder() + +void:set() + +Object:get() + } +initDataBase <-- AbstractInitDataBase : +AbstractInitDataBase <|-- MySqlDataBase +DbConConfiguration <.. DataBaseInitorFactory +initDataBase -- DataBaseInitorFactory +``` + +> **扩展其他类型数据库:在action目录下新建相应的数据库类型目录,然后继承AbstractInitDataBase类,实现对应的几个数据库操作方法,在DatabaseProperties的getDbDeriver()中新增对应的映射** + +## 3.使用方式 + +可直接集成至SpringBoot项目中使用 + +| SpringBoot版本要求 | +| -------------------------------------- | +| `SpringBoot version` >=  2.3.6.RELEASE | + +### 1.引入Conscript + +1.1.使用jar引入 + +> 本地编译源码后,install到本地的maven私仓后,直接引入项目 + +```xml + + com.gcc.airbase + Conscript + 1.0 + +``` + +### 2.配置yml文件 + +```yml +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/test?user=root&password=1234 + username: root + password: 1234 + driver-class-name: com.mysql.cj.jdbc.Driver + db-config-file-url: sql/mysql/dbconfig.json + db-driver: mysql + db-name: test +``` + +配置内容遵循标准的`spring.datasource`配置,并进行了增强 + +| 字段 | 含义 | 是否必填 | +| ------------------ | ------------------------------------------------ | ---- | +| url | 必选字段,遵循标准datasource即可,若使用mybaits,则按照mybaits标准填写 | 是 | +| username | 必选字段,标准datasource即可,填写数据库账号 | 是 | +| password | 必选字段,标准datasource即可,填写数据库连接密码 | 是 | +| driver-class-name | 必选字段,标准datasource即可,填写数据库连接驱动类 | 是 | +| db-config-file-url | 必选字段,指定静态SQL文件存放位置 | 是 | +| db-driver | 必选字段,指定数据库类型,扩展时,可填写类路径,默认填写mysql,详细见扩展用法章节 | 是 | +| dbport | 非必选字段,数据库服务端口,若url填写,可省略该字段 | 否 | +| db-name | 非必选字段,需要连接的数据库名称,若url中填写,可省略该字段 | 否 | +| schema | 非必须字段,若url中填写,则可省略,主要用于对部分数据库的模式配置 | 否 | +| root-user | 非必选字段,**若存在对数据库权限分离有要求的需求**,可以在此填写专门用于建库的高权限账号 | 否 | +| root-pass | 非必选字段,**若存在对数据库权限分离有要求的需求**,可以在此填写专门用于建库的高权限账号密码 | 否 | + +此处配置相较 `spring.datasource`的基础的 `url、username、password、driver-class-name`外,增加了独有的`db-driver、db-config-file-url`,原则上只需要满足此6项配置即可使用Conscript,但建议将配置补全使用 + + `使用该组件,必须确保拥有较高的数据库角色权限,例如mysql的root、pgsql的postgres,否则无法使用创建数据库的功能,如需清晰划分权限,则可以通过配置项中的root-user,root-pass来将系统数据库的使用区分开来` + +### 3.建立配置文件及SQL文件 + +以标准maven项目为例 + +​ 1.根据 yml中`spring.datasource.db-config-file-url`配置的值,在resource目录下新建相应路径json文件 + +XX.json文件样例如下: + +```json + [ + { + "version": "1.0", + "sqlfile": "a.sql", + "desc": "基础数据库结构" + }, + { + "version": "1.1", + "sqlfile": "ddd.sql", + "desc": "第一版升级数据库" + } + ] +``` + +| 字段 | 含义 | +| ------- | --------------------------------------------------------------------------- | +| version | 数据库的版本,**数字类型** | +| sqlfile | 数据库升级的sql文件,叠加式追加,**注:这里要写清楚sql文件的路径(基于resource目录为基准),此处的配置决定后续sql文件的存放位置** | +| desc | 维护使用的描述信息 | + +​ 2.根据XX.json配置文件中的sqlfile配置项,新建相应目录追加需要预制的SQL文件 + +### 4.提供一个标准的用例 + +yml配置文件如下: + +``` +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/test?user=root&password=1234?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2B8 + username: root + password: 1234 + driver-class-name: com.mysql.cj.jdbc.Driver + db-dirver: mysql + db-config-file-url: sql/mysql-dbconfig.json + db-name: test +``` + +mysql-dbconfig.json配置如下: + +```json + [ + { + "version": "1.0", + "sqlfile": "sql/a.sql", + "desc": "基础数据库结构" + }, + { + "version": "1.1", + "sqlfile": "sql/ddd.sql", + "desc": "第一版升级数据库" + } + ] +``` + +目录结构如下: + +```shell ++-java #java源码 ++-resource #资源文件 +| +---sql #sql初始化配置内容 + |+---mysql-dbconfig.json #sql初始化配置内容 + |+---a.sql #sql初始化配置内容 + |+---ddd.sql #sql初始化配置内容 +``` + +> yml配置中的`db-config-file-url`配置决定着json配置文件的存放,如填写的路径为:sql/mysql/a.json,则需要在resource目录下新建sql文件夹,并在sql文件夹下新建mysql文件夹,然后在mysql文件夹中按照样例创建json文件;json配置文件中的sqlfile属性决定着需要执行的sql文件存放位置; +> +> 为了方便,建议json文件中的sql文件存放位置和json文件在同级目录 + +### 5.其他说明 + +使用过程中获取建库结果,需要在代码中获取数据库的升级结果以便后续操作,可直接获取bean `DbIsExist` 的值来进行判定: + +```java +@Service +public class AfterStartProcess{ + + @Qualifier("DbIsExid") + @Autowired + Boolean dbIsOk; + + + public void test(){ + if(dbIsOk){ + System.out.print("数据库升级完成!") + } + } +} +``` + +默认数据库版本表名称修改,需要新增配置 `conscript.table-name` 配置项: + +```yml +conscript: + table-Name: xxxx +``` + +## 4.扩展 + +若支持的数据库类型不满足要求,需要自行进行扩展,项目引入后,可新建类继承 `AbstractInitDataBase`类,仅实现对应的 `initCommConn() initDbConn() databaseIsExitd() ` + +`createDataBase() `方法,并将新建的类路径配置到db-driver中即可 + +### method:initCommConn() + +> 创建数据库基础JDBC连接, +> +> `AbstractInitDataBase`类中定义了 `commConn` 、` dbConn` 两个**Connection** 变量,该方法主要用于对 `commConn`变量进行初始化,建立基础的数据库连接,用于测试数据库联通以及执行数据库建库语句,例如MySQL中,需要建立连接mysql数据库的JDBC + +```java + @Override + public void initCommConn() { + try { + Class.forName(dataBaseProperties.getDriverClassName()); + String jdbc_url = "jdbc:mysql://" + dataBaseProperties.getHost() + ":" + dataBaseProperties.getDbport() + "/mysql?characterEncoding=utf8&serverTimezone=GMT%2B8"; + commConn = DriverManager.getConnection(jdbc_url, dataBaseProperties.getUsername(), dataBaseProperties.getPassword()); + }catch (Exception e){ + log.error("【Conscript】Database initialization :data base is not connection....."); + } + } +``` + +### method: initDbConn() + +> 创建数据库基础JDBC连接, +> +> `AbstractInitDataBase`类中定义了 `commConn` 、` dbConn` 两个**Connection** 变量,该方法主要用于对 `dbConn`变量进行初始化,建立对目标数据库(配置中指定的数据库)实例的JDBC连接,用于执行SQL语句 + +```java + @Override + public void initDbConn() { + try{ + String url = "jdbc:mysql://"+ dataBaseProperties.getHost()+":"+ dataBaseProperties.getDbport()+"/"+ dataBaseProperties.getDbName()+"?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2B8"; + dbConn = DriverManager.getConnection(url, dataBaseProperties.getUsername(), dataBaseProperties.getPassword()); + }catch (Exception e){ + log.warn(""); + } + } +``` + +### method:databaseIsExitd(Connection connection) + +> 确定需要连接的目标数据库实例((配置中指定的数据库))是否存在,使用`commConn`进行确认,不同的数据库确认实例的方式不同,可根据具体要扩展的数据库类型自行进行定义 + +```java +@Override + public boolean databaseIsExitd(Connection connection){ + try { + Statement stmt = connection.createStatement(); + ResultSet res = stmt.executeQuery("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name= \""+ dataBaseProperties.getDbName()+"\""); + if(res.next() && res.getInt(1) == 0){ + stmt.close(); + return false; + } + return true; + }catch (Exception e){ + log.error("【Conscript】Database initialization :database base query is error"); + } + return false; + } +``` + +### method:createDataBaseSQL() + +> 创建指定的数据库的建库语句,仅返回对应的建库语句即可 + +```java +@Override + public String createDataBaseSQL() { + return "CREATE DATABASE IF NOT EXISTS "+ dataBaseProperties.getDbName()+" DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"; + } +``` + +## 5.回滚保护机制 + +为防止用户自定义的sql文件中存在错误的语法,导致升级建库过程因部分sql错误而失败,但正常SQL却已经执行,污染了原始数据库;Conscript进行了加强,可以将升级过程停止于错误sql文件之前,保证存在错误语法的sql文件不会被执行,从而保证不会污染原始数据库 + +```mermaid +graph LR; + sql文件 --> 语法校验; + 语法校验 --> 数据事务操作保护 +``` + +保护机制为两层防护,第一层为语法保护,保证执行的sql语法都是正确的,能够被数据库执行的,其次进行一次数据操作的回滚,当正确的SQL满足了语法要求,但是如果存在语义错误(主键冲突、字段和值不匹配等造成的数据操作失败),则进行数据 `增删改`的回滚机制,保证数据不被污染 + +> 注:因开启回滚保护机制,需要对sql文件进行语法校验,sql文件数量较大时会有较高的性能损耗,可根据实际情况使用,默认是不开启状态 + +### 使用方法 + +yml文件中新增`conscript.parse-enable`属性,取值范围为布尔,不配置时默认为 false + +```yml +conscript: + parse-enable: true +``` + +## 6.其他问题 + +6.1 与Mybatis-plus一起使用时,会出现Conscript在Mybatis-Plus之后加载的情况,此时会因为未创建数据库,导致Mybatis-plus的SqlSession创建失败,解决方案需要在启动类上使用注解@DependsOn,手动干预starter加载顺序,先加载Conscript的 `DbIsExist` bean,如下: + +```java +@SpringBootApplication +@DependsOn("DbIsExist") +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +``` \ No newline at end of file -- Gitee From da2f1ed56e212318efe737ad09c07cead3c32cfc Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 19:17:29 +0800 Subject: [PATCH 02/33] =?UTF-8?q?=E8=A1=A5=E5=85=A8=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/META-INF/spring.factories | 2 +- redis-component/src/main/resources/META-INF/spring.factories | 1 + rest-component/src/main/resources/META-INF/spring.factories | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 redis-component/src/main/resources/META-INF/spring.factories create mode 100644 rest-component/src/main/resources/META-INF/spring.factories diff --git a/initdatabse-component/src/main/resources/META-INF/spring.factories b/initdatabse-component/src/main/resources/META-INF/spring.factories index 812ff55..04a6ae1 100644 --- a/initdatabse-component/src/main/resources/META-INF/spring.factories +++ b/initdatabse-component/src/main/resources/META-INF/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.airbase.conscript.ApplicationConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.conscript.ApplicationConfiguration \ No newline at end of file diff --git a/redis-component/src/main/resources/META-INF/spring.factories b/redis-component/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..7080fd0 --- /dev/null +++ b/redis-component/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.web.ApplicationConfiguration \ No newline at end of file diff --git a/rest-component/src/main/resources/META-INF/spring.factories b/rest-component/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..7080fd0 --- /dev/null +++ b/rest-component/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.web.ApplicationConfiguration \ No newline at end of file -- Gitee From 9a8e5bd2b9a1f3766f7933c387a0155cce11b1e4 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 21:34:32 +0800 Subject: [PATCH 03/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9swagger=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 -- ...aggerConfig.java => SwaggerConfigure.java} | 51 +++++++--------- ...java => WebMvcRegistrationsConfigure.java} | 2 +- .../web/property/ApiDocProperties.java | 60 ++++++++++++++----- .../web/property/ApiInfoProperties.java | 25 -------- .../src/main/resources/application.yml | 12 ++-- 6 files changed, 75 insertions(+), 81 deletions(-) rename rest-component/src/main/java/com/gcc/container/components/web/configure/{SwaggerConfig.java => SwaggerConfigure.java} (39%) rename rest-component/src/main/java/com/gcc/container/components/web/configure/{WebMvcRegistrationsConfig.java => WebMvcRegistrationsConfigure.java} (87%) delete mode 100644 rest-component/src/main/java/com/gcc/container/components/web/property/ApiInfoProperties.java diff --git a/pom.xml b/pom.xml index f1de576..67dc53c 100644 --- a/pom.xml +++ b/pom.xml @@ -54,12 +54,6 @@ org.projectlombok lombok - - - org.slf4j - slf4j-log4j12 - ${slf4j.version} - cn.hutool diff --git a/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfig.java b/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java similarity index 39% rename from rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfig.java rename to rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java index e01dbd8..46fee20 100644 --- a/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfig.java +++ b/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java @@ -1,8 +1,9 @@ package com.gcc.container.components.web.configure; import com.gcc.container.components.web.property.ApiDocProperties; -import com.gcc.container.components.web.property.ApiInfoProperties; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; @@ -13,40 +14,34 @@ import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; -import java.util.ArrayList; -import java.util.List; - @Configuration -public class SwaggerConfig { +public class SwaggerConfigure { @Autowired private ApiDocProperties properties; + @ConditionalOnWebApplication + @ConditionalOnProperty(name="rest-component.api-doc.enable", havingValue = "false") @Bean - public List taskApis(){ - if(properties.getEnable()){ - List result = new ArrayList<>(); - List apis = properties.getApiDocs(); - for(ApiInfoProperties apidoc:apis){ - ApiInfo onePage = new ApiInfoBuilder() - .title(apidoc.getTitle()) - .description(apidoc.getTitle()) - .contact(new Contact("GCC", "#", "gcc.com")) - .version(apidoc.getVersion()) - .build(); - result.add(new Docket(DocumentationType.OAS_30) - .apiInfo(onePage) - .select() - .apis(RequestHandlerSelectors.basePackage(apidoc.getPackagePath())) - .paths(PathSelectors.any()) - .build() - .groupName(apidoc.getTitle()) - .enable(true)); - } - return result; - }else { - return null; + public Docket createDockets() { + if (properties.isEnable()) { + ApiInfo apiInfo = new ApiInfoBuilder() + .title(properties.getTitle()) + .description(properties.getDescription()) + .contact(new Contact("GCC", "#", "gcc.com")) + .version(properties.getVersion()) + .build(); + Docket docket = new Docket(DocumentationType.OAS_30) + .apiInfo(apiInfo) + .select() + .apis(RequestHandlerSelectors.basePackage(properties.getPackagePath())) + .paths(PathSelectors.any()) + .build() + .groupName(properties.getTitle()) + .enable(true); + return docket; } + return null; } diff --git a/rest-component/src/main/java/com/gcc/container/components/web/configure/WebMvcRegistrationsConfig.java b/rest-component/src/main/java/com/gcc/container/components/web/configure/WebMvcRegistrationsConfigure.java similarity index 87% rename from rest-component/src/main/java/com/gcc/container/components/web/configure/WebMvcRegistrationsConfig.java rename to rest-component/src/main/java/com/gcc/container/components/web/configure/WebMvcRegistrationsConfigure.java index 93b9933..c78e3ea 100644 --- a/rest-component/src/main/java/com/gcc/container/components/web/configure/WebMvcRegistrationsConfig.java +++ b/rest-component/src/main/java/com/gcc/container/components/web/configure/WebMvcRegistrationsConfigure.java @@ -6,7 +6,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @Configuration -public class WebMvcRegistrationsConfig implements WebMvcRegistrations { +public class WebMvcRegistrationsConfigure implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new ApiRequestMappingHandlerMapping(); diff --git a/rest-component/src/main/java/com/gcc/container/components/web/property/ApiDocProperties.java b/rest-component/src/main/java/com/gcc/container/components/web/property/ApiDocProperties.java index 89edf0b..5f56f7c 100644 --- a/rest-component/src/main/java/com/gcc/container/components/web/property/ApiDocProperties.java +++ b/rest-component/src/main/java/com/gcc/container/components/web/property/ApiDocProperties.java @@ -1,25 +1,57 @@ package com.gcc.container.components.web.property; -import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; -import java.util.List; - -@ConfigurationProperties(prefix = "rest-component") -@Data +@ConfigurationProperties(prefix = "rest-component.api-doc") @Configuration public class ApiDocProperties { - /** - * 是否启用 - */ - private Boolean enable = false; + private boolean enable = false; + private String packagePath; + private String title; + private String description; + private String version; + + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getPackagePath() { + return packagePath; + } + + public void setPackagePath(String packagePath) { + this.packagePath = packagePath; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } - /** - * swagger页面 - */ - private List apiDocs; + public String getVersion() { + return version; + } + public void setVersion(String version) { + this.version = version; + } -} +} \ No newline at end of file diff --git a/rest-component/src/main/java/com/gcc/container/components/web/property/ApiInfoProperties.java b/rest-component/src/main/java/com/gcc/container/components/web/property/ApiInfoProperties.java deleted file mode 100644 index 0216621..0000000 --- a/rest-component/src/main/java/com/gcc/container/components/web/property/ApiInfoProperties.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gcc.container.components.web.property; - -import lombok.Data; - -@Data -public class ApiInfoProperties { - private String packagePath; - private String title; - private String description; - private String version; - - public String getDescription() { - if(null == description || "".equals(description) ) { - return this.title; - } - return description; - } - - public String getVersion() { - if(null == version || "".equals(version)){ - return "1.0.0"; - } - return version; - } -} diff --git a/rest-component/src/main/resources/application.yml b/rest-component/src/main/resources/application.yml index 773fc74..26c9e5c 100644 --- a/rest-component/src/main/resources/application.yml +++ b/rest-component/src/main/resources/application.yml @@ -1,9 +1,7 @@ rest-component: - apiDoc: + api-doc: enable: true - - packagePath: com.gcc.container.client.* - title: 客户端接口 - description: 客户端服务接口 - - packagePath: com.gcc.container.web.* - title: web页面接口 - description: B/S架构下web页面接口 + packagePath: com.gcc.container.taskschedule.taskscheduling.controller.* + title: 任务调度 + description: 定时任务相关数据查看 + version: 1.0.0 \ No newline at end of file -- Gitee From 0c026ff44d2ac04c3159191358114356df151ac3 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 21:54:41 +0800 Subject: [PATCH 04/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=89=93=E5=8C=85?= =?UTF-8?q?=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest-component/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-component/pom.xml b/rest-component/pom.xml index 18f9d38..0f62dd1 100644 --- a/rest-component/pom.xml +++ b/rest-component/pom.xml @@ -8,7 +8,7 @@ 1.0.0 - com.gcc.container.commpont + com.gcc.container.commponts rest-component ${component.version} jar -- Gitee From 25673eb8f1e4ddbc944d9f5a7e15fa24d1af9469 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 21:55:44 +0800 Subject: [PATCH 05/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=89=93=E5=8C=85?= =?UTF-8?q?=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest-component/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-component/pom.xml b/rest-component/pom.xml index 0f62dd1..c3fb011 100644 --- a/rest-component/pom.xml +++ b/rest-component/pom.xml @@ -8,7 +8,7 @@ 1.0.0 - com.gcc.container.commponts + com.gcc.container.components rest-component ${component.version} jar -- Gitee From 579e1831e51bd4e39d1038e308d7ecb1dab60b63 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 21:57:22 +0800 Subject: [PATCH 06/33] =?UTF-8?q?=E8=A7=84=E8=8C=83=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- initdatabse-component/pom.xml | 2 +- redis-component/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/initdatabse-component/pom.xml b/initdatabse-component/pom.xml index 952fbbe..cf04c0d 100644 --- a/initdatabse-component/pom.xml +++ b/initdatabse-component/pom.xml @@ -6,7 +6,7 @@ components 1.0.0 - com.gcc.container.components.conscript + com.gcc.container.components initdatabse-component ${component.version} jar diff --git a/redis-component/pom.xml b/redis-component/pom.xml index a56ce44..c069687 100644 --- a/redis-component/pom.xml +++ b/redis-component/pom.xml @@ -6,7 +6,7 @@ components 1.0.0 - com.gcc.container.components.redis + com.gcc.container.components redis-component ${component.version} jar -- Gitee From ce85cf22870e22d1d743c91ab8253b9beb758bd7 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Sun, 17 Nov 2024 22:28:43 +0800 Subject: [PATCH 07/33] =?UTF-8?q?=E8=B0=83=E6=95=B4swagger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../container/components/web/configure/SwaggerConfigure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java b/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java index 46fee20..37ff527 100644 --- a/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java +++ b/rest-component/src/main/java/com/gcc/container/components/web/configure/SwaggerConfigure.java @@ -21,7 +21,7 @@ public class SwaggerConfigure { private ApiDocProperties properties; @ConditionalOnWebApplication - @ConditionalOnProperty(name="rest-component.api-doc.enable", havingValue = "false") + @ConditionalOnProperty(name="rest-component.api-doc.enable", havingValue = "true",matchIfMissing = false) @Bean public Docket createDockets() { if (properties.isEnable()) { -- Gitee From beadfe60eb9240007880745d307770d43a88878c Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 01:14:48 +0000 Subject: [PATCH 08/33] =?UTF-8?q?=E6=96=B0=E5=A2=9EEs=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- es-component/README.md | 252 +++++++++++ es-component/pom.xml | 46 ++ .../ApplictionConfiguration.java | 9 + .../actuator/ElasticSearchActuator.java | 194 ++++++++ .../impl/ElasticSearchActuatorImpl.java | 420 ++++++++++++++++++ .../configure/ElasticSearchCondition.java | 23 + .../configure/ElasticSearchLogCondition.java | 21 + .../configure/ElasticSearchSqlCondition.java | 21 + .../elasticsearch/configure/LoadEsClient.java | 93 ++++ .../log/annotation/ExecuteDslLog.java | 11 + .../aspect/ElasticSearchMonitorAspect.java | 30 ++ .../elasticsearch/model/SearchResult.java | 50 +++ .../model/entity/DocBaseEntity.java | 36 ++ .../model/entity/FieldEntity.java | 21 + .../property/ElasticSearchProperties.java | 41 ++ .../main/resources/META-INF/spring.factories | 1 + .../src/main/resources/application.yml | 9 + 17 files changed, 1278 insertions(+) create mode 100644 es-component/README.md create mode 100644 es-component/pom.xml create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/ApplictionConfiguration.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/ElasticSearchActuator.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/impl/ElasticSearchActuatorImpl.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchCondition.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchLogCondition.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchSqlCondition.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/LoadEsClient.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/log/annotation/ExecuteDslLog.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/log/aspect/ElasticSearchMonitorAspect.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/model/SearchResult.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/DocBaseEntity.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/FieldEntity.java create mode 100644 es-component/src/main/java/com/gcc/container/components/elasticsearch/property/ElasticSearchProperties.java create mode 100644 es-component/src/main/resources/META-INF/spring.factories create mode 100644 es-component/src/main/resources/application.yml diff --git a/es-component/README.md b/es-component/README.md new file mode 100644 index 0000000..bc80fd2 --- /dev/null +++ b/es-component/README.md @@ -0,0 +1,252 @@ +# 使用说明 + +## 1、引入依赖 + +使用maven引入依赖: + +```xml + + com.gcc.aribase + ElasticSearchServer + ${相关版本号} + +``` + + + +## 2、新增yml文件配置项 + +在yml配置文件中新增es所需的参数项: + +```yml +spring: + elasticsearch: + host: 127.0.0.1 + port: 9500 + tcpport: 9300 #若不需要es-sql功能则可忽略该属性 + user: elastic + password: ABCDEF + scheme: http + log-enable: false +``` + +参数说明: + +| 参数 | 作用 | 是否必填 | +| ---------- | ---------------------------------------- | ----- | +| host | es服务的ip地址 | 是 | +| port | es服务的端口 | 是 | +| tcpport | es的tcp服务端口,若追加该属性并进行配置,则可使用`es-sql`的功能,默认无此属性 | **否** | +| user | 如果es服务设置了安全认证,则填写用户名,否则可不填 | 否 | +| password | 如果es服务设置了安全认证,则填写密码,否则可不填 | 否 | +| scheme | 默认http方式 | 否 | +| log-enable | 是否开启dsl语句的执行记录日志,无此字段则默认是false | 否 | + + + +## 3、注入ElasticSearchActuator + +完成前两步后,则可在项目中直接使用 ElasticSearchActuator,如下: + +```java +@Service +public class ElasticSearchTest { + + @Autowired + private ElasticSearchActuator elasticSearchActuator; + +} +``` + + + +ElasticSearchActuator推荐使用官方的SearchSourceBuilder对象进行Es数据查询,如下: + +```java +@Service +public class ElasticSearchTest { + + + private final static String INDEX_NAME = "tb_user"; + + @Autowired + private ElasticSearchActuator elasticSearchActuator; + + + public Object excuteSearchData(int pageNo,String asset_type){ + Long startTime = DateUtil.beginOfDay(new Date()).getTime(); + Long endTime = DateUtil.endOfDay(new Date()).getTime(); + BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); + boolQueryBuilder.filter().add(QueryBuilders.rangeQuery("update_time").gte(startTime).lte(endTime)); + if(!StringUtils.isEmpty(asset_type)){ + boolQueryBuilder.filter().add(QueryBuilders.termQuery("asset_type",asset_type)); + } + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder() + .size(10) + .query(boolQueryBuilder) + .aggregation(AggregationBuilders.terms("uniqueKey").field("unique_key")); + SearchResult scrollret = elasticSearchActuator.scrollSearchElasticSearchDatas(INDEX_NAME,searchSourceBuilder,pageNo, JKEntity.class); + return scrollret; + } +} + +``` + + + +也可支持直接使用字符串拼写的DSL,如下: + + + +```java +@Service +public class ElasticSearchTest { + + + private final static String INDEX_NAME = "tb_user"; + + @Autowired + private ElasticSearchActuator elasticSearchActuator; + + + public Object searchUserInfo(){ + String dsl = "{\n" + + " \"size\": 0,\n" + + " \"query\": {\n" + + " \"bool\": {\n" + + " \"filter\": [\n" + + " {\n" + + " \"range\": {\n" + + " \"update_time\": {\n" + + " \"from\": 1684684800000,\n" + + " \"to\": 1684771199999\n" + + " }\n" + + " }\n" + + " },\n" + + " {\n" + + " \"term\": {\n" + + " \"asset_type\": \"server\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " },\n" + + " \"aggregations\": {\n" + + " \"userName\": {\n" + + " \"cardinality\": {\n" + + " \"field\": \"userName\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + return elasticSearchActuator.executeSearchDslStr(INDEX_NAME,dsl); + } +} +``` + + + +## 4、特殊方法使用说明 + +### method: executeSearchDslStr(String indexName,String dslBodyStr) + +> ```java +> /** +> * 执行Es的dsl(默认文档类型为_doc) +> * @param indexName 索引名称 +> * @param dslBodyStr dsl +> * @return JSONObject +> */ +> JSONObject executeSearchDslStr(String indexName,String dslBodyStr); +> ``` + + 该方法直接执行DSL,可用字符串拼接的DSL,返回值为`JSON对象`,可自行拆解 + + + +### method:executeSearchSearchSourceBuilder(String indexName, SearchSourceBuilder searchSourceBuilder,Class resultObj) + +> ```java +> /** +> * 执行Es的查询对象 SearchSourceBuilder 默认文档为_doc +> * @param indexName 索引名称 +> * @param searchSourceBuilder 查询对象 +> * @return JSONObject +> */ +> SearchResult executeSearchSearchSourceBuilder(String indexName, SearchSourceBuilder searchSourceBuilder,Class resultObj); +> ``` + + 基于`SearchSourceBuilder` 对象的执行方法,可直接执行构建好的Es查询对象,返回值为 `SearchResult` 对象;`T` 可由参数 `resultObj` 指定,可根据文档结构定义实体传入,或直接使用Map结构 + + + +### method:searchElasticSearchDatas(String indexName, SearchSourceBuilder searchSourceBuilder,Class resultObj) + +> ```java +> /** +> * 查询es +> * @param indexName 索引名称 +> * @param searchSourceBuilder 自定义查询内容 +> * @param resultObj 目标实体对象 +> * @return SearchResult +> */ +> SearchResult searchElasticSearchDatas(String indexName, SearchSourceBuilder searchSourceBuilder,Class resultObj); +> ``` + + 基于`SearchSourceBuilder` 对象的查询方法,可直接执行构建好的Es查询对象,返回值为 `SearchResult` 对象;与 ` method:executeSearchSearchSourceBuilder` 不同的地方在于,此方法仅返回查询内容,不处理聚合结果,如`SearchSourceBuilder` 对象中包含聚合语法,则建议使用 ` method:executeSearchSearchSourceBuilder` + + + +### method:scrollSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,Class resultObj) + +> ```java +> /** +> * 分页滚动查询 +> * @param indexName 索引名称 +> * @param searchSourceBuilder 查询条件 +> * @param pageNo 页码 +> * @param resultObj 具体目标对象 +> * @return SearchResult +> */ +> SearchResult scrollSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,Class resultObj); +> ``` + +Es的Scroll滚动分页查询,除索引和条件外,只需要传入对应的页码即可; 如不进行大范围跳页操作,使用该分页方式效果更好,如存在大范围跳页,则不建议使用该分页方式, + + + +### method:aggregateDatas(String indexName, Object searchDslStr) + +> ```java +> /** +> * 聚合es数据 +> * @param indexName 索引名称 +> * @param searchDslStr 自定义查询内容 +> * @return +> */ +> SearchResult aggregateDatas(String indexName, String searchDslStr); +> /** +> * 聚合es数据 +> * @param indexName 索引名称 +> * @param searchSourceBuilder 自定义查询内容 +> * @return +> */ +> SearchResult aggregateDatas(String indexName, SearchSourceBuilder searchSourceBuilder); +> ``` + +与 `method:searchElasticSearchDatas` 相对,专门进行聚合查询操作所建立的方法,只返回聚合结果内容,为优化聚合的性能,默认会将查询DSL对象中的 size 改为0 + + + +### method: translateSQL(String sql) + +> ```java +> /** +> * 将sql语句转换为dsl语句 +> * @param sql sql 语句 +> * @return String +> */ +> String translateSQL(String sql); +> ``` + +可将sql语句翻译为Es的DSL语句,若DSL学习不精可用此方法作为补充,使用该方法需要在 `yml配置文件` 中追加 tcpport 属性,es默认的tcp通信端口为9300,详细见 第二节`新增yml文件配置项` \ No newline at end of file diff --git a/es-component/pom.xml b/es-component/pom.xml new file mode 100644 index 0000000..9cae275 --- /dev/null +++ b/es-component/pom.xml @@ -0,0 +1,46 @@ + + 4.0.0 + + com.gcc.container + components + 1.0.0 + + com.gcc.container.components + es-component + ${component.version} + jar + + + + + 7.6.2 + + + + + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + ${es.version} + + + + + org.elasticsearch.client + transport + 7.6.1 + + + org.nlpcn + elasticsearch-sql + 7.8.0.1 + + + + + + + + diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/ApplictionConfiguration.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/ApplictionConfiguration.java new file mode 100644 index 0000000..5575b3e --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/ApplictionConfiguration.java @@ -0,0 +1,9 @@ +package com.gcc.container.components.elasticsearch; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "com.gcc.container.components.elasticsearch.*") +public class ApplictionConfiguration { +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/ElasticSearchActuator.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/ElasticSearchActuator.java new file mode 100644 index 0000000..5bf53e2 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/ElasticSearchActuator.java @@ -0,0 +1,194 @@ +package com.gcc.container.components.elasticsearch.actuator; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.gcc.container.components.elasticsearch.model.SearchResult; +import com.gcc.container.components.elasticsearch.model.entity.FieldEntity; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +import java.util.List; + +/** + * es执行器 + * @author GCC + */ +public interface ElasticSearchActuator { + + + /** + * 判断索引是否存在 + * @param indexName 索引名称 + * @return boolean + */ + boolean checkIndex(String indexName); + + + + /** + * 创建索引 + * @param indexName 索引名称 + * @param mapping 创建索引的mapping + * @return boolean + */ + boolean createIndex(String indexName, JSONObject mapping); + + + + /** + * 删除索引 + * @param indexName 所有名称 + * @return boolean + */ + boolean deleteIndex(String indexName); + + + + + /** + * 向指定索引内追加单条数据 + * @param indexName 索引名称 + * @param data 数据 + * @return boolean + */ + boolean addIndexData(String indexName, JSONObject data); + + + + + /** + * 向指定索引中批量追加数据 + * @param indexName 索引名称 + * @param datas 数据 + * @return boolean + */ + boolean addIndexDatas(String indexName, JSONArray datas); + + + + /** + * 清空指定索引内数据 + * @param indexName 索引名称 + * @return boolean + */ + boolean clearIndexData(String indexName); + + + + /** + * 根据id删除指定索引内的数据 + * @param indexName 索引名称 + * @param id 待删除数据的id + * @return boolean + */ + boolean deleteIndexDataById(String indexName, String id); + + + + /** + * 获取所有索引名称 + * @return List + */ + List getAllIndexName(); + + + + + /** + * 根据索引名称获取对应的字段集合 + * @param indexName 索引名称 + * @return List + */ + List getFieldsByIndexName(String indexName); + + + /** + * 根据文档id(_id)查询具体数据 + * @param indexName 索引名称 + * @param docType 文档类型 + * @param id _id + * @return JSONObject + */ + JSONObject getElasticSearchDataById(String indexName,String docType,String id); + + + + /** + * 根据文档id(_id)查询具体数据,默认文档为_doc类型 + * @param indexName 索引名称 + * @param id _id + * @return JSONObject + */ + JSONObject getElasticSearchDataById(String indexName,String id); + + + + + /** + * 执行Es的dsl(默认文档类型为_doc) + * @param indexName 索引名称 + * @param dslBodyStr dsl + * @return JSONObject + */ + JSONObject executeSearchDslStr(String indexName,String dslBodyStr); + + + + /** + * 执行Es的查询对象 SearchSourceBuilder 默认文档为_doc + * @param indexName 索引名称 + * @param searchSourceBuilder 查询对象 + * @return JSONObject + */ + SearchResult executeSearchSearchSourceBuilder(String indexName, SearchSourceBuilder searchSourceBuilder, Class resultObj); + + + + + /** + * 查询es + * @param indexName 索引名称 + * @param searchSourceBuilder 自定义查询内容 + * @param resultObj 目标实体对象 + * @return SearchResult + */ + SearchResult searchElasticSearchDatas(String indexName, SearchSourceBuilder searchSourceBuilder,Class resultObj); + + /** + * 分页滚动查询 + * @param indexName 索引名称 + * @param searchSourceBuilder 查询条件 + * @param pageNo 页码 + * @param resultObj 具体目标对象 + * @return SearchResult + */ + SearchResult scrollSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,Class resultObj); + + /** + * 聚合es数据 + * @param indexName 索引名称 + * @param searchDslStr 自定义查询内容 + * @return + */ + SearchResult aggregateDatas(String indexName, String searchDslStr); + + + + /** + * 聚合es数据 + * @param indexName 索引名称 + * @param searchSourceBuilder 自定义查询内容 + * @return + */ + SearchResult aggregateDatas(String indexName, SearchSourceBuilder searchSourceBuilder); + + + /** + * 将sql语句转换为dsl语句 + * @param sql sql 语句 + * @return String + */ + String translateSQL(String sql); + + + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/impl/ElasticSearchActuatorImpl.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/impl/ElasticSearchActuatorImpl.java new file mode 100644 index 0000000..e9ddf92 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/actuator/impl/ElasticSearchActuatorImpl.java @@ -0,0 +1,420 @@ +package com.gcc.container.components.elasticsearch.actuator.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.elasticsearch.actuator.ElasticSearchActuator; +import com.gcc.container.components.elasticsearch.configure.ElasticSearchCondition; +import com.gcc.container.components.elasticsearch.configure.ElasticSearchSqlCondition; +import com.gcc.container.components.elasticsearch.log.annotation.ExecuteDslLog; +import com.gcc.container.components.elasticsearch.model.SearchResult; +import com.gcc.container.components.elasticsearch.model.entity.DocBaseEntity; +import com.gcc.container.components.elasticsearch.model.entity.FieldEntity; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpException; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.delete.DeleteRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.search.*; +import org.elasticsearch.client.*; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.GetIndexRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; +import org.elasticsearch.client.indices.GetMappingsResponse; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.search.Scroll; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.nlpcn.es4sql.SearchDao; +import org.nlpcn.es4sql.query.QueryAction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Conditional; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.util.*; + +@Conditional(ElasticSearchCondition.class) +@Component +@Slf4j +public class ElasticSearchActuatorImpl implements ElasticSearchActuator { + + private final static String DEFAULT_DOC_TYPE = "_doc"; + + private final static String CREATE_OPERATE_TYPE = "create"; + + private final static String HITS_STR = "hits"; + + private final static String SOURCE_STR = "_source"; + + private final static String AGGREGATE_KEY = "aggregations"; + + private RestHighLevelClient restHighLevelClient; + + private TransportClient transportClient; + + + @Conditional(ElasticSearchCondition.class) + @Qualifier("EsHighLevelClient") + @Autowired + public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) { + this.restHighLevelClient = restHighLevelClient; + } + + + @Conditional(ElasticSearchSqlCondition.class) + @Qualifier("TransportClient") + @Autowired + public void setTransportClient(TransportClient transportClient) { + this.transportClient = transportClient; + } + + + @Override + public boolean checkIndex(String indexName) { + if(!StringUtils.isEmpty(indexName)) { + try { + return restHighLevelClient.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT); + } catch (Exception e) { + log.error("Es检测索引 {} 失败!." + e,indexName); + e.printStackTrace(); + } + } + return false; + } + + @Override + public boolean createIndex(String indexName, JSONObject mapping) { + if(checkIndex(indexName)){ + log.warn("索引{}已经存在,创建索引失败.",indexName); + }else if(null == mapping || mapping.isEmpty() || StrUtil.isBlankIfStr(indexName)){ + log.error("构建mapping或索引名称为空,创建索引失败."); + }else { + CreateIndexRequest request = new CreateIndexRequest(indexName); + Map source = new HashMap<>(); + source.put("properties",mapping); + request.mapping(source); + try { + restHighLevelClient.indices().create(request,RequestOptions.DEFAULT); + return true; + }catch (Exception e){ + log.error("构建索引{}失败,es错误 "+e,indexName); + e.printStackTrace(); + } + } + return false; + } + + @Override + public boolean deleteIndex(String indexName) { + DeleteIndexRequest request = new DeleteIndexRequest(indexName); + try { + restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT); + return true; + }catch (Exception e){ + log.error("删除索引 {} 失败"+e,indexName); + e.printStackTrace(); + } + return false; + } + + @Override + public boolean addIndexData(String indexName, JSONObject data) { + BulkRequest request = new BulkRequest(); + request.add(new IndexRequest().index(indexName).opType(CREATE_OPERATE_TYPE).source(data, XContentType.JSON).create(true)); + try { + restHighLevelClient.bulk(request, RequestOptions.DEFAULT); + return true; + }catch (Exception e){ + log.error("插入数据失败"+e); + e.printStackTrace(); + } + return false; + } + + @Override + public boolean addIndexDatas(String indexName, JSONArray datas) { + BulkRequest request = new BulkRequest(); + for (Object obj:datas){ + JSONObject dataMap = (JSONObject)obj; + request.add(new IndexRequest().index(indexName).opType(CREATE_OPERATE_TYPE).source(dataMap,XContentType.JSON).create(true)); + } + try { + restHighLevelClient.bulk(request, RequestOptions.DEFAULT); + return true; + }catch (Exception e){ + log.error("索引{}批量插入数据失败"+e,indexName); + e.printStackTrace(); + } + return false; + } + + @Override + public boolean clearIndexData(String indexName) { + try { + DeleteRequest deleteRequest = new DeleteRequest(indexName, DEFAULT_DOC_TYPE); + restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT); + return true; + }catch (Exception e){ + log.error("清除索引{}的数据失败!"+e,indexName); + e.printStackTrace(); + } + return false; + } + + @Override + public boolean deleteIndexDataById(String indexName, String id) { + try { + DeleteRequest deleteRequest = new DeleteRequest(indexName, DEFAULT_DOC_TYPE, id); + restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT); + return true; + }catch (Exception e){ + log.error("删除索引{}中id为{}的数据失败!"+e,indexName,id); + e.printStackTrace(); + } + return false; + } + + @Override + public List getAllIndexName() { + List result = new ArrayList<>(); + GetAliasesRequest request = new GetAliasesRequest(); + GetAliasesResponse response = null; + try { + response = restHighLevelClient.indices().getAlias(request, RequestOptions.DEFAULT); + }catch (Exception e){ + log.error("es获取所有索引错误,"+e); + e.printStackTrace(); + } + if(null != response){ + Map> indexmap = response.getAliases(); + for(String key:indexmap.keySet()){ + result.add(key); + } + } + return result; + } + + @Override + public List getFieldsByIndexName(String indexName) { + List result = new ArrayList<>(); + GetMappingsRequest getMappings=new GetMappingsRequest().indices(indexName); + try { + GetMappingsResponse getMappingResponse = restHighLevelClient.indices().getMapping(getMappings, RequestOptions.DEFAULT); + Map allMappings = getMappingResponse.mappings(); + MappingMetaData indexMapping = allMappings.get(indexName); + Map mapping = indexMapping.sourceAsMap(); + Map fields = (Map)mapping.get("properties"); + Iterator> entries=fields.entrySet().iterator(); + while(entries.hasNext()){ + Map.Entry entry = entries.next(); + String key = entry.getKey(); + Map value = (Map)entry.getValue(); + String type = value.get("type"); + if(null == type || "null".equals(type)){ + continue; + } + FieldEntity temp = new FieldEntity(key,type); + result.add(temp); + } + }catch (Exception e){ + log.error("es查询索引{}的字段集合错误"+e,indexName); + e.printStackTrace(); + } + return result; + } + + @Override + public JSONObject getElasticSearchDataById(String indexName, String docType, String id) { + Request request = new Request("get","/"+indexName+"/"+docType+"/"+id); + try{ + return excuteHttpRequest(request); + }catch (Exception e){ + log.error("获取索引{}中id为{}的数据失败!"+e,indexName,id); + e.printStackTrace(); + } + return null; + } + + @Override + public JSONObject getElasticSearchDataById(String indexName, String id) { + return getElasticSearchDataById(indexName,DEFAULT_DOC_TYPE,id); + } + + + @Override + @ExecuteDslLog + public JSONObject executeSearchDslStr(String indexName, String dslBodyStr) { + Request req = new Request("post","/"+indexName+"/_search"); + req.setJsonEntity(dslBodyStr); + try{ + return excuteHttpRequest(req); + }catch (Exception e){ + log.error("executeSearchDslStr Error \nindexName:{} \n DSL:\n {}",indexName,dslBodyStr); + e.printStackTrace(); + } + return new JSONObject(); + } + + + @Override + public SearchResult executeSearchSearchSourceBuilder(String indexName, SearchSourceBuilder searchSourceBuilder, Class resultObj) { + JSONObject retJSon = executeSearchDslStr(indexName,searchSourceBuilder.toString()); + SearchResult result = new SearchResult<>(); + if(!retJSon.isEmpty()) { + result.setTotal(retJSon.getJSONObject(HITS_STR).getJSONObject("total").getInt("value")); + JSONArray arra = retJSon.getJSONObject(HITS_STR).getJSONArray(HITS_STR); + for (int i = 0; i < arra.size(); i++) { + JSONObject obj = arra.getJSONObject(i); + DocBaseEntity tem = new DocBaseEntity<>(obj); + tem.setDatas(JSONUtil.toBean(obj.getJSONObject(SOURCE_STR), resultObj)); + result.addData(tem); + } + if (retJSon.containsKey(AGGREGATE_KEY)) { + result.setAggregations(retJSon.getJSONObject(AGGREGATE_KEY)); + } + } + return result; + } + + + @Override + @ExecuteDslLog + public SearchResult searchElasticSearchDatas(String indexName, SearchSourceBuilder searchSourceBuilder, Class resultObj) { + SearchResult result = new SearchResult<>(); + SearchRequest searchRequest = new SearchRequest(indexName); + searchRequest.source(searchSourceBuilder); + try { + SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + result = createSearchResult(response,resultObj); + }catch (Exception e){ + log.error("searchElasticSearchDatas Error \nindexName:{}\nDSL:\n {}",indexName,searchSourceBuilder.toString()); + e.printStackTrace(); + } + return result; + } + + + @Override + @ExecuteDslLog + public SearchResult scrollSearchElasticSearchDatas(String indexName, SearchSourceBuilder searchSourceBuilder, int pageNo, Class resultObj) { + SearchResult resultMap = new SearchResult(); + SearchRequest searchRequest = new SearchRequest(indexName); + searchRequest.source(searchSourceBuilder); + try{ + SearchResponse searchResp = scrollSearch(pageNo,searchRequest); + resultMap = createSearchResult(searchResp,resultObj); + }catch (Exception e){ + log.error("scrollSearch Error!\nindexName:{}\n dls:\n {}",indexName,searchSourceBuilder.toString()); + e.printStackTrace(); + } + return resultMap; + } + + @Override + public SearchResult aggregateDatas(String indexName, String searchDslStr) { + JSONObject retJSon = executeSearchDslStr(indexName,searchDslStr); + if(null == retJSon || !retJSon.containsKey(AGGREGATE_KEY)){ + return new SearchResult<>(); + }else { + SearchResult ret = new SearchResult<>(); + ret.setAggregations(retJSon.getJSONObject(AGGREGATE_KEY)); + return ret; + } + } + + @Override + public SearchResult aggregateDatas(String indexName, SearchSourceBuilder searchSourceBuilder) { + return aggregateDatas(indexName,searchSourceBuilder.size(0).toString()); + } + + + @Override + public String translateSQL(String sql) { + if(null != transportClient){ + try { + SearchDao searchDao = new SearchDao(transportClient); + QueryAction queryAction = searchDao.explain(sql); + return queryAction.explain().explain(); + } catch (Exception e) { + log.error("translateSQL Failed!sql:{}"+e,sql); + e.printStackTrace(); + } + }else { + log.warn("Confirm whether the configuration of es-sql is enabled !!! spring.elasticsearch.tcpport: xxx"); + } + return null; + } + + + + /** + * 执行ES的HTTP的API查询 + * @param request 请求 + * @return JSONObject + * @throws Exception + */ + private JSONObject excuteHttpRequest(Request request) throws Exception{ + Response ret = restHighLevelClient.getLowLevelClient().performRequest(request); + if(200 == ret.getStatusLine().getStatusCode()){ + return JSONUtil.parseObj(EntityUtils.toString(ret.getEntity()),false,false); + }else { + log.error("ElasticSearch HTTP API status:{} Error!!!!!",ret.getStatusLine().getStatusCode()); + throw new HttpException(); + } + } + + private SearchResponse scrollSearch(int pageNo,SearchRequest searchRequest) { + Scroll scroll = new Scroll(TimeValue.timeValueMinutes(3)); + searchRequest.scroll(scroll); + SearchResponse searchResponse = null; + try { + searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + String scrollId = searchResponse.getScrollId(); + SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId); + searchScrollRequest.scroll(scroll); + for (int i = 0; i < (pageNo -1); i++) { + searchResponse = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT); + } + if (scrollId != null) { + ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); + clearScrollRequest.addScrollId(scrollId); + ClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); + clearScrollResponse.isSucceeded(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return searchResponse; + } + + /** + * 构建目标结果 + * @param response 返回参数 + * @param resultObj 类对象 + * @param + * @return + */ + private SearchResult createSearchResult(SearchResponse response,Class resultObj){ + SearchResult resultMap = new SearchResult<>(); + SearchHit[] datas = response.getHits().getHits(); + for(SearchHit data:datas){ + DocBaseEntity temp = new DocBaseEntity<>(data); + temp.setDatas(JSONUtil.toBean(JSONUtil.parseObj(data.getSourceAsMap()),resultObj)); + resultMap.addData(temp); + } + resultMap.setTotal(response.getHits().getTotalHits().value); + return resultMap; + } + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchCondition.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchCondition.java new file mode 100644 index 0000000..c3317dd --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchCondition.java @@ -0,0 +1,23 @@ +package com.gcc.container.components.elasticsearch.configure; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + + +public class ElasticSearchCondition implements Condition { + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + String host = conditionContext.getEnvironment().getProperty("spring.elasticsearch.host"); + String port = conditionContext.getEnvironment().getProperty("spring.elasticsearch.port"); + + if(null != host && null != port){ + return true; + } + + return false; + + } + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchLogCondition.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchLogCondition.java new file mode 100644 index 0000000..91ee7d0 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchLogCondition.java @@ -0,0 +1,21 @@ +package com.gcc.container.components.elasticsearch.configure; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.StringUtils; + +public class ElasticSearchLogCondition implements Condition { + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + String logEnable = conditionContext.getEnvironment().getProperty("spring.elasticsearch.log-enable"); + + if(!StringUtils.isEmpty(logEnable)){ + return Boolean.parseBoolean(logEnable); + } + return false; + + } + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchSqlCondition.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchSqlCondition.java new file mode 100644 index 0000000..e9908f5 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/ElasticSearchSqlCondition.java @@ -0,0 +1,21 @@ +package com.gcc.container.components.elasticsearch.configure; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.util.StringUtils; + +public class ElasticSearchSqlCondition implements Condition { + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + String tcpport = conditionContext.getEnvironment().getProperty("spring.elasticsearch.tcpport"); + + if(!StringUtils.isEmpty(tcpport)){ + return true; + } + return false; + + } + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/LoadEsClient.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/LoadEsClient.java new file mode 100644 index 0000000..31a4cd6 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/configure/LoadEsClient.java @@ -0,0 +1,93 @@ +package com.gcc.container.components.elasticsearch.configure; + +import com.gcc.container.components.elasticsearch.property.ElasticSearchProperties; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.transport.client.PreBuiltTransportClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class LoadEsClient { + + + private ElasticSearchProperties properties; + + + @Autowired + public void setProperties(ElasticSearchProperties properties) { + this.properties = properties; + } + + + @Conditional(ElasticSearchCondition.class) + @Bean("EsHighLevelClient") + public RestHighLevelClient getClient() { + RestHighLevelClient highLevelClient = null ; + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(properties.getUser(), properties.getPassword())); + highLevelClient = new RestHighLevelClient( + RestClient.builder(getESHosts()).setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { + @Override + public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { + // 设置连接超时和套接字超时时长 + return requestConfigBuilder.setConnectTimeout(60000).setSocketTimeout(60000*3); + } + }).setHttpClientConfigCallback( + new RestClientBuilder.HttpClientConfigCallback() { + @Override + public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) { + return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + } + } + ) + ); + return highLevelClient; + } + + + @Conditional(ElasticSearchSqlCondition.class) + @Bean("TransportClient") + public TransportClient getTransportClient() throws UnknownHostException { + Settings settings = Settings.builder() + .put("client.transport.sniff", true) + .put("client.transport.ignore_cluster_name",true) + .build(); + TransportClient client = new PreBuiltTransportClient(settings) + .addTransportAddress(new TransportAddress(InetAddress.getByName(properties.getHost()),properties.getTcpPort())); + + return client; + } + + + private HttpHost[] getESHosts() { + String[] esHosts = properties.getHost().trim().split(","); + List host = new ArrayList(); + for(String it:esHosts){ + host.add(new HttpHost(it,properties.getPort(), properties.getScheme())); + } + HttpHost[] hostArray = host.toArray(new HttpHost[esHosts.length]); + return hostArray; + } + + + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/log/annotation/ExecuteDslLog.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/log/annotation/ExecuteDslLog.java new file mode 100644 index 0000000..1f39b4a --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/log/annotation/ExecuteDslLog.java @@ -0,0 +1,11 @@ +package com.gcc.container.components.elasticsearch.log.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExecuteDslLog { +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/log/aspect/ElasticSearchMonitorAspect.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/log/aspect/ElasticSearchMonitorAspect.java new file mode 100644 index 0000000..0446ffe --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/log/aspect/ElasticSearchMonitorAspect.java @@ -0,0 +1,30 @@ +package com.gcc.container.components.elasticsearch.log.aspect; + +import com.gcc.container.components.elasticsearch.configure.ElasticSearchLogCondition; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.context.annotation.Conditional; +import org.springframework.stereotype.Component; + +@Conditional(ElasticSearchLogCondition.class) +@Component +@Aspect +@Slf4j(topic = "ES-Monitor") +public class ElasticSearchMonitorAspect { + + + @Before("@annotation(com.gcc.container.components.elasticsearch.log.annotation.ExecuteDslLog)") + public void beforeAdvice(JoinPoint point) throws Throwable{ + Object[] args = point.getArgs(); + if(args.length >= 2){ + String index = String.valueOf(args[0]); + String dsl = args[1].toString(); + MethodSignature signature = (MethodSignature) point.getSignature(); + log.info("\nmethod: {} , indexName: {} \nDSL: {}",signature.getMethod().getName(),index,dsl); + } + + } +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/SearchResult.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/SearchResult.java new file mode 100644 index 0000000..661b995 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/SearchResult.java @@ -0,0 +1,50 @@ +package com.gcc.container.components.elasticsearch.model; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.elasticsearch.model.entity.DocBaseEntity; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +@Data +public class SearchResult implements Serializable { + + + private int total; + + + private List> source = new ArrayList<>(); + + + private JSONObject aggregations; + + + public void addData(DocBaseEntity obj){ + source.add(obj); + } + + public List getDatas(){ + return source.stream().map(DocBaseEntity::getDatas).collect(Collectors.toList()); + } + + public void addDatas(List> objs){ + source.addAll(objs); + } + + + public void setTotal(Object total){ + this.total = Integer.parseInt(String.valueOf(total)); + } + + + public JSONObject toJSONObject(){ + return JSONUtil.parseObj(this,true); + } + + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/DocBaseEntity.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/DocBaseEntity.java new file mode 100644 index 0000000..a759a0b --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/DocBaseEntity.java @@ -0,0 +1,36 @@ +package com.gcc.container.components.elasticsearch.model.entity; + +import cn.hutool.json.JSONObject; +import lombok.Data; +import org.elasticsearch.search.SearchHit; + +import java.io.Serializable; + +@Data +public class DocBaseEntity implements Serializable { + + private String _index; + + private String _type; + + private String _id; + + private T datas; + + public DocBaseEntity(SearchHit data) { + this._index = data.getIndex(); + this._type = data.getType(); + this._id = data.getId(); + } + + public DocBaseEntity(JSONObject jsonHits){ + this._index = jsonHits.getStr("_index"); + this._type = jsonHits.getStr("_type"); + this._id = jsonHits.getStr("_id"); + } + + public T getDatas(){ + return datas; + } + +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/FieldEntity.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/FieldEntity.java new file mode 100644 index 0000000..b38eb87 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/model/entity/FieldEntity.java @@ -0,0 +1,21 @@ +package com.gcc.container.components.elasticsearch.model.entity; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class FieldEntity implements Serializable { + + + private String properties; + + + private String type; + + + public FieldEntity(String properties, String type) { + this.properties = properties; + this.type = type; + } +} diff --git a/es-component/src/main/java/com/gcc/container/components/elasticsearch/property/ElasticSearchProperties.java b/es-component/src/main/java/com/gcc/container/components/elasticsearch/property/ElasticSearchProperties.java new file mode 100644 index 0000000..7f2d806 --- /dev/null +++ b/es-component/src/main/java/com/gcc/container/components/elasticsearch/property/ElasticSearchProperties.java @@ -0,0 +1,41 @@ +package com.gcc.container.components.elasticsearch.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@ConfigurationProperties(prefix = "spring.elasticsearch") +@Data +@Configuration +public class ElasticSearchProperties { + + private String host; + + + private String port; + + + private String tcpPort; + + + private String user = ""; + + + private String password = ""; + + + private String Scheme; + + + private Boolean logEnable = false; + + + public Integer getPort(){ + return Integer.valueOf(port); + } + + + public Integer getTcpPort() { + return Integer.valueOf(tcpPort); + } +} diff --git a/es-component/src/main/resources/META-INF/spring.factories b/es-component/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..3798cbb --- /dev/null +++ b/es-component/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.elasticsearch.ApplicationConfiguration \ No newline at end of file diff --git a/es-component/src/main/resources/application.yml b/es-component/src/main/resources/application.yml new file mode 100644 index 0000000..46bb617 --- /dev/null +++ b/es-component/src/main/resources/application.yml @@ -0,0 +1,9 @@ +spring: + elasticsearch: + host: 10.11.203.7 + port: 9500 + tcpport: 9300 + user: elastic + password: 1234 + scheme: http + log-enable: false \ No newline at end of file -- Gitee From 0475fc240ae2e5bdc0af436341f364e88425ce9e Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 01:15:32 +0000 Subject: [PATCH 09/33] update pom.xml. Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 67dc53c..94e2555 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ rest-component redis-component initdatabse-component + es-component -- Gitee From ae5a0c94adf4863a3691af59b669c408e1d25d33 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 03:05:38 +0000 Subject: [PATCH 10/33] =?UTF-8?q?=E8=A7=A3=E5=86=B3swagger=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E4=BD=BF=E7=94=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../components/web/exception/ControllerExceptionAdvice.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java b/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java index e80fae0..e870ef3 100644 --- a/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java +++ b/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java @@ -15,8 +15,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import java.util.LinkedHashMap; - -@RestControllerAdvice +//仅支持自定义编写的API接口全局拦截 +@RestControllerAdvice(annotations = {GetMapping.class, PostMapping.class}) public class ControllerExceptionAdvice implements ResponseBodyAdvice { @Override -- Gitee From d485521fd90851d26a64c9607b9ed6780c2adf5e Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 09:27:31 +0000 Subject: [PATCH 11/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- task-components/pom.xml | 13 ++ .../task/ApplicationConfiguration.java | 9 + .../components/task/annotation/TaskJob.java | 19 ++ .../task/compont/AbstractBaseCronTask.java | 111 ++++++++++++ .../InitTaskSchedulingApplication.java | 48 ++++++ .../components/task/compont/TaskSchedule.java | 62 +++++++ .../task/compont/TaskScheduleImpl.java | 160 +++++++++++++++++ .../task/compont/TaskTempFactory.java | 83 +++++++++ .../components/task/dao/TaskRepository.java | 58 +++++++ .../dao/impl/FileOpTaskRepositoryImpl.java | 163 ++++++++++++++++++ .../task/model/TaskVoConvertor.java | 40 +++++ .../task/model/dto/SearchTaskDto.java | 28 +++ .../task/model/entity/TaskEntity.java | 88 ++++++++++ .../task/model/vo/TaskRunRetVo.java | 70 ++++++++ .../components/task/model/vo/TaskVo.java | 55 ++++++ .../task/property/TaskDataProperties.java | 15 ++ .../main/resources/META-INF/spring.factories | 1 + 17 files changed, 1023 insertions(+) create mode 100644 task-components/pom.xml create mode 100644 task-components/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java create mode 100644 task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java create mode 100644 task-components/src/main/resources/META-INF/spring.factories diff --git a/task-components/pom.xml b/task-components/pom.xml new file mode 100644 index 0000000..a1076fc --- /dev/null +++ b/task-components/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + + com.gcc.container + components + 1.0.0 + + com.gcc.container.components + task-component + ${component.version} + jar + diff --git a/task-components/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java b/task-components/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java new file mode 100644 index 0000000..0697cbc --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java @@ -0,0 +1,9 @@ +package com.gcc.container.components.task; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "com.gcc.container.components.task.*") +public class ApplicationConfiguration { +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java b/task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java new file mode 100644 index 0000000..a62c457 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java @@ -0,0 +1,19 @@ +package com.gcc.container.components.task.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TaskJob { + + String desc() default "暂无描述"; + + String cron() default "00 00 00 * * ?"; + + boolean bootup() default false; + +} \ No newline at end of file diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java b/task-components/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java new file mode 100644 index 0000000..93d3586 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java @@ -0,0 +1,111 @@ +package com.gcc.container.components.task.compont; + + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; + +/** + * 抽象定时任务类 + * 实现定时任务需要继承该类 + * 子类实现时,不要使用Spring的任何注解 + * 若依赖外部的对象,使用 getServer()方法进行手动注入 + * @author GCC + */ +public abstract class AbstractBaseCronTask implements Runnable{ + + public Logger log; + + + private TaskEntity taskEntity; + + + private Double consumptionTime; + + private ApplicationContext applicationContext; + + + public AbstractBaseCronTask(TaskEntity taskEntity){ + log = LoggerFactory.getLogger(taskEntity.getTaskName()); + this.taskEntity = taskEntity; + } + + + //前置操作 + public abstract void beforeJob(); + + + //任务操作 + public abstract void startJob(); + + + //后置操作 + public abstract void afterJob(); + + + @Override + public void run() { + log.info("---------------------任务 {} 开始执行-----------------------",taskEntity.getTaskName()); + log.info("任务描述:"+taskEntity.getTaskDesc()); + consumptionTime = 0d; + try { + Long start = System.currentTimeMillis(); + beforeJob(); + startJob(); + afterJob(); + Long end = System.currentTimeMillis(); + consumptionTime = NumberUtil.div((end - start),1000); + log.info("任务耗时:约 {} s",consumptionTime); + taskEntity.setTaskLastRun(1); + }catch (Exception e){ + log.error("任务{}计算出错!请及时排查问题!", taskEntity.getTaskName(),e); + taskEntity.setTaskLastRun(0); + } + getServer(TaskRepository.class).updateRunStatus(taskEntity); + String id = this.taskEntity.getTaskId(); + this.taskEntity = getServer(TaskRepository.class).queryData(id); + log.info("---------------------任务 {} 结束执行-----------------------\n",taskEntity.getTaskName()); + } + + + public Object getSelfConfig(String key){ + try{ + TaskEntity entity = getServer(TaskRepository.class).queryData(taskEntity.getTaskId()); + JSONObject config = JSONUtil.parseObj(entity.getTaskOutConfig()); + return config.get(key); + }catch (Exception e){ + log.error("获取任务 {} 的配置参数失败,请确认参数配置格式是否正确!",taskEntity.getTaskName()); + } + return new JSONObject(); + } + + + public double getRunTime(){ return this.consumptionTime;} + + public TaskEntity getThisTaskInfo(){ + return this.taskEntity; + } + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + + /** + * 为适配反射生成的对象不受Spring容器管辖导致对象不共用问题 + * 提供手动获取系统上下文容器完成依赖注入 + * 通过类名使用Spring容器中的对象 + * @param className 类 + * @param 返回类型 + * @return T + */ + public T getServer(Class className){ + return applicationContext.getBean(className); + } + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java b/task-components/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java new file mode 100644 index 0000000..6085c3a --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java @@ -0,0 +1,48 @@ +package com.gcc.container.components.task.compont; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 初始化任务调度机制 + * @author GCC + */ +@Order(1) +@Slf4j +@Component +public class InitTaskSchedulingApplication implements ApplicationRunner { + + private TaskSchedule taskSchedule; + + + private TaskTempFactory taskTempFactory; + + + @Autowired + public void setTaskScheduleServer(TaskSchedule taskSchedule) { + this.taskSchedule = taskSchedule; + } + + @Autowired + public void setTaskTempFactory(TaskTempFactory taskTempFactory) { + this.taskTempFactory = taskTempFactory; + } + + @Override + public void run(ApplicationArguments args) throws Exception { + //开启扫描 + taskTempFactory.scanTaskInfo(); + log.info("【定时任务初始化】 容器初始化"); + taskSchedule.initScheduling(); + log.info("【定时任务初始化】定时任务初始化任务开始"); + taskSchedule.loadAllTask(); + log.info("【定时任务初始化】定时任务初始化任务完成"); + + } + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java new file mode 100644 index 0000000..c2d2949 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java @@ -0,0 +1,62 @@ +package com.gcc.container.components.task.compont; + + + + +import com.gcc.container.components.task.model.entity.TaskEntity; + +import java.util.concurrent.ConcurrentHashMap; + +public interface TaskSchedule { + + + + ConcurrentHashMap getTaskSchedulingRam(); + + + /** + * 初始化任务调度 + */ + void initScheduling(); + + /** + * 添加任务至内存及容器 + * @param taskEntity 任务实体 + * @return boolean + */ + boolean addTaskToScheduling(TaskEntity taskEntity); + + /** + * 从任务调度器中移除任务 + * @param id 任务id + * @return Boolean + */ + boolean removeTaskFromScheduling(String id); + + + /** + * 执行指定任务 + * @param id 任务id + * @return double 耗时 + */ + double runTaskById(String id); + + + /** + * 清空任务 + */ + void claearAllTask(); + + + + /** + * 加载所有任务 + */ + void loadAllTask(); + + /** + * 运行开机自启任务 + */ + void runBootUpTask(); + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java new file mode 100644 index 0000000..be53fc1 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java @@ -0,0 +1,160 @@ +package com.gcc.container.components.task.compont; + + +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Constructor; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; + +@Slf4j +@Component +public class TaskScheduleImpl implements TaskSchedule { + + //正在运行的任务 + private static ConcurrentHashMap runningTasks = new ConcurrentHashMap<>(); + + //线程池任务调度 + private ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); + + //内存中任务对象 + private static ConcurrentHashMap ramTasks = new ConcurrentHashMap<>(); + + //Spring容器池,用于注入Spring的bean + private ApplicationContext context; + + + private TaskRepository taskRepository; + + + private TaskTempFactory taskFactory; + + + @Autowired + public void setTaskRepository(TaskRepository taskRepository) { + this.taskRepository = taskRepository; + } + + @Autowired + public void setContext(ApplicationContext context) { + this.context = context; + } + + @Autowired + public void setTaskFactory(TaskTempFactory taskFactory) { + this.taskFactory = taskFactory; + } + + @Autowired + + + @Override + public ConcurrentHashMap getTaskSchedulingRam() { + return ramTasks; + } + + @Override + public void initScheduling() { + int num = taskFactory.mergeTaskEntities().size(); + num = num > 0 ? num:1; + this.threadPoolTaskScheduler.setPoolSize(num); + this.threadPoolTaskScheduler.setThreadNamePrefix("task-thread-"); + this.threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); + this.threadPoolTaskScheduler.initialize(); + } + + + @Override + public boolean addTaskToScheduling(TaskEntity task) { + if(!runningTasks.containsKey(task.getTaskId())){ + try{ + Class clazz = Class.forName(task.getTaskClass()); + Constructor c = clazz.getConstructor(TaskEntity.class); + AbstractBaseCronTask runnable = (AbstractBaseCronTask) c.newInstance(task); + //反射方式生成对象不属于Spring容器管控,对于Spring的bean使用需要手动注入 + runnable.setApplicationContext(context); + CronTrigger cron = new CronTrigger(task.getTaskCron()); + //put到runTasks + runningTasks.put(task.getTaskId(), Objects.requireNonNull(this.threadPoolTaskScheduler.schedule(runnable, cron))); + //存入内存中,便于外部调用 + ramTasks.put(task.getTaskId(),runnable); + task.setTaskRamStatus(1); + taskRepository.update(task); + return true; + }catch (Exception e){ + log.error("定时任务加载失败..."+e); + } + } + return false; + } + + + @Override + public boolean removeTaskFromScheduling(String id) { + if(runningTasks.containsKey(id)){ + runningTasks.get(id).cancel(true); + runningTasks.remove(id); + ramTasks.remove(id); + TaskEntity entity = taskRepository.queryData(id); + entity.setTaskRamStatus(0); + entity.setTaskLastRun(null); + if( 1 == taskRepository.update(entity) && !runningTasks.containsKey(id)){ + log.info("【定时任务控制器】任务"+id+"从内存进程池中移除,被终止!"); + return true; + } + } + return false; + } + + @Override + public double runTaskById(String id) { + TaskEntity task = taskRepository.queryData(id); + if(null!=task) { + if (runningTasks.containsKey(task.getTaskId())){ + ramTasks.get(task.getTaskId()).run(); + return ramTasks.get(task.getTaskId()).getRunTime(); + } + } + return 0d; + } + + @Override + public void claearAllTask() { + ramTasks.clear(); + log.info("【定时任务控制器】清除内存任务 完成"); + runningTasks.clear(); + log.info("【定时任务控制器】清除线程任务 完成"); + threadPoolTaskScheduler.shutdown(); + } + + @Override + public void loadAllTask() { + List allTask = taskFactory.mergeTaskEntities(); + for (TaskEntity task : allTask) { + if(addTaskToScheduling(task)){ + log.info("【定时任务初始化】装填任务:{} [ 任务执行周期:{} ] [ bootup:{}]",task.getTaskName(),task.getTaskCron(),task.getTaskBootUp()); + } + } + } + + + @Override + public void runBootUpTask() { + TaskEntity entity = new TaskEntity() + .taskIsUse(1) + .taskBootUp(1); + List list = taskRepository.queryData(entity); + for(TaskEntity task:list){ + runTaskById(task.getTaskId()); + } + } +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java new file mode 100644 index 0000000..65e7a67 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java @@ -0,0 +1,83 @@ +package com.gcc.container.components.task.compont; + + +import cn.hutool.crypto.digest.DigestUtil; + +import com.gcc.container.components.task.annotation.TaskJob; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +class TaskTempFactory { + + @Autowired + private TaskRepository taskRepository; + + + private List tempContainer = new ArrayList<>(); + + + public void scanTaskInfo() throws Exception { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(TaskJob.class)); + Set beanDefinitions = provider.findCandidateComponents("com.gcc.*"); // 替换为你的包名 + for (BeanDefinition beanDefinition : beanDefinitions) { + Class clazz = Class.forName(beanDefinition.getBeanClassName()); + TaskJob taskJob = clazz.getAnnotation(TaskJob.class); + if (AbstractBaseCronTask.class.isAssignableFrom(clazz)) { + tempContainer.add(builderTaskEntity(clazz,taskJob)); + } else { + throw new IllegalArgumentException("Class " + clazz.getName() + " must extend AbstractBaseCronTask"); + } + } + } + + + public List mergeTaskEntities() { + List db = taskRepository.queryData(new TaskEntity().taskIsUse(1)); + Map map = db.stream() + .collect(Collectors.toMap( + TaskEntity::getTaskClass, + task -> task + )); + for(TaskEntity entity:tempContainer){ + if(!map.containsKey(entity.getTaskClass())){ + taskRepository.save(entity); + db.add(entity); + } + } + return db; + } + + + private TaskEntity builderTaskEntity(Class cronTaskClass, TaskJob taskJob) { + String path = cronTaskClass.getName(); TaskEntity entity = new TaskEntity(); + entity.setTaskId(DigestUtil.md5Hex(path)); + entity.setTaskClass(path); + entity.setTaskIsUse(1); + entity.setTaskName(cronTaskClass.getSimpleName()); + entity.setTaskDesc("暂无描述"); + entity.setTaskBootUp(converBootUp(taskJob.bootup())); + entity.setTaskCron(taskJob.cron()); + //todo 外部配置 + return entity; + } + + private Integer converBootUp(Boolean flag){ + if(flag){ + return 1; + } + return 0; + } +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java b/task-components/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java new file mode 100644 index 0000000..13db404 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java @@ -0,0 +1,58 @@ +package com.gcc.container.components.task.dao; + + +import com.gcc.container.components.task.model.entity.TaskEntity; + +import java.util.List; + +/** + * 任务数据操作 + */ +public interface TaskRepository { + + /** + * 新增数据 + * @param entity + * @return int + */ + int save(TaskEntity entity); + + + /** + * 删除任务ID + * @param id id + * @return int + */ + int remove(String id); + + + /** + * 更新整个任务 + * @param entity 实体 + * @return int + */ + int update(TaskEntity entity); + + /** + * 更新数据(运行状态) + * @param entity 参数 + * @return int + */ + int updateRunStatus(TaskEntity entity); + + + /** + * 查询数据 + * @param entity 查询 + * @return TaskEntity + */ + List queryData(TaskEntity entity); + + + /** + * 查询具体的任务实体 + * @param id id + * @return TaskEntity + */ + TaskEntity queryData(String id); +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java b/task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java new file mode 100644 index 0000000..8cbe032 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java @@ -0,0 +1,163 @@ +package com.gcc.container.components.task.dao.impl; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; + +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.property.TaskDataProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +@Repository +@Slf4j +public class FileOpTaskRepositoryImpl implements TaskRepository { + + + @Autowired + private TaskDataProperties properties; + + + + @Override + public int save(TaskEntity entity) { + List list = readFileInfo(); + list.add(entity); + writeFileInfo(list); + return 1; + } + + @Override + public int remove(String id) { + List list = readFileInfo(); + List data = new ArrayList<>(); + for(TaskEntity entity:list){ + if(!entity.getTaskId().equals(id)){ + data.add(entity); + } + } + writeFileInfo(data); + return list.size() - data.size(); + } + + @Override + public int update(TaskEntity entity) { + List list = readFileInfo(); + List data = new ArrayList<>(); + for(TaskEntity one:list){ + if(!one.getTaskId().equals(entity.getTaskId())){ + data.add(entity); + } + } + data.add(entity); + writeFileInfo(data); + return 1; + } + + @Override + public int updateRunStatus(TaskEntity entity) { + List list = readFileInfo(); + for(TaskEntity one:list){ + if(one.getTaskId().equals(entity.getTaskId())){ + one.setTaskLastRun(entity.getTaskLastRun()); + one.setTaskRamStatus(entity.getTaskRamStatus()); + } + } + writeFileInfo(list); + return 1; + } + + @Override + public List queryData(TaskEntity entity) { + List list = readFileInfo(); + // 获取不为空的属性 + Map nonNullProperties = entity.getNonNullProperties(); + // 进行 AND 查询 + List result = new ArrayList<>(); + for (TaskEntity t : list) { + boolean match = true; + for (Map.Entry entry : nonNullProperties.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if ("taskDesc".equals(key) && !StrUtil.equals(t.getTaskDesc(), (String) value)) { + match = false; + break; + } + if ("taskIsUse".equals(key) && t.getTaskIsUse() != (Integer) value) { + match = false; + break; + } + if ("taskBootUp".equals(key) && t.getTaskBootUp() != (Integer) value) { + match = false; + break; + } + } + if (match) { + result.add(t); + } + } + return result; + } + + @Override + public TaskEntity queryData(String id) { + List list = readFileInfo(); + for(TaskEntity entity:list){ + if(1 == entity.getTaskIsUse() && id.equals(entity.getTaskId())){ + return entity; + } + } + return null; + } + + + private List readFileInfo(){ + // 确保文件存在 + File file = FileUtil.file(getDefaultPath()); + if (!file.exists()) { + log.error("FILE is not exists"); + return new ArrayList<>(); + } + // 读取 JSON 文件内容 + String jsonContent = FileUtil.readUtf8String(getDefaultPath()); + // 将 JSON 字符串转换为 JSON 对象 + JSONArray data = JSONUtil.parseArray(jsonContent); + List result = new ArrayList<>(); + for(int i = 0; i < data.size(); i++){ + result.add(JSONUtil.toBean(data.getJSONObject(i),TaskEntity.class)); + } + return result; + } + + + + /** + * 覆盖写入 JSONArray 文件 + */ + private void writeFileInfo(List data) { + JSONArray array = new JSONArray(data); + // 确保文件存在或创建文件 + File file = FileUtil.touch(getDefaultPath()); + FileUtil.writeUtf8String(array.toJSONString(0), file); + } + + + private String getDefaultPath(){ + if(StrUtil.isNotBlank(properties.getDataFilePath())){ + return properties.getDataFilePath(); + } + ClassPathResource classPathResource = new ClassPathResource("db/task_info.json"); + return classPathResource.getPath(); + } + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java b/task-components/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java new file mode 100644 index 0000000..fe9089c --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java @@ -0,0 +1,40 @@ +package com.gcc.container.components.task.model; + + +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.model.vo.TaskVo; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class TaskVoConvertor { + + + public TaskVo toTaskVo(TaskEntity entity){ + return TaskVo.builder() + .taskId(entity.getTaskId()) + .taskName(entity.getTaskName()) + .taskDesc(entity.getTaskDesc()) + .taskCron(entity.getTaskCron()) + .taskOutConfig(entity.getTaskOutConfig()) + .taskBootUp(entity.getTaskBootUp()) + .taskCreateTime(entity.getTaskCreateTime()) + .status(ramStatusToRunStatus(entity.getTaskRamStatus())) + .build(); + } + + public List toTaskVos(List entities){ + return entities.stream().map(this::toTaskVo).collect(Collectors.toList()); + } + + private TaskVo.TaskRunStatus ramStatusToRunStatus(Integer ramStatus){ + if(1 == ramStatus){ + return TaskVo.TaskRunStatus.open; + }else { + return TaskVo.TaskRunStatus.shutdown; + } + } + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java b/task-components/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java new file mode 100644 index 0000000..0dcf6f1 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java @@ -0,0 +1,28 @@ +package com.gcc.container.components.task.model.dto; + +import lombok.Data; +import java.io.Serializable; + + +/** + * 查询参数 + */ +@Data +public class SearchTaskDto implements Serializable { + + + private String filterKey; + + + private Integer bootUp; + + + private Integer lastRunStatus; + + + private Integer pageNo; + + + private Integer pageSize; + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java b/task-components/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java new file mode 100644 index 0000000..287b3ed --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java @@ -0,0 +1,88 @@ +package com.gcc.container.components.task.model.entity; + + +import lombok.Data; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 任务实体类 + * @author GCC + */ +@Data + +public class TaskEntity implements Serializable { + + + private String taskId; + + private String taskName; + + private String taskDesc; + + private String taskCron; + + private String taskClass; + + /** + * 任务相关配置 + */ + private String taskOutConfig; + + /** + * 任务注册时间 + */ + private String taskCreateTime; + + /** + * 是否启用 + */ + private Integer taskIsUse; + + /** + * 是否开启自启动 + */ + private Integer taskBootUp; + + /** + * 上次运行状态 + */ + private Integer taskLastRun; + + /** + * 任务是否在内存中 + */ + private Integer taskRamStatus; + + + public TaskEntity taskIsUse(Integer taskIsUse) { + this.taskIsUse = taskIsUse; + return this; + } + + public TaskEntity taskBootUp(Integer taskBootUp) { + this.taskBootUp = taskBootUp; + return this; + } + + public TaskEntity taskLastRun(Integer taskLastRun) { + this.taskLastRun = taskLastRun; + return this; + } + + public TaskEntity taskRamStatus(Integer taskRamStatus) { + this.taskRamStatus = taskRamStatus; + return this; + } + + public Map getNonNullProperties() { + Map properties = new HashMap<>(); + if (taskDesc != null) properties.put("taskDesc", taskDesc); + if (taskIsUse != null) properties.put("taskIsUse", taskIsUse); + if (taskBootUp != null) properties.put("taskBootUp", taskBootUp); + return properties; + } + + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java b/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java new file mode 100644 index 0000000..300d935 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java @@ -0,0 +1,70 @@ +package com.gcc.container.components.task.model.vo; + + +import com.gcc.container.components.task.model.entity.TaskEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * 任务运行状态 + */ +@Data +public class TaskRunRetVo implements Serializable { + + + private String taskId; + + + private String taskName; + + + private TaskOperation taskOperation; + + /** + * 执行状态 + * 1:成功 + * 0:失败 + */ + private Integer result; + + + private String extend = "successful"; + + + public TaskRunRetVo(TaskOperation taskOperation, int result) { + this.taskOperation = taskOperation; + this.result = result; + if(result == 0){ + this.extend = "fail"; + } + } + + public TaskRunRetVo taskInfo(TaskEntity taskEntity){ + this.taskId = taskEntity.getTaskId(); + this.taskName = taskEntity.getTaskName(); + return this; + } + + public TaskRunRetVo extend(Object extend){ + this.extend =String.valueOf(extend); + return this; + } + + public enum TaskOperation{ + + //开启 + open, + + //关闭/停止 + shutdown, + + //更新任务 + update, + + //立即执行 + run; + } + + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java b/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java new file mode 100644 index 0000000..433c27a --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java @@ -0,0 +1,55 @@ +package com.gcc.container.components.task.model.vo; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Builder +public class TaskVo implements Serializable { + + private String taskId; + + private String taskName; + + private String taskDesc; + + private String taskCron; + + /** + * 任务相关配置 + */ + private String taskOutConfig; + + /** + * 任务注册时间 + */ + private String taskCreateTime; + + + /** + * 是否开启自启动 + */ + private Integer taskBootUp; + + /** + * 启停状态 + */ + private TaskRunStatus status; + + + public enum TaskRunStatus{ + //开启 + open(1), + //关闭 + shutdown(0); + + Integer code; + + TaskRunStatus(Integer code){ + this.code = code; + } + } + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java b/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java new file mode 100644 index 0000000..e8c0295 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java @@ -0,0 +1,15 @@ +package com.gcc.container.components.task.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties("taskscheduling.task-data") +@Data +public class TaskDataProperties { + + + private String dataFilePath; + +} diff --git a/task-components/src/main/resources/META-INF/spring.factories b/task-components/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..7080fd0 --- /dev/null +++ b/task-components/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.web.ApplicationConfiguration \ No newline at end of file -- Gitee From 01e180c9e8e6244873be1511ecdd02fd734ff3a1 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 09:28:22 +0000 Subject: [PATCH 12/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 94e2555..33c307f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ redis-component initdatabse-component es-component + task-components -- Gitee From 522610e5ab5150fe2570e6bf519add9db3a7a930 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 09:31:33 +0000 Subject: [PATCH 13/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../components/task/AfterAppStarted.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 task-components/src/main/java/com/gcc/container/components/task/AfterAppStarted.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/AfterAppStarted.java b/task-components/src/main/java/com/gcc/container/components/task/AfterAppStarted.java new file mode 100644 index 0000000..74bd974 --- /dev/null +++ b/task-components/src/main/java/com/gcc/container/components/task/AfterAppStarted.java @@ -0,0 +1,32 @@ +package com.gcc.container.components.task; + + + +import com.gcc.container.components.task.compont.TaskSchedule; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Order(3) +@Component +@Slf4j +public class AfterAppStarted implements ApplicationRunner { + + + TaskSchedule taskSchedule; + + @Autowired + public void setTaskScheduleServer(TaskSchedule taskSchedule) { + this.taskSchedule = taskSchedule; + } + + @Override + public void run(ApplicationArguments args) throws Exception { + //运行随系统启动的定时任务 + taskSchedule.runBootUpTask(); + } + +} -- Gitee From bc6fa24a0a3de7b844f54e0a0296387591c6e88f Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 09:35:38 +0000 Subject: [PATCH 14/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../container/components/task/property/TaskDataProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java b/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java index e8c0295..7e6cdfb 100644 --- a/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java +++ b/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java @@ -5,7 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration -@ConfigurationProperties("taskscheduling.task-data") +@ConfigurationProperties("task.task-data") @Data public class TaskDataProperties { -- Gitee From c7753f55b0af834b6f2339a76ce36ee7ffced7ef Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 09:36:52 +0000 Subject: [PATCH 15/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=A0=B7=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- task-components/src/main/resources/application.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 task-components/src/main/resources/application.yml diff --git a/task-components/src/main/resources/application.yml b/task-components/src/main/resources/application.yml new file mode 100644 index 0000000..e0a16e9 --- /dev/null +++ b/task-components/src/main/resources/application.yml @@ -0,0 +1,3 @@ +task: + task-data: + data-file-path: F:\Myself\task_info.json \ No newline at end of file -- Gitee From a5ce014b34b71d730b21540b1603d3a629479615 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Mon, 18 Nov 2024 09:44:59 +0000 Subject: [PATCH 16/33] =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../gcc/container/components/task/compont/TaskTempFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java index 65e7a67..ee29628 100644 --- a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java +++ b/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java @@ -67,7 +67,7 @@ class TaskTempFactory { entity.setTaskClass(path); entity.setTaskIsUse(1); entity.setTaskName(cronTaskClass.getSimpleName()); - entity.setTaskDesc("暂无描述"); + entity.setTaskDesc(entity.setTaskDesc(taskJob.desc())); entity.setTaskBootUp(converBootUp(taskJob.bootup())); entity.setTaskCron(taskJob.cron()); //todo 外部配置 -- Gitee From d327948dfc916a05b1a063d0256316c3dfd64a65 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 20:52:30 +0800 Subject: [PATCH 17/33] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../exception/ControllerExceptionAdvice.java | 2 + {task-components => task-component}/pom.xml | 26 +- .../components/task/AfterAppStarted.java | 0 .../task/ApplicationConfiguration.java | 0 .../components/task/annotation/TaskJob.java | 36 +- .../task/compont/AbstractBaseCronTask.java | 0 .../InitTaskSchedulingApplication.java | 0 .../components/task/compont/TaskSchedule.java | 0 .../task/compont/TaskScheduleImpl.java | 0 .../task/compont/TaskTempFactory.java | 166 ++++----- .../components/task/dao/TaskRepository.java | 0 .../dao/impl/FileOpTaskRepositoryImpl.java | 326 +++++++++--------- .../task/model/TaskVoConvertor.java | 0 .../task/model/dto/SearchTaskDto.java | 0 .../task/model/entity/TaskEntity.java | 0 .../task/model/vo/TaskRunRetVo.java | 0 .../components/task/model/vo/TaskVo.java | 0 .../task/property/TaskDataProperties.java | 30 +- .../main/resources/META-INF/spring.factories | 0 .../src/main/resources/application.yml | 3 + .../src/main/resources/application.yml | 3 - 22 files changed, 298 insertions(+), 296 deletions(-) rename {task-components => task-component}/pom.xml (97%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/AfterAppStarted.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java (96%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java (95%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java (96%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java (100%) rename {task-components => task-component}/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java (95%) rename {task-components => task-component}/src/main/resources/META-INF/spring.factories (100%) create mode 100644 task-component/src/main/resources/application.yml delete mode 100644 task-components/src/main/resources/application.yml diff --git a/pom.xml b/pom.xml index 33c307f..5b300ad 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ redis-component initdatabse-component es-component - task-components + task-component diff --git a/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java b/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java index e870ef3..ac801d0 100644 --- a/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java +++ b/rest-component/src/main/java/com/gcc/container/components/web/exception/ControllerExceptionAdvice.java @@ -12,6 +12,8 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import java.util.LinkedHashMap; diff --git a/task-components/pom.xml b/task-component/pom.xml similarity index 97% rename from task-components/pom.xml rename to task-component/pom.xml index a1076fc..79591f2 100644 --- a/task-components/pom.xml +++ b/task-component/pom.xml @@ -1,13 +1,13 @@ - - 4.0.0 - - com.gcc.container - components - 1.0.0 - - com.gcc.container.components - task-component - ${component.version} - jar - + + 4.0.0 + + com.gcc.container + components + 1.0.0 + + com.gcc.container.components + task-component + ${component.version} + jar + diff --git a/task-components/src/main/java/com/gcc/container/components/task/AfterAppStarted.java b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/AfterAppStarted.java rename to task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java b/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java rename to task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java b/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java similarity index 96% rename from task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java rename to task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java index a62c457..39a90f8 100644 --- a/task-components/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java +++ b/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java @@ -1,19 +1,19 @@ -package com.gcc.container.components.task.annotation; - - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface TaskJob { - - String desc() default "暂无描述"; - - String cron() default "00 00 00 * * ?"; - - boolean bootup() default false; - +package com.gcc.container.components.task.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TaskJob { + + String desc() default "暂无描述"; + + String cron() default "00 00 00 * * ?"; + + boolean bootup() default false; + } \ No newline at end of file diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java b/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java rename to task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java b/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java rename to task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java rename to task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java rename to task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java similarity index 95% rename from task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java rename to task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java index ee29628..2239f04 100644 --- a/task-components/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java @@ -1,83 +1,83 @@ -package com.gcc.container.components.task.compont; - - -import cn.hutool.crypto.digest.DigestUtil; - -import com.gcc.container.components.task.annotation.TaskJob; -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.entity.TaskEntity; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -@Component -class TaskTempFactory { - - @Autowired - private TaskRepository taskRepository; - - - private List tempContainer = new ArrayList<>(); - - - public void scanTaskInfo() throws Exception { - ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); - provider.addIncludeFilter(new AnnotationTypeFilter(TaskJob.class)); - Set beanDefinitions = provider.findCandidateComponents("com.gcc.*"); // 替换为你的包名 - for (BeanDefinition beanDefinition : beanDefinitions) { - Class clazz = Class.forName(beanDefinition.getBeanClassName()); - TaskJob taskJob = clazz.getAnnotation(TaskJob.class); - if (AbstractBaseCronTask.class.isAssignableFrom(clazz)) { - tempContainer.add(builderTaskEntity(clazz,taskJob)); - } else { - throw new IllegalArgumentException("Class " + clazz.getName() + " must extend AbstractBaseCronTask"); - } - } - } - - - public List mergeTaskEntities() { - List db = taskRepository.queryData(new TaskEntity().taskIsUse(1)); - Map map = db.stream() - .collect(Collectors.toMap( - TaskEntity::getTaskClass, - task -> task - )); - for(TaskEntity entity:tempContainer){ - if(!map.containsKey(entity.getTaskClass())){ - taskRepository.save(entity); - db.add(entity); - } - } - return db; - } - - - private TaskEntity builderTaskEntity(Class cronTaskClass, TaskJob taskJob) { - String path = cronTaskClass.getName(); TaskEntity entity = new TaskEntity(); - entity.setTaskId(DigestUtil.md5Hex(path)); - entity.setTaskClass(path); - entity.setTaskIsUse(1); - entity.setTaskName(cronTaskClass.getSimpleName()); - entity.setTaskDesc(entity.setTaskDesc(taskJob.desc())); - entity.setTaskBootUp(converBootUp(taskJob.bootup())); - entity.setTaskCron(taskJob.cron()); - //todo 外部配置 - return entity; - } - - private Integer converBootUp(Boolean flag){ - if(flag){ - return 1; - } - return 0; - } -} +package com.gcc.container.components.task.compont; + + +import cn.hutool.crypto.digest.DigestUtil; + +import com.gcc.container.components.task.annotation.TaskJob; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +class TaskTempFactory { + + @Autowired + private TaskRepository taskRepository; + + + private List tempContainer = new ArrayList<>(); + + + public void scanTaskInfo() throws Exception { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(TaskJob.class)); + Set beanDefinitions = provider.findCandidateComponents("com.gcc.*"); // 替换为你的包名 + for (BeanDefinition beanDefinition : beanDefinitions) { + Class clazz = Class.forName(beanDefinition.getBeanClassName()); + TaskJob taskJob = clazz.getAnnotation(TaskJob.class); + if (AbstractBaseCronTask.class.isAssignableFrom(clazz)) { + tempContainer.add(builderTaskEntity(clazz,taskJob)); + } else { + throw new IllegalArgumentException("Class " + clazz.getName() + " must extend AbstractBaseCronTask"); + } + } + } + + + public List mergeTaskEntities() { + List db = taskRepository.queryData(new TaskEntity().taskIsUse(1)); + Map map = db.stream() + .collect(Collectors.toMap( + TaskEntity::getTaskClass, + task -> task + )); + for(TaskEntity entity:tempContainer){ + if(!map.containsKey(entity.getTaskClass())){ + taskRepository.save(entity); + db.add(entity); + } + } + return db; + } + + + private TaskEntity builderTaskEntity(Class cronTaskClass, TaskJob taskJob) { + String path = cronTaskClass.getName(); TaskEntity entity = new TaskEntity(); + entity.setTaskId(DigestUtil.md5Hex(path)); + entity.setTaskClass(path); + entity.setTaskIsUse(1); + entity.setTaskName(cronTaskClass.getSimpleName()); + entity.setTaskDesc(taskJob.desc()); + entity.setTaskBootUp(converBootUp(taskJob.bootup())); + entity.setTaskCron(taskJob.cron()); + //todo 外部配置 + return entity; + } + + private Integer converBootUp(Boolean flag){ + if(flag){ + return 1; + } + return 0; + } +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java b/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java rename to task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java similarity index 96% rename from task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java rename to task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java index 8cbe032..f07ee56 100644 --- a/task-components/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java +++ b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java @@ -1,163 +1,163 @@ -package com.gcc.container.components.task.dao.impl; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.resource.ClassPathResource; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONUtil; - -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.entity.TaskEntity; -import com.gcc.container.components.task.property.TaskDataProperties; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - - -@Repository -@Slf4j -public class FileOpTaskRepositoryImpl implements TaskRepository { - - - @Autowired - private TaskDataProperties properties; - - - - @Override - public int save(TaskEntity entity) { - List list = readFileInfo(); - list.add(entity); - writeFileInfo(list); - return 1; - } - - @Override - public int remove(String id) { - List list = readFileInfo(); - List data = new ArrayList<>(); - for(TaskEntity entity:list){ - if(!entity.getTaskId().equals(id)){ - data.add(entity); - } - } - writeFileInfo(data); - return list.size() - data.size(); - } - - @Override - public int update(TaskEntity entity) { - List list = readFileInfo(); - List data = new ArrayList<>(); - for(TaskEntity one:list){ - if(!one.getTaskId().equals(entity.getTaskId())){ - data.add(entity); - } - } - data.add(entity); - writeFileInfo(data); - return 1; - } - - @Override - public int updateRunStatus(TaskEntity entity) { - List list = readFileInfo(); - for(TaskEntity one:list){ - if(one.getTaskId().equals(entity.getTaskId())){ - one.setTaskLastRun(entity.getTaskLastRun()); - one.setTaskRamStatus(entity.getTaskRamStatus()); - } - } - writeFileInfo(list); - return 1; - } - - @Override - public List queryData(TaskEntity entity) { - List list = readFileInfo(); - // 获取不为空的属性 - Map nonNullProperties = entity.getNonNullProperties(); - // 进行 AND 查询 - List result = new ArrayList<>(); - for (TaskEntity t : list) { - boolean match = true; - for (Map.Entry entry : nonNullProperties.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if ("taskDesc".equals(key) && !StrUtil.equals(t.getTaskDesc(), (String) value)) { - match = false; - break; - } - if ("taskIsUse".equals(key) && t.getTaskIsUse() != (Integer) value) { - match = false; - break; - } - if ("taskBootUp".equals(key) && t.getTaskBootUp() != (Integer) value) { - match = false; - break; - } - } - if (match) { - result.add(t); - } - } - return result; - } - - @Override - public TaskEntity queryData(String id) { - List list = readFileInfo(); - for(TaskEntity entity:list){ - if(1 == entity.getTaskIsUse() && id.equals(entity.getTaskId())){ - return entity; - } - } - return null; - } - - - private List readFileInfo(){ - // 确保文件存在 - File file = FileUtil.file(getDefaultPath()); - if (!file.exists()) { - log.error("FILE is not exists"); - return new ArrayList<>(); - } - // 读取 JSON 文件内容 - String jsonContent = FileUtil.readUtf8String(getDefaultPath()); - // 将 JSON 字符串转换为 JSON 对象 - JSONArray data = JSONUtil.parseArray(jsonContent); - List result = new ArrayList<>(); - for(int i = 0; i < data.size(); i++){ - result.add(JSONUtil.toBean(data.getJSONObject(i),TaskEntity.class)); - } - return result; - } - - - - /** - * 覆盖写入 JSONArray 文件 - */ - private void writeFileInfo(List data) { - JSONArray array = new JSONArray(data); - // 确保文件存在或创建文件 - File file = FileUtil.touch(getDefaultPath()); - FileUtil.writeUtf8String(array.toJSONString(0), file); - } - - - private String getDefaultPath(){ - if(StrUtil.isNotBlank(properties.getDataFilePath())){ - return properties.getDataFilePath(); - } - ClassPathResource classPathResource = new ClassPathResource("db/task_info.json"); - return classPathResource.getPath(); - } - -} +package com.gcc.container.components.task.dao.impl; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; + +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.property.TaskDataProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +@Repository +@Slf4j +public class FileOpTaskRepositoryImpl implements TaskRepository { + + + @Autowired + private TaskDataProperties properties; + + + + @Override + public int save(TaskEntity entity) { + List list = readFileInfo(); + list.add(entity); + writeFileInfo(list); + return 1; + } + + @Override + public int remove(String id) { + List list = readFileInfo(); + List data = new ArrayList<>(); + for(TaskEntity entity:list){ + if(!entity.getTaskId().equals(id)){ + data.add(entity); + } + } + writeFileInfo(data); + return list.size() - data.size(); + } + + @Override + public int update(TaskEntity entity) { + List list = readFileInfo(); + List data = new ArrayList<>(); + for(TaskEntity one:list){ + if(!one.getTaskId().equals(entity.getTaskId())){ + data.add(one); + } + } + data.add(entity); + writeFileInfo(data); + return 1; + } + + @Override + public int updateRunStatus(TaskEntity entity) { + List list = readFileInfo(); + for(TaskEntity one:list){ + if(one.getTaskId().equals(entity.getTaskId())){ + one.setTaskLastRun(entity.getTaskLastRun()); + one.setTaskRamStatus(entity.getTaskRamStatus()); + } + } + writeFileInfo(list); + return 1; + } + + @Override + public List queryData(TaskEntity entity) { + List list = readFileInfo(); + // 获取不为空的属性 + Map nonNullProperties = entity.getNonNullProperties(); + // 进行 AND 查询 + List result = new ArrayList<>(); + for (TaskEntity t : list) { + boolean match = true; + for (Map.Entry entry : nonNullProperties.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if ("taskDesc".equals(key) && !StrUtil.equals(t.getTaskDesc(), (String) value)) { + match = false; + break; + } + if ("taskIsUse".equals(key) && t.getTaskIsUse() != (Integer) value) { + match = false; + break; + } + if ("taskBootUp".equals(key) && t.getTaskBootUp() != (Integer) value) { + match = false; + break; + } + } + if (match) { + result.add(t); + } + } + return result; + } + + @Override + public TaskEntity queryData(String id) { + List list = readFileInfo(); + for(TaskEntity entity:list){ + if(1 == entity.getTaskIsUse() && id.equals(entity.getTaskId())){ + return entity; + } + } + return null; + } + + + private List readFileInfo(){ + // 确保文件存在 + File file = FileUtil.file(getDefaultPath()); + if (!file.exists()) { + log.error("FILE is not exists"); + return new ArrayList<>(); + } + // 读取 JSON 文件内容 + String jsonContent = FileUtil.readUtf8String(getDefaultPath()); + // 将 JSON 字符串转换为 JSON 对象 + JSONArray data = JSONUtil.parseArray(jsonContent); + List result = new ArrayList<>(); + for(int i = 0; i < data.size(); i++){ + result.add(JSONUtil.toBean(data.getJSONObject(i),TaskEntity.class)); + } + return result; + } + + + + /** + * 覆盖写入 JSONArray 文件 + */ + private void writeFileInfo(List data) { + JSONArray array = new JSONArray(data); + // 确保文件存在或创建文件 + File file = FileUtil.touch(getDefaultPath()); + FileUtil.writeUtf8String(array.toJSONString(0), file); + } + + + private String getDefaultPath(){ + if(StrUtil.isNotBlank(properties.getDataFilePath())){ + return properties.getDataFilePath(); + } + ClassPathResource classPathResource = new ClassPathResource("db/task_info.json"); + return classPathResource.getPath(); + } + +} diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java b/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java rename to task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java b/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java rename to task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java b/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java rename to task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java rename to task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java similarity index 100% rename from task-components/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java rename to task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java diff --git a/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java similarity index 95% rename from task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java rename to task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java index 7e6cdfb..ac43fcd 100644 --- a/task-components/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java +++ b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java @@ -1,15 +1,15 @@ -package com.gcc.container.components.task.property; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties("task.task-data") -@Data -public class TaskDataProperties { - - - private String dataFilePath; - -} +package com.gcc.container.components.task.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties("task.task-data") +@Data +public class TaskDataProperties { + + + private String dataFilePath; + +} diff --git a/task-components/src/main/resources/META-INF/spring.factories b/task-component/src/main/resources/META-INF/spring.factories similarity index 100% rename from task-components/src/main/resources/META-INF/spring.factories rename to task-component/src/main/resources/META-INF/spring.factories diff --git a/task-component/src/main/resources/application.yml b/task-component/src/main/resources/application.yml new file mode 100644 index 0000000..890a6fa --- /dev/null +++ b/task-component/src/main/resources/application.yml @@ -0,0 +1,3 @@ +task: + task-data: + data-file-path: E:\JavaProject\task_info.json \ No newline at end of file diff --git a/task-components/src/main/resources/application.yml b/task-components/src/main/resources/application.yml deleted file mode 100644 index e0a16e9..0000000 --- a/task-components/src/main/resources/application.yml +++ /dev/null @@ -1,3 +0,0 @@ -task: - task-data: - data-file-path: F:\Myself\task_info.json \ No newline at end of file -- Gitee From a0fdfbbaf00fb2bee013c13b41f743f157c1b92d Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 21:01:34 +0800 Subject: [PATCH 18/33] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/TaskScheduleManagerService.java | 55 +++++++ .../impl/TaskScheduleManagerServiceImpl.java | 142 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java b/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java new file mode 100644 index 0000000..ec07f9c --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java @@ -0,0 +1,55 @@ +package com.gcc.container.components.task.service; + +import com.gcc.container.components.task.model.dto.SearchTaskDto; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.model.vo.TaskRunRetVo; +import com.gcc.container.components.task.model.vo.TaskVo; +import java.util.List; +public interface TaskScheduleManagerService { + + /** + * 查询在用任务 + * @return + */ + List searchTask(SearchTaskDto dto); + + /** + * 查询任务详情 + * @param taskId 任务id + * @return TaskEntity + */ + TaskVo searchTaskDetail(String taskId); + + + /** + * 运行指定任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo runTask(String taskId); + + + /** + * 关停任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo shutdownTask(String taskId); + + + /** + * 开启任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo openTask(String taskId); + + + /** + * 更新任务信息 + * @param entity 实体 + * @return TaskRunRetDto + */ + TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity); + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java new file mode 100644 index 0000000..895c48d --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java @@ -0,0 +1,142 @@ +package com.gcc.container.components.task.service.impl; + +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.task.compont.AbstractBaseCronTask; +import com.gcc.container.components.task.compont.TaskSchedule; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.TaskVoConvertor; +import com.gcc.container.components.task.model.dto.SearchTaskDto; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.model.vo.TaskRunRetVo; +import com.gcc.container.components.task.model.vo.TaskVo; +import com.gcc.container.components.task.service.TaskScheduleManagerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.List; + + +@Service +public class TaskScheduleManagerServiceImpl implements TaskScheduleManagerService { + + + private TaskSchedule taskSchedule; + + private TaskRepository taskRepository; + + private TaskVoConvertor taskVoConvertor; + + @Autowired + public void setTaskScheduleServer(TaskSchedule taskSchedule) { + this.taskSchedule = taskSchedule; + } + + @Autowired + public void setTaskRepository(TaskRepository taskRepository) { + this.taskRepository = taskRepository; + } + + @Autowired + public void setTaskVoConvertor(TaskVoConvertor taskVoConvertor) { + this.taskVoConvertor = taskVoConvertor; + } + + @Override + public List searchTask(SearchTaskDto dto) { + TaskEntity entity = new TaskEntity() + .taskIsUse(1) + .taskBootUp(dto.getBootUp()) + .taskLastRun(dto.getLastRunStatus()); + entity.setTaskDesc(dto.getFilterKey()); + return taskVoConvertor.toTaskVos(taskRepository.queryData(entity)); + } + + + @Override + public TaskVo searchTaskDetail(String taskId) { + if(!StringUtils.isEmpty(taskId)){ + return taskVoConvertor.toTaskVo(taskRepository.queryData(taskId)); + } + return null; + } + + + @Override + public TaskRunRetVo runTask(String taskId) { + AbstractBaseCronTask task = taskSchedule.getTaskSchedulingRam().get(taskId); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.run, 0); + if(null != task) { + double time = taskSchedule.runTaskById(taskId); + result.setResult(1); + return result.extend(time).taskInfo(task.getThisTaskInfo()); + } else { + return result.extend("任务未启用"); + } + } + + @Override + public TaskRunRetVo shutdownTask(String taskId) { + AbstractBaseCronTask task = taskSchedule.getTaskSchedulingRam().get(taskId); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.shutdown, 0); + if(null != task) { + boolean flag = taskSchedule.removeTaskFromScheduling(taskId); + if(flag) { + result.setResult(1); + } + return result.extend("任务成功关闭").taskInfo(task.getThisTaskInfo()); + } else { + return result.extend("任务未启用"); + } + } + + @Override + public TaskRunRetVo openTask(String taskId) { + TaskEntity task = taskRepository.queryData(taskId); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.open, 0); + if(null != task) { + if (!taskSchedule.getTaskSchedulingRam().containsKey(taskId)) { + boolean flag = taskSchedule.addTaskToScheduling(task); + if(flag) { + result.setResult(1); + } + return result.extend("任务开启成功").taskInfo(task); + } else { + return result.extend("任务处于启动状态").taskInfo(task); + } + }else { + return result.extend("任务不存在!"); + } + } + + @Override + public TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity) { + TaskEntity task = taskRepository.queryData(entity.getTaskId()); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.update, 0).taskInfo(entity); + String config = entity.getTaskOutConfig(); + if(null != config && !JSONUtil.isJson(config) && !JSONUtil.isJsonArray(config)){ + result.setResult(0); + result.extend("更新任务失败,任务配置必须为JSON或空"); + result.taskInfo(entity); + return result; + } + task.setTaskCron(entity.getTaskCron()); + task.setTaskOutConfig(entity.getTaskOutConfig()); + task.setTaskName(entity.getTaskName()); + task.setTaskDesc(entity.getTaskDesc()); + int num = taskRepository.update(task); + if (num == 1) { + result.setResult(1); + result.extend("成功更新任务"); + result.taskInfo(entity); + //重新刷新任务 + taskSchedule.removeTaskFromScheduling(entity.getTaskId()); + taskSchedule.addTaskToScheduling(task); + } + + return result; + } + + + +} -- Gitee From 089c4a62b0d8bcfeb917e6abaf212095f8a44d75 Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 21:03:28 +0800 Subject: [PATCH 19/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=9A=84=E6=95=B0=E6=8D=AE=E6=96=87=E4=BB=B6=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/task/dao/impl/FileOpTaskRepositoryImpl.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java index f07ee56..20da2e1 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java +++ b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java @@ -1,18 +1,15 @@ package com.gcc.container.components.task.dao.impl; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.resource.ClassPathResource; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONUtil; - import com.gcc.container.components.task.dao.TaskRepository; import com.gcc.container.components.task.model.entity.TaskEntity; import com.gcc.container.components.task.property.TaskDataProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; - import java.io.File; import java.util.ArrayList; import java.util.List; @@ -156,8 +153,7 @@ public class FileOpTaskRepositoryImpl implements TaskRepository { if(StrUtil.isNotBlank(properties.getDataFilePath())){ return properties.getDataFilePath(); } - ClassPathResource classPathResource = new ClassPathResource("db/task_info.json"); - return classPathResource.getPath(); + return "db/task_info.json"; } } -- Gitee From 21825d2546d3b15a21c9f25415799aace9683e8a Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 21:19:30 +0800 Subject: [PATCH 20/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/service/impl/TaskScheduleManagerServiceImpl.java | 4 ++-- task-component/src/main/resources/META-INF/spring.factories | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java index 895c48d..b99412e 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java +++ b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java @@ -11,13 +11,13 @@ import com.gcc.container.components.task.model.vo.TaskRunRetVo; import com.gcc.container.components.task.model.vo.TaskVo; import com.gcc.container.components.task.service.TaskScheduleManagerService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.List; -@Service +@Component public class TaskScheduleManagerServiceImpl implements TaskScheduleManagerService { diff --git a/task-component/src/main/resources/META-INF/spring.factories b/task-component/src/main/resources/META-INF/spring.factories index 7080fd0..0be5d40 100644 --- a/task-component/src/main/resources/META-INF/spring.factories +++ b/task-component/src/main/resources/META-INF/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.web.ApplicationConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.task.ApplicationConfiguration \ No newline at end of file -- Gitee From 38d01d6b37f3b346c0c05a89ddb4f757d115d0ec Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 21:34:33 +0800 Subject: [PATCH 21/33] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=8C=85=E5=90=8D=E5=8F=8A=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/task/compont/TaskTempFactory.java | 5 ++++- .../components/task/property/TaskDataProperties.java | 12 +++++++++++- task-component/src/main/resources/application.yml | 6 +++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java index 2239f04..f5dca65 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java @@ -6,6 +6,7 @@ import cn.hutool.crypto.digest.DigestUtil; import com.gcc.container.components.task.annotation.TaskJob; import com.gcc.container.components.task.dao.TaskRepository; import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.property.TaskDataProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; @@ -24,6 +25,8 @@ class TaskTempFactory { @Autowired private TaskRepository taskRepository; + @Autowired + TaskDataProperties taskDataProperties; private List tempContainer = new ArrayList<>(); @@ -31,7 +34,7 @@ class TaskTempFactory { public void scanTaskInfo() throws Exception { ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); provider.addIncludeFilter(new AnnotationTypeFilter(TaskJob.class)); - Set beanDefinitions = provider.findCandidateComponents("com.gcc.*"); // 替换为你的包名 + Set beanDefinitions = provider.findCandidateComponents(taskDataProperties.getTaskClassPackage()); for (BeanDefinition beanDefinition : beanDefinitions) { Class clazz = Class.forName(beanDefinition.getBeanClassName()); TaskJob taskJob = clazz.getAnnotation(TaskJob.class); diff --git a/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java index ac43fcd..20f6cb1 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java +++ b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java @@ -1,15 +1,25 @@ package com.gcc.container.components.task.property; +import cn.hutool.core.util.StrUtil; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration -@ConfigurationProperties("task.task-data") +@ConfigurationProperties("gcc-task") @Data public class TaskDataProperties { private String dataFilePath; + + private String taskClassPackage; + + public String getTaskClassPackage() { + if(StrUtil.isBlankIfStr(this.taskClassPackage)){ + return "*"; + } + return taskClassPackage; + } } diff --git a/task-component/src/main/resources/application.yml b/task-component/src/main/resources/application.yml index 890a6fa..d5b182d 100644 --- a/task-component/src/main/resources/application.yml +++ b/task-component/src/main/resources/application.yml @@ -1,3 +1,3 @@ -task: - task-data: - data-file-path: E:\JavaProject\task_info.json \ No newline at end of file +gcc-task: + task-class-package : * + data-file-path: E:\JavaProject\task_info.json \ No newline at end of file -- Gitee From 78cdd4931737c63aefa4ff9a9baa0b4a91e08c1f Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 22:13:23 +0800 Subject: [PATCH 22/33] =?UTF-8?q?=E8=A1=A5=E5=85=A8=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gcc/container/components/task/compont/TaskTempFactory.java | 2 ++ .../components/task/dao/impl/FileOpTaskRepositoryImpl.java | 1 - task-component/src/main/resources/application.yml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java index f5dca65..83221c1 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java @@ -1,6 +1,7 @@ package com.gcc.container.components.task.compont; +import cn.hutool.core.date.DateUtil; import cn.hutool.crypto.digest.DigestUtil; import com.gcc.container.components.task.annotation.TaskJob; @@ -73,6 +74,7 @@ class TaskTempFactory { entity.setTaskDesc(taskJob.desc()); entity.setTaskBootUp(converBootUp(taskJob.bootup())); entity.setTaskCron(taskJob.cron()); + entity.setTaskCreateTime(DateUtil.now()); //todo 外部配置 return entity; } diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java index 20da2e1..ec2062f 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java +++ b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; - @Repository @Slf4j public class FileOpTaskRepositoryImpl implements TaskRepository { diff --git a/task-component/src/main/resources/application.yml b/task-component/src/main/resources/application.yml index d5b182d..78cba49 100644 --- a/task-component/src/main/resources/application.yml +++ b/task-component/src/main/resources/application.yml @@ -1,3 +1,3 @@ gcc-task: task-class-package : * - data-file-path: E:\JavaProject\task_info.json \ No newline at end of file + data-file-path: E:\JavaProject\task_info.json -- Gitee From ef90796edaf04c4ea62c6281f8209c761e5d6e9c Mon Sep 17 00:00:00 2001 From: GCC1566 <156654540@qq.com> Date: Mon, 18 Nov 2024 22:31:54 +0800 Subject: [PATCH 23/33] =?UTF-8?q?=E8=A1=A5=E5=85=A8=E4=BB=A3=E5=8A=9E?= =?UTF-8?q?=E4=BA=8B=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gcc/container/components/task/AfterAppStarted.java | 2 +- .../com/gcc/container/components/task/dao/TaskRepository.java | 4 ---- .../container/components/task/model/entity/TaskEntity.java | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java index 74bd974..14b24c3 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java +++ b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java @@ -15,7 +15,7 @@ import org.springframework.stereotype.Component; @Slf4j public class AfterAppStarted implements ApplicationRunner { - + //todo 解决外部无法开机自启动问题 TaskSchedule taskSchedule; @Autowired diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java b/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java index 13db404..6983543 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java +++ b/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java @@ -1,10 +1,6 @@ package com.gcc.container.components.task.dao; - - import com.gcc.container.components.task.model.entity.TaskEntity; - import java.util.List; - /** * 任务数据操作 */ diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java b/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java index 287b3ed..df0cfd2 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java +++ b/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java @@ -11,9 +11,9 @@ import java.util.Map; * @author GCC */ @Data - public class TaskEntity implements Serializable { + //todo 解决外部创建表的操作 private String taskId; -- Gitee From 204fab6b31cf43bcff0ad62ba4d53c5fe05550e4 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 01:21:04 +0000 Subject: [PATCH 24/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=BA=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=9B=91=E5=90=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../components/task/AfterAppStarted.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java index 14b24c3..fdff9f5 100644 --- a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java +++ b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java @@ -2,20 +2,18 @@ package com.gcc.container.components.task; + import com.gcc.container.components.task.compont.TaskSchedule; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.core.annotation.Order; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; -@Order(3) @Component @Slf4j -public class AfterAppStarted implements ApplicationRunner { +public class AfterAppStarted { - //todo 解决外部无法开机自启动问题 TaskSchedule taskSchedule; @Autowired @@ -23,10 +21,9 @@ public class AfterAppStarted implements ApplicationRunner { this.taskSchedule = taskSchedule; } - @Override - public void run(ApplicationArguments args) throws Exception { + @EventListener + public void onApplicationEvent(ApplicationReadyEvent event){ //运行随系统启动的定时任务 taskSchedule.runBootUpTask(); } - } -- Gitee From e4353583f913484f0d904a384a906ce732de2fe7 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 02:32:04 +0000 Subject: [PATCH 25/33] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20ta?= =?UTF-8?q?sk-component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- task-component/pom.xml | 13 -- .../components/task/AfterAppStarted.java | 29 ---- .../task/ApplicationConfiguration.java | 9 - .../components/task/annotation/TaskJob.java | 19 --- .../task/compont/AbstractBaseCronTask.java | 111 ------------ .../InitTaskSchedulingApplication.java | 48 ------ .../components/task/compont/TaskSchedule.java | 62 ------- .../task/compont/TaskScheduleImpl.java | 160 ------------------ .../task/compont/TaskTempFactory.java | 88 ---------- .../components/task/dao/TaskRepository.java | 54 ------ .../dao/impl/FileOpTaskRepositoryImpl.java | 158 ----------------- .../task/model/TaskVoConvertor.java | 40 ----- .../task/model/dto/SearchTaskDto.java | 28 --- .../task/model/entity/TaskEntity.java | 88 ---------- .../task/model/vo/TaskRunRetVo.java | 70 -------- .../components/task/model/vo/TaskVo.java | 55 ------ .../task/property/TaskDataProperties.java | 25 --- .../service/TaskScheduleManagerService.java | 55 ------ .../impl/TaskScheduleManagerServiceImpl.java | 142 ---------------- .../main/resources/META-INF/spring.factories | 1 - .../src/main/resources/application.yml | 3 - 21 files changed, 1258 deletions(-) delete mode 100644 task-component/pom.xml delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java delete mode 100644 task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java delete mode 100644 task-component/src/main/resources/META-INF/spring.factories delete mode 100644 task-component/src/main/resources/application.yml diff --git a/task-component/pom.xml b/task-component/pom.xml deleted file mode 100644 index 79591f2..0000000 --- a/task-component/pom.xml +++ /dev/null @@ -1,13 +0,0 @@ - - 4.0.0 - - com.gcc.container - components - 1.0.0 - - com.gcc.container.components - task-component - ${component.version} - jar - diff --git a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java deleted file mode 100644 index fdff9f5..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gcc.container.components.task; - - - - -import com.gcc.container.components.task.compont.TaskSchedule; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -public class AfterAppStarted { - - TaskSchedule taskSchedule; - - @Autowired - public void setTaskScheduleServer(TaskSchedule taskSchedule) { - this.taskSchedule = taskSchedule; - } - - @EventListener - public void onApplicationEvent(ApplicationReadyEvent event){ - //运行随系统启动的定时任务 - taskSchedule.runBootUpTask(); - } -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java b/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java deleted file mode 100644 index 0697cbc..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gcc.container.components.task; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan(basePackages = "com.gcc.container.components.task.*") -public class ApplicationConfiguration { -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java b/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java deleted file mode 100644 index 39a90f8..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gcc.container.components.task.annotation; - - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface TaskJob { - - String desc() default "暂无描述"; - - String cron() default "00 00 00 * * ?"; - - boolean bootup() default false; - -} \ No newline at end of file diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java b/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java deleted file mode 100644 index 93d3586..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.gcc.container.components.task.compont; - - -import cn.hutool.core.util.NumberUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.entity.TaskEntity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContext; - -/** - * 抽象定时任务类 - * 实现定时任务需要继承该类 - * 子类实现时,不要使用Spring的任何注解 - * 若依赖外部的对象,使用 getServer()方法进行手动注入 - * @author GCC - */ -public abstract class AbstractBaseCronTask implements Runnable{ - - public Logger log; - - - private TaskEntity taskEntity; - - - private Double consumptionTime; - - private ApplicationContext applicationContext; - - - public AbstractBaseCronTask(TaskEntity taskEntity){ - log = LoggerFactory.getLogger(taskEntity.getTaskName()); - this.taskEntity = taskEntity; - } - - - //前置操作 - public abstract void beforeJob(); - - - //任务操作 - public abstract void startJob(); - - - //后置操作 - public abstract void afterJob(); - - - @Override - public void run() { - log.info("---------------------任务 {} 开始执行-----------------------",taskEntity.getTaskName()); - log.info("任务描述:"+taskEntity.getTaskDesc()); - consumptionTime = 0d; - try { - Long start = System.currentTimeMillis(); - beforeJob(); - startJob(); - afterJob(); - Long end = System.currentTimeMillis(); - consumptionTime = NumberUtil.div((end - start),1000); - log.info("任务耗时:约 {} s",consumptionTime); - taskEntity.setTaskLastRun(1); - }catch (Exception e){ - log.error("任务{}计算出错!请及时排查问题!", taskEntity.getTaskName(),e); - taskEntity.setTaskLastRun(0); - } - getServer(TaskRepository.class).updateRunStatus(taskEntity); - String id = this.taskEntity.getTaskId(); - this.taskEntity = getServer(TaskRepository.class).queryData(id); - log.info("---------------------任务 {} 结束执行-----------------------\n",taskEntity.getTaskName()); - } - - - public Object getSelfConfig(String key){ - try{ - TaskEntity entity = getServer(TaskRepository.class).queryData(taskEntity.getTaskId()); - JSONObject config = JSONUtil.parseObj(entity.getTaskOutConfig()); - return config.get(key); - }catch (Exception e){ - log.error("获取任务 {} 的配置参数失败,请确认参数配置格式是否正确!",taskEntity.getTaskName()); - } - return new JSONObject(); - } - - - public double getRunTime(){ return this.consumptionTime;} - - public TaskEntity getThisTaskInfo(){ - return this.taskEntity; - } - - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - - /** - * 为适配反射生成的对象不受Spring容器管辖导致对象不共用问题 - * 提供手动获取系统上下文容器完成依赖注入 - * 通过类名使用Spring容器中的对象 - * @param className 类 - * @param 返回类型 - * @return T - */ - public T getServer(Class className){ - return applicationContext.getBean(className); - } - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java b/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java deleted file mode 100644 index 6085c3a..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.gcc.container.components.task.compont; - - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -/** - * 初始化任务调度机制 - * @author GCC - */ -@Order(1) -@Slf4j -@Component -public class InitTaskSchedulingApplication implements ApplicationRunner { - - private TaskSchedule taskSchedule; - - - private TaskTempFactory taskTempFactory; - - - @Autowired - public void setTaskScheduleServer(TaskSchedule taskSchedule) { - this.taskSchedule = taskSchedule; - } - - @Autowired - public void setTaskTempFactory(TaskTempFactory taskTempFactory) { - this.taskTempFactory = taskTempFactory; - } - - @Override - public void run(ApplicationArguments args) throws Exception { - //开启扫描 - taskTempFactory.scanTaskInfo(); - log.info("【定时任务初始化】 容器初始化"); - taskSchedule.initScheduling(); - log.info("【定时任务初始化】定时任务初始化任务开始"); - taskSchedule.loadAllTask(); - log.info("【定时任务初始化】定时任务初始化任务完成"); - - } - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java deleted file mode 100644 index c2d2949..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.gcc.container.components.task.compont; - - - - -import com.gcc.container.components.task.model.entity.TaskEntity; - -import java.util.concurrent.ConcurrentHashMap; - -public interface TaskSchedule { - - - - ConcurrentHashMap getTaskSchedulingRam(); - - - /** - * 初始化任务调度 - */ - void initScheduling(); - - /** - * 添加任务至内存及容器 - * @param taskEntity 任务实体 - * @return boolean - */ - boolean addTaskToScheduling(TaskEntity taskEntity); - - /** - * 从任务调度器中移除任务 - * @param id 任务id - * @return Boolean - */ - boolean removeTaskFromScheduling(String id); - - - /** - * 执行指定任务 - * @param id 任务id - * @return double 耗时 - */ - double runTaskById(String id); - - - /** - * 清空任务 - */ - void claearAllTask(); - - - - /** - * 加载所有任务 - */ - void loadAllTask(); - - /** - * 运行开机自启任务 - */ - void runBootUpTask(); - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java deleted file mode 100644 index be53fc1..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.gcc.container.components.task.compont; - - -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.entity.TaskEntity; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.support.CronTrigger; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Constructor; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; - -@Slf4j -@Component -public class TaskScheduleImpl implements TaskSchedule { - - //正在运行的任务 - private static ConcurrentHashMap runningTasks = new ConcurrentHashMap<>(); - - //线程池任务调度 - private ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); - - //内存中任务对象 - private static ConcurrentHashMap ramTasks = new ConcurrentHashMap<>(); - - //Spring容器池,用于注入Spring的bean - private ApplicationContext context; - - - private TaskRepository taskRepository; - - - private TaskTempFactory taskFactory; - - - @Autowired - public void setTaskRepository(TaskRepository taskRepository) { - this.taskRepository = taskRepository; - } - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; - } - - @Autowired - public void setTaskFactory(TaskTempFactory taskFactory) { - this.taskFactory = taskFactory; - } - - @Autowired - - - @Override - public ConcurrentHashMap getTaskSchedulingRam() { - return ramTasks; - } - - @Override - public void initScheduling() { - int num = taskFactory.mergeTaskEntities().size(); - num = num > 0 ? num:1; - this.threadPoolTaskScheduler.setPoolSize(num); - this.threadPoolTaskScheduler.setThreadNamePrefix("task-thread-"); - this.threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); - this.threadPoolTaskScheduler.initialize(); - } - - - @Override - public boolean addTaskToScheduling(TaskEntity task) { - if(!runningTasks.containsKey(task.getTaskId())){ - try{ - Class clazz = Class.forName(task.getTaskClass()); - Constructor c = clazz.getConstructor(TaskEntity.class); - AbstractBaseCronTask runnable = (AbstractBaseCronTask) c.newInstance(task); - //反射方式生成对象不属于Spring容器管控,对于Spring的bean使用需要手动注入 - runnable.setApplicationContext(context); - CronTrigger cron = new CronTrigger(task.getTaskCron()); - //put到runTasks - runningTasks.put(task.getTaskId(), Objects.requireNonNull(this.threadPoolTaskScheduler.schedule(runnable, cron))); - //存入内存中,便于外部调用 - ramTasks.put(task.getTaskId(),runnable); - task.setTaskRamStatus(1); - taskRepository.update(task); - return true; - }catch (Exception e){ - log.error("定时任务加载失败..."+e); - } - } - return false; - } - - - @Override - public boolean removeTaskFromScheduling(String id) { - if(runningTasks.containsKey(id)){ - runningTasks.get(id).cancel(true); - runningTasks.remove(id); - ramTasks.remove(id); - TaskEntity entity = taskRepository.queryData(id); - entity.setTaskRamStatus(0); - entity.setTaskLastRun(null); - if( 1 == taskRepository.update(entity) && !runningTasks.containsKey(id)){ - log.info("【定时任务控制器】任务"+id+"从内存进程池中移除,被终止!"); - return true; - } - } - return false; - } - - @Override - public double runTaskById(String id) { - TaskEntity task = taskRepository.queryData(id); - if(null!=task) { - if (runningTasks.containsKey(task.getTaskId())){ - ramTasks.get(task.getTaskId()).run(); - return ramTasks.get(task.getTaskId()).getRunTime(); - } - } - return 0d; - } - - @Override - public void claearAllTask() { - ramTasks.clear(); - log.info("【定时任务控制器】清除内存任务 完成"); - runningTasks.clear(); - log.info("【定时任务控制器】清除线程任务 完成"); - threadPoolTaskScheduler.shutdown(); - } - - @Override - public void loadAllTask() { - List allTask = taskFactory.mergeTaskEntities(); - for (TaskEntity task : allTask) { - if(addTaskToScheduling(task)){ - log.info("【定时任务初始化】装填任务:{} [ 任务执行周期:{} ] [ bootup:{}]",task.getTaskName(),task.getTaskCron(),task.getTaskBootUp()); - } - } - } - - - @Override - public void runBootUpTask() { - TaskEntity entity = new TaskEntity() - .taskIsUse(1) - .taskBootUp(1); - List list = taskRepository.queryData(entity); - for(TaskEntity task:list){ - runTaskById(task.getTaskId()); - } - } -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java deleted file mode 100644 index 83221c1..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.gcc.container.components.task.compont; - - -import cn.hutool.core.date.DateUtil; -import cn.hutool.crypto.digest.DigestUtil; - -import com.gcc.container.components.task.annotation.TaskJob; -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.entity.TaskEntity; -import com.gcc.container.components.task.property.TaskDataProperties; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -@Component -class TaskTempFactory { - - @Autowired - private TaskRepository taskRepository; - - @Autowired - TaskDataProperties taskDataProperties; - - private List tempContainer = new ArrayList<>(); - - - public void scanTaskInfo() throws Exception { - ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); - provider.addIncludeFilter(new AnnotationTypeFilter(TaskJob.class)); - Set beanDefinitions = provider.findCandidateComponents(taskDataProperties.getTaskClassPackage()); - for (BeanDefinition beanDefinition : beanDefinitions) { - Class clazz = Class.forName(beanDefinition.getBeanClassName()); - TaskJob taskJob = clazz.getAnnotation(TaskJob.class); - if (AbstractBaseCronTask.class.isAssignableFrom(clazz)) { - tempContainer.add(builderTaskEntity(clazz,taskJob)); - } else { - throw new IllegalArgumentException("Class " + clazz.getName() + " must extend AbstractBaseCronTask"); - } - } - } - - - public List mergeTaskEntities() { - List db = taskRepository.queryData(new TaskEntity().taskIsUse(1)); - Map map = db.stream() - .collect(Collectors.toMap( - TaskEntity::getTaskClass, - task -> task - )); - for(TaskEntity entity:tempContainer){ - if(!map.containsKey(entity.getTaskClass())){ - taskRepository.save(entity); - db.add(entity); - } - } - return db; - } - - - private TaskEntity builderTaskEntity(Class cronTaskClass, TaskJob taskJob) { - String path = cronTaskClass.getName(); TaskEntity entity = new TaskEntity(); - entity.setTaskId(DigestUtil.md5Hex(path)); - entity.setTaskClass(path); - entity.setTaskIsUse(1); - entity.setTaskName(cronTaskClass.getSimpleName()); - entity.setTaskDesc(taskJob.desc()); - entity.setTaskBootUp(converBootUp(taskJob.bootup())); - entity.setTaskCron(taskJob.cron()); - entity.setTaskCreateTime(DateUtil.now()); - //todo 外部配置 - return entity; - } - - private Integer converBootUp(Boolean flag){ - if(flag){ - return 1; - } - return 0; - } -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java b/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java deleted file mode 100644 index 6983543..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gcc.container.components.task.dao; -import com.gcc.container.components.task.model.entity.TaskEntity; -import java.util.List; -/** - * 任务数据操作 - */ -public interface TaskRepository { - - /** - * 新增数据 - * @param entity - * @return int - */ - int save(TaskEntity entity); - - - /** - * 删除任务ID - * @param id id - * @return int - */ - int remove(String id); - - - /** - * 更新整个任务 - * @param entity 实体 - * @return int - */ - int update(TaskEntity entity); - - /** - * 更新数据(运行状态) - * @param entity 参数 - * @return int - */ - int updateRunStatus(TaskEntity entity); - - - /** - * 查询数据 - * @param entity 查询 - * @return TaskEntity - */ - List queryData(TaskEntity entity); - - - /** - * 查询具体的任务实体 - * @param id id - * @return TaskEntity - */ - TaskEntity queryData(String id); -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java deleted file mode 100644 index ec2062f..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.gcc.container.components.task.dao.impl; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONUtil; -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.entity.TaskEntity; -import com.gcc.container.components.task.property.TaskDataProperties; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@Repository -@Slf4j -public class FileOpTaskRepositoryImpl implements TaskRepository { - - - @Autowired - private TaskDataProperties properties; - - - - @Override - public int save(TaskEntity entity) { - List list = readFileInfo(); - list.add(entity); - writeFileInfo(list); - return 1; - } - - @Override - public int remove(String id) { - List list = readFileInfo(); - List data = new ArrayList<>(); - for(TaskEntity entity:list){ - if(!entity.getTaskId().equals(id)){ - data.add(entity); - } - } - writeFileInfo(data); - return list.size() - data.size(); - } - - @Override - public int update(TaskEntity entity) { - List list = readFileInfo(); - List data = new ArrayList<>(); - for(TaskEntity one:list){ - if(!one.getTaskId().equals(entity.getTaskId())){ - data.add(one); - } - } - data.add(entity); - writeFileInfo(data); - return 1; - } - - @Override - public int updateRunStatus(TaskEntity entity) { - List list = readFileInfo(); - for(TaskEntity one:list){ - if(one.getTaskId().equals(entity.getTaskId())){ - one.setTaskLastRun(entity.getTaskLastRun()); - one.setTaskRamStatus(entity.getTaskRamStatus()); - } - } - writeFileInfo(list); - return 1; - } - - @Override - public List queryData(TaskEntity entity) { - List list = readFileInfo(); - // 获取不为空的属性 - Map nonNullProperties = entity.getNonNullProperties(); - // 进行 AND 查询 - List result = new ArrayList<>(); - for (TaskEntity t : list) { - boolean match = true; - for (Map.Entry entry : nonNullProperties.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if ("taskDesc".equals(key) && !StrUtil.equals(t.getTaskDesc(), (String) value)) { - match = false; - break; - } - if ("taskIsUse".equals(key) && t.getTaskIsUse() != (Integer) value) { - match = false; - break; - } - if ("taskBootUp".equals(key) && t.getTaskBootUp() != (Integer) value) { - match = false; - break; - } - } - if (match) { - result.add(t); - } - } - return result; - } - - @Override - public TaskEntity queryData(String id) { - List list = readFileInfo(); - for(TaskEntity entity:list){ - if(1 == entity.getTaskIsUse() && id.equals(entity.getTaskId())){ - return entity; - } - } - return null; - } - - - private List readFileInfo(){ - // 确保文件存在 - File file = FileUtil.file(getDefaultPath()); - if (!file.exists()) { - log.error("FILE is not exists"); - return new ArrayList<>(); - } - // 读取 JSON 文件内容 - String jsonContent = FileUtil.readUtf8String(getDefaultPath()); - // 将 JSON 字符串转换为 JSON 对象 - JSONArray data = JSONUtil.parseArray(jsonContent); - List result = new ArrayList<>(); - for(int i = 0; i < data.size(); i++){ - result.add(JSONUtil.toBean(data.getJSONObject(i),TaskEntity.class)); - } - return result; - } - - - - /** - * 覆盖写入 JSONArray 文件 - */ - private void writeFileInfo(List data) { - JSONArray array = new JSONArray(data); - // 确保文件存在或创建文件 - File file = FileUtil.touch(getDefaultPath()); - FileUtil.writeUtf8String(array.toJSONString(0), file); - } - - - private String getDefaultPath(){ - if(StrUtil.isNotBlank(properties.getDataFilePath())){ - return properties.getDataFilePath(); - } - return "db/task_info.json"; - } - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java b/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java deleted file mode 100644 index fe9089c..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gcc.container.components.task.model; - - -import com.gcc.container.components.task.model.entity.TaskEntity; -import com.gcc.container.components.task.model.vo.TaskVo; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.stream.Collectors; - -@Component -public class TaskVoConvertor { - - - public TaskVo toTaskVo(TaskEntity entity){ - return TaskVo.builder() - .taskId(entity.getTaskId()) - .taskName(entity.getTaskName()) - .taskDesc(entity.getTaskDesc()) - .taskCron(entity.getTaskCron()) - .taskOutConfig(entity.getTaskOutConfig()) - .taskBootUp(entity.getTaskBootUp()) - .taskCreateTime(entity.getTaskCreateTime()) - .status(ramStatusToRunStatus(entity.getTaskRamStatus())) - .build(); - } - - public List toTaskVos(List entities){ - return entities.stream().map(this::toTaskVo).collect(Collectors.toList()); - } - - private TaskVo.TaskRunStatus ramStatusToRunStatus(Integer ramStatus){ - if(1 == ramStatus){ - return TaskVo.TaskRunStatus.open; - }else { - return TaskVo.TaskRunStatus.shutdown; - } - } - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java b/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java deleted file mode 100644 index 0dcf6f1..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gcc.container.components.task.model.dto; - -import lombok.Data; -import java.io.Serializable; - - -/** - * 查询参数 - */ -@Data -public class SearchTaskDto implements Serializable { - - - private String filterKey; - - - private Integer bootUp; - - - private Integer lastRunStatus; - - - private Integer pageNo; - - - private Integer pageSize; - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java b/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java deleted file mode 100644 index df0cfd2..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.gcc.container.components.task.model.entity; - - -import lombok.Data; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -/** - * 任务实体类 - * @author GCC - */ -@Data -public class TaskEntity implements Serializable { - - //todo 解决外部创建表的操作 - - private String taskId; - - private String taskName; - - private String taskDesc; - - private String taskCron; - - private String taskClass; - - /** - * 任务相关配置 - */ - private String taskOutConfig; - - /** - * 任务注册时间 - */ - private String taskCreateTime; - - /** - * 是否启用 - */ - private Integer taskIsUse; - - /** - * 是否开启自启动 - */ - private Integer taskBootUp; - - /** - * 上次运行状态 - */ - private Integer taskLastRun; - - /** - * 任务是否在内存中 - */ - private Integer taskRamStatus; - - - public TaskEntity taskIsUse(Integer taskIsUse) { - this.taskIsUse = taskIsUse; - return this; - } - - public TaskEntity taskBootUp(Integer taskBootUp) { - this.taskBootUp = taskBootUp; - return this; - } - - public TaskEntity taskLastRun(Integer taskLastRun) { - this.taskLastRun = taskLastRun; - return this; - } - - public TaskEntity taskRamStatus(Integer taskRamStatus) { - this.taskRamStatus = taskRamStatus; - return this; - } - - public Map getNonNullProperties() { - Map properties = new HashMap<>(); - if (taskDesc != null) properties.put("taskDesc", taskDesc); - if (taskIsUse != null) properties.put("taskIsUse", taskIsUse); - if (taskBootUp != null) properties.put("taskBootUp", taskBootUp); - return properties; - } - - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java deleted file mode 100644 index 300d935..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.gcc.container.components.task.model.vo; - - -import com.gcc.container.components.task.model.entity.TaskEntity; -import lombok.Data; - -import java.io.Serializable; - -/** - * 任务运行状态 - */ -@Data -public class TaskRunRetVo implements Serializable { - - - private String taskId; - - - private String taskName; - - - private TaskOperation taskOperation; - - /** - * 执行状态 - * 1:成功 - * 0:失败 - */ - private Integer result; - - - private String extend = "successful"; - - - public TaskRunRetVo(TaskOperation taskOperation, int result) { - this.taskOperation = taskOperation; - this.result = result; - if(result == 0){ - this.extend = "fail"; - } - } - - public TaskRunRetVo taskInfo(TaskEntity taskEntity){ - this.taskId = taskEntity.getTaskId(); - this.taskName = taskEntity.getTaskName(); - return this; - } - - public TaskRunRetVo extend(Object extend){ - this.extend =String.valueOf(extend); - return this; - } - - public enum TaskOperation{ - - //开启 - open, - - //关闭/停止 - shutdown, - - //更新任务 - update, - - //立即执行 - run; - } - - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java deleted file mode 100644 index 433c27a..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.gcc.container.components.task.model.vo; - -import lombok.Builder; -import lombok.Data; - -import java.io.Serializable; - -@Data -@Builder -public class TaskVo implements Serializable { - - private String taskId; - - private String taskName; - - private String taskDesc; - - private String taskCron; - - /** - * 任务相关配置 - */ - private String taskOutConfig; - - /** - * 任务注册时间 - */ - private String taskCreateTime; - - - /** - * 是否开启自启动 - */ - private Integer taskBootUp; - - /** - * 启停状态 - */ - private TaskRunStatus status; - - - public enum TaskRunStatus{ - //开启 - open(1), - //关闭 - shutdown(0); - - Integer code; - - TaskRunStatus(Integer code){ - this.code = code; - } - } - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java deleted file mode 100644 index 20f6cb1..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gcc.container.components.task.property; - -import cn.hutool.core.util.StrUtil; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties("gcc-task") -@Data -public class TaskDataProperties { - - - private String dataFilePath; - - - private String taskClassPackage; - - public String getTaskClassPackage() { - if(StrUtil.isBlankIfStr(this.taskClassPackage)){ - return "*"; - } - return taskClassPackage; - } -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java b/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java deleted file mode 100644 index ec07f9c..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.gcc.container.components.task.service; - -import com.gcc.container.components.task.model.dto.SearchTaskDto; -import com.gcc.container.components.task.model.entity.TaskEntity; -import com.gcc.container.components.task.model.vo.TaskRunRetVo; -import com.gcc.container.components.task.model.vo.TaskVo; -import java.util.List; -public interface TaskScheduleManagerService { - - /** - * 查询在用任务 - * @return - */ - List searchTask(SearchTaskDto dto); - - /** - * 查询任务详情 - * @param taskId 任务id - * @return TaskEntity - */ - TaskVo searchTaskDetail(String taskId); - - - /** - * 运行指定任务 - * @param taskId 任务id - * @return TaskRunRetDto - */ - TaskRunRetVo runTask(String taskId); - - - /** - * 关停任务 - * @param taskId 任务id - * @return TaskRunRetDto - */ - TaskRunRetVo shutdownTask(String taskId); - - - /** - * 开启任务 - * @param taskId 任务id - * @return TaskRunRetDto - */ - TaskRunRetVo openTask(String taskId); - - - /** - * 更新任务信息 - * @param entity 实体 - * @return TaskRunRetDto - */ - TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity); - -} diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java deleted file mode 100644 index b99412e..0000000 --- a/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.gcc.container.components.task.service.impl; - -import cn.hutool.json.JSONUtil; -import com.gcc.container.components.task.compont.AbstractBaseCronTask; -import com.gcc.container.components.task.compont.TaskSchedule; -import com.gcc.container.components.task.dao.TaskRepository; -import com.gcc.container.components.task.model.TaskVoConvertor; -import com.gcc.container.components.task.model.dto.SearchTaskDto; -import com.gcc.container.components.task.model.entity.TaskEntity; -import com.gcc.container.components.task.model.vo.TaskRunRetVo; -import com.gcc.container.components.task.model.vo.TaskVo; -import com.gcc.container.components.task.service.TaskScheduleManagerService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import java.util.List; - - -@Component -public class TaskScheduleManagerServiceImpl implements TaskScheduleManagerService { - - - private TaskSchedule taskSchedule; - - private TaskRepository taskRepository; - - private TaskVoConvertor taskVoConvertor; - - @Autowired - public void setTaskScheduleServer(TaskSchedule taskSchedule) { - this.taskSchedule = taskSchedule; - } - - @Autowired - public void setTaskRepository(TaskRepository taskRepository) { - this.taskRepository = taskRepository; - } - - @Autowired - public void setTaskVoConvertor(TaskVoConvertor taskVoConvertor) { - this.taskVoConvertor = taskVoConvertor; - } - - @Override - public List searchTask(SearchTaskDto dto) { - TaskEntity entity = new TaskEntity() - .taskIsUse(1) - .taskBootUp(dto.getBootUp()) - .taskLastRun(dto.getLastRunStatus()); - entity.setTaskDesc(dto.getFilterKey()); - return taskVoConvertor.toTaskVos(taskRepository.queryData(entity)); - } - - - @Override - public TaskVo searchTaskDetail(String taskId) { - if(!StringUtils.isEmpty(taskId)){ - return taskVoConvertor.toTaskVo(taskRepository.queryData(taskId)); - } - return null; - } - - - @Override - public TaskRunRetVo runTask(String taskId) { - AbstractBaseCronTask task = taskSchedule.getTaskSchedulingRam().get(taskId); - TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.run, 0); - if(null != task) { - double time = taskSchedule.runTaskById(taskId); - result.setResult(1); - return result.extend(time).taskInfo(task.getThisTaskInfo()); - } else { - return result.extend("任务未启用"); - } - } - - @Override - public TaskRunRetVo shutdownTask(String taskId) { - AbstractBaseCronTask task = taskSchedule.getTaskSchedulingRam().get(taskId); - TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.shutdown, 0); - if(null != task) { - boolean flag = taskSchedule.removeTaskFromScheduling(taskId); - if(flag) { - result.setResult(1); - } - return result.extend("任务成功关闭").taskInfo(task.getThisTaskInfo()); - } else { - return result.extend("任务未启用"); - } - } - - @Override - public TaskRunRetVo openTask(String taskId) { - TaskEntity task = taskRepository.queryData(taskId); - TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.open, 0); - if(null != task) { - if (!taskSchedule.getTaskSchedulingRam().containsKey(taskId)) { - boolean flag = taskSchedule.addTaskToScheduling(task); - if(flag) { - result.setResult(1); - } - return result.extend("任务开启成功").taskInfo(task); - } else { - return result.extend("任务处于启动状态").taskInfo(task); - } - }else { - return result.extend("任务不存在!"); - } - } - - @Override - public TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity) { - TaskEntity task = taskRepository.queryData(entity.getTaskId()); - TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.update, 0).taskInfo(entity); - String config = entity.getTaskOutConfig(); - if(null != config && !JSONUtil.isJson(config) && !JSONUtil.isJsonArray(config)){ - result.setResult(0); - result.extend("更新任务失败,任务配置必须为JSON或空"); - result.taskInfo(entity); - return result; - } - task.setTaskCron(entity.getTaskCron()); - task.setTaskOutConfig(entity.getTaskOutConfig()); - task.setTaskName(entity.getTaskName()); - task.setTaskDesc(entity.getTaskDesc()); - int num = taskRepository.update(task); - if (num == 1) { - result.setResult(1); - result.extend("成功更新任务"); - result.taskInfo(entity); - //重新刷新任务 - taskSchedule.removeTaskFromScheduling(entity.getTaskId()); - taskSchedule.addTaskToScheduling(task); - } - - return result; - } - - - -} diff --git a/task-component/src/main/resources/META-INF/spring.factories b/task-component/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 0be5d40..0000000 --- a/task-component/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.task.ApplicationConfiguration \ No newline at end of file diff --git a/task-component/src/main/resources/application.yml b/task-component/src/main/resources/application.yml deleted file mode 100644 index 78cba49..0000000 --- a/task-component/src/main/resources/application.yml +++ /dev/null @@ -1,3 +0,0 @@ -gcc-task: - task-class-package : * - data-file-path: E:\JavaProject\task_info.json -- Gitee From f819844c0fb08488515c70a45954e08407ce06af Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 02:33:44 +0000 Subject: [PATCH 26/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- task-component/pom.xml | 13 +++++++++++++ .../components/task/ApplicationConfiguration.java | 9 +++++++++ .../src/main/resources/META-INF/spring.factories | 1 + 3 files changed, 23 insertions(+) create mode 100644 task-component/pom.xml create mode 100644 task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java create mode 100644 task-component/src/main/resources/META-INF/spring.factories diff --git a/task-component/pom.xml b/task-component/pom.xml new file mode 100644 index 0000000..79591f2 --- /dev/null +++ b/task-component/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + + com.gcc.container + components + 1.0.0 + + com.gcc.container.components + task-component + ${component.version} + jar + diff --git a/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java b/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java new file mode 100644 index 0000000..0697cbc --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/ApplicationConfiguration.java @@ -0,0 +1,9 @@ +package com.gcc.container.components.task; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "com.gcc.container.components.task.*") +public class ApplicationConfiguration { +} diff --git a/task-component/src/main/resources/META-INF/spring.factories b/task-component/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..0be5d40 --- /dev/null +++ b/task-component/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gcc.container.components.task.ApplicationConfiguration \ No newline at end of file -- Gitee From a5b2283f87262e6abbeb5826795db8f07c6fc460 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 02:35:01 +0000 Subject: [PATCH 27/33] =?UTF-8?q?=E6=A0=B8=E5=BF=83=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../components/task/annotation/TaskJob.java | 19 +++ .../task/compont/AbstractBaseCronTask.java | 111 ++++++++++++ .../InitTaskSchedulingApplication.java | 48 ++++++ .../components/task/compont/TaskSchedule.java | 62 +++++++ .../task/compont/TaskScheduleImpl.java | 160 ++++++++++++++++++ .../task/compont/TaskTempFactory.java | 99 +++++++++++ .../components/task/dao/TaskRepository.java | 57 +++++++ .../dao/impl/FileOpTaskRepositoryImpl.java | 154 +++++++++++++++++ .../task/model/TaskVoConvertor.java | 40 +++++ .../task/model/dto/SearchTaskDto.java | 28 +++ .../task/model/entity/TaskEntity.java | 115 +++++++++++++ .../task/model/vo/TaskRunRetVo.java | 70 ++++++++ .../components/task/model/vo/TaskVo.java | 55 ++++++ 13 files changed, 1018 insertions(+) create mode 100644 task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java diff --git a/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java b/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java new file mode 100644 index 0000000..39a90f8 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/annotation/TaskJob.java @@ -0,0 +1,19 @@ +package com.gcc.container.components.task.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TaskJob { + + String desc() default "暂无描述"; + + String cron() default "00 00 00 * * ?"; + + boolean bootup() default false; + +} \ No newline at end of file diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java b/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java new file mode 100644 index 0000000..7264f39 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/AbstractBaseCronTask.java @@ -0,0 +1,111 @@ +package com.gcc.container.components.task.compont; + + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; + +/** + * 抽象定时任务类 + * 实现定时任务需要继承该类 + * 子类实现时,不要使用Spring的任何注解 + * 若依赖外部的对象,使用 getServer()方法进行手动注入 + * @author GCC + */ +public abstract class AbstractBaseCronTask implements Runnable{ + + public Logger log; + + + private TaskEntity taskEntity; + + + private Double consumptionTime; + + private ApplicationContext applicationContext; + + + public AbstractBaseCronTask(TaskEntity taskEntity){ + log = LoggerFactory.getLogger(taskEntity.getTaskName()); + this.taskEntity = taskEntity; + } + + + //前置操作 + public abstract void beforeJob(); + + + //任务操作 + public abstract void startJob(); + + + //后置操作 + public abstract void afterJob(); + + + @Override + public void run() { + String id = this.taskEntity.getTaskId(); + this.taskEntity = getServer(TaskRepository.class).queryData(id); + log.info("---------------------任务 {} 开始执行-----------------------",taskEntity.getTaskName()); + log.info("任务描述:"+taskEntity.getTaskDesc()); + consumptionTime = 0d; + try { + Long start = System.currentTimeMillis(); + beforeJob(); + startJob(); + afterJob(); + Long end = System.currentTimeMillis(); + consumptionTime = NumberUtil.div((end - start),1000); + log.info("任务耗时:约 {} s",consumptionTime); + taskEntity.setTaskLastRun(1); + }catch (Exception e){ + log.error("任务{}计算出错!请及时排查问题!", taskEntity.getTaskName(),e); + taskEntity.setTaskLastRun(0); + } + getServer(TaskRepository.class).update(taskEntity); + log.info("---------------------任务 {} 结束执行-----------------------\n",taskEntity.getTaskName()); + } + + + public Object getSelfConfig(String key){ + try{ + TaskEntity entity = getServer(TaskRepository.class).queryData(taskEntity.getTaskId()); + JSONObject config = JSONUtil.parseObj(entity.getTaskOutConfig()); + return config.get(key); + }catch (Exception e){ + log.error("获取任务 {} 的配置参数失败,请确认参数配置格式是否正确!",taskEntity.getTaskName()); + } + return new JSONObject(); + } + + + public double getRunTime(){ return this.consumptionTime;} + + public TaskEntity getThisTaskInfo(){ + return this.taskEntity; + } + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + + /** + * 为适配反射生成的对象不受Spring容器管辖导致对象不共用问题 + * 提供手动获取系统上下文容器完成依赖注入 + * 通过类名使用Spring容器中的对象 + * @param className 类 + * @param 返回类型 + * @return T + */ + public T getServer(Class className){ + return applicationContext.getBean(className); + } + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java b/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java new file mode 100644 index 0000000..6085c3a --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/InitTaskSchedulingApplication.java @@ -0,0 +1,48 @@ +package com.gcc.container.components.task.compont; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 初始化任务调度机制 + * @author GCC + */ +@Order(1) +@Slf4j +@Component +public class InitTaskSchedulingApplication implements ApplicationRunner { + + private TaskSchedule taskSchedule; + + + private TaskTempFactory taskTempFactory; + + + @Autowired + public void setTaskScheduleServer(TaskSchedule taskSchedule) { + this.taskSchedule = taskSchedule; + } + + @Autowired + public void setTaskTempFactory(TaskTempFactory taskTempFactory) { + this.taskTempFactory = taskTempFactory; + } + + @Override + public void run(ApplicationArguments args) throws Exception { + //开启扫描 + taskTempFactory.scanTaskInfo(); + log.info("【定时任务初始化】 容器初始化"); + taskSchedule.initScheduling(); + log.info("【定时任务初始化】定时任务初始化任务开始"); + taskSchedule.loadAllTask(); + log.info("【定时任务初始化】定时任务初始化任务完成"); + + } + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java new file mode 100644 index 0000000..c2d2949 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskSchedule.java @@ -0,0 +1,62 @@ +package com.gcc.container.components.task.compont; + + + + +import com.gcc.container.components.task.model.entity.TaskEntity; + +import java.util.concurrent.ConcurrentHashMap; + +public interface TaskSchedule { + + + + ConcurrentHashMap getTaskSchedulingRam(); + + + /** + * 初始化任务调度 + */ + void initScheduling(); + + /** + * 添加任务至内存及容器 + * @param taskEntity 任务实体 + * @return boolean + */ + boolean addTaskToScheduling(TaskEntity taskEntity); + + /** + * 从任务调度器中移除任务 + * @param id 任务id + * @return Boolean + */ + boolean removeTaskFromScheduling(String id); + + + /** + * 执行指定任务 + * @param id 任务id + * @return double 耗时 + */ + double runTaskById(String id); + + + /** + * 清空任务 + */ + void claearAllTask(); + + + + /** + * 加载所有任务 + */ + void loadAllTask(); + + /** + * 运行开机自启任务 + */ + void runBootUpTask(); + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java new file mode 100644 index 0000000..d9f58a7 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskScheduleImpl.java @@ -0,0 +1,160 @@ +package com.gcc.container.components.task.compont; + + +import cn.hutool.core.util.NumberUtil; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Constructor; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; + +@Slf4j +@Component +public class TaskScheduleImpl implements TaskSchedule { + + //正在运行的任务 + private static ConcurrentHashMap runningTasks = new ConcurrentHashMap<>(); + + //线程池任务调度 + private ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); + + //内存中任务对象 + private static ConcurrentHashMap ramTasks = new ConcurrentHashMap<>(); + + //Spring容器池,用于注入Spring的bean + private ApplicationContext context; + + + private TaskRepository taskRepository; + + + private TaskTempFactory taskFactory; + + + @Autowired + public void setTaskRepository(TaskRepository taskRepository) { + this.taskRepository = taskRepository; + } + + @Autowired + public void setContext(ApplicationContext context) { + this.context = context; + } + + @Autowired + public void setTaskFactory(TaskTempFactory taskFactory) { + this.taskFactory = taskFactory; + } + + @Autowired + + + @Override + public ConcurrentHashMap getTaskSchedulingRam() { + return ramTasks; + } + + @Override + public void initScheduling() { + int num = taskFactory.mergeTaskEntities().size(); + num = num > 0 ? num:1; + this.threadPoolTaskScheduler.setPoolSize(num); + this.threadPoolTaskScheduler.setThreadNamePrefix("task-thread-"); + this.threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); + this.threadPoolTaskScheduler.initialize(); + } + + + @Override + public boolean addTaskToScheduling(TaskEntity task) { + if(!runningTasks.containsKey(task.getTaskId())){ + try{ + Class clazz = Class.forName(task.getTaskClass()); + Constructor c = clazz.getConstructor(TaskEntity.class); + AbstractBaseCronTask runnable = (AbstractBaseCronTask) c.newInstance(task); + //反射方式生成对象不属于Spring容器管控,对于Spring的bean使用需要手动注入 + runnable.setApplicationContext(context); + CronTrigger cron = new CronTrigger(task.getTaskCron()); + //put到runTasks + runningTasks.put(task.getTaskId(), Objects.requireNonNull(this.threadPoolTaskScheduler.schedule(runnable, cron))); + //存入内存中,便于外部调用 + ramTasks.put(task.getTaskId(),runnable); + task.setTaskRamStatus(1); + taskRepository.update(task); + return true; + }catch (Exception e){ + log.error("定时任务加载失败..."+e); + } + } + return false; + } + + + @Override + public boolean removeTaskFromScheduling(String id) { + if(runningTasks.containsKey(id)){ + runningTasks.get(id).cancel(true); + runningTasks.remove(id); + ramTasks.remove(id); + TaskEntity entity = taskRepository.queryData(id); + entity.setTaskRamStatus(0); + entity.setTaskLastRun(null); + if( 1 == taskRepository.update(entity) && !runningTasks.containsKey(id)){ + log.info("【定时任务控制器】任务"+id+"从内存进程池中移除,被终止!"); + return true; + } + } + return false; + } + + @Override + public double runTaskById(String id) { + TaskEntity task = taskRepository.queryData(id); + if(null!=task) { + if (runningTasks.containsKey(task.getTaskId())){ + ramTasks.get(task.getTaskId()).run(); + return ramTasks.get(task.getTaskId()).getRunTime(); + } + } + return 0d; + } + + @Override + public void claearAllTask() { + ramTasks.clear(); + log.info("【定时任务控制器】清除内存任务 完成"); + runningTasks.clear(); + log.info("【定时任务控制器】清除线程任务 完成"); + threadPoolTaskScheduler.shutdown(); + } + + @Override + public void loadAllTask() { + List allTask = taskFactory.mergeTaskEntities(); + for (TaskEntity task : allTask) { + if(addTaskToScheduling(task)){ + log.info("【定时任务初始化】装填任务:{} [ 任务执行周期:{} ] [ bootup:{}]",task.getTaskName(),task.getTaskCron(),task.getTaskBootUp()); + } + } + } + + + @Override + public void runBootUpTask() { + List list = taskRepository.queryAllTask(); + for(TaskEntity task:list){ + if(1 == task.getTaskIsUse() && 1 == task.getTaskBootUp()) { + runTaskById(task.getTaskId()); + } + } + } +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java new file mode 100644 index 0000000..1f0eca5 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/compont/TaskTempFactory.java @@ -0,0 +1,99 @@ +package com.gcc.container.components.task.compont; + + +import cn.hutool.core.date.DateUtil; +import cn.hutool.crypto.digest.DigestUtil; + +import com.gcc.container.components.task.annotation.TaskJob; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.property.TaskDataProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +class TaskTempFactory { + + @Autowired + private TaskRepository taskRepository; + + @Autowired + TaskDataProperties taskDataProperties; + + private List tempContainer = new ArrayList<>(); + + + public void scanTaskInfo() throws Exception { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AnnotationTypeFilter(TaskJob.class)); + Set beanDefinitions = provider.findCandidateComponents(taskDataProperties.getTaskClassPackage()); + for (BeanDefinition beanDefinition : beanDefinitions) { + Class clazz = Class.forName(beanDefinition.getBeanClassName()); + TaskJob taskJob = clazz.getAnnotation(TaskJob.class); + if (AbstractBaseCronTask.class.isAssignableFrom(clazz)) { + tempContainer.add(builderTaskEntity(clazz,taskJob)); + } else { + throw new IllegalArgumentException("Class " + clazz.getName() + " must extend AbstractBaseCronTask"); + } + } + } + + + public List mergeTaskEntities() { + List db = getIsUseTask(); + Map map = db.stream() + .collect(Collectors.toMap( + TaskEntity::getTaskClass, + task -> task + )); + for(TaskEntity entity:tempContainer){ + if(!map.containsKey(entity.getTaskClass())){ + taskRepository.save(entity); + db.add(entity); + } + } + return db; + } + + + private TaskEntity builderTaskEntity(Class cronTaskClass, TaskJob taskJob) { + String path = cronTaskClass.getName(); TaskEntity entity = new TaskEntity(); + entity.setTaskId(DigestUtil.md5Hex(path)); + entity.setTaskClass(path); + entity.setTaskIsUse(1); + entity.setTaskName(cronTaskClass.getSimpleName()); + entity.setTaskDesc(taskJob.desc()); + entity.setTaskBootUp(converBootUp(taskJob.bootup())); + entity.setTaskCron(taskJob.cron()); + entity.setTaskCreateTime(DateUtil.now()); + //todo 外部配置 + return entity; + } + + + private List getIsUseTask(){ + List list = taskRepository.queryAllTask(); + List result = new ArrayList<>(); + for(TaskEntity entity:list){ + if(entity.isUse()){ + result.add(entity); + } + } + return result; + } + + private Integer converBootUp(Boolean flag){ + if(flag){ + return 1; + } + return 0; + } +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java b/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java new file mode 100644 index 0000000..c05ea46 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/dao/TaskRepository.java @@ -0,0 +1,57 @@ +package com.gcc.container.components.task.dao; +import com.gcc.container.components.task.model.entity.TaskEntity; +import java.util.List; +/** + * 任务数据操作 + */ +public interface TaskRepository { + + /** + * 新增数据 + * @param entity + * @return int + */ + int save(TaskEntity entity); + + + /** + * 删除任务ID + * @param id id + * @return int + */ + int removeByTaskId(String id); + + + /** + * 更新整个任务 + * @param entity 实体 + * @return int + */ + int update(TaskEntity entity); + + + /** + * 查询全部任务 + * @return List + */ + List queryAllTask(); + + + + /** + * 查询数据 + * @param entity 查询 + * @return TaskEntity + */ + List queryData(TaskEntity entity); + + + + + /** + * 查询具体的任务实体 + * @param taskId 任务id + * @return TaskEntity + */ + TaskEntity queryData(String taskId); +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java new file mode 100644 index 0000000..50fefe6 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/dao/impl/FileOpTaskRepositoryImpl.java @@ -0,0 +1,154 @@ +package com.gcc.container.components.task.dao.impl; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.property.TaskDataProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Repository +@Slf4j +public class FileOpTaskRepositoryImpl implements TaskRepository { + + + @Autowired + private TaskDataProperties properties; + + + + @Override + public int save(TaskEntity entity) { + List list = readFileInfo(); + list.add(entity); + writeFileInfo(list); + return 1; + } + + @Override + public int removeByTaskId(String id) { + List list = readFileInfo(); + List data = new ArrayList<>(); + for(TaskEntity entity:list){ + if(!entity.getTaskId().equals(id)){ + data.add(entity); + } + } + writeFileInfo(data); + return list.size() - data.size(); + } + + + @Override + public int update(TaskEntity entity) { + List list = readFileInfo(); + List data = new ArrayList<>(); + for(TaskEntity one:list){ + if(!one.getTaskId().equals(entity.getTaskId())){ + data.add(one); + } + } + data.add(entity); + writeFileInfo(data); + return 1; + } + + @Override + public List queryAllTask() { + return readFileInfo(); + } + + @Override + public List queryData(TaskEntity entity) { + List list = readFileInfo(); + // 获取不为空的属性 + Map nonNullProperties = entity.getNonNullProperties(); + // 进行 AND 查询 + List result = new ArrayList<>(); + for (TaskEntity t : list) { + boolean match = true; + for (Map.Entry entry : nonNullProperties.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if ("taskDesc".equals(key) && !StrUtil.equals(t.getTaskDesc(), (String) value)) { + match = false; + break; + } + if ("taskIsUse".equals(key) && t.getTaskIsUse() != (Integer) value) { + match = false; + break; + } + if ("taskBootUp".equals(key) && t.getTaskBootUp() != (Integer) value) { + match = false; + break; + } + } + if (match) { + result.add(t); + } + } + return result; + } + + + + + @Override + public TaskEntity queryData(String id) { + List list = readFileInfo(); + for(TaskEntity entity:list){ + if(1 == entity.getTaskIsUse() && id.equals(entity.getTaskId())){ + return entity; + } + } + return null; + } + + + private List readFileInfo(){ + // 确保文件存在 + File file = FileUtil.file(getDefaultPath()); + if (!file.exists()) { + log.error("FILE is not exists"); + return new ArrayList<>(); + } + // 读取 JSON 文件内容 + String jsonContent = FileUtil.readUtf8String(getDefaultPath()); + // 将 JSON 字符串转换为 JSON 对象 + JSONArray data = JSONUtil.parseArray(jsonContent); + List result = new ArrayList<>(); + for(int i = 0; i < data.size(); i++){ + result.add(JSONUtil.toBean(data.getJSONObject(i),TaskEntity.class)); + } + return result; + } + + + + /** + * 覆盖写入 JSONArray 文件 + */ + private void writeFileInfo(List data) { + JSONArray array = new JSONArray(data); + // 确保文件存在或创建文件 + File file = FileUtil.touch(getDefaultPath()); + FileUtil.writeUtf8String(array.toJSONString(0), file); + } + + + private String getDefaultPath(){ + if(StrUtil.isNotBlank(properties.getDataFilePath())){ + return properties.getDataFilePath(); + } + return "db/task_info.json"; + } + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java b/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java new file mode 100644 index 0000000..fe9089c --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/model/TaskVoConvertor.java @@ -0,0 +1,40 @@ +package com.gcc.container.components.task.model; + + +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.model.vo.TaskVo; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class TaskVoConvertor { + + + public TaskVo toTaskVo(TaskEntity entity){ + return TaskVo.builder() + .taskId(entity.getTaskId()) + .taskName(entity.getTaskName()) + .taskDesc(entity.getTaskDesc()) + .taskCron(entity.getTaskCron()) + .taskOutConfig(entity.getTaskOutConfig()) + .taskBootUp(entity.getTaskBootUp()) + .taskCreateTime(entity.getTaskCreateTime()) + .status(ramStatusToRunStatus(entity.getTaskRamStatus())) + .build(); + } + + public List toTaskVos(List entities){ + return entities.stream().map(this::toTaskVo).collect(Collectors.toList()); + } + + private TaskVo.TaskRunStatus ramStatusToRunStatus(Integer ramStatus){ + if(1 == ramStatus){ + return TaskVo.TaskRunStatus.open; + }else { + return TaskVo.TaskRunStatus.shutdown; + } + } + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java b/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java new file mode 100644 index 0000000..d4f352c --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/model/dto/SearchTaskDto.java @@ -0,0 +1,28 @@ +package com.gcc.container.components.task.model.dto; + +import lombok.Data; +import java.io.Serializable; + + +/** + * 查询参数 + */ +@Data +public class SearchTaskDto implements Serializable { + + + private String filterKey; + + + private Boolean isBootUp; + + + private Integer lastRunStatus; + + + private Integer pageNo; + + + private Integer pageSize; + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java b/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java new file mode 100644 index 0000000..cfb9bcc --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/model/entity/TaskEntity.java @@ -0,0 +1,115 @@ +package com.gcc.container.components.task.model.entity; + + +import lombok.Data; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 任务实体类 + * @author GCC + */ +@Data +public class TaskEntity implements Serializable { + + //todo 解决外部创建表的操作 + + private String taskId; + + private String taskName; + + private String taskDesc; + + private String taskCron; + + private String taskClass; + + /** + * 任务相关配置 + */ + private String taskOutConfig; + + /** + * 任务注册时间 + */ + private String taskCreateTime; + + /** + * 是否启用 + */ + private Integer taskIsUse; + + /** + * 是否开启自启动 + */ + private Integer taskBootUp; + + /** + * 上次运行状态 + */ + private Integer taskLastRun; + + /** + * 任务是否在内存中 + */ + private Integer taskRamStatus; + + + public TaskEntity taskIsUse(Boolean isUse) { + if(isUse) { + this.taskIsUse = 1; + }else { + this.taskIsUse = 0; + } + return this; + } + + public TaskEntity taskBootUp(Boolean isBootUp) { + if(isBootUp) { + this.taskBootUp = 1; + }else { + this.taskBootUp = 0; + } + return this; + } + + public TaskEntity taskLastRun(Integer taskLastRun) { + this.taskLastRun = taskLastRun; + return this; + } + + public TaskEntity taskRamStatus(Integer taskRamStatus) { + this.taskRamStatus = taskRamStatus; + return this; + } + + + + public Boolean isUse(){ + if(null != this.taskIsUse && 1 == this.taskIsUse){ + return true; + } + return false; + } + + + public Boolean isBootUp(){ + if(null != this.taskBootUp && 1 == this.taskBootUp){ + return true; + } + return false; + } + + + + public Map getNonNullProperties() { + Map properties = new HashMap<>(); + if (taskDesc != null) properties.put("taskDesc", taskDesc); + if (taskIsUse != null) properties.put("taskIsUse", taskIsUse); + if (taskBootUp != null) properties.put("taskBootUp", taskBootUp); + return properties; + } + + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java new file mode 100644 index 0000000..300d935 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskRunRetVo.java @@ -0,0 +1,70 @@ +package com.gcc.container.components.task.model.vo; + + +import com.gcc.container.components.task.model.entity.TaskEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * 任务运行状态 + */ +@Data +public class TaskRunRetVo implements Serializable { + + + private String taskId; + + + private String taskName; + + + private TaskOperation taskOperation; + + /** + * 执行状态 + * 1:成功 + * 0:失败 + */ + private Integer result; + + + private String extend = "successful"; + + + public TaskRunRetVo(TaskOperation taskOperation, int result) { + this.taskOperation = taskOperation; + this.result = result; + if(result == 0){ + this.extend = "fail"; + } + } + + public TaskRunRetVo taskInfo(TaskEntity taskEntity){ + this.taskId = taskEntity.getTaskId(); + this.taskName = taskEntity.getTaskName(); + return this; + } + + public TaskRunRetVo extend(Object extend){ + this.extend =String.valueOf(extend); + return this; + } + + public enum TaskOperation{ + + //开启 + open, + + //关闭/停止 + shutdown, + + //更新任务 + update, + + //立即执行 + run; + } + + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java new file mode 100644 index 0000000..433c27a --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/model/vo/TaskVo.java @@ -0,0 +1,55 @@ +package com.gcc.container.components.task.model.vo; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Builder +public class TaskVo implements Serializable { + + private String taskId; + + private String taskName; + + private String taskDesc; + + private String taskCron; + + /** + * 任务相关配置 + */ + private String taskOutConfig; + + /** + * 任务注册时间 + */ + private String taskCreateTime; + + + /** + * 是否开启自启动 + */ + private Integer taskBootUp; + + /** + * 启停状态 + */ + private TaskRunStatus status; + + + public enum TaskRunStatus{ + //开启 + open(1), + //关闭 + shutdown(0); + + Integer code; + + TaskRunStatus(Integer code){ + this.code = code; + } + } + +} -- Gitee From 059c95078a37c2df883028323c2d5b2c453cbdf2 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 02:35:36 +0000 Subject: [PATCH 28/33] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- .../components/task/AfterAppStarted.java | 28 ++++ .../task/property/TaskDataProperties.java | 25 +++ .../service/TaskScheduleManagerService.java | 55 +++++++ .../impl/TaskScheduleManagerServiceImpl.java | 142 ++++++++++++++++++ 4 files changed, 250 insertions(+) create mode 100644 task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java create mode 100644 task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java diff --git a/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java new file mode 100644 index 0000000..cc51b48 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/AfterAppStarted.java @@ -0,0 +1,28 @@ +package com.gcc.container.components.task; + + + +import com.gcc.container.components.task.compont.TaskSchedule; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class AfterAppStarted { + + TaskSchedule taskSchedule; + + @Autowired + public void setTaskScheduleServer(TaskSchedule taskSchedule) { + this.taskSchedule = taskSchedule; + } + + @EventListener + public void onApplicationEvent(ApplicationReadyEvent event){ + //运行随系统启动的定时任务 + taskSchedule.runBootUpTask(); + } +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java new file mode 100644 index 0000000..20f6cb1 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/property/TaskDataProperties.java @@ -0,0 +1,25 @@ +package com.gcc.container.components.task.property; + +import cn.hutool.core.util.StrUtil; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties("gcc-task") +@Data +public class TaskDataProperties { + + + private String dataFilePath; + + + private String taskClassPackage; + + public String getTaskClassPackage() { + if(StrUtil.isBlankIfStr(this.taskClassPackage)){ + return "*"; + } + return taskClassPackage; + } +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java b/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java new file mode 100644 index 0000000..ec07f9c --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/service/TaskScheduleManagerService.java @@ -0,0 +1,55 @@ +package com.gcc.container.components.task.service; + +import com.gcc.container.components.task.model.dto.SearchTaskDto; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.model.vo.TaskRunRetVo; +import com.gcc.container.components.task.model.vo.TaskVo; +import java.util.List; +public interface TaskScheduleManagerService { + + /** + * 查询在用任务 + * @return + */ + List searchTask(SearchTaskDto dto); + + /** + * 查询任务详情 + * @param taskId 任务id + * @return TaskEntity + */ + TaskVo searchTaskDetail(String taskId); + + + /** + * 运行指定任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo runTask(String taskId); + + + /** + * 关停任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo shutdownTask(String taskId); + + + /** + * 开启任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo openTask(String taskId); + + + /** + * 更新任务信息 + * @param entity 实体 + * @return TaskRunRetDto + */ + TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity); + +} diff --git a/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java new file mode 100644 index 0000000..e0c0ba5 --- /dev/null +++ b/task-component/src/main/java/com/gcc/container/components/task/service/impl/TaskScheduleManagerServiceImpl.java @@ -0,0 +1,142 @@ +package com.gcc.container.components.task.service.impl; + +import cn.hutool.json.JSONUtil; +import com.gcc.container.components.task.compont.AbstractBaseCronTask; +import com.gcc.container.components.task.compont.TaskSchedule; +import com.gcc.container.components.task.dao.TaskRepository; +import com.gcc.container.components.task.model.TaskVoConvertor; +import com.gcc.container.components.task.model.dto.SearchTaskDto; +import com.gcc.container.components.task.model.entity.TaskEntity; +import com.gcc.container.components.task.model.vo.TaskRunRetVo; +import com.gcc.container.components.task.model.vo.TaskVo; +import com.gcc.container.components.task.service.TaskScheduleManagerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.List; + + +@Component +public class TaskScheduleManagerServiceImpl implements TaskScheduleManagerService { + + + private TaskSchedule taskSchedule; + + private TaskRepository taskRepository; + + private TaskVoConvertor taskVoConvertor; + + @Autowired + public void setTaskScheduleServer(TaskSchedule taskSchedule) { + this.taskSchedule = taskSchedule; + } + + @Autowired + public void setTaskRepository(TaskRepository taskRepository) { + this.taskRepository = taskRepository; + } + + @Autowired + public void setTaskVoConvertor(TaskVoConvertor taskVoConvertor) { + this.taskVoConvertor = taskVoConvertor; + } + + @Override + public List searchTask(SearchTaskDto dto) { + TaskEntity entity = new TaskEntity() + .taskIsUse(true) + .taskBootUp(dto.getIsBootUp()) + .taskLastRun(dto.getLastRunStatus()); + entity.setTaskDesc(dto.getFilterKey()); + return taskVoConvertor.toTaskVos(taskRepository.queryData(entity)); + } + + + @Override + public TaskVo searchTaskDetail(String taskId) { + if(!StringUtils.isEmpty(taskId)){ + return taskVoConvertor.toTaskVo(taskRepository.queryData(taskId)); + } + return null; + } + + + @Override + public TaskRunRetVo runTask(String taskId) { + AbstractBaseCronTask task = taskSchedule.getTaskSchedulingRam().get(taskId); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.run, 0); + if(null != task) { + double time = taskSchedule.runTaskById(taskId); + result.setResult(1); + return result.extend(time).taskInfo(task.getThisTaskInfo()); + } else { + return result.extend("任务未启用"); + } + } + + @Override + public TaskRunRetVo shutdownTask(String taskId) { + AbstractBaseCronTask task = taskSchedule.getTaskSchedulingRam().get(taskId); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.shutdown, 0); + if(null != task) { + boolean flag = taskSchedule.removeTaskFromScheduling(taskId); + if(flag) { + result.setResult(1); + } + return result.extend("任务成功关闭").taskInfo(task.getThisTaskInfo()); + } else { + return result.extend("任务未启用"); + } + } + + @Override + public TaskRunRetVo openTask(String taskId) { + TaskEntity task = taskRepository.queryData(taskId); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.open, 0); + if(null != task) { + if (!taskSchedule.getTaskSchedulingRam().containsKey(taskId)) { + boolean flag = taskSchedule.addTaskToScheduling(task); + if(flag) { + result.setResult(1); + } + return result.extend("任务开启成功").taskInfo(task); + } else { + return result.extend("任务处于启动状态").taskInfo(task); + } + }else { + return result.extend("任务不存在!"); + } + } + + @Override + public TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity) { + TaskEntity task = taskRepository.queryData(entity.getTaskId()); + TaskRunRetVo result = new TaskRunRetVo(TaskRunRetVo.TaskOperation.update, 0).taskInfo(entity); + String config = entity.getTaskOutConfig(); + if(null != config && !JSONUtil.isJson(config) && !JSONUtil.isJsonArray(config)){ + result.setResult(0); + result.extend("更新任务失败,任务配置必须为JSON或空"); + result.taskInfo(entity); + return result; + } + task.setTaskCron(entity.getTaskCron()); + task.setTaskOutConfig(entity.getTaskOutConfig()); + task.setTaskName(entity.getTaskName()); + task.setTaskDesc(entity.getTaskDesc()); + int num = taskRepository.update(task); + if (num == 1) { + result.setResult(1); + result.extend("成功更新任务"); + result.taskInfo(entity); + //重新刷新任务 + taskSchedule.removeTaskFromScheduling(entity.getTaskId()); + taskSchedule.addTaskToScheduling(task); + } + + return result; + } + + + +} -- Gitee From 58e528f4ab2c8937707fcceebc22a29cd759e12a Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 02:36:18 +0000 Subject: [PATCH 29/33] =?UTF-8?q?=E6=A0=B7=E4=BE=8B=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- task-component/src/main/resources/application.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 task-component/src/main/resources/application.yml diff --git a/task-component/src/main/resources/application.yml b/task-component/src/main/resources/application.yml new file mode 100644 index 0000000..78cba49 --- /dev/null +++ b/task-component/src/main/resources/application.yml @@ -0,0 +1,3 @@ +gcc-task: + task-class-package : * + data-file-path: E:\JavaProject\task_info.json -- Gitee From 5a009e06a7ba1b5e6d4d9bcecb55c5fa331c11db Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 03:36:02 +0000 Subject: [PATCH 30/33] =?UTF-8?q?=E6=96=B0=E5=A2=9EREADME=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- task-component/README.md | 333 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 task-component/README.md diff --git a/task-component/README.md b/task-component/README.md new file mode 100644 index 0000000..eb4143d --- /dev/null +++ b/task-component/README.md @@ -0,0 +1,333 @@ +# task-component + +> 相比于SpringBoot本身自带的定时任务注解的死板(程序一旦运行,无法更改定时任务执行周期、相关配置等问题)和xxl-Job的笨重,该组件从代码级提供了轻量级的定时任务管理解决方案 +> +> 引入该组件,只需要实现定时任务基类,即可完成自动注册定时任务,通过定时任务接口来动态控制任务的状态,使用接口配合页面,可扩展到页面功能,做到随时启停、修改定时任务 + +## 组件依赖说明 + +组件整体继承自Components包,所依赖Spring相关组件及通用的公共组件依赖跟随Components版本进行调整管控,相关内容可查看Components的README文档 + +```xml + + com.gcc.container + components + 1.0.0 + +``` + +除基本的SpringAOP、autoconfigure外无其他依赖 + +## 使用说明 + +找到对应版本的Components源码,下载到本地,本地编译安装到私仓中,在你的项目中引入: + +```xml + + + com.gcc.container.components + task-component + 1.0.0 + +``` + +### yaml配置 + +因该组件是基于包扫描去识别定时任务类和默认以JSON文件的形式去存储项目的定时任务信息,需要通过yaml配置文件来指定包路径和文件的存放路径,引入组件后,可在自己的yml文件中追加: + +```yml +gcc-task: + #指定定时任务存放的包路径,默认不填写则扫描全项目 + task-class-package : * + #定时任务管理的数据存放文件及其路径,默认不填写则存放项目运行目录下,如自行扩展实现,则该配置自动失效 + data-file-path: /opt/myproject/task_info.json +``` + +此处的两个配置项都包含默认值,所以不进行yml的`gcc-task`仍旧可以使用该组件 + +### 新建定时任务 + +引入依赖后,需要新增一个定时任务逻辑,则需要实现基类`AbstractBaseCronTask` ,并加入注解 `@TaskJob` + +**TaskJob的参数如下**: + +| 参数 | 说明 | 样例 | +| ------ | --------------------------------------------- | -------------- | +| cron | 定时任务默认的执行周期,仅在首次初始化该任务使用(**必填**) | 10 0/2 * * * ? | +| desc | 任务描述,非必填 | 这是测试任务 | +| bootup | 是否开机自启动,**缺省值为 false** | false | + +*`cron` 属性仅在第一次新增该任务时提供一个默认的执行周期,必须填写,后续任务加载后,定时任务相关数据会被存放在文件或数据库中,此时则以文件或数据库中该任务的cron为主* + +完整一个定时任务demo如下: + +```java +@TaskJob(cron = "10 0/2 * * * ?" ,desc = "这是一个测试任务",bootup = true) +public class TaskMysqlOne extends AbstractBaseCronTask { + + public TaskMysqlOne(TaskEntity taskEntity) { + super(taskEntity); + } + + @Override + public void beforeJob() { + } + + @Override + public void startJob() { + } + + @Override + public void afterJob() { + } +} +``` + +继承`AbstractBaseCronTask` 必须要实现携带TaskEntity参数的`构造函数`、`beforeJob()`、`startJob()` 、`afterJob()` 三个方法即可。**原则上这三个方法是规范定时任务的执行,实际使用,只需要把核心逻辑放在三个方法中任何一个即可**。 + + + +因定时任务类是非SpringBean管理的类,所以**在自定义的定时任务类内无法使用任何Spring相关的注解(如@Autowired)**,**但是却可以通过自带的**`getServer(Class className)`**方法来获取任何Spring上下文中的Bean** + +例如,你有一个UserService的接口及其Impl的实现类 + +```java +@TaskJob(cron = "10 0/2 * * * ?" ,desc = "这是一个测试任务",bootup = true) +public class TaskMysqlOne extends AbstractBaseCronTask { + + public TaskMysqlOne(TaskEntity taskEntity) { + super(taskEntity); + } + + @Override + public void beforeJob() { + } + + @Override + public void startJob() { + List names = getServer(UserService.class).searchAllUserName(); + //后续逻辑…… + //其他逻辑 + } + + @Override + public void afterJob() { + + } +} +``` + +### 服务接口说明 + +定时任务相关的管理操作均封装在`TaskScheduleManagerService`接口中,可直接在外部项目中注入使用即可: + +```java +@RestController +@RequestMapping("/myself/manage") +public class TaskSchedulingController { + + @Autowired + TaskScheduleManagerService taskScheduleManagerService; + + @GetMapping("/detail") + @Operation(summary = "具体任务对象") + public Response searchDetail(String taskId){ + return Response.success(taskScheduleManagerService.searchTaskDetail(taskId)); + } + + @GetMapping("/shutdown") + @Operation(summary = "关闭指定任务") + public Response shutdownTask(String taskId){ + return Response.success(taskScheduleManagerService.shutdownTask(taskId)); + } + + @GetMapping("/open") + @Operation(summary = "开启指定任务") + public Response openTask(String taskId){ + return Response.success(taskScheduleManagerService.openTask(taskId)); + } + +``` + +`TaskScheduleManagerService`的接口定义如下: + +```java +public interface TaskScheduleManagerService { + /** + * 查询在用任务 + * @return + */ + List searchTask(SearchTaskDto dto); + /** + * 查询任务详情 + * @param taskId 任务id + * @return TaskEntity + */ + TaskVo searchTaskDetail(String taskId); + /** + * 运行指定任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo runTask(String taskId); + /** + * 关停任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo shutdownTask(String taskId); + /** + * 开启任务 + * @param taskId 任务id + * @return TaskRunRetDto + */ + TaskRunRetVo openTask(String taskId); + /** + * 更新任务信息 + * @param entity 实体 + * @return TaskRunRetDto + */ + TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity); +} +``` + +## 扩展说明 + +定时任务类首次新增被扫描后,会以TaskEntity的形式存在于内存中,TaskEntity如下: + +```java +@Data +public class TaskEntity implements Serializable { + + private String taskId; + + private String taskName; + + private String taskDesc; + + private String taskCron; + + private String taskClass; + + /** + * 任务相关配置 + */ + private String taskOutConfig; + + /** + * 任务注册时间 + */ + private String taskCreateTime; + + /** + * 是否启用 + */ + private Integer taskIsUse; + + /** + * 是否开启自启动 + */ + private Integer taskBootUp; + + /** + * 上次运行状态 + */ + private Integer taskLastRun; + + /** + * 任务是否在内存中 + */ + private Integer taskRamStatus; +``` + +task-component会将内存中的TaskEntity进行持久化,下次再启动项目时,则直接使用持久化的TaskEntity来加载定时任务,task-component默认是以JSON文件进行持久化,实际使用中为了能带来更好的体验,建议扩展为数据库存储,扩展方式如下: + +1、新建数据库表(以Mysql为例) + +```SQL +DROP TABLE IF EXISTS `tb_task_info`; +CREATE TABLE `tb_task_info` ( + `task_id` varchar(100) NOT NULL PRIMARY KEY , + `task_name` varchar(255) DEFAULT NULL, + `task_desc` text, + `task_cron` varchar(20) DEFAULT NULL, + `task_class` varchar(100) DEFAULT NULL COMMENT '定时任务类路径', + `task_is_use` tinyint DEFAULT NULL COMMENT '是否启用该任务,1:启用,0禁用', + `task_boot_up` tinyint DEFAULT NULL COMMENT '是否为开机即运行,1:初始化即运行,0,初始化不运行', + `task_out_config` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '定时任务额外配置项,采用json结构存放', + `task_create_time` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '定时任务追加时间', + `task_last_run` tinyint DEFAULT NULL COMMENT '任务上次执行状态;1正常,0执行失败,null未知', + `task_ram_status` tinyint DEFAULT NULL COMMENT '任务当前状态;1内存运行中,0内存移除', + PRIMARY KEY (`task_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC; +``` + +2、项目中实现`TaskRepository`接口,并使用@Primary注解: + +```java +@Repository +@Primary +public class TaskRepositoryImpl implements TaskRepository { + + @Autowired + private TaskDataMapper taskDataMapper; + + @Override + public int save(TaskEntity entity) { + entity.setTaskCreateTime(DateUtil.now()); + return taskDataMapper.insert(entity); + } + + @Override + public int update(TaskEntity entity) { + UpdateWrapper update = new UpdateWrapper<>(); + update.eq("task_id",entity.getTaskId()); + return taskDataMapper.update(entity,update); + } + + + @Override + public int removeByTaskId(String id) { + QueryWrapper query = new QueryWrapper<>(); + query.eq("task_id",id); + return taskDataMapper.delete(query); + } + + @Override + public List queryAllTask() { + return taskDataMapper.selectList(new QueryWrapper<>()); + } + + @Override + public TaskEntity queryData(String id) { + QueryWrapper query = new QueryWrapper<>(); + query.eq("task_id",id); + return taskDataMapper.selectOne(query); + } + + @Override + public List queryData(TaskEntity entity) { + QueryWrapper query = new QueryWrapper<>(); + query.orderByAsc("task_create_time"); + if(null != entity) { + if (null != entity.getTaskIsUse()) { + query.eq("task_is_use", entity.getTaskIsUse()); + } + if (null != entity.getTaskBootUp()) { + query.eq("task_boot_up", entity.getTaskBootUp()); + } + if (!StringUtils.isEmpty(entity.getTaskDesc())) { + query.like("task_desc", entity.getTaskDesc()); + } + } + return taskDataMapper.selectList(query); + } +} + +``` + + + +只需要实现其中指定的几个持久化和查询方法即可替换component中的JSON文件持久化 + + -- Gitee From 6c0ffd089ed8bedb6ecbf5d5dcbebdcda3007da2 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 03:44:58 +0000 Subject: [PATCH 31/33] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20in?= =?UTF-8?q?itdatabse-component/README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- initdatabse-component/README.md | 354 -------------------------------- 1 file changed, 354 deletions(-) delete mode 100644 initdatabse-component/README.md diff --git a/initdatabse-component/README.md b/initdatabse-component/README.md deleted file mode 100644 index 3d04a68..0000000 --- a/initdatabse-component/README.md +++ /dev/null @@ -1,354 +0,0 @@ -# Conscript 数据库初始化工具 - -> Conscript基于Spring-boot-starter的方式提供数据库初始化功能,可以随项目初次启动,自动创建相关数据库,后续系统升级所引发的数据库变化及升级也可由此完成,拆箱即用,随系统程序代码运行,省去额外的数据库升级操作, -> -> `支持数据库种类可扩展,目前支持通用mysql、postgreSQL、 国产数据库达梦和金仓` -> -> `支持执行失败回滚机制` - -## 1.支持数据库类型 - -| 数据库类型 | 是否支持 | db-driver参数 | -| ---------- | ---- | ----------- | -| mysql | 是 | mysql | -| mariadb | 是 | mariadb | -| PostgreSQL | 是 | pgsql | -| 达梦数据库 | 是 | dm | -| 人大金仓8 | 是 | kingbase8 | - -## 2.实现设计 - -核心代码结构: - -```shell -+---action #基础功能包 -| +---mysql #mysql数据库实现 -----initDataBase #数据库初始化接口 -----DataBaseInitorFactory #数据库初始器工厂 -----AbstractInitDataBase #数据库初始器基类 -``` - -| 类 | 介绍 | -| --------------------- | -------------- | -| initDataBase | 初始化接口 | -| AbstractInitDataBase | 初始化基类,定义核心逻辑 | -| MySqlDataBase | Mysql实现,具体执行方式 | -| DataBaseInitorFactory | 工厂类 | - -```mermaid -classDiagram -direction TD -class initDataBase{ - <> - isInitEd() - startCoreJob() - createConnection() - databaseIsExitd() - getCurrenDbVersion() - excuteSQL(Map sqlcontent) - close() -} -class AbstractInitDataBase { - <> - +void : startCoreJob() - } -class MySqlDataBase { - +void : createConnection() - +boolean:databaseIsExitd() - +Float:getCurrenDbVersion() - +void:excuteSQL(Map sqlcontent) - } -class DataBaseInitorFactory { - +InitDataBase : createInitiator(DbConConfiguration config) - +String:getClassUrlValue(DbType dbType) - } - class DbConConfiguration { - +DbConConfiguration : builder() - +void:set() - +Object:get() - } -initDataBase <-- AbstractInitDataBase : -AbstractInitDataBase <|-- MySqlDataBase -DbConConfiguration <.. DataBaseInitorFactory -initDataBase -- DataBaseInitorFactory -``` - -> **扩展其他类型数据库:在action目录下新建相应的数据库类型目录,然后继承AbstractInitDataBase类,实现对应的几个数据库操作方法,在DatabaseProperties的getDbDeriver()中新增对应的映射** - -## 3.使用方式 - -可直接集成至SpringBoot项目中使用 - -| SpringBoot版本要求 | -| -------------------------------------- | -| `SpringBoot version` >=  2.3.6.RELEASE | - -### 1.引入Conscript - -1.1.使用jar引入 - -> 本地编译源码后,install到本地的maven私仓后,直接引入项目 - -```xml - - com.gcc.airbase - Conscript - 1.0 - -``` - -### 2.配置yml文件 - -```yml -spring: - datasource: - url: jdbc:mysql://127.0.0.1:3306/test?user=root&password=1234 - username: root - password: 1234 - driver-class-name: com.mysql.cj.jdbc.Driver - db-config-file-url: sql/mysql/dbconfig.json - db-driver: mysql - db-name: test -``` - -配置内容遵循标准的`spring.datasource`配置,并进行了增强 - -| 字段 | 含义 | 是否必填 | -| ------------------ | ------------------------------------------------ | ---- | -| url | 必选字段,遵循标准datasource即可,若使用mybaits,则按照mybaits标准填写 | 是 | -| username | 必选字段,标准datasource即可,填写数据库账号 | 是 | -| password | 必选字段,标准datasource即可,填写数据库连接密码 | 是 | -| driver-class-name | 必选字段,标准datasource即可,填写数据库连接驱动类 | 是 | -| db-config-file-url | 必选字段,指定静态SQL文件存放位置 | 是 | -| db-driver | 必选字段,指定数据库类型,扩展时,可填写类路径,默认填写mysql,详细见扩展用法章节 | 是 | -| dbport | 非必选字段,数据库服务端口,若url填写,可省略该字段 | 否 | -| db-name | 非必选字段,需要连接的数据库名称,若url中填写,可省略该字段 | 否 | -| schema | 非必须字段,若url中填写,则可省略,主要用于对部分数据库的模式配置 | 否 | -| root-user | 非必选字段,**若存在对数据库权限分离有要求的需求**,可以在此填写专门用于建库的高权限账号 | 否 | -| root-pass | 非必选字段,**若存在对数据库权限分离有要求的需求**,可以在此填写专门用于建库的高权限账号密码 | 否 | - -此处配置相较 `spring.datasource`的基础的 `url、username、password、driver-class-name`外,增加了独有的`db-driver、db-config-file-url`,原则上只需要满足此6项配置即可使用Conscript,但建议将配置补全使用 - - `使用该组件,必须确保拥有较高的数据库角色权限,例如mysql的root、pgsql的postgres,否则无法使用创建数据库的功能,如需清晰划分权限,则可以通过配置项中的root-user,root-pass来将系统数据库的使用区分开来` - -### 3.建立配置文件及SQL文件 - -以标准maven项目为例 - -​ 1.根据 yml中`spring.datasource.db-config-file-url`配置的值,在resource目录下新建相应路径json文件 - -XX.json文件样例如下: - -```json - [ - { - "version": "1.0", - "sqlfile": "a.sql", - "desc": "基础数据库结构" - }, - { - "version": "1.1", - "sqlfile": "ddd.sql", - "desc": "第一版升级数据库" - } - ] -``` - -| 字段 | 含义 | -| ------- | --------------------------------------------------------------------------- | -| version | 数据库的版本,**数字类型** | -| sqlfile | 数据库升级的sql文件,叠加式追加,**注:这里要写清楚sql文件的路径(基于resource目录为基准),此处的配置决定后续sql文件的存放位置** | -| desc | 维护使用的描述信息 | - -​ 2.根据XX.json配置文件中的sqlfile配置项,新建相应目录追加需要预制的SQL文件 - -### 4.提供一个标准的用例 - -yml配置文件如下: - -``` -spring: - datasource: - url: jdbc:mysql://127.0.0.1:3306/test?user=root&password=1234?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2B8 - username: root - password: 1234 - driver-class-name: com.mysql.cj.jdbc.Driver - db-dirver: mysql - db-config-file-url: sql/mysql-dbconfig.json - db-name: test -``` - -mysql-dbconfig.json配置如下: - -```json - [ - { - "version": "1.0", - "sqlfile": "sql/a.sql", - "desc": "基础数据库结构" - }, - { - "version": "1.1", - "sqlfile": "sql/ddd.sql", - "desc": "第一版升级数据库" - } - ] -``` - -目录结构如下: - -```shell -+-java #java源码 -+-resource #资源文件 -| +---sql #sql初始化配置内容 - |+---mysql-dbconfig.json #sql初始化配置内容 - |+---a.sql #sql初始化配置内容 - |+---ddd.sql #sql初始化配置内容 -``` - -> yml配置中的`db-config-file-url`配置决定着json配置文件的存放,如填写的路径为:sql/mysql/a.json,则需要在resource目录下新建sql文件夹,并在sql文件夹下新建mysql文件夹,然后在mysql文件夹中按照样例创建json文件;json配置文件中的sqlfile属性决定着需要执行的sql文件存放位置; -> -> 为了方便,建议json文件中的sql文件存放位置和json文件在同级目录 - -### 5.其他说明 - -使用过程中获取建库结果,需要在代码中获取数据库的升级结果以便后续操作,可直接获取bean `DbIsExist` 的值来进行判定: - -```java -@Service -public class AfterStartProcess{ - - @Qualifier("DbIsExid") - @Autowired - Boolean dbIsOk; - - - public void test(){ - if(dbIsOk){ - System.out.print("数据库升级完成!") - } - } -} -``` - -默认数据库版本表名称修改,需要新增配置 `conscript.table-name` 配置项: - -```yml -conscript: - table-Name: xxxx -``` - -## 4.扩展 - -若支持的数据库类型不满足要求,需要自行进行扩展,项目引入后,可新建类继承 `AbstractInitDataBase`类,仅实现对应的 `initCommConn() initDbConn() databaseIsExitd() ` - -`createDataBase() `方法,并将新建的类路径配置到db-driver中即可 - -### method:initCommConn() - -> 创建数据库基础JDBC连接, -> -> `AbstractInitDataBase`类中定义了 `commConn` 、` dbConn` 两个**Connection** 变量,该方法主要用于对 `commConn`变量进行初始化,建立基础的数据库连接,用于测试数据库联通以及执行数据库建库语句,例如MySQL中,需要建立连接mysql数据库的JDBC - -```java - @Override - public void initCommConn() { - try { - Class.forName(dataBaseProperties.getDriverClassName()); - String jdbc_url = "jdbc:mysql://" + dataBaseProperties.getHost() + ":" + dataBaseProperties.getDbport() + "/mysql?characterEncoding=utf8&serverTimezone=GMT%2B8"; - commConn = DriverManager.getConnection(jdbc_url, dataBaseProperties.getUsername(), dataBaseProperties.getPassword()); - }catch (Exception e){ - log.error("【Conscript】Database initialization :data base is not connection....."); - } - } -``` - -### method: initDbConn() - -> 创建数据库基础JDBC连接, -> -> `AbstractInitDataBase`类中定义了 `commConn` 、` dbConn` 两个**Connection** 变量,该方法主要用于对 `dbConn`变量进行初始化,建立对目标数据库(配置中指定的数据库)实例的JDBC连接,用于执行SQL语句 - -```java - @Override - public void initDbConn() { - try{ - String url = "jdbc:mysql://"+ dataBaseProperties.getHost()+":"+ dataBaseProperties.getDbport()+"/"+ dataBaseProperties.getDbName()+"?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2B8"; - dbConn = DriverManager.getConnection(url, dataBaseProperties.getUsername(), dataBaseProperties.getPassword()); - }catch (Exception e){ - log.warn(""); - } - } -``` - -### method:databaseIsExitd(Connection connection) - -> 确定需要连接的目标数据库实例((配置中指定的数据库))是否存在,使用`commConn`进行确认,不同的数据库确认实例的方式不同,可根据具体要扩展的数据库类型自行进行定义 - -```java -@Override - public boolean databaseIsExitd(Connection connection){ - try { - Statement stmt = connection.createStatement(); - ResultSet res = stmt.executeQuery("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name= \""+ dataBaseProperties.getDbName()+"\""); - if(res.next() && res.getInt(1) == 0){ - stmt.close(); - return false; - } - return true; - }catch (Exception e){ - log.error("【Conscript】Database initialization :database base query is error"); - } - return false; - } -``` - -### method:createDataBaseSQL() - -> 创建指定的数据库的建库语句,仅返回对应的建库语句即可 - -```java -@Override - public String createDataBaseSQL() { - return "CREATE DATABASE IF NOT EXISTS "+ dataBaseProperties.getDbName()+" DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"; - } -``` - -## 5.回滚保护机制 - -为防止用户自定义的sql文件中存在错误的语法,导致升级建库过程因部分sql错误而失败,但正常SQL却已经执行,污染了原始数据库;Conscript进行了加强,可以将升级过程停止于错误sql文件之前,保证存在错误语法的sql文件不会被执行,从而保证不会污染原始数据库 - -```mermaid -graph LR; - sql文件 --> 语法校验; - 语法校验 --> 数据事务操作保护 -``` - -保护机制为两层防护,第一层为语法保护,保证执行的sql语法都是正确的,能够被数据库执行的,其次进行一次数据操作的回滚,当正确的SQL满足了语法要求,但是如果存在语义错误(主键冲突、字段和值不匹配等造成的数据操作失败),则进行数据 `增删改`的回滚机制,保证数据不被污染 - -> 注:因开启回滚保护机制,需要对sql文件进行语法校验,sql文件数量较大时会有较高的性能损耗,可根据实际情况使用,默认是不开启状态 - -### 使用方法 - -yml文件中新增`conscript.parse-enable`属性,取值范围为布尔,不配置时默认为 false - -```yml -conscript: - parse-enable: true -``` - -## 6.其他问题 - -6.1 与Mybatis-plus一起使用时,会出现Conscript在Mybatis-Plus之后加载的情况,此时会因为未创建数据库,导致Mybatis-plus的SqlSession创建失败,解决方案需要在启动类上使用注解@DependsOn,手动干预starter加载顺序,先加载Conscript的 `DbIsExist` bean,如下: - -```java -@SpringBootApplication -@DependsOn("DbIsExist") -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} -``` \ No newline at end of file -- Gitee From 37acec737ff9452b15cfe3f74a093d1ab8276595 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 03:45:20 +0000 Subject: [PATCH 32/33] =?UTF-8?q?=E6=96=B0=E5=A2=9EREADME=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- initdatabse-component/README.md | 374 ++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 initdatabse-component/README.md diff --git a/initdatabse-component/README.md b/initdatabse-component/README.md new file mode 100644 index 0000000..70c8225 --- /dev/null +++ b/initdatabse-component/README.md @@ -0,0 +1,374 @@ +# initdatabse-component + +> initdatabse是基于之前Conscript进行改造的项目,主要是以component的形式统一管理此部分代码, +> +> initdatabse基于Spring-boot-starter的方式提供数据库初始化功能,可以随项目初次启动,自动创建相关数据库,后续系统升级所引发的数据库变化及升级也可由此完成,拆箱即用,随系统程序代码运行,省去额外的数据库升级操作, +> +> `支持数据库种类可扩展,目前支持通用mysql、postgreSQL、 国产数据库达梦和金仓` +> +> `支持执行失败回滚机制` + +## 组件依赖说明 + +组件整体继承自Components包,所依赖Spring相关组件及通用的公共组件依赖跟随Components版本进行调整管控,相关内容可查看Components的README文档 + +```xml + + com.gcc.container + components + 1.0.0 + +``` + +除基本的SpringAOP、autoconfigure外,需要依赖jsqlparser,如下: + +```xml + + com.github.jsqlparser + jsqlparser + ${jsqlparser.version} + +``` + +## 支持数据库类型 + +| 数据库类型 | 是否支持 | db-driver参数 | +| ---------- | ---- | ----------- | +| mysql | 是 | mysql | +| mariadb | 是 | mariadb | +| PostgreSQL | 是 | pgsql | +| 达梦数据库 | 是 | dm | +| 人大金仓8 | 是 | kingbase8 | + +## 实现设计 + +核心代码结构: + +```shell ++---action #基础功能包 +| +---mysql #mysql数据库实现 +----initDataBase #数据库初始化接口 +----DataBaseInitorFactory #数据库初始器工厂 +----AbstractInitDataBase #数据库初始器基类 +``` + +| 类 | 介绍 | +| --------------------- | -------------- | +| initDataBase | 初始化接口 | +| AbstractInitDataBase | 初始化基类,定义核心逻辑 | +| MySqlDataBase | Mysql实现,具体执行方式 | +| DataBaseInitorFactory | 工厂类 | + +```mermaid +classDiagram +direction TD +class initDataBase{ + <> + isInitEd() + startCoreJob() + createConnection() + databaseIsExitd() + getCurrenDbVersion() + excuteSQL(Map sqlcontent) + close() +} +class AbstractInitDataBase { + <> + +void : startCoreJob() + } +class MySqlDataBase { + +void : createConnection() + +boolean:databaseIsExitd() + +Float:getCurrenDbVersion() + +void:excuteSQL(Map sqlcontent) + } +class DataBaseInitorFactory { + +InitDataBase : createInitiator(DbConConfiguration config) + +String:getClassUrlValue(DbType dbType) + } + class DbConConfiguration { + +DbConConfiguration : builder() + +void:set() + +Object:get() + } +initDataBase <-- AbstractInitDataBase : +AbstractInitDataBase <|-- MySqlDataBase +DbConConfiguration <.. DataBaseInitorFactory +initDataBase -- DataBaseInitorFactory +``` + +> **扩展其他类型数据库:在action目录下新建相应的数据库类型目录,然后继承AbstractInitDataBase类,实现对应的几个数据库操作方法,在DatabaseProperties的getDbDeriver()中新增对应的映射** + +## 3.使用方式 + +找到对应版本的Components源码,下载到本地,本地编译安装到私仓中 + +### 1.引入Conscript + +1.1.使用jar引入 + +> 本地编译源码后,install到本地的maven私仓后,直接引入项目 + +```xml + + com.gcc.container.components + initdatabse-component + 1.0 + +``` + +### 2.配置yml文件 + +```yml +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/test?user=root&password=1234 + username: root + password: 1234 + driver-class-name: com.mysql.cj.jdbc.Driver + db-config-file-url: sql/mysql/dbconfig.json + db-driver: mysql + db-name: test +``` + +配置内容遵循标准的`spring.datasource`配置,并进行了增强 + +| 字段 | 含义 | 是否必填 | +| ------------------ | ------------------------------------------------ | ---- | +| url | 必选字段,遵循标准datasource即可,若使用mybaits,则按照mybaits标准填写 | 是 | +| username | 必选字段,标准datasource即可,填写数据库账号 | 是 | +| password | 必选字段,标准datasource即可,填写数据库连接密码 | 是 | +| driver-class-name | 必选字段,标准datasource即可,填写数据库连接驱动类 | 是 | +| db-config-file-url | 必选字段,指定静态SQL文件存放位置 | 是 | +| db-driver | 必选字段,指定数据库类型,扩展时,可填写类路径,默认填写mysql,详细见扩展用法章节 | 是 | +| dbport | 非必选字段,数据库服务端口,若url填写,可省略该字段 | 否 | +| db-name | 非必选字段,需要连接的数据库名称,若url中填写,可省略该字段 | 否 | +| schema | 非必须字段,若url中填写,则可省略,主要用于对部分数据库的模式配置 | 否 | +| root-user | 非必选字段,**若存在对数据库权限分离有要求的需求**,可以在此填写专门用于建库的高权限账号 | 否 | +| root-pass | 非必选字段,**若存在对数据库权限分离有要求的需求**,可以在此填写专门用于建库的高权限账号密码 | 否 | + +此处配置相较 `spring.datasource`的基础的 `url、username、password、driver-class-name`外,增加了独有的`db-driver、db-config-file-url`,原则上只需要满足此6项配置即可使用Conscript,但建议将配置补全使用 + + `使用该组件,必须确保拥有较高的数据库角色权限,例如mysql的root、pgsql的postgres,否则无法使用创建数据库的功能,如需清晰划分权限,则可以通过配置项中的root-user,root-pass来将系统数据库的使用区分开来` + +### 3.建立配置文件及SQL文件 + +以标准maven项目为例 + +​ 1.根据 yml中`spring.datasource.db-config-file-url`配置的值,在resource目录下新建相应路径json文件 + +XX.json文件样例如下: + +```json + [ + { + "version": "1.0", + "sqlfile": "a.sql", + "desc": "基础数据库结构" + }, + { + "version": "1.1", + "sqlfile": "ddd.sql", + "desc": "第一版升级数据库" + } + ] +``` + +| 字段 | 含义 | +| ------- | --------------------------------------------------------------------------- | +| version | 数据库的版本,**数字类型** | +| sqlfile | 数据库升级的sql文件,叠加式追加,**注:这里要写清楚sql文件的路径(基于resource目录为基准),此处的配置决定后续sql文件的存放位置** | +| desc | 维护使用的描述信息 | + +​ 2.根据XX.json配置文件中的sqlfile配置项,新建相应目录追加需要预制的SQL文件 + +### 4.提供一个标准的用例 + +yml配置文件如下: + +``` +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/test?user=root&password=1234?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2B8 + username: root + password: 1234 + driver-class-name: com.mysql.cj.jdbc.Driver + db-dirver: mysql + db-config-file-url: sql/mysql-dbconfig.json + db-name: test +``` + +mysql-dbconfig.json配置如下: + +```json + [ + { + "version": "1.0", + "sqlfile": "sql/a.sql", + "desc": "基础数据库结构" + }, + { + "version": "1.1", + "sqlfile": "sql/ddd.sql", + "desc": "第一版升级数据库" + } + ] +``` + +目录结构如下: + +```shell ++-java #java源码 ++-resource #资源文件 +| +---sql #sql初始化配置内容 + |+---mysql-dbconfig.json #sql初始化配置内容 + |+---a.sql #sql初始化配置内容 + |+---ddd.sql #sql初始化配置内容 +``` + +> yml配置中的`db-config-file-url`配置决定着json配置文件的存放,如填写的路径为:sql/mysql/a.json,则需要在resource目录下新建sql文件夹,并在sql文件夹下新建mysql文件夹,然后在mysql文件夹中按照样例创建json文件;json配置文件中的sqlfile属性决定着需要执行的sql文件存放位置; +> +> 为了方便,建议json文件中的sql文件存放位置和json文件在同级目录 + +### 5.其他说明 + +使用过程中获取建库结果,需要在代码中获取数据库的升级结果以便后续操作,可直接获取bean `DbIsExist` 的值来进行判定: + +```java +@Service +public class AfterStartProcess{ + + @Qualifier("DbIsExid") + @Autowired + Boolean dbIsOk; + + + public void test(){ + if(dbIsOk){ + System.out.print("数据库升级完成!") + } + } +} +``` + +默认数据库版本表名称修改,需要新增配置 `conscript.table-name` 配置项: + +```yml +conscript: + table-Name: xxxx +``` + +## 4.扩展 + +若支持的数据库类型不满足要求,需要自行进行扩展,项目引入后,可新建类继承 `AbstractInitDataBase`类,仅实现对应的 `initCommConn() initDbConn() databaseIsExitd() ` + +`createDataBase() `方法,并将新建的类路径配置到db-driver中即可 + +### method:initCommConn() + +> 创建数据库基础JDBC连接, +> +> `AbstractInitDataBase`类中定义了 `commConn` 、` dbConn` 两个**Connection** 变量,该方法主要用于对 `commConn`变量进行初始化,建立基础的数据库连接,用于测试数据库联通以及执行数据库建库语句,例如MySQL中,需要建立连接mysql数据库的JDBC + +```java + @Override + public void initCommConn() { + try { + Class.forName(dataBaseProperties.getDriverClassName()); + String jdbc_url = "jdbc:mysql://" + dataBaseProperties.getHost() + ":" + dataBaseProperties.getDbport() + "/mysql?characterEncoding=utf8&serverTimezone=GMT%2B8"; + commConn = DriverManager.getConnection(jdbc_url, dataBaseProperties.getUsername(), dataBaseProperties.getPassword()); + }catch (Exception e){ + log.error("【Conscript】Database initialization :data base is not connection....."); + } + } +``` + +### method: initDbConn() + +> 创建数据库基础JDBC连接, +> +> `AbstractInitDataBase`类中定义了 `commConn` 、` dbConn` 两个**Connection** 变量,该方法主要用于对 `dbConn`变量进行初始化,建立对目标数据库(配置中指定的数据库)实例的JDBC连接,用于执行SQL语句 + +```java + @Override + public void initDbConn() { + try{ + String url = "jdbc:mysql://"+ dataBaseProperties.getHost()+":"+ dataBaseProperties.getDbport()+"/"+ dataBaseProperties.getDbName()+"?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2B8"; + dbConn = DriverManager.getConnection(url, dataBaseProperties.getUsername(), dataBaseProperties.getPassword()); + }catch (Exception e){ + log.warn(""); + } + } +``` + +### method:databaseIsExitd(Connection connection) + +> 确定需要连接的目标数据库实例((配置中指定的数据库))是否存在,使用`commConn`进行确认,不同的数据库确认实例的方式不同,可根据具体要扩展的数据库类型自行进行定义 + +```java +@Override + public boolean databaseIsExitd(Connection connection){ + try { + Statement stmt = connection.createStatement(); + ResultSet res = stmt.executeQuery("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name= \""+ dataBaseProperties.getDbName()+"\""); + if(res.next() && res.getInt(1) == 0){ + stmt.close(); + return false; + } + return true; + }catch (Exception e){ + log.error("【Conscript】Database initialization :database base query is error"); + } + return false; + } +``` + +### method:createDataBaseSQL() + +> 创建指定的数据库的建库语句,仅返回对应的建库语句即可 + +```java +@Override + public String createDataBaseSQL() { + return "CREATE DATABASE IF NOT EXISTS "+ dataBaseProperties.getDbName()+" DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"; + } +``` + +## 5.回滚保护机制 + +为防止用户自定义的sql文件中存在错误的语法,导致升级建库过程因部分sql错误而失败,但正常SQL却已经执行,污染了原始数据库;Conscript进行了加强,可以将升级过程停止于错误sql文件之前,保证存在错误语法的sql文件不会被执行,从而保证不会污染原始数据库 + +```mermaid +graph LR; + sql文件 --> 语法校验; + 语法校验 --> 数据事务操作保护 +``` + +保护机制为两层防护,第一层为语法保护,保证执行的sql语法都是正确的,能够被数据库执行的,其次进行一次数据操作的回滚,当正确的SQL满足了语法要求,但是如果存在语义错误(主键冲突、字段和值不匹配等造成的数据操作失败),则进行数据 `增删改`的回滚机制,保证数据不被污染 + +> 注:因开启回滚保护机制,需要对sql文件进行语法校验,sql文件数量较大时会有较高的性能损耗,可根据实际情况使用,默认是不开启状态 + +### 使用方法 + +yml文件中新增`conscript.parse-enable`属性,取值范围为布尔,不配置时默认为 false + +```yml +conscript: + parse-enable: true +``` + +## 6.其他问题 + +6.1 与Mybatis-plus一起使用时,会出现Conscript在Mybatis-Plus之后加载的情况,此时会因为未创建数据库,导致Mybatis-plus的SqlSession创建失败,解决方案需要在启动类上使用注解@DependsOn,手动干预starter加载顺序,先加载Conscript的 `DbIsExist` bean,如下: + +```java +@SpringBootApplication +@DependsOn("DbIsExist") +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +``` \ No newline at end of file -- Gitee From 69cd0e7b9bec93b46fef506c1925ca054a4c6488 Mon Sep 17 00:00:00 2001 From: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> Date: Tue, 19 Nov 2024 04:07:44 +0000 Subject: [PATCH 33/33] =?UTF-8?q?README=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: GCC1566 <8714475+gcc1566@user.noreply.gitee.com> --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..60253e4 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Component + +> 公共组件包,对应COLA框架中的公共组件层,为快速搭建项目抽离的通用部分,以Spring-starter的形式存在,可无缝集成到以SpringBoot为主框架的项目中。 + +## 依赖说明 + +该组件整体基于SpringBoot的`2.3.6.RELEASE`版本 + +```xml + + org.springframework.boot + spring-boot-starter-parent + 2.3.6.RELEASE + + +``` + +其他依赖仅包含通用的hutool,使用版本为:`5.7.8` + +```xml + + cn.hutool + hutool-all + 5.7.8 + +``` + +## 内容说明 + +该组件内部以构件为独立单元,项目components仅作为公共父pom进行组件依赖管理。 + +components内涵构件有: + +| 构件 | 说明 | 版本号 | +| ---------------------- | --------------- | ----- | +| es-component | ElasticSearch封装 | 1.0.0 | +| redis-component | Redis数据操作封装 | 1.0.0 | +| rest-component | REST风格的服务端封装 | 1.0.0 | +| task-component | 定时任务构件 | 1.0.0 | +| initdatabase-component | 数据库初始化构件 | 1.0.0 | + +## 使用方式 + +下载对应版本的components项目源码,本地进行编译安装,install到本地的私仓中即可单独使用包内的构件 -- Gitee