初始化

master
面包骑士 2024-09-09 16:57:22 +08:00
commit 7ef4152750
49 changed files with 3559 additions and 0 deletions

36
.gitignore vendored 100644
View File

@ -0,0 +1,36 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea
logs
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

15
Dockerfile 100644
View File

@ -0,0 +1,15 @@
#指定构建镜像的起始镜像
FROM anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/dragonwell:17.0.4.0.4.8-standard-ga-8.6
#定义时区参数
ENV TZ=Asia/Shanghai
#设置时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone
#挂载目录
VOLUME ["/home/logs/muyu-quest"]
#拷贝执行jar报
COPY ./muyu-quest-server/target/muyu-quest.jar /home/app.jar
ENTRYPOINT ["java","-Dfile.encoding=utf-8","-jar"]
CMD ["/home/app.jar"]

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>muyu-quest-client</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>muyu-quest-common</artifactId>
<version>3.6.5</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-etl-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,80 @@
package com.muyu.quest.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.validation.custom.IsSysNodeType;
import com.muyu.common.core.validation.custom.IsSysYesNo;
import com.muyu.common.core.web.domain.BaseEntity;
import lombok.*;
import lombok.experimental.SuperBuilder;
/**
* node_source
*
* @Author:
* @date 2024-08-23
*/
@Data
@Setter
@Getter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("node_info")
public class Node extends BaseEntity{
private static final long serialVersionUID = 1L;
/** 自增主键 */
@TableId( type = IdType.AUTO)
private Long id;
/** 节点编码 */
@Excel(name = "节点编码")
private String nodeCode;
/** 任务编码 */
@Excel(name = "任务编码")
private String taskCode;
/** 节点类型 */
@Excel(name = "节点类型")
@IsSysNodeType
private String nodeType;
/** 节点名称 */
@Excel(name = "节点名称")
private String nodeName;
/** 节点位置Y */
@Excel(name = "节点位置Y")
private String nodePositionTop;
/** 节点位置X */
@Excel(name = "节点位置X")
private String nodePositionLeft;
/** 节点上一级 */
@Excel(name = "节点上一级")
private String nodePreCode;
/** 节点下一级 */
@Excel(name = "节点下一级")
private String nodeNextCode;
/** 启用状态 */
@Excel(name = "启用状态")
@IsSysYesNo
private String state;
@Override
public String toString() {
return "编码:"+this.getNodeCode() +
",名称:"+this.getNodeName() +
",类型:"+this.getNodeType();
}
}

View File

@ -0,0 +1,72 @@
package com.muyu.quest.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.validation.custom.IsSysNodeType;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* node_disposition
*
* @Author:
* @date 2024-08-29
*/
@Data
@Setter
@Getter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("node_disposition")
public class NodeDisposition {
private static final long serialVersionUID = 1L;
/** 自增主键 */
@TableId( type = IdType.AUTO)
private Long id;
/** 节点编码 */
@Excel(name = "节点编码")
private String nodeCode;
/** 配置编码 */
@Excel(name = "配置编码")
private String dispKey;
/** 配置名称 */
@Excel(name = "配置名称")
@IsSysNodeType
private String dispLabel;
/** 配置内容 */
@Excel(name = "配置内容")
private Object dispValue;
/** 配置类型 */
@Excel(name = "配置类型")
private String dispType;
/** 其他信息 */
private String dispDesc;
@Override
public String toString() {
return "配置编码:'" + dispKey + '\'' +
", 配置名称:'" + dispLabel + '\'' +
", 配置内容:" + dispValue +
", 配置类型:'" + dispType + '\'' +
", 其他信息:'" + dispDesc ;
}
public NodeDisposition buildNodeCode(String nodeCode) {
this.nodeCode = nodeCode;
return this;
}
}

View File

@ -0,0 +1,48 @@
package com.muyu.quest.domain;
import lombok.*;
import java.util.Arrays;
import java.util.List;
/**
* @Author:
* @Name: NodeType
* @Description:
* @CreatedDate: 2024/9/1 10:01
* @FilePath: com.muyu.quest.domain
*/
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class NodeType {
/** 节点类型主键 */
private String id;
/** 节点类型编码 */
private String nodeTypeCode;
/** 节点类型名称 */
private String nodeTypeName;
/** 节点存储格式编码集 */
private String nodeTypeData;
private String nextNodeTypeCode;
// 节点类型数量限制
private Integer nodeMaxNum;
private Integer nodeMinNum;
/** 下级节点类型编码集 */
private List<String> nextNodeTypeCodeList;
public void setNextNodeTypeCode(String nextNodeTypeCode) {
this.nextNodeTypeCode = nextNodeTypeCode;
this.nextNodeTypeCodeList = Arrays.stream(nextNodeTypeCode.split(",")).toList();
}
}

View File

@ -0,0 +1,72 @@
package com.muyu.quest.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.validation.custom.IsSysYesNo;
import com.muyu.common.core.web.domain.BaseEntity;
import jakarta.validation.constraints.NotEmpty;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* task_source
*
* @Author:
* @date 2024-08-22
*/
@EqualsAndHashCode(callSuper = true)
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("task_source")
public class Task extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 自增主键 */
@TableId( type = IdType.AUTO)
private Long id;
/** 任务编码 */
@Excel(name = "任务编码")
private String taskCode;
/** 任务名称 */
@Excel(name = "任务名称")
private String taskName;
private String taskData;
/** 任务类型 */
@Excel(name = "任务类型")
private String taskType;
/** 启用状态 */
@Excel(name = "启用状态")
@IsSysYesNo
private String state;
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("taskCode", getTaskCode())
.append("taskName", getTaskName())
.append("taskType", getTaskType())
.append("state", getState())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -0,0 +1,72 @@
package com.muyu.quest.domain;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.web.domain.BaseEntity;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import java.io.Serializable;
/**
* task_export
*
* @Author:
* @date 2024-09-06
*/
@Data
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("task_export")
public class TaskExport implements Serializable {
/** ID */
@TableId( type = IdType.AUTO)
private Long id;
/** 任务编码 */
@Excel(name = "任务编码")
private String taskCode;
/** 执行编码 */
@Excel(name = "执行编码")
private String exportCode;
/** 执行SQL */
@Excel(name = "执行SQL")
private Object addSql;
/** 执行状态 */
@Excel(name = "执行状态")
private Integer start;
/** 失败原因 */
@Excel(name = "失败原因")
private Object error;
public TaskExport(String taskCode,String exportCode, String addSql, Integer start, String error) {
this.taskCode = taskCode;
this.exportCode = exportCode;
this.addSql = addSql;
this.start = start;
this.error = error;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("taskCode", getTaskCode())
.append("addSql", getAddSql())
.append("start", getStart())
.append("error", getError())
.toString();
}
}

View File

@ -0,0 +1,39 @@
package com.muyu.quest.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @Author:
* @ ToolIntelliJ IDEA
* @ Author:
* @ Date2024-08-23-9:41
* @ Version1.0
* @ Description
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class DataModel {
/**
*
*/
private String key;
/**
*
*/
private String label;
/**
*
*/
private String type;
/**
*
*/
private Object value;
}

View File

@ -0,0 +1,30 @@
package com.muyu.quest.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @Author:
* @ ToolIntelliJ IDEA
* @ Author:
* @ Date2024-09-03-22:14
* @ Version1.0
* @ Description
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class DataValueModel {
/**
* ID
*/
private Long basicId;
/**
* sql
*/
private String sql;
}

View File

@ -0,0 +1,51 @@
package com.muyu.quest.req;
import com.muyu.common.core.validation.custom.IsSysYesNo;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* node_source
*
* @Author:
* @date 2024-08-23
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class NodeReq{
/** 任务编码 */
private String taskCode;
/** 节点名称 */
private String nodeName;
/** 上一级节点 */
private String nodePreCode;
/** 下一级节点 */
private String nodeNextCode;
/** 启用状态 */
@IsSysYesNo
private String state;
public NodeReq buildTaskCode(String taskCode){
this.taskCode = taskCode;
return this;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("nodeName", getNodeName())
.append("nodePreCode", getNodePreCode())
.append("nodeNextCode", getNodeNextCode())
.append("state", getState())
.toString();
}
}

View File

@ -0,0 +1,50 @@
package com.muyu.quest.req;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.validation.custom.IsSysYesNo;
import com.muyu.common.core.web.domain.BaseEntity;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* task_source
*
* @Author:
* @date 2024-08-22
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TaskReq{
private static final long serialVersionUID = 1L;
/** 任务名称 */
private String taskName;
/** 任务类型 */
private String taskType;
/** 启用状态 */
@IsSysYesNo
private String state;
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("taskName", getTaskName())
.append("taskType", getTaskType())
.append("state", getState())
.toString();
}
}

View File

