ZhuDeKang hai 6 meses
pai
achega
26e1d41d8b
Modificáronse 24 ficheiros con 1219 adicións e 5 borrados
  1. 1 0
      pom.xml
  2. 2 0
      ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 7 0
      ruoyi-admin/src/main/resources/application-test.yml
  4. 12 0
      ruoyi-admin/src/main/resources/application.yml
  5. 93 0
      ruoyi-admin/src/main/resources/logback.xml
  6. 7 0
      ruoyi-admin/src/test/java/com/ruoyi/JasyptTest.java
  7. 16 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/api/SnailJobApi.java
  8. 440 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/web/SnailJobController.java
  9. 166 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/Job.java
  10. 45 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobRequestVo.java
  11. 43 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobUserResponseVO.java
  12. 41 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/NamespaceResponseVO.java
  13. 19 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/PermissionsResponseVO.java
  14. 15 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/SnailJobMapper.java
  15. 10 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/SnailJobService.java
  16. 1 1
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/PtServiceServiceImpl.java
  17. 28 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/SnailJobServiceImpl.java
  18. 85 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/AuthService.java
  19. 19 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/TestJob.java
  20. 83 0
      ruoyi-api-patform/src/main/resources/mapper/interfaces/SnailJobMapper.xml
  21. 22 0
      ruoyi-common/pom.xml
  22. 4 0
      ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
  23. 51 4
      ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
  24. 9 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java

+ 1 - 0
pom.xml

@@ -33,6 +33,7 @@
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
         <dom4j.version>2.1.4</dom4j.version>
+        <snail-job.version>1.7.1-jdk8</snail-job.version>
     </properties>
 
     <!-- 依赖声明 -->

+ 2 - 0
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -1,5 +1,6 @@
 package com.ruoyi;
 
