钟日健
2022-05-18 ed41701a2954172d20b85da0ae01436375210840
新增任务配置
5 files modified
15 files added
992 ■■■■■ changed files
pom.xml 11 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/config/ScheduleConfig.java 6 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/FTP/Monitor.java 5 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/config/QuartzJob.java 37 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/config/ScheduledManager.java 165 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/controller/ScheduledController.java 164 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/entity/ScheduledJob.java 91 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/enums/ScheduledStatus.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/event/ScheduleEvent.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/listener/SchedulerListener.java 41 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/mapper/ScheduledJobMapper.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/mapper/ScheduledJobMapper.xml 30 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/service/ScheduledJobService.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/service/impl/ScheduledJobServiceImpl.java 64 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/task/Task.java 179 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/util/SpringBeanTaskUtil.java 35 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/util/SpringContextUtils.java 42 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/quartz/vo/ScheduledJobVO.java 23 ●●●●● patch | view | raw | blame | history
src/main/resources/application-test.yml 8 ●●●● patch | view | raw | blame | history
src/main/resources/application.yml 1 ●●●● patch | view | raw | blame | history
pom.xml
@@ -251,6 +251,17 @@
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
        </dependency>
        <!-- quartz 定时任务-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.2</version>
        </dependency>
        <!--springboot-quartz-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
    </dependencies>
    <build>