@ -0,0 +1,68 @@
package com.muyu.quest.resp;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.enums.SysYesNo;
import com.muyu.quest.domain.Node;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* node_source
*
* @Author:
* @date 2024-08-23
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class NodeResp{
/** 自增主键 */
private Long id;
/** 节点编码 */
private String nodeCode;
/** 任务编码 */
private String taskCode;
/** 节点名称 */
private String nodeName;
/** 节点类型 */
private String nodeType;
/** 节点位置Y */
private String nodePositionTop;
/** 节点位置X */
private String nodePositionLeft;
/** 上一级节点 */
private String nodePreCode;
/** 下一级节点 */
private String nodeNextCode;
/** 启用状态 */
private String state;
public static NodeResp build(Node node) {
return NodeResp.builder()
.id(node.getId())
.nodeCode(node.getNodeCode())
.taskCode(node.getTaskCode())
.nodeName(node.getNodeName())
.nodeType(node.getNodeType())
.nodePositionTop(node.getNodePositionTop())
.nodePositionLeft(node.getNodePositionLeft())
.nodePreCode(node.getNodePreCode())
.nodeNextCode(node.getNodeNextCode())
.state(SysYesNo.getInfoByCode(node.getState()))
.build();
}
}

View File

@ -0,0 +1,64 @@
package com.muyu.quest.resp;
import com.muyu.common.core.enums.SysYesNo;
import com.muyu.quest.domain.Task;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* task_source
*
* @Author:
* @date 2024-08-22
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TaskResp {
/** 自增主键 */
private Long id;
/** 任务编码 */
private String taskCode;
/** 任务名称 */
private String taskName;
/** 任务描述 */
private String taskData;
/** 任务类型 */
private String taskType;
/** 启用状态 */
private String state;
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("taskCode", getTaskCode())
.append("taskName", getTaskName())
.append("taskType", getTaskType())
.append("state", getState())
.toString();
}
public static TaskResp build(Task task) {
return TaskResp.builder()
.id(task.getId())
.taskCode(task.getTaskCode())
.taskName(task.getTaskName())
.taskData(task.getTaskData())
.taskType(task.getTaskType())
.state(SysYesNo.getInfoByCode(task.getState()))
.build();
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>muyu-quest-remote</artifactId>
<version>3.6.5</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>muyu-quest-server</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>etl-datasource-remote</artifactId>
<version>3.6.5</version>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- MuYu Common DataSource -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-datasource</artifactId>
</dependency>
<!-- MuYu Common DataScope -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-datascope</artifactId>
</dependency>
<!-- &lt;!&ndash; MuYu Common Log &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.muyu</groupId>-->
<!-- <artifactId>cloud-common-log</artifactId>-->
<!-- </dependency>-->
<!-- 接口模块 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-api-doc</artifactId>
</dependency>
<!-- XllJob定时任务 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-xxl</artifactId>
</dependency>
<!-- &lt;!&ndash;rabbitmq 公共依赖&ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.muyu</groupId>-->
<!-- <artifactId>cloud-common-rabbit</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest-common</artifactId>
</dependency>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-quest-remote</artifactId>
</dependency>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>etl-rule-remote</artifactId>
<version>3.6.5</version>
</dependency>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>etl-datasource-client</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>
<build>
<finalName>muyu-quest</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 加入maven deploy插件当在deploy时忽略些model-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- 加入maven compiler插件确保使用-parameters标志 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 确保版本是你项目所需的版本 -->
<version>3.8.1</version>
<configuration>
<source>16</source>
<target>16</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,31 @@
package com.muyu.quest;
import com.muyu.common.security.annotation.EnableCustomConfig;
import com.muyu.common.security.annotation.EnableMyFeignClients;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* @Author:
* @Name: MyTask
* @Description:
* @CreatedDate: 2024/8/22 6:23
* @FilePath: com.muyu.quest
*/
@EnableCustomConfig
//@EnableCustomSwagger2
@EnableMyFeignClients
@SpringBootApplication
public class MyTaskApplication {
public static void main(String[] args) {
try {
SpringApplication.run(MyTaskApplication.class, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("MyTask 模块启动成功!");
}
}

View File

@ -0,0 +1,33 @@
package com.muyu.quest.advice;
/**
* @Author:
* @Name: TaskAdvice
* @Description:
* @CreatedDate: 2024/9/1 4:12
* @FilePath: com.muyu.quest.advice
*/
import com.alibaba.nacos.api.model.v2.Result;
import com.muyu.quest.exception.TaskException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* @Author:
* @Name: TaskAdvice
* @Description:
* @CreatedDate: 2024/9/1 4:12
* @FilePath: com.muyu.quest.advice
*/
@Slf4j
@Component
public class TaskAdvice {
@ExceptionHandler(TaskException.class)
public Result<String> commonException(TaskException e) {
log.error("任务异常处理,异常信息:[{}]",e.toString());
return Result.failure(e.getMessage());
}
}

View File

@ -0,0 +1,157 @@
package com.muyu.quest.controller;
import java.util.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.muyu.common.security.annotation.RequiresPermissions;
import com.muyu.quest.req.NodeReq;
import com.muyu.quest.resp.NodeResp;
import jakarta.servlet.http.HttpServletResponse;
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.muyu.quest.domain.Node;
import com.muyu.quest.service.INodeService;
import com.muyu.common.core.web.controller.BaseController;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.poi.ExcelUtil;
import com.muyu.common.security.utils.SecurityUtils;
import org.springframework.validation.annotation.Validated;
import com.muyu.common.core.web.page.TableDataInfo;
/**
* Controller
*
* @Author:
* @date 2024-08-23
*/
@RestController
@RequestMapping("/node")
public class NodeController extends BaseController {
@Resource
private INodeService nodeService;
/**
*
*/
// @RequiresPermissions("quest:node:list")
@GetMapping("/list")
public Result<TableDataInfo<NodeResp>> list(NodeReq nodeReq) {
startPage();
List<Node> list = nodeService.selectNodeList(nodeReq);
return getDataTable(list
.stream()
.map(NodeResp::build)
.toList());
}
/**
*
*/
// @RequiresPermissions("quest:node:export")
@PostMapping("/export")
public void export(HttpServletResponse response, NodeReq nodeReq) {
List<Node> list = nodeService.selectNodeList(nodeReq);
ExcelUtil<Node> util = new ExcelUtil<Node>(Node.class);
util.exportExcel(response, list, "节点管理数据");
}
/**
*
*/
// @RequiresPermissions("quest:node:query")
@GetMapping(value = "/{id}")
public Result<List<Node>> getInfo(@PathVariable("id") Long id) {
return success(nodeService.selectNodeById(id));
}
/**
*
*/
// @RequiresPermissions("quest:node:add")
@PostMapping
@Transactional
public Result<Integer> add(
@Validated @RequestBody Node node) {
if (nodeService.checkIdUnique(node)) {
return error("新增 节点管理 '" + node + "'失败,节点已存在");
}
String code = UUID.randomUUID().toString().replace("-", "");
node.setNodeCode(code);
node.setCreateBy(SecurityUtils.getUsername());
boolean save = nodeService.save(node);
// if (save){
// // 新增任务节点中间表信息
// middleService.save(new TaskNodeMiddle(null,taskCode,code));
// }
return toAjax(save);
}
/**
*
*/
@RequiresPermissions("quest:node:edit")
@PutMapping
public Result<Integer> edit(
@Validated @RequestBody Node node) {
if (!nodeService.checkIdUnique(node)) {
return error("修改 节点管理 '" + node + "'失败,节点不存在");
}
node.setUpdateBy(SecurityUtils.getUsername());
return toAjax(nodeService.updateById(node));
}
/**
*
*/
// @RequiresPermissions("quest:node:remove")
@DeleteMapping("/{ids}")
@Transactional
public Result<Integer> removeByIds(@PathVariable("ids") Long[] ids) {
nodeService.removeBatchByIds(Arrays.asList(ids));
return success();
}
/**
*
* @param nodeCodes
* @param taskCode
* @return
*/
@DeleteMapping("/{taskCode}/{nodeCodes}")
@Transactional
public Result<Integer> removeByTaskCode(@PathVariable("nodeCodes") String[] nodeCodes, @PathVariable("taskCode") String taskCode) {
LambdaQueryWrapper<Node> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Node::getTaskCode,taskCode);
if (!Arrays.asList(nodeCodes).isEmpty()){
queryWrapper.eq(Node::getNodeCode,nodeCodes);
}
nodeService.remove(queryWrapper);
return success();
}
/**
*
*/
@PostMapping("/batch/{taskCode}")
@Transactional
public Result<Integer> batch(@Validated @RequestBody ArrayList<Node> nodeList,@PathVariable("taskCode") String[] taskCode) {
// 批量删除
nodeService.batchDelect(taskCode);
if (nodeList.isEmpty()){
return Result.success();
}
// 批量添加
boolean save = nodeService.saveBatch(nodeList);
return toAjax(save);
}
}

View File

@ -0,0 +1,133 @@
package com.muyu.quest.controller;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.muyu.quest.domain.Node;
import jakarta.servlet.http.HttpServletResponse;
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.muyu.common.security.annotation.RequiresPermissions;
import com.muyu.quest.domain.NodeDisposition;
import com.muyu.quest.service.INodeDispositionService;
import com.muyu.common.core.web.controller.BaseController;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.poi.ExcelUtil;
import com.muyu.common.security.utils.SecurityUtils;
import org.springframework.validation.annotation.Validated;
import com.muyu.common.core.web.page.TableDataInfo;
/**
* Controller
*
* @Author:
* @date 2024-08-29
*/
@RestController
@RequestMapping("/disposition")
public class NodeDispositionController extends BaseController
{
@Resource
private INodeDispositionService nodeDispositionService;
/**
*
*/
@RequiresPermissions("quest:disposition:list")
@GetMapping("/list")
public Result<TableDataInfo<NodeDisposition>> list(NodeDisposition nodeDisposition)
{
startPage();
List<NodeDisposition> list = nodeDispositionService.selectNodeDispositionList(nodeDisposition);
return getDataTable(list);
}
/**
*
*/
@RequiresPermissions("quest:disposition:export")
@PostMapping("/export")
public void export(HttpServletResponse response, NodeDisposition nodeDisposition)
{
List<NodeDisposition> list = nodeDispositionService.selectNodeDispositionList(nodeDisposition);
ExcelUtil<NodeDisposition> util = new ExcelUtil<NodeDisposition>(NodeDisposition.class);
util.exportExcel(response, list, "节点配置数据");
}
/**
*
*/
@RequiresPermissions("quest:disposition:query")
@GetMapping(value = "/{id}")
public Result<List<NodeDisposition>> getInfo(@PathVariable("id") Long id)
{
return success(nodeDispositionService.selectNodeDispositionById(id));
}
/**
*
*/
@RequiresPermissions("quest:disposition:add")
@PostMapping
public Result<Integer> add(
@Validated @RequestBody NodeDisposition nodeDisposition)
{
if (nodeDispositionService.checkIdUnique(nodeDisposition)) {
return error("新增 节点配置 '" + nodeDisposition + "'失败,节点配置已存在");
}
return toAjax(nodeDispositionService.save(nodeDisposition));
}
/**
*
*/
@RequiresPermissions("quest:disposition:edit")
@PutMapping
public Result<Integer> edit(
@Validated @RequestBody NodeDisposition nodeDisposition)
{
if (!nodeDispositionService.checkIdUnique(nodeDisposition)) {
nodeDispositionService.save(nodeDisposition);
}
return toAjax(nodeDispositionService.updateById(nodeDisposition));
}
/**
*
*/
@RequiresPermissions("quest:disposition:remove")
@DeleteMapping("/{ids}")
public Result<Integer> remove(@PathVariable("ids") Long[] ids)
{
nodeDispositionService.removeBatchByIds(Arrays.asList(ids));
return success();
}
/**
*
*/
@PostMapping("/batch/{nodeCode}")
@Transactional
public Result<Integer> batch(
@Validated @RequestBody ArrayList<NodeDisposition> dispList,
@PathVariable("nodeCode") String[] nodeCode){
// 根据节点编码删除
nodeDispositionService.batchDelect(nodeCode);
// 批量新增
if (!dispList.isEmpty()) {
nodeDispositionService.saveBatch(dispList);
}
return success();
}
}

View File

@ -0,0 +1,141 @@
package com.muyu.quest.controller;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import com.muyu.common.security.utils.SecurityUtils;
import com.muyu.quest.domain.Node;
import com.muyu.quest.domain.Task;
import javax.annotation.Resource;
import com.muyu.quest.job.TaskJob;
import com.muyu.quest.req.TaskReq;
import com.muyu.quest.resp.TaskResp;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.muyu.quest.service.TaskService;
import com.muyu.common.core.web.controller.BaseController;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.web.page.TableDataInfo;
/**
* Controller
*
* @Author:
* @date 2024-08-22
*/
@RestController
@RequestMapping("/task")
public class TaskController extends BaseController
{
@Resource
private TaskService taskService;
@Resource
private TaskJob taskJob;
/**
*
*/
// @RequiresPermissions("quest:quest:list")
@GetMapping("/list")
public Result<TableDataInfo<TaskResp>> list(TaskReq taskReq)
{
startPage();
List<TaskResp> list = taskService.selectTaskList(taskReq);
return getDataTable(list);
}
/**
*
*/
// @RequiresPermissions("quest:quest:query")
@GetMapping(value = "/selectTaskByTaskCode/{taskCode}")
public Result<Task> getInfo(@PathVariable("taskCode") String taskCode) {
return success(taskService.selectTaskByTaskCode(taskCode));
}
/**
*
*/
// @RequiresPermissions("quest:quest:query")
@GetMapping(value = "/selectTaskById/{id}")
public Result<Task> getInfo(@PathVariable("id") Long id) {
return success(taskService.selectTaskById(id));
}
/**
*
*/
// @RequiresPermissions("quest:quest:quest")
@PostMapping
public Result<Integer> add (@Validated @RequestBody Task task) {
if (taskService.checkTaskCodeUnique(task)) {
return error("新增参数'" + task.getTaskName() + "'失败,任务已存在");
}
String code = UUID.randomUUID().toString().replace("-", "");
task.setTaskCode(code);
task.setCreateBy(SecurityUtils.getUsername());
return toAjax(taskService.save(task));
}
/**
*
*/
// @RequiresPermissions("quest:quest:quest")
@PutMapping
public Result edit (@Validated @RequestBody Task task) {
if (!taskService.checkTaskCodeUnique(task)) {
return error("修改参数'" + task.getTaskName() + "'失败,任务不存在");
}
task.setUpdateBy(SecurityUtils.getUsername());
return toAjax(taskService.updateById(task));
}
/**
*
*/
// @RequiresPermissions("system:task:remove")
@DeleteMapping("/{taskIds}")
public Result remove (@PathVariable("taskIds") Long[] taskIds) {
taskService.removeBatch(Arrays.asList(taskIds));
return success();
}
/**
*
*/
@PostMapping("/testExecute")
public Result<String> testExecute(@RequestBody List<Node> nodeList) {
return success(taskService.testExecute(nodeList));
}
/**
*
*/
@PostMapping("/execute/{taskCode}")
public Result<String> execute(@PathVariable("taskCode") String taskCode) {
return success(taskService.execute(taskCode));
}
/**
*
*/
@PostMapping("/clearTask")
public Result clearTask() {
taskJob.clearTask();
return success();
}
}

View File

@ -0,0 +1,122 @@
package com.muyu.quest.controller;
import java.util.Arrays;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.muyu.common.security.annotation.RequiresPermissions;
import com.muyu.quest.domain.TaskExport;
import com.muyu.quest.service.ITaskExportService;
import com.muyu.common.core.web.controller.BaseController;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.poi.ExcelUtil;
import com.muyu.common.security.utils.SecurityUtils;
import org.springframework.validation.annotation.Validated;
import com.muyu.common.core.web.page.TableDataInfo;
/**
* Controller
*
* @Author:
* @date 2024-09-06
*/
@RestController
@RequestMapping("/export")
public class TaskExportController extends BaseController
{
@Resource
private ITaskExportService taskExportService;
/**
*
*/
@RequiresPermissions("quest:export:list")
@GetMapping("/list")
public Result<TableDataInfo<TaskExport>> list(TaskExport taskExport)
{
startPage();
List<TaskExport> list = taskExportService.selectTaskExportList(taskExport);
return getDataTable(list);
}
/**
*
*/
@RequiresPermissions("quest:export:export")
@PostMapping("/export")
public void export(HttpServletResponse response, TaskExport taskExport)
{
List<TaskExport> list = taskExportService.selectTaskExportList(taskExport);
ExcelUtil<TaskExport> util = new ExcelUtil<TaskExport>(TaskExport.class);
util.exportExcel(response, list, "任务执行记录数据");
}
/**
*
*/
@RequiresPermissions("quest:export:query")
@GetMapping(value = "/{id}")
public Result<List<TaskExport>> getInfo(@PathVariable("id") Long id)
{
return success(taskExportService.selectTaskExportById(id));
}
/**
*
*/
@RequiresPermissions("quest:export:add")
@PostMapping
public Result<Integer> add(
@Validated @RequestBody TaskExport taskExport)
{
if (taskExportService.checkIdUnique(taskExport)) {
return error("新增 任务执行记录 '" + taskExport + "'失败,任务执行记录已存在");
}
return toAjax(taskExportService.save(taskExport));
}
/**
*
*/
@RequiresPermissions("quest:export:edit")
@PutMapping
public Result<Integer> edit(
@Validated @RequestBody TaskExport taskExport)
{
if (!taskExportService.checkIdUnique(taskExport)) {
return error("修改 任务执行记录 '" + taskExport + "'失败,任务执行记录不存在");
}
return toAjax(taskExportService.updateById(taskExport));
}
/**
*
*/
@RequiresPermissions("quest:export:remove")
@DeleteMapping("/{ids}")
public Result<Integer> remove(@PathVariable("ids") Long[] ids)
{
taskExportService.removeBatchByIds(Arrays.asList(ids));
return success();
}
@PostMapping("/selTaskStart")
public Result selTaskStart(String taskCode){
TaskExport taskExport = new TaskExport();
taskExport.setTaskCode(taskCode);
List<TaskExport> taskExports = taskExportService.selectTaskExportList(taskExport);
int num = taskExports.size();
int yNum = taskExports.stream().filter(taskExport1 -> taskExport1.getStart() == 1).toArray().length;
int nNum = num - yNum;
return success("共执行线程"+num+"个,完成"+yNum+"个,未完成"+nNum+"个");
}
}

View File

@ -0,0 +1,43 @@
package com.muyu.quest.exception;
/**
* @Author:
* @Name: TaskException
* @Description:
* @CreatedDate: 2024/9/1 4:11
* @FilePath: com.muyu.quest.exception
*/
import org.springframework.stereotype.Component;
/**
* @Author:
* @Name: TaskException
* @Description:
* @CreatedDate: 2024/9/1 4:11
* @FilePath: com.muyu.quest.exception
*/
@Component
public class TaskException extends RuntimeException {
public TaskException() {
super();
}
public TaskException(String message) {
super(message);
}
public TaskException(String message, Throwable cause) {
super(message, cause);
}
public TaskException(Throwable cause) {
super(cause);
}
protected TaskException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,81 @@
package com.muyu.quest.job;
/**
* @Author:
* @Name: TaskJob
* @Description:
* @CreatedDate: 2024/9/4 2:37
* @FilePath: com.muyu.quest.job
*/
import com.muyu.quest.domain.Node;
import com.muyu.quest.domain.NodeDisposition;
import com.muyu.quest.req.NodeReq;
import com.muyu.quest.req.TaskReq;
import com.muyu.quest.resp.TaskResp;
import com.muyu.quest.service.INodeDispositionService;
import com.muyu.quest.service.INodeService;
import com.muyu.quest.service.TaskService;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @Author:
* @Name: TaskJob
* @Description:
* @CreatedDate: 2024/9/4 2:37
* @FilePath: com.muyu.quest.job
*/
@Component
public class TaskJob {
@Resource
private TaskService taskService;
@Resource
private INodeService nodeService;
@Resource
private INodeDispositionService nodeDispositionService;
// 定时清理过期任务与其相关数据
@XxlJob(value = "clearTask")
public void clearTask() {
List<TaskResp> tasks = taskService.selectTaskList(new TaskReq());
List<Node> nodes = nodeService.selectNodeList(new NodeReq());
List<NodeDisposition> dispositions = nodeDispositionService.selectNodeDispositionList(new NodeDisposition());
// 查询节点表存在但任务表不存在的任务编码
Set<String> notContainsTaskCodeList = nodes.
stream().
map(Node::getTaskCode).
filter(nodeTaskCode -> !tasks.
stream().
map(TaskResp::getTaskCode).
toList().contains(nodeTaskCode)).
collect(Collectors.toSet());
// 删除相关节点表数据
if (!notContainsTaskCodeList.isEmpty()) {
nodeService.batchDelect(notContainsTaskCodeList.toArray(new String[0]));
}
// 查询配置表存在但节点表不存在的节点编码
Set<String> notContainsNodeCodeList = dispositions.
stream().
map(NodeDisposition::getNodeCode).
filter(nodeDispositionNodeCode -> !nodes.
stream().
map(Node::getNodeCode).
toList().contains(nodeDispositionNodeCode)).
collect(Collectors.toSet());
// 删除相关配置表数据
if (!notContainsNodeCodeList.isEmpty()) {
nodeDispositionService.batchDelect(notContainsNodeCodeList.toArray(new String[0]));
}
}
}

View File

@ -0,0 +1,182 @@
package com.muyu.quest.manager;
/**
* @Author:
* @Name: TaskManager
* @Description:
* @CreatedDate: 2024/9/4 7:44
* @FilePath: com.muyu.quest.manager
*/
import lombok.extern.slf4j.Slf4j;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @Author:
* @Name: TaskManager
* @Description: 线
* @CreatedDate: 2024/9/4 7:44
* @FilePath: com.muyu.quest.manager
*/
@Slf4j
public final class TaskManager {
// 线程池中默认线程的个数为5
private static int workerNum = 9;
// 工作线程
private final WorkThread[] workThrads;
// 未处理的任务
private static volatile int finishedTask = 0;
// 任务队列
private final List<Runnable> taskQueue = new LinkedList<Runnable>();
private static TaskManager taskManager;
private long startTime;
private long endTime;
// 创建具有默认线程个数的线程池
private TaskManager() {
this(9);
}
// 创建线程池,workerNum为线程池中工作线程的个数
private TaskManager(int workerNum) {
taskManager.workerNum = workerNum;
workThrads = new WorkThread[workerNum];
for (int i = 0; i < workerNum; i++) {
workThrads[i] = new WorkThread();
workThrads[i].start();// 开启线程池中的线程
}
startTime = System.currentTimeMillis();
}
// 单态模式,获得一个默认线程个数的线程池
public static TaskManager getTaskManager() {
return getTaskManager(TaskManager.workerNum);
}
// 单态模式,获得一个指定线程个数的线程池,workerNum(>0)为线程池中工作线程的个数
// workerNum<=0创建默认的工作线程个数
public static TaskManager getTaskManager(int workerNum1) {
if (workerNum1 <= 0) {
workerNum1 = TaskManager.workerNum;
}
if (taskManager == null) {
taskManager = new TaskManager(workerNum1);
}
return taskManager;
}
// 把任务加入任务队列
public void execute(List<Runnable> task) {
execute(task.toArray(new Runnable[0]));
}
// 把任务加入任务队列
public void execute(Runnable... task) {
synchronized (taskQueue) {
Collections.addAll(taskQueue, task);
taskQueue.notify();
}
}
// 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
public void destroy() {
while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 工作线程停止工作且置为null
for (int i = 0; i < workerNum; i++) {
workThrads[i].stopWorker();
workThrads[i] = null;
}
taskManager=null;
taskQueue.clear();// 清空任务队列
}
// 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
public void close() {
while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
taskManager=null;
endTime = System.currentTimeMillis();
log.info("任务执行完成,任务执行情况: {},共计耗时: {}ms",this.toString(),endTime-startTime);
}
// 返回工作线程的个数
public int getWorkThreadNumber() {
return workerNum;
}
// 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成
public int getFinishedTasknumber() {
return finishedTask;
}
// 返回任务队列的长度,即还没处理的任务个数
public int getWaitTasknumber() {
return taskQueue.size();
}
// 覆盖toString方法返回线程池信息工作线程个数和已完成任务个数
@Override
public String toString() {
return "工作任务数:" + workerNum + ",已完成任务数:"
+ finishedTask + ",等待任务数:" + getWaitTasknumber();
}
/**
* 线
*/
private class WorkThread extends Thread {
// 该工作线程是否有效,用于结束该工作线程
private boolean isRunning = true;
/*
*
*/
@Override
public void run() {
Runnable r = null;
while (isRunning) {// 若线程无效则自然结束run方法该线程就没用了
synchronized (taskQueue) {
while (isRunning && taskQueue.isEmpty()) {// 队列为空
try {
taskQueue.wait(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!taskQueue.isEmpty()) {
r = taskQueue.remove(0);// 取出任务
}
}
if (r != null) {
r.run();// 执行任务
}
finishedTask++;
r = null;
}
}
// 停止工作让该线程自然执行完run方法自然结束
public void stopWorker() {
isRunning = false;
}
}
}

View File

@ -0,0 +1,16 @@
package com.muyu.quest.mapper;
import com.muyu.quest.domain.NodeDisposition;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @Author:
* @date 2024-08-29
*/
@Mapper
public interface NodeDispositionMapper extends BaseMapper<NodeDisposition>{
}

View File

@ -0,0 +1,17 @@
package com.muyu.quest.mapper;
import java.util.List;
import com.muyu.quest.domain.Node;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @Author:
* @date 2024-08-23
*/
@Mapper
public interface NodeMapper extends BaseMapper<Node>{
}

View File

@ -0,0 +1,17 @@
package com.muyu.quest.mapper;
import java.util.List;
import com.muyu.quest.domain.TaskExport;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @Author:
* @date 2024-09-06
*/
@Mapper
public interface TaskExportMapper extends BaseMapper<TaskExport>{
}

View File

@ -0,0 +1,22 @@
package com.muyu.quest.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.muyu.quest.domain.NodeType;
import com.muyu.quest.domain.Task;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @Author:
* @date 2024-08-22
*/
@Mapper
public interface TaskMapper extends BaseMapper<Task> {
List<NodeType> selectNodeTypeList();
}

View File

@ -0,0 +1,40 @@
package com.muyu.quest.service;
import java.util.List;
import com.muyu.quest.domain.NodeDisposition;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* Service
*
* @Author:
* @date 2024-08-29
*/
public interface INodeDispositionService extends IService<NodeDisposition> {
/**
*
*
* @param id
* @return
*/
public NodeDisposition selectNodeDispositionById(Long id);
/**
*
*
* @param nodeDisposition
* @return
*/
public List<NodeDisposition> selectNodeDispositionList(NodeDisposition nodeDisposition);
/**
* id
* @param nodeDisposition
* @return
*/
Boolean checkIdUnique(NodeDisposition nodeDisposition);
Boolean checkDispUnique(NodeDisposition disp);
void batchDelect(String[] nodeCode);
}

View File

@ -0,0 +1,41 @@
package com.muyu.quest.service;
import java.util.List;
import com.muyu.quest.domain.Node;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.quest.req.NodeReq;
/**
* Service
*
* @Author:
* @date 2024-08-23
*/
public interface INodeService extends IService<Node> {
/**
*
*
* @param id
* @return
*/
public Node selectNodeById(Long id);
/**
*
*
* @param nodeReq
* @return
*/
public List<Node> selectNodeList(NodeReq nodeReq);
/**
* id
* @param node
* @return
*/
Boolean checkIdUnique(Node node);
List<Node> selectNodeByIds(Long[] ids);
void batchDelect(String[] taskCode);
}

View File

@ -0,0 +1,44 @@
package com.muyu.quest.service;
import java.util.List;
import com.muyu.quest.domain.TaskExport;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* Service
*
* @Author:
* @date 2024-09-06
*/
public interface ITaskExportService extends IService<TaskExport> {
/**
*
*
* @param id
* @return
*/
public TaskExport selectTaskExportById(Long id);
/**
*
*
* @param taskExport
* @return
*/
public List<TaskExport> selectTaskExportList(TaskExport taskExport);
/**
* id
* @param taskExport
* @return
*/
Boolean checkIdUnique(TaskExport taskExport);
/**
*
*/
TaskExport selectTaskExport(TaskExport taskExport);
void updateByExportCode(TaskExport entity);
}

View File

@ -0,0 +1,52 @@
package com.muyu.quest.service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.quest.domain.Node;
import com.muyu.quest.domain.Task;
import com.muyu.quest.req.TaskReq;
import com.muyu.quest.resp.TaskResp;
/**
* Service
*
* @Author:
* @date 2024-08-22
*/
public interface TaskService extends IService<Task> {
/**
*
*
* @param taskCode
* @return
*/
public Task selectTaskByTaskCode(String taskCode);
/**
*
*
* @param taskReq
* @return
*/
public List<TaskResp> selectTaskList(TaskReq taskReq);
Task selectTaskById(Long id);
Boolean checkTaskCodeUnique(Task task);
/**
* id
* @param task
* @return
*/
Boolean checkIdUnique(Task task);
void removeBatch(List<Long> list);
String execute(String taskCode);
String testExecute(List<Node> nodeList);
}

View File

@ -0,0 +1,92 @@
package com.muyu.quest.service.impl;
import java.util.List;
import org.springframework.stereotype.Service;
import com.muyu.quest.mapper.NodeDispositionMapper;
import com.muyu.quest.domain.NodeDisposition;
import com.muyu.quest.service.INodeDispositionService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.common.core.utils.StringUtils;
import org.springframework.util.Assert;
/**
* Service
*
* @Author:
* @date 2024-08-29
*/
@Service
public class NodeDispositionServiceImpl
extends ServiceImpl<NodeDispositionMapper, NodeDisposition>
implements INodeDispositionService {
/**
*
*
* @param id
* @return
*/
@Override
public NodeDisposition selectNodeDispositionById(Long id)
{
LambdaQueryWrapper<NodeDisposition> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(id, "id不可为空");
queryWrapper.eq(NodeDisposition::getId, id);
return this.getOne(queryWrapper);
}
/**
*
*
* @param nodeDisposition
* @return
*/
@Override
public List<NodeDisposition> selectNodeDispositionList(NodeDisposition nodeDisposition)
{
LambdaQueryWrapper<NodeDisposition> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(nodeDisposition.getNodeCode())){
queryWrapper.eq(NodeDisposition::getNodeCode, nodeDisposition.getNodeCode());
}
if (StringUtils.isNotEmpty(nodeDisposition.getDispKey())){
queryWrapper.eq(NodeDisposition::getDispKey, nodeDisposition.getDispKey());
}
if (StringUtils.isNotEmpty(nodeDisposition.getDispLabel())){
queryWrapper.eq(NodeDisposition::getDispLabel, nodeDisposition.getDispLabel());
}
if (StringUtils.isNotEmpty(nodeDisposition.getDispType())){
queryWrapper.eq(NodeDisposition::getDispType, nodeDisposition.getDispType());
}
return this.list(queryWrapper);
}
/**
*
* @param nodeDisposition
* @return
*/
@Override
public Boolean checkIdUnique(NodeDisposition nodeDisposition) {
LambdaQueryWrapper<NodeDisposition> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(NodeDisposition::getId, nodeDisposition.getId());
return this.count(queryWrapper) > 0;
}
@Override
public Boolean checkDispUnique(NodeDisposition disp) {
LambdaQueryWrapper<NodeDisposition> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(NodeDisposition::getId, disp.getId());
queryWrapper.eq(NodeDisposition::getNodeCode, disp.getNodeCode());
return this.exists(queryWrapper);
}
@Override
public void batchDelect(String[] nodeCode) {
LambdaQueryWrapper<NodeDisposition> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(NodeDisposition::getNodeCode, nodeCode);
this.remove(queryWrapper);
}
}

View File

@ -0,0 +1,98 @@
package com.muyu.quest.service.impl;
import java.util.Arrays;
import java.util.List;
import com.muyu.quest.req.NodeReq;
import org.springframework.stereotype.Service;
import com.muyu.quest.mapper.NodeMapper;
import com.muyu.quest.domain.Node;
import com.muyu.quest.service.INodeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.common.core.utils.StringUtils;
import org.springframework.util.Assert;
/**
* Service
*
* @Author:
* @date 2024-08-23
*/
@Service
public class NodeServiceImpl
extends ServiceImpl<NodeMapper, Node>
implements INodeService {
/**
*
*
* @param id
* @return
*/
@Override
public Node selectNodeById(Long id)
{
LambdaQueryWrapper<Node> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(id, "id不可为空");
queryWrapper.eq(Node::getId, id);
return this.getOne(queryWrapper);
}
/**
*
*
* @param nodeReq
* @return
*/
@Override
public List<Node> selectNodeList(NodeReq nodeReq)
{
LambdaQueryWrapper<Node> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(nodeReq.getTaskCode())){
queryWrapper.eq(Node::getTaskCode, nodeReq.getTaskCode());
}
if (StringUtils.isNotEmpty(nodeReq.getNodeName())){
queryWrapper.like(Node::getNodeName, nodeReq.getNodeName());
}
if (StringUtils.isNotEmpty(nodeReq.getNodePreCode())){
queryWrapper.eq(Node::getNodePreCode, nodeReq.getNodePreCode());
}
if (StringUtils.isNotEmpty(nodeReq.getNodeNextCode())){
queryWrapper.eq(Node::getNodeNextCode, nodeReq.getNodeNextCode());
}
if (StringUtils.isNotEmpty(nodeReq.getState())){
queryWrapper.eq(Node::getState, nodeReq.getState());
}
return this.list(queryWrapper);
}
/**
*
* @param node
* @return
*/
@Override
public Boolean checkIdUnique(Node node) {
LambdaQueryWrapper<Node> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Node::getId, node.getId());
return this.exists(queryWrapper);
}
@Override
public List<Node> selectNodeByIds(Long[] ids) {
LambdaQueryWrapper<Node> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Node::getId, Arrays.asList(ids));
return this.list(queryWrapper);
}
@Override
public void batchDelect(String[] taskCode) {
LambdaQueryWrapper<Node> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Node::getTaskCode,taskCode);
this.remove(queryWrapper);
}
}