+import com.aizuda.snailjob.client.starter.EnableSnailJob;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -10,6 +11,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  * @author ruoyi
  */
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@EnableSnailJob
 public class RuoYiApplication
 {
     public static void main(String[] args)

+ 7 - 0
ruoyi-admin/src/main/resources/application-test.yml

@@ -18,6 +18,13 @@ spring:
         url: jdbc:mysql://39.98.38.2:13306/sh_model?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
         username: shmodel
         password: shmodel#$0526
+      job:
+        # 从数据源开关/默认关闭
+        enabled: true
+        #url: jdbc:mysql://192.168.0.146:3306/sh_project?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        url: jdbc:mysql://39.98.38.2:13306/snail_job?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: shmodel
+        password: shmodel#$0526
       # 初始连接数
       initialSize: 5
       # 最小连接池数量

+ 12 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -129,3 +129,15 @@ sys:
     upload:
       path: D:/tmp/map/
 
+snail-job:
+  login:
+    url: http://localhost:8080/snail-job
+    username: admin
+    password: 21232f297a57a5a743894a0e4a801fc3
+    timeout: 60
+  server:
+    port: 17888
+    host: 127.0.0.1
+  namespace: M18Z4tm7bKJmswwcLMlGgzLUEn5I2_A8
+  group: test_sh_group
+  token: SJ_bM5DeeFSAV6ltYwqqCKoA7v5HuwGH5Hr

+ 93 - 0
ruoyi-admin/src/main/resources/logback.xml

@@ -1,5 +1,93 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
+
+
+
+    <!-- job配置↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
+
+    <property name="log.base" value="snail-job-demo" />
+
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n
+            </Pattern>
+        </encoder>
+    </appender>
+
+    <appender name="fileInfo"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./data/log/${log.base}/info/info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>./data/log/${log.base}/info/info.%d{yyyy-MM-dd}.log</FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n</pattern>
+        </layout>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="fileWarn" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./data/log/${log.base}/warn/warn.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>./data/log/${log.base}/warn/warn.%d{yyyy-MM-dd}.log
+            </FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n</pattern>
+        </layout>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./data/log/${log.base}/error/error.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>./data/log/${log.base}/error/error.%d{yyyy-MM-dd}.log
+            </FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n</pattern>
+        </layout>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name ="asyncInfo" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="fileInfo"/>
+    </appender>
+
+    <appender name ="asyncWarn" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="fileWarn"/>
+    </appender>
+
+    <appender name ="asyncError" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="fileError"/>
+    </appender>
+
+    <!-- Snail appender -->
+    <appender name="snailLogAppender" class="com.aizuda.snailjob.client.common.appender.SnailLogbackAppender">
+    </appender>
+
+    <!-- job配置↑↑↑↑↑↑↑↑↑↑↑↑↑ -->
     <!-- 日志存放路径 -->
 	<property name="log.path" value="/tmp/sh-models/logs" />
     <!-- 日志输出格式 -->
@@ -84,6 +172,11 @@
     <root level="info">
         <appender-ref ref="file_info" />
         <appender-ref ref="file_error" />
+        <appender-ref ref="stdout" />
+        <appender-ref ref="asyncInfo" />
+        <appender-ref ref="asyncWarn" />
+        <appender-ref ref="asyncError" />
+        <appender-ref ref="snailLogAppender" />
     </root>
 	
 	<!--系统用户操作日志-->

+ 7 - 0
ruoyi-admin/src/test/java/com/ruoyi/JasyptTest.java

@@ -1,7 +1,11 @@
 package com.ruoyi;
 
+import com.aizuda.snailjob.client.job.core.handler.query.RequestQueryHandler;
+import com.aizuda.snailjob.model.response.JobApiResponse;
 import com.ruoyi.RuoYiApplication;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.interfaces.api.SnailJobApi;
+import com.ruoyi.interfaces.snailJob.AuthService;
 import org.jasypt.encryption.StringEncryptor;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
@@ -21,6 +25,9 @@ public class JasyptTest {
 
     @Test
     public void encryptPwd() {
+        RequestQueryHandler jobDetail = SnailJobApi.getJobDetail(1l);
+        JobApiResponse execute = jobDetail.execute();
+        System.out.println(execute.toString());
     }
 
 }

+ 16 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/api/SnailJobApi.java

@@ -0,0 +1,16 @@
+package com.ruoyi.interfaces.api;
+
+import com.aizuda.snailjob.client.job.core.handler.query.RequestQueryHandler;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.naming.ldap.PagedResultsControl;
+
+public class SnailJobApi {
+
+
+    public static RequestQueryHandler getJobDetail(Long jobId) {
+        return new RequestQueryHandler(jobId);
+    }
+}

+ 440 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/web/SnailJobController.java

@@ -0,0 +1,440 @@
+package com.ruoyi.interfaces.controller.web;
+
+import com.aizuda.snailjob.client.job.core.enums.AllocationAlgorithmEnum;
+import com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum;
+import com.aizuda.snailjob.client.job.core.handler.add.BroadcastAddHandler;
+import com.aizuda.snailjob.client.job.core.handler.add.ClusterAddHandler;
+import com.aizuda.snailjob.client.job.core.handler.query.RequestQueryHandler;
+import com.aizuda.snailjob.client.job.core.handler.update.BroadcastUpdateHandler;
+import com.aizuda.snailjob.client.job.core.handler.update.ClusterUpdateHandler;
+import com.aizuda.snailjob.client.job.core.openapi.SnailJobOpenApi;
+import com.aizuda.snailjob.common.core.enums.JobBlockStrategyEnum;
+import com.aizuda.snailjob.common.core.enums.StatusEnum;
+import com.aizuda.snailjob.model.request.base.JobRequest;
+import com.aizuda.snailjob.model.response.JobApiResponse;
+import com.aizuda.snailjob.model.response.JobBatchApiResponse;
+import com.aizuda.snailjob.model.response.WorkflowDetailApiResponse;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.interfaces.api.SnailJobApi;
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+import com.ruoyi.interfaces.service.SnailJobService;
+import com.ruoyi.interfaces.service.impl.SnailJobServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+@RestController
+@RequestMapping("/snail/job")
+public class SnailJobController extends BaseController {
+
+    @Autowired
+    private SnailJobService snailJobService;
+
+
+    @GetMapping("/jobList")
+    public TableDataInfo jobList(Job jobRequestVo){
+        startPage();
+        List<Job> list = snailJobService.selectJobList(jobRequestVo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 根据任务id获取job任务详情
+     *
+     * @return
+     */
+    @GetMapping("/getJobDetail")
+    public JobApiResponse getJobDetail(Long jobId) {
+        return SnailJobOpenApi.getJobDetail(jobId).execute();
+    }
+
+    /**
+     * @return
+     */
+    @GetMapping("/getJobBatchDetail")
+    public JobBatchApiResponse getJobBatchDetail(Long jobId) {
+        return SnailJobOpenApi.getJobBatchDetail(jobId).execute();
+    }
+
+    /**
+     * @return
+     */
+    @GetMapping("/getWorkflowBatchDetail")
+    public WorkflowDetailApiResponse getWorkflowBatchDetail(Long jobId) {
+        return SnailJobOpenApi.getWorkflowBatchDetail(jobId).execute();
+    }
+
+
+    /**
+     * 更新定时任务状态
+     *
+     * @param jobId  定时任务ID
+     * @param status
+     */
+    @GetMapping("/updateJobStatus")
+    public Boolean updateJobStatus(Long jobId, Long status) {
+        return SnailJobOpenApi
+                .updateJobStatus(jobId)
+                .setStatus(StatusEnum.YES.getStatus().equals(status.intValue()) ? StatusEnum.YES : StatusEnum.NO)
+                .execute();
+    }
+
+    /**
+     * 更新工作流任务状态
+     *
+     * @param workFlowId 工作流ID
+     * @param status
+     */
+    @GetMapping("/updateWorkFlowStatus")
+    public Boolean updateWorkFlowStatus(Long workFlowId, Long status) {
+        return SnailJobOpenApi
+                .updateWorkFlowStatus(workFlowId)
+                .setStatus(StatusEnum.YES.getStatus().equals(status.intValue()) ? StatusEnum.YES : StatusEnum.NO)
+                .execute();
+    }
+
+    /**
+     * 手动调度任务
+     *
+     * @param jobId 任务Id
+     */
+    @GetMapping("/triggerJob")
+    public Boolean triggerJob(Long jobId, Integer taskType) {
+        switch (taskType) {
+            case 1:
+                return SnailJobOpenApi.triggerClusterJob(jobId).execute();
+            case 2:
+                return SnailJobOpenApi.triggerBroadcastJob(jobId).execute();
+            case 3:
+                return SnailJobOpenApi.triggerShardingJob(jobId).execute();
+            case 4:
+                return SnailJobOpenApi.triggerMapJob(jobId).execute();
+            case 5:
+                return SnailJobOpenApi.triggerMapReduceJob(jobId).execute();
+            case 6:
+                return SnailJobOpenApi.triggerWorkFlow(jobId).execute();
+        }
+        return false;
+    }
+
+    @DeleteMapping("job")
+    public Boolean deleteJob(@RequestParam Set<Long> jobIds) {
+        return SnailJobOpenApi.deleteJob(jobIds).execute();
+    }
+
+    /**
+     * 删除工作流任务
+     *
+     * @param workflowIds 工作流任务ID
+     */
+    @DeleteMapping("workflow")
+    public Boolean deleteWorkflow(Set<Long> workflowIds) {
+        return SnailJobOpenApi.deleteWorkflow(workflowIds).execute();
+    }
+    /**
+     * 新增任务
+     * @param jobRequest
+     * @return
+     */
+    @PostMapping()
+    public Long saveJob(@RequestBody JobRequestVo jobRequest) {
+        switch (jobRequest.getTaskType()) {
+            case 1:
+                return addClusterJob(jobRequest);
+            case 2:
+                return addBroadcastJob(jobRequest);
+            case 3:
+                return addShardingJob(jobRequest);
+            case 4:
+                return addMapJob(jobRequest);
+            case 5:
+                return addMapReduceJob(jobRequest);
+        }
+        return 0L;
+    }
+
+
+
+    /**
+     * 更新任务
+     * @param jobRequest
+     * @return
+     */
+    @PutMapping()
+    public Boolean updateJob(@RequestBody JobRequestVo jobRequest) {
+        switch (jobRequest.getTaskType()) {
+            case 1:
+                return updateClusterJob(jobRequest);
+            case 2:
+                return updateBroadcastJob(jobRequest);
+            case 3:
+                return updateShardingJob(jobRequest);
+            case 4:
+                return updateMapJob(jobRequest);
+            case 5:
+                return updateMapReduceJob(jobRequest);
+        }
+        return false;
+    }
+
+    /**
+     * 新增集群模式的任务
+     *
+     * @param jobRequest
+     * @return 任务id
+     */
+    public Long addClusterJob(JobRequestVo jobRequest) {
+        ClusterAddHandler clusterAddHandler = SnailJobOpenApi.addClusterJob()
+                //.setRouteKey(AllocationAlgorithmEnum.RANDOM)
+                .setRouteKey(getAllocationAlgorithmEnum(jobRequest.getRouteKey()))
+                .setJobName(jobRequest.getJobName())//
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .setRetryInterval(jobRequest.getRetryInterval());
+
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(clusterAddHandler::addArgsStr);
+        }
+        return clusterAddHandler.execute();
+    }
+
+    /**
+     * 修改集群模式的任务
+     */
+    public Boolean updateClusterJob(JobRequestVo jobRequest) {
+        ClusterUpdateHandler clusterUpdateHandler = SnailJobOpenApi.updateClusterJob(jobRequest.getId())
+                .setRouteKey(getAllocationAlgorithmEnum(jobRequest.getRouteKey()))
+                .setJobName(jobRequest.getJobName())//
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setRetryInterval(jobRequest.getRetryInterval());
+
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(clusterUpdateHandler::addArgsStr);
+        }
+
+        return clusterUpdateHandler.execute();
+
+    }
+
+
+    /**
+     * 新增广播模式的任务
+     *
+     * @param jobRequest
+     * @return
+     */
+    public Long addBroadcastJob(JobRequestVo jobRequest) {
+        BroadcastAddHandler broadcastAddHandler = SnailJobOpenApi.addBroadcastJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .setRetryInterval(jobRequest.getRetryInterval());
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(broadcastAddHandler::addArgsStr);
+        }
+        return broadcastAddHandler.execute();
+    }
+
+
+    /**
+     * 修改广播任务
+     */
+    public Boolean updateBroadcastJob(JobRequestVo jobRequest) {
+        BroadcastUpdateHandler broadcastUpdateHandler = SnailJobOpenApi.updateBroadcastJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setRetryInterval(jobRequest.getRetryInterval());
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(broadcastUpdateHandler::addArgsStr);
+        }
+        return broadcastUpdateHandler.execute();
+    }
+
+    /**
+     * 新增Sharding模式的任务
+     *
+     * @param jobRequest 任务名称
+     * @return 任务id
+     */
+    public Long addShardingJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.addShardingJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .addShardingArgs(jobRequest.getShardingArgs())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 修改Sharding模式的任务
+     *
+     * @param jobRequest 任务名称
+     * @return 任务id
+     */
+    public Boolean updateShardingJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.updateShardingJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .addShardingArgs(jobRequest.getShardingArgs())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 新增Map模式的任务
+     *
+     * @param jobRequest 任务名称
+     * @return 任务id
+     */
+    public Long addMapJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.addMapJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .execute();
+    }
+
+    /**
+     * 修改Map模式的任务
+     *
+     * @param jobRequest
+     * @return
+     */
+    public Boolean updateMapJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.updateMapJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 新增MapReduce模式的任务
+     *
+     * @param jobRequest
+     * @return 任务id
+     */
+    public Long addMapReduceJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.addMapReduceJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setShardNum(jobRequest.getShardNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 修改MapReduce模式的任务
+     *
+     * @param jobRequest
+     * @return 任务id
+     */
+    public Boolean updateMapReduceJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.updateMapReduceJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setShardNum(jobRequest.getShardNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+
+    }
+
+
+    public AllocationAlgorithmEnum getAllocationAlgorithmEnum(Integer type) {
+        for (AllocationAlgorithmEnum algorithm : AllocationAlgorithmEnum.values()) {
+            if (type.equals(algorithm.getType())) {
+                return algorithm;
+            }
+        }
+        return null;
+    }
+
+    public TriggerTypeEnum getTriggerTypeEnum(Integer type) {
+        for (TriggerTypeEnum triggerTypeEnum : TriggerTypeEnum.values()) {
+            if (type.equals(triggerTypeEnum.getType())) {
+                return triggerTypeEnum;
+            }
+        }
+        return null;
+    }
+
+
+}