src/main/java/org/springblade/common/config/ScheduleConfig.java
@@ -3,6 +3,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
@@ -18,6 +19,9 @@
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(100));
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.initialize();
        scheduledTaskRegistrar.setScheduler(taskScheduler);
    }
}
src/main/java/org/springblade/modules/FTP/Monitor.java
@@ -18,7 +18,7 @@
@Component
public class Monitor {
    @Scheduled(cron = "*/5 * * * * ?")
//    @Scheduled(cron = "*/5 * * * * ?")
    public static boolean isFTPFileExist() {
        FTPClient ftp = new FTPClient();
@@ -52,14 +52,12 @@
            FTPFile[] files = ftp.listFiles();
            if (files.length == 0) {
                ftp.disconnect();
                return false;
            } else {
                for (FTPFile file : files) {
                    fileName = file.getName();
                    InputStream is = ftp.retrieveFileStream(new String(fileName.getBytes("GBK"), FTP.DEFAULT_CONTROL_ENCODING));
                    if (null == is) {
                        ftp.disconnect();
                        return false;
                    } else {
                        String substring1 = fileName.substring(0, 1);
                        //把文件下载到本地
@@ -146,7 +144,6 @@
                        ftp.completePendingCommand();
                    }
                }
                ftp.disconnect();
                return true;
            }
        } catch (Exception e) {
src/main/java/org/springblade/modules/quartz/config/QuartzJob.java
New file
@@ -0,0 +1,37 @@
package org.springblade.modules.quartz.config;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.event.ScheduleEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
/**
 * 该类将会被org.springframework.scheduling.quartz.SpringBeanJobFactory 实例化
 * 并使@Autowired 生效
 * @author zhongrj
 * @since 2022-03-17
 */
@Slf4j
@DisallowConcurrentExecution
public class QuartzJob implements Job {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    /**
     * 任务调度参数key
     */
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
    @Override
    @SneakyThrows
    public void execute(JobExecutionContext jobExecutionContext){
        ScheduledJob scheduledCron = (ScheduledJob)jobExecutionContext.getMergedJobDataMap().get(JOB_PARAM_KEY);
        eventPublisher.publishEvent(new ScheduleEvent(scheduledCron));
    }
}
src/main/java/org/springblade/modules/quartz/config/ScheduledManager.java
New file
@@ -0,0 +1,165 @@
package org.springblade.modules.quartz.config;
import lombok.AllArgsConstructor;
import org.quartz.*;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.enums.ScheduledStatus;
import org.springframework.stereotype.Component;
/**
 * 任务管理器
 * @author zhongrj
 * @since 2022-03-17
 */
@Component
@AllArgsConstructor
public class ScheduledManager {
    private final static String JOB_NAME = "TASK_";
    private final Scheduler scheduler;
    /**
     * 获取触发器key
     */
    private TriggerKey getTriggerKey(ScheduledJob scheduledJob){
        return TriggerKey.triggerKey(JOB_NAME + scheduledJob.getId());
    }
    /**
     * 获取jobKey
     */
    private JobKey getJobKey(ScheduledJob scheduledJob) {
        return JobKey.jobKey(JOB_NAME + scheduledJob.getId());
    }
    /**
     * 获取表达式触发器
     */
    public CronTrigger getCronTrigger(ScheduledJob scheduledJob) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(scheduledJob));
        } catch (SchedulerException e) {
            throw new RuntimeException("获取定时任务CronTrigger出现异常", e);
        }
    }
    /**
     * 创建定时任务
     */
    public void createScheduledJob(ScheduledJob scheduledJob) {
        try {
            //构建job信息
            JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity(getJobKey(scheduledJob)).build();
            //表达式调度构建器,可以根据scheduledJob修改withMisfireHandling方法,但是使用异步执行定时任务,没必要
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduledJob.getCronExpression())
                .withMisfireHandlingInstructionFireAndProceed();
            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduledJob)).withSchedule(scheduleBuilder).build();
            //放入参数,运行时的方法可以获取
            jobDetail.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, scheduledJob);
            scheduler.scheduleJob(jobDetail, trigger);
            //暂停任务
            if (scheduledJob.getStatus().equals(ScheduledStatus.PAUSE.getType())) {
                pauseJob(scheduledJob);
            }
        } catch (SchedulerException e) {
            throw new RuntimeException("创建定时任务失败", e);
        }
    }
    /**
     * 更新定时任务
     */
    public void updateScheduledJob(ScheduledJob scheduleJob) {
        try {
            TriggerKey triggerKey = getTriggerKey(scheduleJob);
            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()).withMisfireHandlingInstructionFireAndProceed();
            CronTrigger trigger = getCronTrigger(scheduleJob);
            // 如果定时任务不存在,则创建定时任务
            if (trigger == null) {
                createScheduledJob(scheduleJob);
                return;
            }
            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            //参数
            trigger.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, scheduleJob);
            scheduler.rescheduleJob(triggerKey, trigger);
            //暂停任务
            if (scheduleJob.getStatus().equals(ScheduledStatus.PAUSE.getType())) {
                pauseJob(scheduleJob);
            }
        } catch (SchedulerException e) {
            throw new RuntimeException("更新定时任务失败", e);
        }
    }
    /**
     * 立即执行任务
     */
    public void run(ScheduledJob scheduleJob) {
        try {
            //参数
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(QuartzJob.JOB_PARAM_KEY, scheduleJob);
            scheduler.triggerJob(getJobKey(scheduleJob), dataMap);
        } catch (SchedulerException e) {
            throw new RuntimeException("立即执行定时任务失败", e);
        }
    }
    /**
     * 暂停任务
     */
    public void pauseJob(ScheduledJob scheduledJob) {
        try {
            scheduler.pauseJob(getJobKey(scheduledJob));
        } catch (SchedulerException e) {
            throw new RuntimeException("暂停定时任务失败", e);
        }
    }
    /**
     * 恢复任务
     */
    public void resumeJob(ScheduledJob scheduleJob) {
        try {
            scheduler.resumeJob(getJobKey(scheduleJob));
        } catch (SchedulerException e) {
            throw new RuntimeException("恢复定时任务失败", e);
        }
    }
    /**
     * 删除定时任务
     */
    public void deleteScheduledJob(ScheduledJob scheduleJob) {
        try {
            // 停止触发器
            scheduler.pauseTrigger(getTriggerKey(scheduleJob));
            //移除触发器
            scheduler.unscheduleJob(getTriggerKey(scheduleJob));
            //删除任务
            scheduler.deleteJob(getJobKey(scheduleJob));
        } catch (SchedulerException e) {
            throw new RuntimeException("删除定时任务失败", e);
        }
    }
}
src/main/java/org/springblade/modules/quartz/controller/ScheduledController.java
New file
@@ -0,0 +1,164 @@
package org.springblade.modules.quartz.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.quartz.config.ScheduledManager;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.service.ScheduledJobService;
import org.springblade.modules.quartz.vo.ScheduledJobVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
 * 定时任务控制层
 * @author zhongrj
 * @since 2022-03-07
 */