View File

@ -0,0 +1,93 @@
package com.muyu.quest.service.impl;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.stereotype.Service;
import com.muyu.quest.mapper.TaskExportMapper;
import com.muyu.quest.domain.TaskExport;
import com.muyu.quest.service.ITaskExportService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.common.core.utils.StringUtils;
import org.springframework.util.Assert;
/**
* Service
*
* @Author:
* @date 2024-09-06
*/
@Service
public class TaskExportServiceImpl
extends ServiceImpl<TaskExportMapper, TaskExport>
implements ITaskExportService {
/**
*
*
* @param id
* @return
*/
@Override
public TaskExport selectTaskExportById(Long id)
{
LambdaQueryWrapper<TaskExport> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(id, "id不可为空");
queryWrapper.eq(TaskExport::getId, id);
return this.getOne(queryWrapper);
}
/**
*
*
* @param taskExport
* @return
*/
@Override
public List<TaskExport> selectTaskExportList(TaskExport taskExport)
{
LambdaQueryWrapper<TaskExport> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(taskExport.getTaskCode())){
queryWrapper.eq(TaskExport::getTaskCode, taskExport.getTaskCode());
}
return this.list(queryWrapper);
}
/**
*
* @param taskExport
* @return
*/
@Override
public Boolean checkIdUnique(TaskExport taskExport) {
LambdaQueryWrapper<TaskExport> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TaskExport::getId, taskExport.getId());
return this.exists(queryWrapper);
}
@Override
public TaskExport selectTaskExport(TaskExport taskExport) {
LambdaQueryWrapper<TaskExport> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(taskExport.getTaskCode())){
queryWrapper.eq(TaskExport::getTaskCode, taskExport.getTaskCode());
}
if (taskExport.getStart() != null){
queryWrapper.eq(TaskExport::getStart, taskExport.getStart());
}
queryWrapper.last("limit 1");
return this.getOne(queryWrapper);
}
@Override
public void updateByExportCode(TaskExport taskExport) {
LambdaUpdateWrapper<TaskExport> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(TaskExport::getExportCode, taskExport.getExportCode())
.set(TaskExport::getError, taskExport.getError())
.set(TaskExport::getStart, taskExport.getStart());
this.update(null, updateWrapper);
}
}