+ 166 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/Job.java

@@ -0,0 +1,166 @@
+package com.ruoyi.interfaces.domain;
+
+import com.aizuda.snailjob.common.core.enums.ExecutorTypeEnum;
+import com.aizuda.snailjob.common.core.enums.JobTaskTypeEnum;
+import com.aizuda.snailjob.common.core.enums.StatusEnum;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.ibatis.type.JdbcType;
+
+/**
+ * 任务信息
+ *
+ * @author opensnail
+ * @since 2023-09-24
+ */
+@Data
+public class Job  {
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 命名空间id
+     */
+    private String namespaceId;
+
+    /**
+     * 组名称
+     */
+    private String groupName;
+
+    /**
+     * 名称
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String jobName;
+
+    /**
+     * 执行方法参数
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String argsStr;
+
+    /**
+     * 参数类型 text/json
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private Integer argsType;
+
+    /**
+     * 扩展字段
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String extAttrs;
+
+    /**
+     * 下次触发时间
+     */
+    private Long nextTriggerAt;
+
+    /**
+     * 重试状态 0、关闭、1、开启
+     * {@link StatusEnum}
+     */
+    private Integer jobStatus;
+
+    /**
+     * 执行器路由策略
+     */
+    private Integer routeKey;
+
+    /**
+     * 执行器类型 1、Java
+     * {@link ExecutorTypeEnum}
+     */
+    private Integer executorType;
+
+    /**
+     * 执行器信息
+     */
+    private String executorInfo;
+
+    /**
+     * 触发类型 1.CRON 表达式 2. 固定时间
+     */
+    private Integer triggerType;
+
+    /**
+     * 间隔时长
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String triggerInterval;
+
+    /**
+     * 阻塞策略 1、丢弃 2、覆盖 3、并行
+     */
+    private Integer blockStrategy;
+
+    /**
+     * 任务执行超时时间,单位秒
+     */
+    private Integer executorTimeout;
+
+    /**
+     * 最大重试次数
+     */
+    private Integer maxRetryTimes;
+
+    /**
+     * 重试间隔(s)
+     */
+    private Integer retryInterval;
+
+    /**
+     * 任务类型
+     * {@link JobTaskTypeEnum}
+     */
+    private Integer taskType;
+
+    /**
+     * 并行数
+     */
+    private Integer parallelNum;
+
+    /**
+     * bucket
+     */
+    private Integer bucketIndex;
+
+    /**
+     * 是否是常驻任务
+     */
+    private Integer resident;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 逻辑删除 1、删除
+     */
+    private Integer deleted;
+
+    /**
+     * 通知告警场景配置id列表
+     */
+    private String notifyIds;
+
+    /**
+     * 负责人id
+     */
+    private Long ownerId;
+
+    /**
+     * 标签
+     * json格式,如:{"key1":"value1","key2":"value2"}
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String labels;
+
+}

+ 45 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobRequestVo.java

@@ -0,0 +1,45 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import com.aizuda.snailjob.model.request.base.JobRequest;
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.HashMap;
+
+public class JobRequestVo extends JobRequest {
+    private HashMap<String,Object> argsStrMap;
+    private String[] shardingArgs;
+
+    private Integer shardNum;
+
+    public Integer getShardNum() {
+        return shardNum;
+    }
+
+    public void setShardNum(Integer shardNum) {
+        this.shardNum = shardNum;
+    }
+
+    public String[] getShardingArgs() {
+        return shardingArgs;
+    }
+
+    public void setShardingArgs(String[] shardingArgs) {
+        this.shardingArgs = shardingArgs;
+    }
+
+    public HashMap<String, Object> getArgsStrMap() {
+        return argsStrMap;
+    }
+
+    public void setArgsStrMap(HashMap<String, Object> argsStrMap) {
+        this.argsStrMap = argsStrMap;
+    }
+
+    public JobRequestVo(HashMap<String, Object> argsStrMap) {
+        this.argsStrMap = argsStrMap;
+    }
+
+    public JobRequestVo() {
+    }
+}

+ 43 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobUserResponseVO.java

@@ -0,0 +1,43 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author opensnail
+ * @date 2022-03-05
+ * @since 2.0
+ */
+@Data
+public class JobUserResponseVO {
+
+    private Long id;
+
+    private String username;
+
+    private Integer role;
+
+    private List<String> groupNameList;
+
+    private List<NamespaceResponseVO> namespaceIds;
+
+    private List<PermissionsResponseVO> permissions;
+
+    private String token;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createDt;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateDt;
+
+    private String mode;
+
+
+
+
+}

+ 41 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/NamespaceResponseVO.java

@@ -0,0 +1,41 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * @author: xiaowoniu
+ * @date : 2023-11-21 15:39
+ * @since : 2.5.0
+ */
+@Data
+public class NamespaceResponseVO {
+
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 唯一id
+     */
+    private String uniqueId;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createDt;
+
+    /**
+     * 修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateDt;
+
+}

+ 19 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/PermissionsResponseVO.java

@@ -0,0 +1,19 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import lombok.Data;
+
+import java.util.Set;
+
+/**
+ * @author: xiaowoniu
+ * @date : 2023-11-23 14:01
+ * @since : 2.5.0
+ */
+@Data
+public class PermissionsResponseVO {
+
+    private String groupName;
+    private String namespaceId;
+    private String namespaceName;
+    private Set<String> groupNames;
+}

+ 15 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/SnailJobMapper.java

@@ -0,0 +1,15 @@
+package com.ruoyi.interfaces.mapper;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+@DataSource(DataSourceType.JOB)
+public interface SnailJobMapper {
+    List<Job> selectJobList(Job jobRequestVo);
+}

+ 10 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/SnailJobService.java

@@ -0,0 +1,10 @@
+package com.ruoyi.interfaces.service;
+
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+
+import java.util.List;
+
+public interface SnailJobService {
+    List<Job> selectJobList(Job jobRequestVo);
+}

+ 1 - 1
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/PtServiceServiceImpl.java

@@ -170,7 +170,7 @@ public class PtServiceServiceImpl extends ServiceImpl<PtServiceMapper, PtService
             case "POST":
             return HttpUtils.sendPost(ptService.getUrl(),paramString);
             case "GET":
-                return HttpUtils.sendGet(ptService.getUrl(),paramString, Constants.UTF8,map);
+                return HttpUtils.sendGet(ptService.getUrl(),paramString,map);
         }
         return null;
     }