@AllArgsConstructor
@RestController
@RequestMapping("/scheduled")
public class ScheduledController {
    private final ScheduledJobService scheduledJobService;
    private final ScheduledManager scheduleManager;
    /**
     * 查询定时任务的分页数据
     * @param page
     * @param scheduledJob
     * @return
     */
    @GetMapping("/list")
    public R list(Query query, ScheduledJob scheduledJob){
        return R.data(scheduledJobService.page(Condition.getPage(query),Condition.getQueryWrapper(scheduledJob)));
    }
    /**
     * 自定义定时任务的分页数据
     * @param page
     * @param scheduledJob
     * @return
     */
    @GetMapping("/page")
    public R page(ScheduledJobVO scheduledJob,Query query){
        return R.data(scheduledJobService.selectPageScheduledJobList(Condition.getPage(query),scheduledJob));
    }
    /**
     * 定时任务详情信息
     * @param scheduledJob
     * @return
     */
    @GetMapping("/detail")
    public R detail(ScheduledJob scheduledJob){
        return R.data(scheduledJobService.getOne(new QueryWrapper<>(scheduledJob)));
    }
    /**
     * 定时任务新增
     * @param scheduledJob
     * @return
     */
    @PostMapping("/save")
    public R save(@RequestBody ScheduledJob scheduledJob){
        scheduledJob.setCreateTime(new Date());
        boolean status = scheduledJobService.save(scheduledJob);
        if (status){
            //创建定时任务
            scheduleManager.createScheduledJob(scheduledJob);
        }
        return R.status(status);
    }
    /**
     * 定时任务修改
     * @param scheduledJob
     * @return
     */
    @PostMapping("/update")
    public R update(@RequestBody ScheduledJob scheduledJob){
        scheduledJob.setUpdateTime(new Date());
        boolean status = scheduledJobService.updateById(scheduledJob);
        if (status){
            //修改定时任务
            scheduleManager.updateScheduledJob(scheduledJob);
        }
        return R.status(status);
    }
    /**
     * 删除,批量删除
     * @param ids
     * @return
     */
    @PostMapping("/remove")
    public R remove(@NotNull String ids){
        List<String> list = Arrays.asList(ids.split(","));
        list.forEach(s -> {
            ScheduledJob scheduledJob = new ScheduledJob();
            scheduledJob.setId(Integer.parseInt(s));
            //删除定时任务
            scheduleManager.deleteScheduledJob(scheduledJob);
        });
        return R.status(scheduledJobService.removeByIds(Func.toLongList(ids)));
    }
    /**
     * 定时任务恢复
     * @param scheduledJob
     * @return
     */
    @PostMapping("/activateQuartz")
    public R activateQuartz(@RequestBody ScheduledJob scheduledJob){
        scheduledJob.setUpdateTime(new Date());
        boolean status = scheduledJobService.updateById(scheduledJob);
        if (status){
            //恢复定时任务
            scheduleManager.resumeJob(scheduledJob);
        }
        return R.status(status);
    }
    /**
     * 启动定时任务
     * @param scheduledJob
     * @return
     */
    @PostMapping("/runQuartz")
    public R runQuartz(@RequestBody ScheduledJob scheduledJob){
        scheduledJob.setUpdateTime(new Date());
        boolean status = scheduledJobService.updateById(scheduledJob);
        if (status){
            //立即启动任务
            scheduleManager.run(scheduledJob);
        }
        return R.status(status);
    }
    /**
     * 暂停定时任务
     * @param scheduledJob
     * @return
     */
    @PostMapping("/stopQuartz")
    public R stopQuartz(@RequestBody ScheduledJob scheduledJob){
        scheduledJob.setUpdateTime(new Date());
        boolean status = scheduledJobService.updateById(scheduledJob);
        if (status){
            //暂停定时任务
            scheduleManager.pauseJob(scheduledJob);
        }
        return R.status(status);
    }
}
src/main/java/org/springblade/modules/quartz/entity/ScheduledJob.java
New file
@@ -0,0 +1,91 @@
package org.springblade.modules.quartz.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
 * 定时任务entity
 * @author zhongrj
 * @since 2022-03-17
 */