View File

@ -0,0 +1,318 @@
package com.muyu.quest.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.StringUtils;
import com.muyu.etl.data.access.data.access.client.mysql.MySqlDataSource;
import com.muyu.etl.data.access.data.access.client.mysql.MySqlQuery;
import com.muyu.etl.data.access.domain.req.EtlDataSqlReq;
import com.muyu.etl.data.access.remote.RemoteEtlDataService;
import com.muyu.etl.domain.DataStructure;
import com.muyu.quest.domain.*;
import com.muyu.quest.exception.TaskException;
import com.muyu.quest.manager.TaskManager;
import com.muyu.quest.mapper.TaskMapper;
import com.muyu.quest.model.DataValueModel;
import com.muyu.quest.req.NodeReq;
import com.muyu.quest.req.TaskReq;
import com.muyu.quest.resp.TaskResp;
import com.muyu.quest.service.INodeDispositionService;
import com.muyu.quest.service.INodeService;
import com.muyu.quest.service.ITaskExportService;
import com.muyu.quest.service.TaskService;
import com.muyu.quest.utils.NodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.object.SqlQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
/**
* Service
*
* @Author:
* @date 2024-08-22
*/
@Slf4j
@Service
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task>
implements TaskService {
@Resource
private INodeService nodeService;
@Resource
private INodeDispositionService dispositionService;
@Resource
private TaskMapper taskMapper;
@Resource
private RemoteEtlDataService remoteEtlDataService;
@Resource
private ITaskExportService taskExportService;
@Resource
private MySqlDataSource mySqlDataSource;
private static TaskManager taskManager = null;
/**
*
*
* @param taskCode
* @return
*/
@Override
public Task selectTaskByTaskCode(String taskCode)
{
LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(taskCode, "taskCode不可为空");
queryWrapper.eq(Task::getTaskCode, taskCode);
return this.getOne(queryWrapper);
}
/**
*
*
* @param id
* @return
*/
@Override
public Task selectTaskById(Long id)
{
LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(id, "id不可为空");
queryWrapper.eq(Task::getId, id);
return this.getOne(queryWrapper);
}
/**
*
* @param task
* @return
*/
@Override
public Boolean checkTaskCodeUnique(Task task) {
LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Task::getTaskCode, task.getTaskCode());
return this.exists(queryWrapper);
}
@Override
public Boolean checkIdUnique(Task task) {
LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Task::getId, task.getId());
return this.exists(queryWrapper);
}
@Override
public void removeBatch(List<Long> list) {
this.removeBatchByIds(list);
}
/**
*
*
* @param taskReq
* @return
*/
@Override
public List<TaskResp> selectTaskList(TaskReq taskReq)
{
LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(taskReq.getTaskName())){
queryWrapper.like(Task::getTaskName, taskReq.getTaskName());
}
if (StringUtils.isNotEmpty(taskReq.getState())){
queryWrapper.eq(Task::getState, taskReq.getState());
}
if (StringUtils.isNotEmpty(taskReq.getTaskType())){
queryWrapper.eq(Task::getTaskType, taskReq.getTaskType());
}
return this.list(queryWrapper)
.stream()
.map(TaskResp::build)
.toList();
}
// 查询节点所有类型
public List<NodeType> selectNodeTypeList(){
return taskMapper.selectNodeTypeList();
}
/**
* //TODO 执行任务
* sql
* @param taskCode
* @return
*/
@Override
public String execute(String taskCode) {
log.info("任务编码 {} 开始执行......",taskCode);
// 查询任务所有节点
List<Node> nodeListAll = nodeService.selectNodeList(new NodeReq().buildTaskCode(taskCode));
// 节点初始化
HashMap<String, List<Node>> nodeMap = nodeCheckNorm(nodeListAll);
// 获取查询SQL
String findSql = getFindSql(nodeMap);
// 获取查询条数
int count = getFindCount(findSql, nodeMap);
// 划分线程 每次查询10000条
int pageSize = 100000;
if (count < 500000){
pageSize = 10000;
}
int threadNum = count / pageSize + 1;
if (taskManager == null){
taskManager = TaskManager.getTaskManager();
}
log.info("任务 {} 总共需要 {} 条数据, 划分为线程{}条",taskCode,count,threadNum);
for (int i = 0; i < threadNum; i++) {
int index = i+1;
int limitNum = pageSize;
// 添加进入任务队列
taskManager.execute(() -> {
String exportCode = UUID.randomUUID().toString().replace("-","");
// 获取新SQL 并执行
StringBuilder newAddSql = new StringBuilder(findSql);
newAddSql.append(" LIMIT ")
.append(limitNum)
.append(" OFFSET ")
.append((index-1)*limitNum);
String addSql = getAddSql(nodeMap, newAddSql.toString());
TaskExport entity = new TaskExport(taskCode,exportCode, newAddSql.toString(), 0, "");
taskExportService.save(entity);
mySqlDataSource.setQuery(
MySqlQuery.builder()
.dataSourceId(14L)
.sql(addSql)
.build()
);
Result addResult = mySqlDataSource.addTargetDatabase();
log.info("任务 {} 第 {} 线程执行结果 {}",taskCode,index,addResult.getMsg());
if (addResult.getCode() != 200){
int errorMaxLength = Math.min(addResult.getMsg().length(), 30000);
entity.setError(addResult.getMsg().substring(0,errorMaxLength));
entity.setStart(2);
}else {
entity.setStart(1);
}
taskExportService.updateByExportCode(entity);
});
}
new Thread(() ->{
taskManager.close();
taskManager = null;
});
return "执行成功";
}
@Override
public String testExecute(List<Node> nodeListAll) {
log.info("开始测试执行......");
// 查询节点类型与其规范
List<NodeType> nodeTypeList = selectNodeTypeList();
/* 节点组成校验 */
NodeUtils.nodeCheckMakeUp(nodeListAll, nodeTypeList);
/* 节点连接规范校验 */
NodeUtils.nodeCheckNorm(nodeListAll, nodeTypeList);
return "测试成功,无异常";
}
/**
* : map
*/
private HashMap<String, List<Node>> nodeCheckNorm(List<Node> nodeListAll) {
// 查询节点类型与其校验相关配置
List<NodeType> nodeTypeList = selectNodeTypeList();
/* 节点组成校验 */
NodeUtils.nodeCheckMakeUp(nodeListAll, nodeTypeList);
/* 节点连接规范校验 */
NodeUtils.nodeCheckNorm(nodeListAll, nodeTypeList);
return NodeUtils.nodeInit(nodeListAll);
}
/**
* : SQL
*/
private String getFindSql(HashMap<String, List<Node>> nodeMap) {
String findSql = "";
List<Node> uniteNodes = nodeMap.get("unite");
if (uniteNodes==null || uniteNodes.isEmpty()){
Node tableNode = nodeMap.get("table").get(0);
List<NodeDisposition> dispList = getNodeDisp(tableNode);
findSql = NodeUtils.tableNode(dispList);
}else{
Node uniteNode = uniteNodes.get(0);
List<NodeDisposition> dispList = getNodeDisp(uniteNode);
findSql = NodeUtils.nodeDispUnite(dispList);
}
return findSql;
}
/**
* :
*/
private int getFindCount(String findSql, HashMap<String, List<Node>> nodeMap) {
System.out.println(findSql);
String findCountSql = "";
List<Node> uniteNodes = nodeMap.get("unite");
findSql = findSql.replace(" "," ");
String[] s1 = findSql.split(" ");
if (uniteNodes!=null && !uniteNodes.isEmpty()){
s1[1] = "COUNT(" + s1[1].split(",")[0]+ ")";
findCountSql = StringUtils.join(s1," ");
}else {
String[] split = s1[s1.length-1].split("\\.");
findCountSql = "SELECT TABLE_ROWS " +
"FROM INFORMATION_SCHEMA.TABLES " +
"WHERE TABLE_SCHEMA = "+split[0]+" AND TABLE_NAME = '"+split[1]+"';";
findCountSql = findCountSql.replace("`","'");
}
System.out.println(findCountSql);
mySqlDataSource.setQuery(
MySqlQuery.builder()
.dataSourceId(14L)
.sql(findCountSql)
.build()
);
Result tableValue = mySqlDataSource.getCount();
System.out.println(tableValue);
return (int) tableValue.getData();
}
/**
* SQL
*/
private String getAddSql(HashMap<String, List<Node>> nodeMap, String findSql) {
mySqlDataSource.setQuery(
MySqlQuery.builder()
.dataSourceId(14L)
.sql(findSql)
.build()
);
DataStructure[][] rows = mySqlDataSource.getRows();
List<NodeDisposition> dispList = getNodeDisp(nodeMap.get("exportation").get(0));
return NodeUtils.nodeDispExportation(dispList, rows);
}
// 查询节点配置信息
public List<NodeDisposition> getNodeDisp(Node node){
List<NodeDisposition> dispList = dispositionService
.selectNodeDispositionList(new NodeDisposition().buildNodeCode(node.getNodeCode()));
if (dispList.isEmpty()){
throw new TaskException("节点 "+node+" 配置为空");
}
return dispList;
}
}