+ 28 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/SnailJobServiceImpl.java

@@ -0,0 +1,28 @@
+package com.ruoyi.interfaces.service.impl;
+
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+import com.ruoyi.interfaces.mapper.SnailJobMapper;
+import com.ruoyi.interfaces.service.SnailJobService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class SnailJobServiceImpl implements SnailJobService {
+
+    @Value("${snail-job.group}")
+    private String groupName;
+
+
+    @Autowired
+    private SnailJobMapper snailJobMapper;
+
+    @Override
+    public List<Job> selectJobList(Job jobRequestVo) {
+        jobRequestVo.setGroupName(groupName);
+        return snailJobMapper.selectJobList(jobRequestVo);
+    }
+}

+ 85 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/AuthService.java

@@ -0,0 +1,85 @@
+package com.ruoyi.interfaces.snailJob;
+
+import com.google.gson.Gson;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.HttpUtils;
+import com.ruoyi.interfaces.domain.vo.JobUserResponseVO;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import javax.json.JsonObject;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class AuthService {
+    @Value("${snail-job.login.url}")
+    private  String url;
+    @Value("${snail-job.login.username}")
+    private String username;
+    @Value("${snail-job.login.password}")
+    private String password;
+    @Value("${snail-job.login.timeout}")
+    private Integer timeout;
+
+    public static final String AUTHENTICATION = "SNAIL-JOB-AUTH";
+    public static final String NAMESPACE_ID = "SNAIL-JOB-NAMESPACE-ID";
+    @Autowired
+    private RedisCache redisCache;
+
+    private static final String JOB_USER_KEY = "JOB_USER_KEY";
+
+    public JobUserResponseVO authenticate() {
+
+        String bodyPar = "{\n" +
+                "  \"username\": \"" + username + "\",\n" +
+                "  \"password\": \"" + password + "\"\n" +
+                "}";
+        String token = "";
+        JobUserResponseVO response = new JobUserResponseVO();
+        try {
+            token = HttpUtils.sendBodyPostTest(url+"/auth/login", bodyPar, null);
+            System.out.println(token);
+            String data = new JSONObject(token).getString("data");
+            System.out.println(data);
+            Gson gson = new Gson();
+            response = gson.fromJson(data, JobUserResponseVO.class);
+            redisCache.setCacheObject(JOB_USER_KEY, response, timeout, TimeUnit.MINUTES);
+        } catch (IOException | JSONException e) {
+            throw new RuntimeException(e);
+        }
+        return response;
+    }
+
+    public JobUserResponseVO getJobUserResponse() {
+        JobUserResponseVO jobUser = redisCache.getCacheObject(JOB_USER_KEY);
+        if (StringUtils.isNull(jobUser)) {
+            return authenticate();
+        }
+        return jobUser;
+    }
+
+    public String getUrl(){
+        return url;
+    }
+    public HashMap<String, String> getHeaders(){
+        HashMap<String, String> map = new HashMap<>();
+        HttpServletRequest request = ServletUtils.getRequest();
+        map.put(AUTHENTICATION,request.getHeader(AUTHENTICATION));
+        map.put(NAMESPACE_ID,ServletUtils.getRequest().getHeader(NAMESPACE_ID));
+        return map;
+    }
+}