@Data
@TableName("sys_scheduled_job")
public class ScheduledJob implements Serializable {
    private static final long serialVersionUID = 6350214655057614043L;
    /**
     * 主键
     */
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    /**
     * 名称
     */
    private String name;
    /**
     * 方法名
     */
    private String methodName;
    /**
     * spring bean 名称
     */
    private String BeanName;
    /**
     * 参数
     */
    private String params;
    /**
     * 任务表达式
     */
    private String cronExpression;
    /**
     * 描述/备注
     */
    private String remark;
    /**
     * 状态  1:正常  2:停止
     */
    private Integer status;
    /**
     * 创建时间
     */
    @TableField("create_time")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(locale = "zh",pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date createTime;
    /**
     * 创建时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(locale = "zh",pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date updateTime;
    /**
     * 最近一次执行时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(locale = "zh",pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date activeTime;
}
src/main/java/org/springblade/modules/quartz/enums/ScheduledStatus.java
New file
@@ -0,0 +1,29 @@
package org.springblade.modules.quartz.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * 任务状态
 * @author zhongrj
 * @since 2022-03-17
 */
@Getter
@AllArgsConstructor
public enum ScheduledStatus {
    /**
     * 正常
     */
    NORMAL(1),
    /**
     * 暂停
     */
    PAUSE(2);
    /**
     * 类型  1:正常  2:暂停
     */
    private final Integer type;
}
src/main/java/org/springblade/modules/quartz/event/ScheduleEvent.java
New file
@@ -0,0 +1,15 @@
package org.springblade.modules.quartz.event;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springblade.modules.quartz.entity.ScheduledJob;
/**
 * @author zhongrj
 * @since 2022-03-17
 */
@Getter
@AllArgsConstructor
public class ScheduleEvent{
    private final ScheduledJob scheduledJob;
}
src/main/java/org/springblade/modules/quartz/listener/SchedulerListener.java
New file
@@ -0,0 +1,41 @@
package org.springblade.modules.quartz.listener;
import lombok.AllArgsConstructor;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.event.ScheduleEvent;
import org.springblade.modules.quartz.service.ScheduledJobService;
import org.springblade.modules.quartz.util.SpringBeanTaskUtil;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
 * 异步监听定时任务事件,解决job线程无故丢失的问题
 * @author zhongrj
 * @since 2022-03-10
 */
@Component
@AllArgsConstructor
@EnableAsync
public class SchedulerListener {
    private final ScheduledJobService scheduledJobService;
    @Async
    @EventListener(ScheduleEvent.class)
    public void scheduledJobListener(ScheduleEvent event){
        //获取事件对象
        ScheduledJob scheduledJob = event.getScheduledJob();
//        System.out.println("开始执行任务......");
//        scheduledJob.setActiveTime(new Date());
//        scheduledJobService.updateById(scheduledJob);
        //开始执行任务
        SpringBeanTaskUtil.invokeMethod(scheduledJob);
//        System.out.println("任务执行结束......");
    }
}
src/main/java/org/springblade/modules/quartz/mapper/ScheduledJobMapper.java
New file
@@ -0,0 +1,25 @@
package org.springblade.modules.quartz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.vo.ScheduledJobVO;
import java.util.List;
/**
 * mapper 映射层
 * @author zhongrj
 * @since 2022-03-17
 */
public interface ScheduledJobMapper extends BaseMapper<ScheduledJob> {
    /**
     * 自定义定时任务分页数据
     * @param page
     * @param scheduledJob
     * @return
     */
    List<ScheduledJobVO> selectPageScheduledJobPage(@Param("page") IPage<ScheduledJobVO> page, @Param("scheduledJob")ScheduledJobVO scheduledJob);
}
src/main/java/org/springblade/modules/quartz/mapper/ScheduledJobMapper.xml
New file
@@ -0,0 +1,30 @@
<?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="org.springblade.modules.quartz.mapper.ScheduledJobMapper">
    <!--自定义查询任务分页数据-->
    <select id="selectPageScheduledJobPage" resultType="org.springblade.modules.quartz.vo.ScheduledJobVO">
        select * from sys_scheduled_job
        where 1=1
        <if test="scheduledJob.name!=null and scheduledJob.name!=''">
            and name like concat('%',#{scheduledJob.name},'%')
        </if>
        <if test="scheduledJob.methodName!=null and scheduledJob.methodName!=''">
            and method_name like concat('%',#{scheduledJob.methodName},'%')
        </if>
        <if test="scheduledJob.beanName!=null and scheduledJob.beanName!=''">
            and bean_name like concat('%',#{scheduledJob.beanName},'%')
        </if>
        <if test="scheduledJob.params!=null and scheduledJob.params!=''">
            and params like concat('%',#{scheduledJob.params},'%')
        </if>
        <if test="scheduledJob.cronExpression!=null and scheduledJob.cronExpression!=''">
            and cron_expression like concat('%',#{scheduledJob.cronExpression},'%')
        </if>
        <if test="scheduledJob.status!=null">
            and status = #{scheduledJob.status}
        </if>
        order by id desc
    </select>
</mapper>
src/main/java/org/springblade/modules/quartz/service/ScheduledJobService.java
New file
@@ -0,0 +1,21 @@
package org.springblade.modules.quartz.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.vo.ScheduledJobVO;
/**
 * 任务接口层
 * @author zhongrj
 * @since 2022-03-17
 */
public interface ScheduledJobService  extends IService<ScheduledJob> {
    /**
     * 自定义定时任务分页数据
     * @param page
     * @param scheduledJob
     * @return
     */
    IPage<ScheduledJobVO> selectPageScheduledJobList(IPage<ScheduledJobVO> page, ScheduledJobVO scheduledJob);
}
src/main/java/org/springblade/modules/quartz/service/impl/ScheduledJobServiceImpl.java
New file
@@ -0,0 +1,64 @@
package org.springblade.modules.quartz.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.quartz.CronTrigger;
import org.springblade.modules.quartz.config.ScheduledManager;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springblade.modules.quartz.enums.ScheduledStatus;
import org.springblade.modules.quartz.mapper.ScheduledJobMapper;
import org.springblade.modules.quartz.service.ScheduledJobService;
import org.springblade.modules.quartz.vo.ScheduledJobVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
/**
 * 任务接口实现层
 * @author zhongrj
 * @since 2022-03-17
 */
@Service
public class ScheduledJobServiceImpl extends ServiceImpl<ScheduledJobMapper, ScheduledJob> implements ScheduledJobService  {
    @Autowired
    private ScheduledManager scheduledManager;
    /**
     * 初始化任务
     */
    @PostConstruct
    public void init(){
        List<ScheduledJob> list = list();
        if (list.size()>0) {
            list.forEach(scheduledCron -> {
                //获取 triggerKey
                CronTrigger cronTrigger = scheduledManager.getCronTrigger(scheduledCron);
                if (null == cronTrigger) {
                    //创建定时任务
                    scheduledManager.createScheduledJob(scheduledCron);
                }else if(ScheduledStatus.NORMAL.getType().equals(scheduledCron.getStatus())){
                    //恢复定时任务
                    scheduledManager.resumeJob(scheduledCron);
                }else if(ScheduledStatus.PAUSE.getType().equals(scheduledCron.getStatus())){
                    //暂停任务
                    scheduledManager.pauseJob(scheduledCron);
                }
            });
        }
    }
    /**
     * 自定义定时任务分页数据
     * @param page
     * @param scheduledJob
     * @return
     */
    @Override
    public IPage<ScheduledJobVO> selectPageScheduledJobList(IPage<ScheduledJobVO> page, ScheduledJobVO scheduledJob) {
        return page.setRecords(baseMapper.selectPageScheduledJobPage(page,scheduledJob));
    }
}
src/main/java/org/springblade/modules/quartz/task/Task.java
New file
@@ -0,0 +1,179 @@
package org.springblade.modules.quartz.task;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springblade.modules.FTP.DataHanlder;
import org.springblade.modules.FTP.FtpUtil;
import org.springblade.modules.FTP.MysqlCenlint;
import org.springblade.modules.FTP.OutJson;
import org.springblade.modules.training.service.TrainingRegistrationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import static org.springblade.common.config.FtpConfig.*;
/**
 * 定时任务
 * @author zhongrj
 * @since 2022-03-10
 */
@Component("task")
public class Task {
    /**
     * 定时任务
     * @return
     */
    public boolean readFile() {
        FTPClient ftp = new FTPClient();
        String fileName = null;
        try {
            ftp.connect(ftpHost, ftpPort);
            // 登陆
            ftp.login(ftpUserName, ftpPassword);
            // 检验登陆操作的返回码是否正确
            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
                ftp.disconnect();
                return false;
            }
            System.out.println("ftp 连接成功!时间: "+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            //被动模式,文件上传不成功会有提示
            ftp.enterLocalActiveMode();
            // 设置文件类型为二进制,与ASCII有区别
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            // 设置编码格式
            ftp.setControlEncoding("GBK");
            // 检验文件是否存在
            ftp.changeWorkingDirectory(ftpPath);
            FTPFile[] files = ftp.listFiles();
            if (files.length == 0) {
                ftp.disconnect();
            } else {
                for (FTPFile file : files) {
                    fileName = file.getName();
                    InputStream is = ftp.retrieveFileStream(new String(fileName.getBytes("GBK"), FTP.DEFAULT_CONTROL_ENCODING));
                    if (null == is) {
                        ftp.disconnect();
                    } else {
                        String substring1 = fileName.substring(0, 1);
                        //把文件下载到本地
                        FtpUtil.downloadFtpFile(ftpHost, ftpUserName, ftpPassword, ftpPort, ftpPath, localPath, fileName);
                        if (substring1.equals("w")) {
                            String s = OutJson.TestJson(fileName);
                            //sql语句
                            String sql = OutJson.stringReplace(s);
                            String[] split = sql.split(";");//以逗号分割
                            for (String sqls : split) {
                                //判断是否是新增,删除,修改
                                String substring = sqls.substring(0, 2);
                                //新增
                                if (substring.equals("in")) {
                                    //运行sql语句
                                    MysqlCenlint.inster(sqls);
                                }
                                //修改
                                else if (substring.equals("up")) {
                                    MysqlCenlint.update(sqls);
                                }
                                //删除
                                else {
                                    MysqlCenlint.delete(sqls);
                                }
                            }
                            //删除本地文件
                            MysqlCenlint.deletess(fileName);
                            //删除 ftp 文件
                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
                        }else if(substring1.equals("o")){
                            //获取对象字符串
                            String json = OutJson.TestJson(fileName);
                            //数据处理
                            DataHanlder.handler(json);
                            //删除本地文件
                            MysqlCenlint.deletess(fileName);
                            //删除 ftp 文件
                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
                        }else if(substring1.equals("l")){
                            //用户集合数据
                            //获取对象字符串
                            String json = OutJson.TestJson(fileName);
                            //数据处理
                            DataHanlder.handlerList(json);
                            //删除本地文件
                            MysqlCenlint.deletess(fileName);
                            //删除 ftp 文件
                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
                        }else if(substring1.equals("t")){
                            //培训报名数据
                            //获取对象字符串
                            String json = OutJson.TestJson(fileName);
                            //数据处理
                            DataHanlder.handlerListTrain(json);
                            //删除本地文件
                            MysqlCenlint.deletess(fileName);
                            //删除 ftp 文件
                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
                        }else if(substring1.equals("s")){
                            //获取保安员证编号数据
                            //获取对象字符串
                            String json = OutJson.TestJson(fileName);
                            //数据处理
                            DataHanlder.handlerSecurityNumerBit(json);
                            //删除本地文件
                            MysqlCenlint.deletess(fileName);
                            //删除 ftp 文件
                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
                        }
//                        else if(substring1.equals("f")){
//                            //把文件下载到本地(图片文件类),测试内外网使用同一台服务器
//                            FtpUtil.downloadFtpFile(ftpHost, ftpUserName, ftpPassword, ftpPort, ftpPath, minioPath, fileName);
//                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
//                        }
                        else {
                            //把文件下载到本地(图片文件类),ftp 内外网服务器分开时使用
                            FtpUtil.downloadFtpFile(ftpHost, ftpUserName, ftpPassword, ftpPort, ftpPath, minioPath, fileName);
                            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
                        }
                        //删除本地文件,ftp 文件没有对应读取的不删除
                        MysqlCenlint.deletess(fileName);
                        is.close();
                        ftp.completePendingCommand();
                    }
                }
                return true;
            }
        } catch (Exception e) {
            MysqlCenlint.deletess(fileName);
            FtpUtil.deleteFile(ftpHost, ftpPort, ftpUserName, ftpPassword, "anbao/", fileName);
            e.printStackTrace();
        } finally {
            //如果ftp 没有关闭,则关闭ftp
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException io) {
                    io.printStackTrace();
                }
            }
        }
        return false;
    }
}
src/main/java/org/springblade/modules/quartz/util/SpringBeanTaskUtil.java
New file
@@ -0,0 +1,35 @@
package org.springblade.modules.quartz.util;
import liquibase.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springblade.modules.quartz.entity.ScheduledJob;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
/**
 * 定时任务spring bean 执行定时任务
 * @author LGH
 */
@Slf4j
public class SpringBeanTaskUtil {
    public static void invokeMethod(ScheduledJob scheduleJob) {
        Object target = SpringContextUtils.getBean(scheduleJob.getBeanName());
        try {
            if (StringUtils.isNotEmpty(scheduleJob.getParams())) {
                Method method = target.getClass().getDeclaredMethod(scheduleJob.getMethodName(), String.class);
                ReflectionUtils.makeAccessible(method);
                method.invoke(target, scheduleJob.getParams());
            } else {
                Method method = target.getClass().getDeclaredMethod(scheduleJob.getMethodName());
                ReflectionUtils.makeAccessible(method);
                method.invoke(target);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("执行定时任务失败", e);
        }
    }
}
src/main/java/org/springblade/modules/quartz/util/SpringContextUtils.java
New file
@@ -0,0 +1,42 @@
package org.springblade.modules.quartz.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * Spring Context 工具类
 * @author zhongrj
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {
    public static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }
    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
    public static <T> T getBean(String name, Class<T> requiredType) {
        return applicationContext.getBean(name, requiredType);
    }
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }
    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }
    public static Class<? extends Object> getType(String name) {
        return applicationContext.getType(name);
    }
}
src/main/java/org/springblade/modules/quartz/vo/ScheduledJobVO.java
New file
@@ -0,0 +1,23 @@
package org.springblade.modules.quartz.vo;
import lombok.Data;
import org.springblade.modules.quartz.entity.ScheduledJob;
/**
 * vo
 * @author zhongrj
 * @since 2022-03-17
 */
@Data
public class ScheduledJobVO extends ScheduledJob {
    /**
     * 开始时间
     */
    private String beginTime;
    /**
     * 结束时间
     */
    private String endTime;
}
src/main/resources/application-test.yml
@@ -16,13 +16,13 @@
  datasource:
    # MySql
    url: jdbc:mysql://36.134.81.48:3306/zhba-test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
    url: jdbc:mysql://61.131.136.25:2083/zhba-test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
    username: root
    password: jfpt123
    password: ZHba@0112
#ftp 设置
ftp:
  sqlConnect: jdbc:mysql://36.134.81.48:3306/zhba-test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
  sqlConnect: jdbc:mysql://61.131.136.25:2083/zhba-test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
  ftpHost: 192.168.0.198
  ftpPort: 21
  ftpUserName: arsn
@@ -32,7 +32,7 @@
  minioPath: E:\ftptp\
  jsonUrl: E:\anbao\
  sqlUsername: root
  sqlPassword: jfpt123
  sqlPassword: ZHba@0112
#公共配置
common:
src/main/resources/application.yml
@@ -196,6 +196,7 @@
    #接口放行
    skip-url:
      - /blade-test/**
      - /readFile
#      - /liveLocation/**
#      - /locus/**
#      - /examScore/**