View File

@ -0,0 +1,97 @@
package com.muyu.quest.utils;
/**
* @Author:
* @Name: DispUtils
* @Description:
* @CreatedDate: 2024/9/1 4:27
* @FilePath: com.muyu.quest.utils
*/
import com.muyu.common.core.utils.StringUtils;
import com.muyu.quest.domain.NodeDisposition;
import com.muyu.quest.domain.NodeType;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author:
* @Name: DispUtils
* @Description:
* @CreatedDate: 2024/9/1 4:27
* @FilePath: com.muyu.quest.utils
*/
public class DispUtils {
/**
*
*
* @param nodeType
* @param nodeTypeList
* @return key
*/
public static String[] getDispKeys(String nodeType, List<NodeType> nodeTypeList) {
return nodeTypeList
.stream()
.filter(type -> StringUtils.equals(type.getNodeTypeCode(), nodeType))
.map(NodeType::getNodeTypeData)
.findFirst()
.orElse("-")
.split(",");
}
/**
*
*
* @param nodeType
* @param nodeTypeList
* @param dispList
* @return map
*/
public static Map<String, List<NodeDisposition>> getDispMap(
String nodeType,
List<NodeType> nodeTypeList,
List<NodeDisposition> dispList) {
return getDispMap(getDispKeys(nodeType, nodeTypeList), dispList);
}
/**
*
*
* @param dispKeys key
* @param dispList
* @return map
*/
public static Map<String, List<NodeDisposition>> getDispMap(String[] dispKeys, List<NodeDisposition> dispList) {
HashMap<String, List<NodeDisposition>> dispMap = new HashMap<>();
for (String nodeTypeName : dispKeys) {
dispMap.put(nodeTypeName, dispList.stream()
.filter(disp -> StringUtils.equals(disp.getDispKey(), nodeTypeName))
.toList());
}
return dispMap;
}
/**
*
*
* @param dispList
* @return map
*/
public static Map<String, List<NodeDisposition>> getDispMap(List<NodeDisposition> dispList) {
HashMap<String, List<NodeDisposition>> map = new HashMap<>();
dispList.forEach(disp -> {
List<NodeDisposition> dispositions = map.get(disp.getDispKey());
if (dispositions == null || dispositions.isEmpty()) {
dispositions = new ArrayList<>();
}
dispositions.add(disp);
map.put(disp.getDispKey(), dispositions);
});
return map;
}
}