+ 19 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/TestJob.java

@@ -0,0 +1,19 @@
+package com.ruoyi.interfaces.snailJob;
+
+import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
+import com.aizuda.snailjob.client.job.core.dto.JobArgs;
+import com.aizuda.snailjob.common.log.SnailJobLog;
+import com.aizuda.snailjob.model.dto.ExecuteResult;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestJob {
+    @JobExecutor(name = "testJob")
+    public ExecuteResult job(JobArgs jobArgs) {
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        return ExecuteResult.success("成功");
+    }
+}

+ 83 - 0
ruoyi-api-patform/src/main/resources/mapper/interfaces/SnailJobMapper.xml

@@ -0,0 +1,83 @@
+<?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.ruoyi.interfaces.mapper.SnailJobMapper">
+
+    <resultMap type="com.ruoyi.interfaces.domain.Job" id="JobResult">
+    <result property="id"    column="id"    />
+    <result property="namespaceId"    column="namespace_id"    />
+    <result property="groupName"    column="group_name"    />
+    <result property="jobName"    column="job_name"    />
+    <result property="argsStr"    column="args_str"    />
+    <result property="argsType"    column="args_type"    />
+    <result property="nextTriggerAt"    column="next_trigger_at"    />
+    <result property="jobStatus"    column="job_status"    />
+    <result property="taskType"    column="task_type"    />
+    <result property="routeKey"    column="route_key"    />
+    <result property="executorType"    column="executor_type"    />
+    <result property="executorInfo"    column="executor_info"    />
+    <result property="triggerType"    column="trigger_type"    />
+    <result property="triggerInterval"    column="trigger_interval"    />
+    <result property="blockStrategy"    column="block_strategy"    />
+    <result property="executorTimeout"    column="executor_timeout"    />
+    <result property="maxRetryTimes"    column="max_retry_times"    />
+    <result property="parallelNum"    column="parallel_num"    />
+    <result property="retryInterval"    column="retry_interval"    />
+    <result property="bucketIndex"    column="bucket_index"    />
+    <result property="resident"    column="resident"    />
+    <result property="notifyIds"    column="notify_ids"    />
+    <result property="ownerId"    column="owner_id"    />
+    <result property="labels"    column="labels"    />
+    <result property="description"    column="description"    />
+    <result property="extAttrs"    column="ext_attrs"    />
+    <result property="deleted"    column="deleted"    />
+    </resultMap>
+    <sql id="selectJobVo">
+        select id,
+            namespace_id,
+            group_name,
+            job_name,
+            args_str,
+            args_type,
+            next_trigger_at,
+            job_status,
+            task_type,
+            route_key,
+            executor_type,
+            executor_info,
+            trigger_type,
+            trigger_interval,
+            block_strategy,
+            executor_timeout,
+            max_retry_times,
+            parallel_num,
+            retry_interval,
+            bucket_index,
+            resident,
+            notify_ids,
+            owner_id,
+            labels,
+            description,
+            ext_attrs,
+            deleted
+        from sj_job
+    </sql>
+    <select id="selectJobList" resultType="com.ruoyi.interfaces.domain.Job">
+        <include refid="selectJobVo"></include>
+        <where>
+            <if test="namespaceId != null  and namespaceId != ''">and namespace_id = #{namespaceId}</if>
+            <if test="groupName != null  and groupName != ''">and group_name = #{groupName}</if>
+            <if test="jobName != null  and jobName != ''">and job_name = #{jobName}</if>
+            <if test="argsStr != null  and argsStr != ''">and args_str = #{argsStr}</if>
+            <if test="argsType != null  ">and args_type = #{argsType}</if>
+            <if test="nextTriggerAt != null  ">and next_trigger_at = #{nextTriggerAt}</if>
+            <if test="jobStatus != null  ">and job_status = #{jobStatus}</if>
+            <if test="taskType != null ">and task_type = #{taskType}</if>
+            <if test="routeKey != null ">and route_key = #{routeKey}</if>
+            <if test="executorType != null ">and executor_type = #{executorType}</if>
+            <if test="executorInfo != null ">and executor_info = #{executorInfo}</if>
+        </where>
+        order by id
+    </select>
+</mapper>

