maven
20 小时以前 6047f24edc72a13b71813c3fb6cc0d087c0f6cd7
yys  巡检定时任务持久化
已添加1个文件
已修改7个文件
已删除2个文件
442 ■■■■■ 文件已修改
basic-server/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
basic-server/src/main/java/com/ruoyi/basic/service/impl/SupplyServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/TimingTaskScheduler.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/service/impl/TimingTaskServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/task/QuartzConfig.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main-business/src/main/java/com/ruoyi/business/task/TimingTaskJob.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml.example 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/logback.xml.example 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/pom.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
basic-server/src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -72,21 +72,21 @@
    public int addOrEditCustomer(CustomerDto customerDto) {
        Customer customer = new Customer();
        BeanUtils.copyProperties(customerDto, customer);
        if (customerDto.getBids().size() != 3) {
            throw new RuntimeException("请选择经营地址省市区");
        if (customerDto.getBids() != null && customerDto.getBids().size() == 3) {
            customer.setBusinessProvinceId(customerDto.getBids().get(0));
            customer.setBusinessCityId(customerDto.getBids().get(1));
            customer.setBusinessDistrictId(customerDto.getBids().get(2));
        }
        if (customerDto.getCids().size() != 3) {
            throw new RuntimeException("请选择联系地址省市区");
        if (customerDto.getCids() != null && customerDto.getCids().size() == 3) {
            customer.setProvinceId(customerDto.getCids().get(0));
            customer.setCityId(customerDto.getCids().get(1));
            customer.setDistrictId(customerDto.getCids().get(2));
        }
        customer.setBusinessProvinceId(customerDto.getBids().get(0));
        customer.setBusinessCityId(customerDto.getBids().get(1));
        customer.setBusinessDistrictId(customerDto.getBids().get(2));
        customer.setProvinceId(customerDto.getCids().get(0));
        customer.setCityId(customerDto.getCids().get(1));
        customer.setDistrictId(customerDto.getCids().get(2));
        if (Objects.isNull(customerDto.getId())) {
            return customerMapper.insert(customer);
basic-server/src/main/java/com/ruoyi/basic/service/impl/SupplyServiceImpl.java
@@ -67,21 +67,19 @@
    public int addOrEditSupply(SupplyDto supplyDto) {
        Supply supply = new Supply();
        BeanUtils.copyProperties(supplyDto, supply);
        if (supplyDto.getBids().size() != 3) {
            throw new RuntimeException("请选择经营地址省市区");
        if (supplyDto.getBids() != null && supplyDto.getBids().size() == 3) {
            supply.setBProvinceId(supplyDto.getBids().get(0));
            supply.setBCityId(supplyDto.getBids().get(1));
            supply.setBDistrictId(supplyDto.getBids().get(2));
        }
        if (supplyDto.getCids().size() != 3) {
            throw new RuntimeException("请选择联系地址省市区");
        if (supplyDto.getCids() != null && supplyDto.getCids().size() == 3) {
            supply.setCProvinceId(supplyDto.getCids().get(0));
            supply.setCCityId(supplyDto.getCids().get(1));
            supply.setCDistrictId(supplyDto.getCids().get(2));
        }
        supply.setBProvinceId(supplyDto.getBids().get(0));
        supply.setBCityId(supplyDto.getBids().get(1));
        supply.setBDistrictId(supplyDto.getBids().get(2));
        supply.setCProvinceId(supplyDto.getCids().get(0));
        supply.setCCityId(supplyDto.getCids().get(1));
        supply.setCDistrictId(supplyDto.getCids().get(2));
        if (Objects.isNull(supplyDto.getId())) {
main-business/src/main/java/com/ruoyi/business/service/impl/TimingTaskScheduler.java
@@ -43,13 +43,18 @@
            throw new SchedulerException("Existing trigger is not a CronTrigger");
        }
        // æž„建新触发器
        Trigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withDescription(task.getTaskName())
                .withSchedule(CronScheduleBuilder.cronSchedule(convertToCronExpression(task)))
                .startAt(Date.from(task.getNexExecutionTime().atZone(ZoneId.systemDefault()).toInstant()))
                .forJob(oldTrigger.getJobKey())
        // 3. æž„建CronTrigger,确保持久化配置
        CronTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)                // å”¯ä¸€æ ‡è¯†ï¼Œç”¨äºŽæŒä¹…化存储
                .withDescription(task.getTaskName() + "_TRIGGER") // è§¦å‘器描述
                .forJob(oldTrigger.getJobKey())                       // å…³è”对应的Job
                .withSchedule(CronScheduleBuilder
                        .cronSchedule(convertToCronExpression(task)) // é”™è¿‡æ‰§è¡Œæ—¶çš„策略(根据业务调整)
                )
                // 4. è®¾ç½®å¼€å§‹æ—¶é—´ï¼ˆè‹¥ä¸ºnull则立即生效)
                .startAt(task.getNexExecutionTime() != null
                        ? Date.from(task.getNexExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
                        : new Date())
                .build();
        scheduler.rescheduleJob(triggerKey, newTrigger);
@@ -74,40 +79,55 @@
    /**
     * åˆ é™¤ä»»åŠ¡
     */
    public void unscheduleTimingTask(Long taskId) throws SchedulerException {
        JobKey jobKey = new JobKey("timingTask_" + taskId);
        scheduler.deleteJob(jobKey);
    public void unscheduleTimingTask(Long taskId) {
        try{
            JobKey jobKey = new JobKey("timingTask_" + taskId);
            scheduler.deleteJob(jobKey);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private JobDetail buildJobDetail(TimingTask task) {
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("taskId", task.getId());
        // 1. æž„建唯一JobKey(基于任务ID,确保重启后能识别)
        JobKey jobKey = new JobKey("timingTask_" + task.getId());
        // 2. å°è£…任务数据(仅使用基本类型,确保可序列化)
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("taskId", task.getId().toString());           // ä»»åŠ¡ID(Long,可序列化)
        // æŒ‰éœ€æ·»åŠ å…¶ä»–å¿…è¦çš„åŸºæœ¬ç±»åž‹å‚æ•°
        // 3. æž„建JobDetail,设置持久化相关属性
        return JobBuilder.newJob(TimingTaskJob.class)
                .withIdentity("timingTask_" + task.getId())
                .withDescription(task.getTaskName())
                .usingJobData(jobDataMap)
                .storeDurably()
                .withIdentity(jobKey)                    // å”¯ä¸€æ ‡è¯†ï¼Œç”¨äºŽæŒä¹…化存储
                .withDescription(task.getTaskName())     // ä»»åŠ¡æè¿°ï¼Œå­˜å…¥æ•°æ®åº“
                .usingJobData(jobDataMap)                // ç»‘定任务数据
                .storeDurably(true)                          // å³ä½¿æ²¡æœ‰è§¦å‘器关联也持久化保存
                .requestRecovery(true)                   // å½“调度器崩溃后恢复时,重新执行未完成的任务
                .build();
    }
    private Trigger buildJobTrigger(TimingTask task, JobDetail jobDetail) {
        // 1. æž„建唯一TriggerKey(基于任务ID)
        TriggerKey triggerKey = new TriggerKey("trigger_" + task.getId());
        // 2. ç”ŸæˆCron表达式(原逻辑不变)
        String cronExpression = convertToCronExpression(task);
            TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder.newTrigger()
                .withIdentity("trigger_" + task.getId())
                .withDescription(task.getTaskName())
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));
        if (jobDetail != null) {
            triggerBuilder.forJob(jobDetail);
        }
        if (task.getNexExecutionTime() != null) {
            triggerBuilder.startAt(Date.from(task.getNexExecutionTime().atZone(ZoneId.systemDefault()).toInstant()));
        }
        return triggerBuilder.build();
        // 3. æž„建CronTrigger,确保持久化配置
        return TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)                // å”¯ä¸€æ ‡è¯†ï¼Œç”¨äºŽæŒä¹…化存储
                .withDescription(task.getTaskName() + "_TRIGGER") // è§¦å‘器描述
                .forJob(jobDetail)                       // å…³è”对应的Job
                .withSchedule(CronScheduleBuilder
                        .cronSchedule(cronExpression)
                        .withMisfireHandlingInstructionDoNothing() // é”™è¿‡æ‰§è¡Œæ—¶çš„策略(根据业务调整)
                )
                // 4. è®¾ç½®å¼€å§‹æ—¶é—´ï¼ˆè‹¥ä¸ºnull则立即生效)
                .startAt(task.getNexExecutionTime() != null
                        ? Date.from(task.getNexExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
                        : new Date())
                .build();
    }
    private String convertToCronExpression(TimingTask task) {
main-business/src/main/java/com/ruoyi/business/service/impl/TimingTaskServiceImpl.java
@@ -400,6 +400,12 @@
    @Override
    public int delByIds(Long[] ids) {
        return timingTaskMapper.deleteByIds(Arrays.asList(ids));
        int i = timingTaskMapper.deleteByIds(Arrays.asList(ids));
//        if (i > 0) {
//            for (Long id : ids) {
//                timingTaskScheduler.unscheduleTimingTask(id);
//            }
//        }
        return i;
    }
}
main-business/src/main/java/com/ruoyi/business/task/QuartzConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package com.ruoyi.business.task;
import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import javax.sql.DataSource;
@Configuration
public class QuartzConfig {
    @Autowired
    private ApplicationContext applicationContext;
    // å‡è®¾å·²é…ç½®åä¸ºdataSource的数据源Bean
    @Autowired
    private DataSource dataSource;
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
        // é…ç½®SpringBeanJobFactory,用于支持Job中的依赖注入
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        schedulerFactory.setJobFactory(jobFactory);
        // åœ¨schedulerFactoryBean()方法中添加
//        schedulerFactory.setDataSource(dataSource);
        // å…¶ä»–配置...
        return schedulerFactory;
    }
    @Bean
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }
    // è‡ªå®šä¹‰JobFactory,支持自动注入
    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
            implements ApplicationContextAware {
        private transient AutowireCapableBeanFactory beanFactory;
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) {
            this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
        }
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            Object jobInstance = super.createJobInstance(bundle);
            // å°†Job实例交给Spring容器管理,使其能够进行依赖注入
            beanFactory.autowireBean(jobInstance);
            return jobInstance;
        }
    }
}
main-business/src/main/java/com/ruoyi/business/task/TimingTaskJob.java
@@ -8,15 +8,16 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.time.LocalDateTime;
@Component
@DisallowConcurrentExecution // ç¦æ­¢å¹¶å‘执行同一个Job
public class TimingTaskJob implements Job {
public class TimingTaskJob implements Job,Serializable {
    private static final long serialVersionUID = 1L; // å¿…须定义序列化ID
    @Autowired
    private
    TimingTaskService timingTaskService;
    private TimingTaskService timingTaskService;
    @Autowired
    private InspectionTaskMapper inspectionTaskMapper;
ruoyi-admin/src/main/resources/application.yml.example
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/logback.xml.example
ÎļþÒÑɾ³ý
ruoyi-quartz/pom.xml
@@ -34,6 +34,10 @@
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-common</artifactId>
        </dependency>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>main-business</artifactId>
        </dependency>
    </dependencies>
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
@@ -1,6 +1,10 @@
package com.ruoyi.quartz.service.impl;
import java.util.List;
import com.ruoyi.business.entity.TimingTask;
import com.ruoyi.business.mapper.TimingTaskMapper;
import com.ruoyi.business.service.impl.TimingTaskScheduler;
import jakarta.annotation.PostConstruct;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
@@ -31,17 +35,27 @@
    @Autowired
    private SysJobMapper jobMapper;
    @Autowired
    private TimingTaskMapper timingTaskMapper;
    @Autowired
    private TimingTaskScheduler timingTaskScheduler;
    /**
     * é¡¹ç›®å¯åŠ¨æ—¶ï¼Œåˆå§‹åŒ–å®šæ—¶å™¨ ä¸»è¦æ˜¯é˜²æ­¢æ‰‹åŠ¨ä¿®æ”¹æ•°æ®åº“å¯¼è‡´æœªåŒæ­¥åˆ°å®šæ—¶ä»»åŠ¡å¤„ç†ï¼ˆæ³¨ï¼šä¸èƒ½æ‰‹åŠ¨ä¿®æ”¹æ•°æ®åº“ID和任务组名,否则会导致脏数据)
     */
    @PostConstruct
    public void init() throws SchedulerException, TaskException
    {
        scheduler.clear();
        List<SysJob> jobList = jobMapper.selectJobAll();
        for (SysJob job : jobList)
        {
            ScheduleUtils.createScheduleJob(scheduler, job);
//        scheduler.clear();
//        List<SysJob> jobList = jobMapper.selectJobAll();
//        for (SysJob job : jobList)
//        {
//            ScheduleUtils.createScheduleJob(scheduler, job);
//        }
        List<TimingTask> timingTasks = timingTaskMapper.selectList(null);
        for (TimingTask timingTask : timingTasks) {
            timingTaskScheduler.scheduleTimingTask(timingTask);
        }
    }