View File

@ -0,0 +1,343 @@
package com.muyu.quest.utils;
/**
* @Author:
* @Name: NodeUtils
* @Description:
* @CreatedDate: 2024/9/1 4:27
* @FilePath: com.muyu.quest.utils
*/
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.StringUtils;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.remote.RemoteRuleVersion;
import com.muyu.quest.domain.Node;
import com.muyu.quest.domain.NodeDisposition;
import com.muyu.quest.domain.NodeType;
import com.muyu.quest.exception.TaskException;
import com.muyu.quest.model.DataModel;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author:
* @Name: NodeUtils
* @Description:
* @CreatedDate: 2024/9/1 4:27
* @FilePath: com.muyu.quest.utils
*/
@Component
public class NodeUtils {
private static HashMap<String, String> sqlMap = new HashMap<>();
/**
*
*
*
* @param nodes
* @return Map
*/
public static HashMap<String, List<Node>> nodeInit(List<Node> nodes){
if (nodes == null || nodes.isEmpty()){
throw new TaskException("节点列表为空");
}
HashMap<String, List<Node>> nodeMap = new HashMap<>();
// 整理所有节点
nodes.forEach(node -> {
List<Node> nodeList = nodeMap.get(node.getNodeType());
if (nodeList == null || nodeList.isEmpty()) {
nodeList = new ArrayList<>();
}
nodeList.add(node);
nodeMap.put(node.getNodeType(), nodeList);
});
return nodeMap;
}
/**
*
* @param node
* @param nodes
* @return
*/
public static Node getPreNode(Node node, List<Node> nodes){
if (nodes == null || nodes.isEmpty()){
throw new TaskException("节点列表为空");
}else if (node == null){
throw new TaskException("当前节点为空");
}
return nodes.stream()
.filter(nodeIndex -> StringUtils.equals(node.getNodePreCode() ,nodeIndex.getNodeCode()))
.toList().get(0);
}
/**
*
* @param node
* @param nodes
* @return
*/
public static List<Node> getNextNode(Node node, List<Node> nodes) {
if (nodes == null || nodes.isEmpty()) {
throw new TaskException("节点列表为空");
} else if (node == null) {
throw new TaskException("当前节点为空");
}
return nodes.stream()
.filter(nodeIndex ->
StringUtils.equals(node.getNodeCode(), nodeIndex.getNodePreCode()) ||
StringUtils.equals(node.getNodeNextCode(), nodeIndex.getNodeCode()))
.toList();
}
/**
*
*
* @param nodeListAll
* @param nodeTypeList
*/
public static void nodeCheckMakeUp(List<Node> nodeListAll, List<NodeType> nodeTypeList) {
HashMap<String, List<Node>> nodeMapAll = nodeInit(nodeListAll);
nodeTypeList.forEach(nodeType -> {
// 根据节点类型查询对应类型节点
List<Node> nodes = nodeMapAll.get(nodeType.getNodeTypeCode());
Integer maxNum = nodeType.getNodeMaxNum();
Integer minNum = nodeType.getNodeMinNum();
if (nodes != null && !nodes.isEmpty()){
int num = nodes.size();
if (num < minNum){
throw new TaskException("节点 " + nodeType.getNodeTypeName() + " 数量不足,至少需要 " + minNum + " 个");
}else if (maxNum != -1 && num > maxNum){
throw new TaskException("节点 " + nodeType.getNodeTypeName() + " 数量超出范围,最多允许 " + maxNum + " 个");
}
}else if (minNum > 0){
throw new TaskException("节点 " + nodeType.getNodeTypeName() + " 数量不足,至少需要 " + minNum + " 个");
}
});
}
/**
*
*
* @param nodeListAll
* @param nodeTypeList
*/
public static void nodeCheckNorm(List<Node> nodeListAll, List<NodeType> nodeTypeList) {
HashMap<String, List<Node>> nodeMapAll = nodeInit(nodeListAll);
nodeTypeList.forEach(nodeType -> {
// 根据节点类型查询对应类型节点
List<Node> nodes = nodeMapAll.get(nodeType.getNodeTypeCode());
if (nodes != null) {
nodes.forEach(node -> {
if (StringUtils.equals(node.getNodeType(), "exportation")){
Node nextNode = getPreNode(node, nodeListAll);
if (!StringUtils.equals(nextNode.getNodeType(), "table") &&
!StringUtils.equals(nextNode.getNodeType(), "unite")) {
throw new TaskException("数据输出节点必须紧跟在数据输入/操作节点之后");
}
}
// 获取该节点的下级节点
List<Node> nextNodeList = getNextNode(node, nodeListAll);
if (nextNodeList != null && !nextNodeList.isEmpty()){
for (Node nextNode : nextNodeList) {
// 判断其是否是允许的下级节点
if (!StringUtils.matches(nextNode.getNodeType(), nodeType.getNextNodeTypeCodeList())){
throw new TaskException("节点 " + node + " 连接不符合规范,该节点可有下级节点为: [" + nodeType.getNextNodeTypeCodeList() + "]");
}
}
}else if (!StringUtils.equals(node.getNodeType(), "end")){
throw new TaskException("节点 "+node+" 无下级节点.");
}
});
}
});
}
/**
*
*/
public static Node nodeCheckNorm(Node node, List<Node> nodes) {
List<Node> nextNode = NodeUtils.getNextNode(node, nodes);
Set<String> nextNodeTypes = nextNode.stream().map(Node::getNodeType).collect(Collectors.toSet());
if (nextNode.isEmpty()){
throw new TaskException("任务执行失败,节点 "+node+" 无后续节点");
}else if (nextNodeTypes.size()>1){
throw new TaskException("同级节点 "+nextNode+" 类型不同");
}else if (nextNode.stream().map(Node::getNodeNextCode).collect(Collectors.toSet()).size()>1){
throw new TaskException("同级节点 "+nextNode+" 下级节点不同");
}
return nextNode.get(0);
}
/**
*
* @param dispList
* @return sql
*/
public static String nodeDispUnite(List<NodeDisposition> dispList) {
return nodeDispUnite(DispUtils.getDispMap(dispList));
}
/**
*
* @param dispMap Map
* @return sql
*/
public static String nodeDispUnite(Map<String,List<NodeDisposition>> dispMap) {
List<NodeDisposition> dbList = dispMap.get("db");
List<NodeDisposition> tableList = dispMap.get("table");
List<NodeDisposition> fieldList = dispMap.get("fields");
NodeDisposition join = dispMap.get("join").get(0);
NodeDisposition joinDataForm = dispMap.get("joinDataForm").get(0);
NodeDisposition joinDataTo = dispMap.get("joinDataTo").get(0);
// 查询表
Object[] array = tableList.stream().map(NodeDisposition::getDispDesc).toArray();
StringBuilder table = new StringBuilder(array[0].toString())
.append(" ")
.append(join.getDispValue())
.append(" ")
.append(array[1].toString())
.append(" ON ")
.append(joinDataForm.getDispDesc())
.append(".")
.append(joinDataForm.getDispValue())
.append(" = ")
.append(joinDataTo.getDispDesc())
.append(".")
.append(joinDataTo.getDispValue());
// 查询列
String field = StringUtils.join(fieldList
.stream()
.map(fields -> fields.getDispDesc()+"."+fields.getDispValue())
.toArray(),
",");
Set<Object> dbNameSet = dbList.stream().map(NodeDisposition::getDispValue).collect(Collectors.toSet());
String dbTable = table.toString();
for (Object o : dbNameSet) {
dbTable = StringUtils.replace(dbTable, o.toString()+".", "`" + o.toString() + "`.");
field = StringUtils.replace(field, o.toString()+".", "`" + o.toString() + "`.");
}
return new StringBuilder("SELECT ").append(field).append(" FORM ").append(dbTable).toString();
}
/**
*
* @param dispList
* @return sql
*/
public static String tableNode(List<NodeDisposition> dispList) {
return tableNode(DispUtils.getDispMap(dispList));
}
/**
*
* @param dispMap Map
* @return sql
*/
private static String tableNode(Map<String, List<NodeDisposition>> dispMap) {
NodeDisposition db = dispMap.get("db").get(0);
NodeDisposition table = dispMap.get("table").get(0);
List<NodeDisposition> fieldList = dispMap.get("fields");
StringBuilder findSql = new StringBuilder("SELECT ");
StringBuilder stringBuilder = new StringBuilder("`");
stringBuilder.append(db.getDispValue())
.append("`.")
.append(table.getDispValue());
findSql.append(StringUtils.join(fieldList.stream().
map(field -> stringBuilder.toString() + "." + field.getDispValue()).
toArray(),
","))
.append(" FROM ")
.append(stringBuilder);
return findSql.toString();
}
/**
* sql
* @param table
* @param fields
* @return sql
*/
private static String findSqlSplice(String table, String fields) {
return "SELECT " + fields + " FROM " + table;
}
/**
*
*
* @param dispList
* @param data
* @return sql
*/
public static String nodeDispExportation(List<NodeDisposition> dispList, DataStructure[][] data) {
if (data == null){
throw new TaskException("查询数据为空");
}
return nodeDispExportation(DispUtils.getDispMap(dispList), data);
}
/**
*
*
* @param dispMap Map
* @param data
* @return sql
*/
private static String nodeDispExportation(Map<String, List<NodeDisposition>> dispMap, DataStructure[][] data) {
// 拼接新增表
NodeDisposition db = dispMap.get("toDb").get(0);
StringBuilder insSql = new StringBuilder("INSERT INTO ");
insSql.append("`").append(db.getDispDesc()).append("`.").append(db.getDispValue());
// 根据表结构拼接新增字段
List<NodeDisposition> fieldList = dispMap.get("toFields");
// 拼接新增语句的表与字段
String join = StringUtils.join(fieldList.stream().map(NodeDisposition::getDispValue).toArray(), ",");
insSql.append("( ").append(join).append(" ) VALUES ");
// 整理需新增数据
List<HashMap<String, String>> dataList1 = new ArrayList<>();
for (DataStructure[] datum : data) {
HashMap<String, String> dataMap = new HashMap<>();
for (DataStructure dataModel : datum) {
// 检查 getValue 是否为空
String value = dataModel.getValue() != null ? dataModel.getValue().toString() : null;
// 规则执行 非法字符转换 单引号'和` =>
if (value!=null){
value = StringUtils.replace(value, "'", "");
value = StringUtils.replace(value, "`", "");
value = StringUtils.replace(value, "\\", "");
value = StringUtils.replace(value, " ", "");
}
dataMap.put(dataModel.getKey(), value);
}
dataList1.add(dataMap);
}
// 拼接新增语句的值
dataList1.forEach(map -> insSql.append("( ").
append(StringUtils.join(
fieldList.
stream().
map(field -> map.get(field.getDispDesc())).
map(field -> "'" + field + "'").
toArray(),
",")).append(" ),"));
return insSql.deleteCharAt(insSql.length() - 1).toString();
}
}