+ 22 - 0
ruoyi-common/pom.xml

@@ -163,6 +163,28 @@
             <artifactId>lombok</artifactId>
         </dependency>
 
+        <!-- snail-job 客户端依赖 -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-starter</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+        <!-- snail-job 重试相关依赖 -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-retry-core</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+        <!-- snail-job 客户端核心依赖 -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-job-core</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+
 
         <dependency>
             <groupId>dev.tinyflow</groupId>

+ 4 - 0
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java

@@ -16,6 +16,10 @@ public enum DataSourceType
      * 从库
      */
     SLAVE,
+    /**
+     * snail_job
+     */
+    JOB,
     /**
      * me数据库
      * */

+ 51 - 4
ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java

@@ -8,8 +8,7 @@ import java.net.URLConnection;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.security.cert.X509Certificate;
-import java.util.Base64;
-import java.util.HashMap;
+import java.util.*;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
@@ -18,12 +17,15 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
 import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -74,6 +76,15 @@ public class HttpUtils {
         return sendGet(url, param, Constants.UTF8);
     }
 
+    public static String sendGet(String url, Object param) {
+        return sendGet(url, toQueryString(param));
+    }
+
+    public static String sendGet(String url, Object param,HashMap<String, String> headers) {
+
+        return sendGet(url, toQueryString(param),headers);
+    }
+
     /**
      * 向指定 URL 发送GET方法的请求
      *
@@ -117,10 +128,30 @@ public class HttpUtils {
                 log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
             }
         }
+
         return result.toString();
     }
 
-    public static String sendGet(String url, String param, String contentType, HashMap<String, String> headers) {
+    public static String sendGet(String url, String param, HashMap<String, String> headers) {
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println(url);
+        System.out.println(param);
+        param = param.substring(0,1);
+        System.out.println(param);
+        for (String s : headers.keySet()) {
+            System.out.println(s+":"+headers.get(s));
+        }
+
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+
+
+
         StringBuilder result = new StringBuilder();
         BufferedReader in = null;
         try {
@@ -137,7 +168,7 @@ public class HttpUtils {
             }
 
             connection.connect();
-            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), Constants.UTF8));
             String line;
             while ((line = in.readLine()) != null) {
                 result.append(line);
@@ -548,5 +579,21 @@ public class HttpUtils {
             throw new IOException("SSL configuration failed", e);
         }
     }*/