View File

@ -0,0 +1,2 @@
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}

View File

@ -0,0 +1,55 @@
# Tomcat
server:
port: 19501
# nacos线上地址
nacos:
addr: 10.0.1.97:8848
user-name: nacos
password: nacos
namespace: wu_zu_cloud
# Spring
spring:
main:
allow-bean-definition-overriding: true
application:
# 应用名称
name: muyu-quest
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${nacos.addr}
# nacos用户名
username: ${nacos.user-name}
# nacos密码
password: ${nacos.password}
# 命名空间
namespace: ${nacos.namespace}
config:
# 服务注册地址
server-addr: ${nacos.addr}
# nacos用户名
username: ${nacos.user-name}
# nacos密码
password: ${nacos.password}
# 命名空间
namespace: ${nacos.namespace}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
# 系统共享配置
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# 系统环境Config共享配置
- application-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# xxl-job 配置文件
- application-xxl-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# rabbit 配置文件
# - application-rabbit-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/muyu-quest"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/muyu-quest"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<property name="log.sky.pattern" value="%d{HH:mm:ss.SSS} %yellow([%tid]) [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.sky.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 使用gRpc将日志发送到skywalking服务端 -->
<appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.sky.pattern}</Pattern>
</layout>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="GRPC_LOG"/>
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/muyu-quest"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<property name="log.sky.pattern" value="%d{HH:mm:ss.SSS} %yellow([%tid]) [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.sky.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 使用gRpc将日志发送到skywalking服务端 -->
<appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.sky.pattern}</Pattern>
</layout>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="GRPC_LOG"/>
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.muyu.quest.mapper.TaskMapper">
<select id="selectNodeTypeList" resultType="com.muyu.quest.domain.NodeType">
select t1.*,GROUP_CONCAT(t2.node_type_code) nextNodeTypeCode from
`node_type` t1
left join `node_type_mid` m on m.tid = t1.id
left join `node_type` t2 on m.next_tid = t2.id
GROUP BY t1.id
</select>
</mapper>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.muyu.quest.mapper.TaskExportMapper">
<resultMap type="TaskExport" id="TaskExportResult">
<result property="id" column="id" />
<result property="taskCode" column="taskCode" />
<result property="sql" column="sql" />
<result property="start" column="start" />
<result property="error" column="error" />
</resultMap>
<sql id="selectTaskExportVo">
select id, taskCode, sql, start, error from task_export
</sql>
<select id="selectTaskExportList" parameterType="TaskExport" resultMap="TaskExportResult">
<include refid="selectTaskExportVo"/>
<where>
<if test="taskCode != null and taskCode != ''"> and taskCode = #{taskCode}</if>
<if test="sql != null and sql != ''"> and sql = #{sql}</if>
<if test="start != null and start != ''"> and start = #{start}</if>
<if test="error != null and error != ''"> and error = #{error}</if>
</where>
</select>
<select id="selectTaskExportById" parameterType="Long" resultMap="TaskExportResult">
<include refid="selectTaskExportVo"/>
where id = #{id}
</select>
<insert id="insertTaskExport" parameterType="TaskExport">
insert into task_export
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="taskCode != null">taskCode,</if>
<if test="sql != null">sql,</if>
<if test="start != null">start,</if>
<if test="error != null">error,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="taskCode != null">#{taskCode},</if>
<if test="sql != null">#{sql},</if>
<if test="start != null">#{start},</if>
<if test="error != null">#{error},</if>
</trim>
</insert>
<update id="updateTaskExport" parameterType="TaskExport">
update task_export
<trim prefix="SET" suffixOverrides=",">
<if test="taskCode != null">taskCode = #{taskCode},</if>
<if test="sql != null">sql = #{sql},</if>
<if test="start != null">start = #{start},</if>
<if test="error != null">error = #{error},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteTaskExportById" parameterType="Long">
delete from task_export where id = #{id}
</delete>
<delete id="deleteTaskExportByIds" parameterType="String">
delete from task_export where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

37
pom.xml 100644
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>cloud-modules</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>muyu-quest</artifactId>
<version>3.6.5</version>
<packaging>pom</packaging>
<modules>
<module>muyu-quest-remote</module>
<module>muyu-quest-server</module>
<module>muyu-quest-client</module>
<module>muyu-quest-common</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<distributionManagement>
<repository>
<id>yun-releases</id>
<name>yun-releases</name>
<url>http://10.0.1.3:8081/repository/maven-releases/</url>
</repository>
</distributionManagement>
</project>