+    public static String toQueryString(Object obj) {
+        List<NameValuePair> params = new ArrayList<>();
 
+        // 遍历实体类字段(简化版,实际需处理复杂类型)
+        for (java.lang.reflect.Field field : obj.getClass().getDeclaredFields()) {
+            field.setAccessible(true);
+            try {
+                Object value = field.get(obj);
+                if (value != null) {
+                    params.add(new BasicNameValuePair(field.getName(), value.toString()));
+                }
+            } catch (IllegalAccessException ignored) {
+            }
+        }
+
+        return URLEncodedUtils.format(params, StandardCharsets.UTF_8);
+    }
 }

+ 9 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java

@@ -48,6 +48,14 @@ public class DruidConfig
         DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
         return druidProperties.dataSource(dataSource);
     }
+    @Bean
+    @ConfigurationProperties("spring.datasource.druid.job")
+    @ConditionalOnProperty(prefix = "spring.datasource.druid.job", name = "enabled", havingValue = "true")
+    public DataSource jobDataSource(DruidProperties druidProperties)
+    {
+        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+        return druidProperties.dataSource(dataSource);
+    }
 
     @Bean
     @ConfigurationProperties("spring.datasource.druid.me")
@@ -65,6 +73,7 @@ public class DruidConfig
         Map<Object, Object> targetDataSources = new HashMap<>();
         targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
         setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
+        setDataSource(targetDataSources, DataSourceType.JOB.name(), "jobDataSource");
         setDataSource(targetDataSources, DataSourceType.ME.name(), "meDataSource");
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }