zoukankan      html  css  js  c++  java
  • SpringBoot整合quartz实现多个定时任务管理

    1.添加pom依赖

    <dependency>
    			<groupId>org.quartz-scheduler</groupId>
    			<artifactId>quartz</artifactId>
    			<version>2.3.0</version>
    			<!-- quartz默认使用c3p0连接池,如果项目使用的不是则需要排除依赖包 -->
    		    <exclusions>
    		        <exclusion>
    		            <artifactId>c3p0</artifactId>
    		            <groupId>c3p0</groupId>
    		        </exclusion>
    		    </exclusions>
    		</dependency>
    		
    		<dependency>
    		    <groupId>org.springframework</groupId>
    		    <artifactId>spring-context-support</artifactId>
    		</dependency>
    

      

    2.添加QuartzConfig配置类

    package one.stand.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    import java.util.Properties;
    
    /**
     * 定时任务配置
     *
     */
    @Configuration
    public class QuartzConfig {
    	//@Qualifier("druidDataSource") DataSource dataSource
            //DataSource 根据项目的数据源进行切换,我这里使用的是druidDataSource
        @Bean
        public SchedulerFactoryBean scheduler(DruidDataSource druidDataSource) {
    
            //quartz参数
            Properties prop = new Properties();
            //配置实例
            //prop.put("org.quartz.scheduler.instanceName", "MyScheduler");//实例名称
            prop.put("org.quartz.scheduler.instanceId", "AUTO");
            //线程池配置
            prop.put("org.quartz.threadPool.threadCount", "5");
            //JobStore配置
            prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
            prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
    
            SchedulerFactoryBean factory = new SchedulerFactoryBean();
            factory.setDataSource(druidDataSource);
            factory.setQuartzProperties(prop);
            factory.setSchedulerName("MyScheduler");//数据库中存储的名字
            //QuartzScheduler 延时启动,应用启动5秒后 QuartzScheduler 再启动
            factory.setStartupDelay(5);
    
            //factory.setApplicationContextSchedulerContextKey("applicationContextKey");
            //可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
            factory.setOverwriteExistingJobs(true);
            //设置自动启动,默认为true
            factory.setAutoStartup(true);
    
            return factory;
        }
    }
    

      

    3.quartz常量及工具类

    3.1 Constant常量类

    package one.stand.task;
    
    /**
     * 常量
     * 
     */
    public class Constant {
    	
    	/** 超级管理员ID */
    	public static final int SUPER_ADMIN = 1;
    
    	/**
    	 * 菜单类型
    	 * 
    	 */
        public enum MenuType {
            /**
             * 目录
             */
        	CATALOG(0),
            /**
             * 菜单
             */
            MENU(1),
            /**
             * 按钮
             */
            BUTTON(2);
    
            private int value;
    
            MenuType(int value) {
                this.value = value;
            }
    
            public int getValue() {
                return value;
            }
        }
        
        /**
         * 定时任务状态
         * 
         */
        public enum ScheduleStatus {
            /**
             * 正常
             */
        	NORMAL(0),
            /**
             * 暂停
             */
        	PAUSE(1);
    
            private int value;
    
            ScheduleStatus(int value) {
                this.value = value;
            }
            
            public int getValue() {
                return value;
            }
        }
    
        /**
         * 云服务商
         */
        public enum CloudService {
            /**
             * 七牛云
             */
            QINIU(1),
            /**
             * 阿里云
             */
            ALIYUN(2),
            /**
             * 腾讯云
             */
            QCLOUD(3);
    
            private int value;
    
            CloudService(int value) {
                this.value = value;
            }
    
            public int getValue() {
                return value;
            }
        }
    }
    

      

    3.2 SpringContextUtils工具类

    package one.stand.task.util;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    /**
     * SpringContext工具类
     * @author zgc
     *
     */
    @Component
    public class SpringContextUtils implements ApplicationContextAware{
    	private static ApplicationContext applicationContext;
    	/**
    	 * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
    	 */
    	public void setApplicationContext(ApplicationContext applicationContext) {
    		SpringContextUtils.applicationContext = applicationContext; // NOSONAR
    	}
     
    	/**
    	 * 取得存储在静态变量中的ApplicationContext.
    	 */
    	public static ApplicationContext getApplicationContext() {
    		checkApplicationContext();
    		return applicationContext;
    	}
    	
    	/**
    	 * 清除applicationContext静态变量.
    	 */
    	public static void cleanApplicationContext() {
    		applicationContext = null;
    	}
    	
    	private static void checkApplicationContext() {
    		if (applicationContext == null) {
    			throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
    		}
    	}
    	
    	/**
    	 * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
    	 */
    	@SuppressWarnings("unchecked")
    	public static <T> T getBean(String name) {
    		checkApplicationContext();
    		return (T) applicationContext.getBean(name);
    	}
     
    	/**
    	 * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
    	 */
    	@SuppressWarnings("unchecked")
    	public static <T> T getBean(Class<T> clazz) {
    		checkApplicationContext();
    		return (T) applicationContext.getBeansOfType(clazz);
    	}
    }
    

      

    3.3 SchedulerUtils工具类

    package one.stand.task.util;
    
    import com.alibaba.fastjson.JSON;
    
    import one.stand.entity.ScheduleJob;
    import one.stand.exception.RRException;
    import one.stand.task.QuartzJob;
    
    import org.quartz.*;
    
    /**
     * quartz任务工具类
     * @author zgc
     *
     */
    public class SchedulerUtils {
    
        /**
         * 创建任务
         * @throws RRException 
         */
        public static void createJob(Scheduler scheduler, ScheduleJob scheduleJob) throws RRException {
    
            try {
                Long jobId = scheduleJob.getJobId();
                //创建Job对象
                JobDetail job = JobBuilder.newJob(QuartzJob.class).withIdentity("JOB_" + jobId).build();
                //获取cron表达式 并创建对象
                CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing();
                //创建触发器
                CronTrigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity("TRIGGET_" + jobId)
                        .withSchedule(cronScheduleBuilder) //将cron表达式配置到触发器
                        .build();
    
                //将对象josn序列化存储到Job的getJobDataMap()方法中,为后续根据获取属性执行对应的类的任务
                job.getJobDataMap().put("JOB_PARAM_KEY", JSON.toJSONString(scheduleJob));
                //存数据
                scheduler.scheduleJob(job, trigger);
                scheduler.pauseJob(JobKey.jobKey("JOB_" + jobId));//使任务处于等待状态,创建后不会执行
            } catch (SchedulerException e) {
                throw new RRException("创建任务失败", e);
            }
        }
    
        /**
         * 更新任务
         * @throws RRException 
         */
        public static void updateJob(Scheduler scheduler, ScheduleJob scheduleJob) throws RRException {
            //获取新的cron表达式
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();
    
            Long jobId = scheduleJob.getJobId();
    
            try {
                //拿到原有的trigger
                TriggerKey triggerKey = TriggerKey.triggerKey("TRIGGER_" + jobId);
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                //为原有的trigger赋予新的cron表达式
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                        .withSchedule(cronScheduleBuilder).build();
                //执行原有的trigger更新
                scheduler.rescheduleJob(triggerKey, trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
                throw new RRException("更新定时任务失败", e);
            }
        }
    
        /**
         * 删除任务
         * @throws RRException 
         */
        public static void deleteJob(Scheduler scheduler, Long jobId) throws RRException {
            try {
                scheduler.deleteJob(JobKey.jobKey("JOB_" + jobId));
            } catch (SchedulerException e) {
                e.printStackTrace();
                throw new RRException("删除定时任务失败", e);
            }
        }
    
        /**
         * 恢复任务
         * @throws RRException 
         */
        public static void resumeJob(Scheduler scheduler, Long jobId) throws RRException {
            try {
                scheduler.resumeJob(JobKey.jobKey("JOB_" + jobId));
            } catch (SchedulerException e) {
                e.printStackTrace();
                throw new RRException("恢复定时任务失败", e);
            }
        }
    
        /**
         * 立即执行定时任务
         * @throws RRException 
         */
        public static void run(Scheduler scheduler, Long jobId) throws RRException {
            try {
                //只执行一次并且不会改变任务的状态
                scheduler.triggerJob(JobKey.jobKey("JOB_" + jobId));
            } catch (SchedulerException e) {
                e.printStackTrace();
                throw new RRException("立即执行定时任务失败", e);
            }
        }
    
        /**
         * 暂停任务
         *
         * @param scheduler
         * @param jobId
         * @throws RRException 
         */
        public static void pauseJob(Scheduler scheduler, Long jobId) throws RRException {
            try {
                scheduler.pauseJob(JobKey.jobKey("JOB_" + jobId));
            } catch (SchedulerException e) {
                e.printStackTrace();
                throw new RRException("暂停定时任务失败", e);
            }
        }
        
        public static void main(String[] args) {
        	System.out.println(org.quartz.CronExpression.isValidExpression("*/5 * * * * ?"));
    	}
    }
    

      

    3.4 CronUtils工具类

    package one.stand.task.util;
    
    import java.text.ParsePosition;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Objects;
    
    /**
     * cron表达式生成工具类
     * @author zgc
     *
     */
    public class CronUtils {
    	
    	private static final SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
    
        /***
         *  功能描述:日期转换cron表达式
         * @param date
         * @return
         */
        public static String formatDateByPattern(Date date) {
            String formatTimeStr = null;
            if (Objects.nonNull(date)) {
                formatTimeStr = sdf.format(date);
            }
            return formatTimeStr;
        }
    
        /***
         * convert Date to cron, eg "0 07 10 15 1 ? 2016"
         * @param date  : 时间点
         * @return
         */
        public static String getCron(Date date) {
            return formatDateByPattern(date);
        }
        
        /**
         * 将长时间格式字符串转换为时间 yyyy-MM-dd HH:mm:ss
         *
         * @param strDate
         * @return
         */
    	 public static Date strToDateLong(String strDate) {
    	     SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    	     ParsePosition pos = new ParsePosition(0);
    	     Date strtodate = formatter.parse(strDate, pos);
    	     return strtodate;
    	  }
        
    	/**
    	 * 根据时间字符串生成cron表达式
    	 * @param dateStr
    	 * @return
    	 */
    	public static String getCronByDateStr(String dateStr) {
    		Date date = strToDateLong(dateStr);
    		return getCron(date);
    	}
    	
    	public static void main(String[] args) {
    		System.out.println(getCronByDateStr("2021-09-24 15:10:06"));
    	}
    	
    }
    

      

    4.quartz任务及任务日志实体(sql文件见文末附件)

    4.1 ScheduleJob实体类

    package one.stand.entity;
    
    import java.io.Serializable;
    import java.util.Date;
    
    import lombok.Data;
    
    @Data
    public class ScheduleJob implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private Long jobId;
        
        private Integer taskId;
    
        private String beanName; //执行的类名
    
        private String methodName; //方法名
    
        private String params; //参数
    
        private String cronExpression; //cron表达式
    
        private Integer status; //任务状态 0,运行 1,暂停
    
        private String remark; //备注
    
        private Date createTime; //创建时间
    }
    

      

    4.2 ScheduleJobLog实体类

    package one.stand.entity;
    
    import java.util.Date;
    
    import lombok.Data;
    
    @Data
    public class ScheduleJobLog {
    	//日志ID字符串,逗号间隔
        private Long logId;
        //日志ID字符串,逗号间隔
        private String logIds;
        //任务ID
        private Long jobId;
        //spring bean名称
        private String beanName;
        //方法名
        private String methodName;
        //参数
        private String params;
        //失败信息
        private String error;
        //状态;0=正常,1=暂停
        private Integer status;
        //耗时(单位:毫秒)
        private Long times;
        //开始时间
        private transient String beginTime;
        //结束时间
        private transient String endTime;
        //创建时间
        private Date createTime;
    }
    

      

    5.quartz任务及任务日志Mapper(未使用mybatis可跳过)

    5.1 ScheduleJobMapper.xml

    <?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="one.stand.mapper.ScheduleJobMapper">
        <resultMap id="BaseResultMap" type="one.stand.entity.ScheduleJob">
            <id column="job_id" jdbcType="BIGINT" property="jobId"/>
            <result column="task_id" jdbcType="INTEGER" property="taskId"/>
            <result column="bean_name" jdbcType="VARCHAR" property="beanName"/>
            <result column="method_name" jdbcType="VARCHAR" property="methodName"/>
            <result column="params" jdbcType="VARCHAR" property="params"/>
            <result column="cron_expression" jdbcType="VARCHAR" property="cronExpression"/>
            <result column="status" jdbcType="INTEGER" property="status"/>
            <result column="remark" jdbcType="VARCHAR" property="remark"/>
            <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        </resultMap>
        <sql id="Base_Column_List">
        	`job_id`, `task_id`, `bean_name`, `method_name`, `params`, `cron_expression`, `status`, `remark`, `create_time`
        </sql>
        <sql id="where">
        	<if test="taskId != null">
                and task_id = #{taskId}
            </if>
            <if test="beanName != null">
                and bean_name = #{beanName}
            </if>
            <if test="methodName != null">
                and method_name = #{methodName}
            </if>
            <if test="status != null">
                and status = #{status}
            </if>
        </sql>
        <select id="selectList" parameterType="one.stand.entity.ScheduleJob" resultMap="BaseResultMap">
            select
            <include refid="Base_Column_List"/>
            from schedule_job
           <where>
               <include refid="where"/>
           </where>
        </select>
        <insert id="insertSelective" parameterType="one.stand.entity.ScheduleJob" keyProperty="jobId" useGeneratedKeys="true">
            insert into schedule_job
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="jobId != null">
                    job_id,
                </if>
                <if test="taskId != null">
                    task_id,
                </if>
                <if test="beanName != null" >
    		    	bean_name,
    		    </if>
    		    <if test="methodName != null" >
    		    	method_name,
    		    </if>
    		    <if test="params != null" >
    		    	params,
    		    </if>
    		    <if test="cronExpression != null" >
    		    	cron_expression,
    		    </if>
    		    <if test="status != null" >
    		    	status,
    		    </if>
    		    <if test="remark != null" >
    		    	remark,
    		    </if>
    		    <if test="createTime != null" >
    		    	create_time,
    		    </if>
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="jobId != null">
                    #{jobId,jdbcType=BIGINT},
                </if>
                <if test="taskId != null">
                    #{taskId,jdbcType=INTEGER},
                </if>
                <if test="beanName != null" >
    		    	#{beanName,jdbcType=VARCHAR},
    		    </if>
                <if test="methodName != null" >
    		    	#{methodName,jdbcType=VARCHAR},
    		    </if>
    		    <if test="params != null" >
    		    	#{params,jdbcType=VARCHAR},
    		    </if>
    		    <if test="cronExpression != null" >
    		    	#{cronExpression,jdbcType=VARCHAR},
    		    </if>
    		    <if test="status != null" >
    		    	#{status,jdbcType=INTEGER},
    		    </if>
    		    <if test="remark != null" >
    		    	#{remark,jdbcType=VARCHAR},
    		    </if>
    		    <if test="createTime != null" >
    		    	#{createTime,jdbcType=TIMESTAMP},
    		    </if>
            </trim>
        </insert>
        <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
    		select
    	    	<include refid="Base_Column_List" />
    		from schedule_job
    		where job_id = #{jobId,jdbcType=BIGINT}
    	</select>
    
    	<update id="updateByPrimaryKeySelective" parameterType="one.stand.entity.ScheduleJob" >
    		update schedule_job
    		<set>
    		    <if test="beanName != null" >
    		    	bean_name = #{beanName,jdbcType=VARCHAR},
    		    </if>
    		    <if test="methodName != null" >
    		    	method_name = #{methodName,jdbcType=VARCHAR},
    		    </if>
    		    <if test="params != null" >
    		    	params = #{params,jdbcType=VARCHAR},
    		    </if>
    		    <if test="cronExpression != null" >
    		    	cron_expression = #{cronExpression,jdbcType=VARCHAR},
    		    </if>
    		    <if test="status != null" >
    		    	status = #{status,jdbcType=INTEGER},
    		    </if>
    		    <if test="remark != null" >
    		    	remark = #{remark,jdbcType=VARCHAR},
    		    </if>
    		    <if test="createTime != null" >
    		    	create_time = #{createTime,jdbcType=TIMESTAMP},
    		    </if>
    		</set>
    		where job_id = #{jobId,jdbcType=BIGINT}
    	</update>
    	<!-- 批量删除任务记录 -->
    	<delete id="deleteBatch">
    	    delete from schedule_job where job_id in
    	    <foreach collection="array" item="jobId" open="(" separator="," close=")">
    	        #{jobId}
    	    </foreach>
    	</delete>
    	<!-- 批量更新状态 -->
    	<update id="updateBatch">
    	    update schedule_job set status = #{status} where job_id in
    	    <foreach collection="list" item="jobId" open="(" separator="," close=")">
    	        #{jobId}
    	    </foreach>
    	</update>
    </mapper>
    

      

    5.2 ScheduleJobLogMapper.xml

    <?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="one.stand.mapper.ScheduleJobLogMapper">
        <resultMap id="BaseResultMap" type="one.stand.entity.ScheduleJobLog">
            <id column="log_id" jdbcType="BIGINT" property="logId"/>
            <result column="job_id" jdbcType="BIGINT" property="jobId"/>
            <result column="bean_name" jdbcType="VARCHAR" property="beanName"/>
            <result column="method_name" jdbcType="VARCHAR" property="methodName"/>
            <result column="params" jdbcType="VARCHAR" property="params"/>
            <result column="error" jdbcType="VARCHAR" property="error"/>
            <result column="status" jdbcType="INTEGER" property="status"/>
            <result column="times" jdbcType="BIGINT" property="times"/>
            <result column="begin_time" jdbcType="VARCHAR" property="beginTime"/>
            <result column="end_time" jdbcType="VARCHAR" property="endTime"/>
            <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        </resultMap>
        <sql id="Base_Column_List">
        	`log_id`, `job_id`, `bean_name`, `method_name`, `params`, `error`, `status`, `times`, `begin_time`, `end_time`, `create_time`
        </sql>
        <sql id="where">
            <if test="status != null">
                and status = #{status}
            </if>
        </sql>
        <select id="selectList" parameterType="one.stand.entity.ScheduleJobLog" resultMap="BaseResultMap">
            select
            <include refid="Base_Column_List"/>
            from schedule_job_log
           <where>
               <include refid="where"/>
           </where>
        </select>
        <insert id="save" parameterType="one.stand.entity.ScheduleJobLog">
            insert into schedule_job_log
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="logId != null">
                    log_id,
                </if>
                <if test="jobId != null">
                    job_id,
                </if>
                <if test="beanName != null" >
    		    	bean_name,
    		    </if>
    		    <if test="methodName != null" >
    		    	method_name,
    		    </if>
    		    <if test="params != null" >
    		    	params,
    		    </if>
    		    <if test="error != null" >
    		    	error,
    		    </if>
    		    <if test="status != null" >
    		    	status,
    		    </if>
    		    <if test="times != null" >
    		    	times,
    		    </if>
    		    <if test="beginTime != null" >
    		    	begin_timme,
    		    </if>
    		    <if test="endTime != null" >
    		    	end_timme,
    		    </if>
    		    <if test="createTime != null" >
    		    	create_time,
    		    </if>
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="logId != null">
                    #{logId,jdbcType=BIGINT},
                </if>
                <if test="jobId != null">
                    #{jobId,jdbcType=BIGINT},
                </if>
                <if test="beanName != null" >
    		    	#{beanName,jdbcType=VARCHAR},
    		    </if>
                <if test="methodName != null" >
    		    	#{methodName,jdbcType=VARCHAR},
    		    </if>
    		    <if test="params != null" >
    		    	#{params,jdbcType=VARCHAR},
    		    </if>
    		    <if test="error != null" >
    		    	#{error,jdbcType=VARCHAR},
    		    </if>
    		    <if test="status != null" >
    		    	#{status,jdbcType=INTEGER},
    		    </if>
    		    <if test="times != null" >
    		    	#{times,jdbcType=BIGINT},
    		    </if>
    		    <if test="beginTime != null" >
    		    	#{beginTime,jdbcType=VARCHAR},
    		    </if>
    		    <if test="endTime != null" >
    		    	#{endTime,jdbcType=VARCHAR},
    		    </if>
    		    <if test="createTime != null" >
    		    	#{createTime,jdbcType=TIMESTAMP},
    		    </if>
            </trim>
        </insert>
        <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
    		select
    	    	<include refid="Base_Column_List" />
    		from schedule_job_log
    		where log_id = #{logId,jdbcType=BIGINT}
    	</select>
    
    	<update id="updateByPrimaryKey" parameterType="one.stand.entity.ScheduleJobLog" >
    		update schedule_job_log
    		<set>
    		    <if test="beanName != null" >
    		    	bean_name = #{beanName,jdbcType=VARCHAR},
    		    </if>
    		    <if test="methodName != null" >
    		    	method_name = #{methodName,jdbcType=VARCHAR},
    		    </if>
    		    <if test="params != null" >
    		    	params = #{params,jdbcType=VARCHAR},
    		    </if>
    		    <if test="status != null" >
    		    	status = #{status,jdbcType=INTEGER},
    		    </if>
    		    <if test="createTime != null" >
    		    	create_time = #{createTime,jdbcType=TIMESTAMP},
    		    </if>
    		</set>
    		where log_id = #{logId,jdbcType=BIGINT}
    	</update>
    	<!-- 批量删除记录 -->
    	<delete id="deleteBatch">
    	    delete from schedule_job_log where log_id in
    	    <foreach collection="logIds" item="logId" open="(" separator="," close=")">
    	        #{logId}
    	    </foreach>
    	</delete>
    </mapper>
    

      

    6.quartz任务及任务日志接口

    6.1 ScheduleJobService.java

    package one.stand.service.task;
    
    import java.util.Map;
    
    import one.stand.entity.ScheduleJob;
    import one.stand.model.ResultModel;
    import one.stand.request.ScheduleJobRequest;
    
    public interface ScheduleJobService {
    	/**
    	 * 查询定时任务列表
    	 * @param scheduleJobLog
    	 * @return
    	 */
    	ResultModel<Map<String, Object>> selectList(ScheduleJobRequest request);
    	/**
    	* 接口:保存定时任务
    	*/
    	ResultModel<Boolean> save(ScheduleJob scheduleJob);
    	/**
    	 * 查询定时任务
    	 * @param jobId
    	 * @return
    	 */
    	ResultModel<ScheduleJob> queryObject(Long jobId);
    	/**
    	 * 修改定时任务
    	 * @param scheduleJob
    	 * @return
    	 */
    	ResultModel<Boolean> update(ScheduleJob scheduleJob);
    	/**
    	 * 删除定时任务
    	 * @param jobIds
    	 * @return
    	 */
    	ResultModel<Boolean> deleteBatch(Long[] jobIds);
    	/**
    	 * 暂停定时任务
    	 * @param jobIds
    	 * @return
    	 */
    	ResultModel<Boolean> pause(Long[] jobIds);
    	/**
    	 * 恢复定时任务
    	 * @param jobIds
    	 * @return
    	 */
    	ResultModel<Boolean> resume(Long[] jobIds);
    	/**
    	 * 立即执行定时任务
    	 * @param jobIds
    	 * @return
    	 */
    	ResultModel<Boolean> run(Long[] jobIds);
    }
    

      

    6.2 ScheduleJobLogService.java

    package one.stand.service.task;
    
    import java.util.Map;
    
    import one.stand.entity.ScheduleJobLog;
    import one.stand.request.ScheduleJobLogRequest;
    
    public interface ScheduleJobLogService {
    	/**
    	 * 保存任务执行日志
    	 * @param scheduleJobLog
    	 */
    	void save(ScheduleJobLog scheduleJobLog);
    	/**
    	 * 查询任务执行日志列表
    	 * @param scheduleJobLog
    	 * @return
    	 */
    	Map<String, Object> selectList(ScheduleJobLogRequest request);
    	/**
    	 * 查询任务执行日志信息
    	 * @param logId
    	 * @return
    	 */
    	ScheduleJobLog selectByPrimaryKey(Long logId);
    	/**
    	 * 更新执行任务日志信息
    	 * @param scheduleJobLog
    	 */
    	void updateByPrimaryKey(ScheduleJobLog scheduleJobLog);
    	/**
    	 * 批量删除任务日志信息
    	 * @param logIds
    	 */
    	void deleteBatch(Long[] logIds);
    	
    }
    

      

    6.3 QuartzJob.java(quartz定时任务执行类)

    package one.stand.task;
    
    import com.alibaba.fastjson.JSON;
    
    import one.stand.entity.ScheduleJob;
    import one.stand.entity.ScheduleJobLog;
    import one.stand.service.task.ScheduleJobLogService;
    import one.stand.task.util.SpringContextUtils;
    import one.stand.util.DateUtil;
    
    import org.apache.commons.lang.StringUtils;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    import org.springframework.util.ReflectionUtils;
    
    import java.lang.reflect.Method;
    import java.util.Date;
    
    /**
     * quartz任务执行
     * @author zgc
     *
     */
    public class QuartzJob extends QuartzJobBean {
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            System.out.println("执行quartz任务。。。。。");
    
            String json = context.getMergedJobDataMap().getString("JOB_PARAM_KEY");
            //将获取的对象序列化的json 转化为实体类对象
            ScheduleJob scheduleJob = JSON.parseObject(json, ScheduleJob.class);
    
            Long jobId = scheduleJob.getJobId();
            String beanName = scheduleJob.getBeanName();
            String methodName = scheduleJob.getMethodName();
            String params = scheduleJob.getParams();
    
            //quartz没有被spring管理 所以通过其它方式获取service
            ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService) SpringContextUtils.getBean("scheduleJobLogServiceImpl");
            //保存任务记录日志
            ScheduleJobLog scheduleJobLog = new ScheduleJobLog();
            scheduleJobLog.setJobId(jobId);
            scheduleJobLog.setBeanName(beanName);
            scheduleJobLog.setMethodName(methodName);
            scheduleJobLog.setParams(params);
            scheduleJobLog.setCreateTime(new Date());
            scheduleJobLog.setBeginTime(DateUtil.getNow());
    
            long startTime = System.currentTimeMillis();
    
            try {
                Object targetClass = SpringContextUtils.getBean(beanName);
                Method method = null;
                //通过反射获取方法
                if (StringUtils.isNotBlank(params)) {
                    method = targetClass.getClass().getDeclaredMethod(methodName, String.class);
                } else {
                    method = targetClass.getClass().getDeclaredMethod(methodName);
                }
    
                ReflectionUtils.makeAccessible(method);//使方法具有public权限
                //根据反射执行方法
                if (StringUtils.isNotBlank(params)) {
                    method.invoke(targetClass, params);
                } else {
                    method.invoke(targetClass);
                }
    
                long endTime = System.currentTimeMillis() - startTime;
                scheduleJobLog.setEndTime(DateUtil.getNow());
                scheduleJobLog.setStatus(0);//保存日志里的操作状态 0:成功
                scheduleJobLog.setTimes(endTime);//耗时多长时间
    
                logger.info("任务执行成功,任务ID:" + jobId + ",总耗时:" + endTime + "毫秒");
    
            } catch (Exception e) {
                long endTime = System.currentTimeMillis() - startTime;
                scheduleJobLog.setEndTime(DateUtil.getNow());
                scheduleJobLog.setError(StringUtils.substring(e.toString(),2000));//错误消息
                scheduleJobLog.setStatus(1);//失败
                scheduleJobLog.setTimes(endTime);//耗时
    
                e.printStackTrace();
                logger.error("任务执行失败,任务ID:"+jobId);
            } finally {
                //最后调用service保存定时任务日志记录
                scheduleJobLogService.save(scheduleJobLog);
            }
    
        }
    
    }
    

      

    7.quartz任务及任务日志接口实现类

    7.2 ScheduleJobServiceImpl.java

    package one.stand.service.task.impl;
    
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.quartz.Scheduler;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.github.pagehelper.Page;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    
    import one.stand.entity.ScheduleJob;
    import one.stand.exception.RRException;
    import one.stand.mapper.ScheduleJobMapper;
    import one.stand.model.ResultModel;
    import one.stand.request.ScheduleJobRequest;
    import one.stand.service.task.ScheduleJobService;
    import one.stand.task.Constant;
    import one.stand.task.util.SchedulerUtils;
    
    @SuppressWarnings("unchecked")
    @Service
    public class ScheduleJobServiceImpl implements ScheduleJobService{
    
    	@Autowired
    	private ScheduleJobMapper scheduleJobMapper;
    	
    	@Autowired
    	private Scheduler scheduler;
    	
    	@Override
    	@Transactional(propagation = Propagation.REQUIRED)
    	public ResultModel<Boolean> save(ScheduleJob scheduleJob) {
    	    //保存实体类的信息
    	    scheduleJob.setCreateTime(new Date());
    	    scheduleJob.setStatus(Constant.ScheduleStatus.PAUSE.getValue());
    	    scheduleJobMapper.insertSelective(scheduleJob);
    
    	    //创建定时任务 并保存到对应的quatrz表中
    	    try {
    			SchedulerUtils.createJob(scheduler, scheduleJob);
    		} catch (RRException e) {
    			e.printStackTrace();
    			return ResultModel.success(false);
    		}
    	    return ResultModel.success(true);
    	}
    
    	@Override
    	public ResultModel<ScheduleJob> queryObject(Long jobId) {
    		return ResultModel.success(scheduleJobMapper.selectByPrimaryKey(jobId));
    	}
    
    	@Override
    	public ResultModel<Boolean> update(ScheduleJob scheduleJob) {
    		try {
    			SchedulerUtils.updateJob(scheduler, scheduleJob);
    		} catch (RRException e) {
    			e.printStackTrace();
    			return ResultModel.success(false);
    		}
    	    scheduleJobMapper.updateByPrimaryKeySelective(scheduleJob);
    	    return ResultModel.success(true);
    	}
    
    	@Override
    	public ResultModel<Boolean> deleteBatch(Long[] jobIds) {
    		for(Long jobId : jobIds){
    	        try {
    				SchedulerUtils.deleteJob(scheduler, jobId);
    			} catch (RRException e) {
    				e.printStackTrace();
    				return ResultModel.success(false);
    			}
    	    }
    	    //删除数据
    	    scheduleJobMapper.deleteBatch(jobIds);
    	    return ResultModel.success(true);
    	}
    
    	@Override
    	@Transactional(propagation = Propagation.REQUIRED)
    	public ResultModel<Boolean> pause(Long[] jobIds) {
    		for(Long jobId : jobIds){
    	        try {
    				SchedulerUtils.pauseJob(scheduler, jobId);
    			} catch (RRException e) {
    				e.printStackTrace();
    				return ResultModel.success(false);
    			}
    	    }
    	    Map<String, Object> map = new HashMap<>();
    	    map.put("list", jobIds);
    	    map.put("status", Constant.ScheduleStatus.PAUSE.getValue());
    	    scheduleJobMapper.updateBatch(map);
    	    return ResultModel.success(true);
    	}
    
    	@Override
    	@Transactional(propagation = Propagation.REQUIRED)
    	public ResultModel<Boolean> resume(Long[] jobIds) {
    		for(Long jobId : jobIds){
    	        try {
    				SchedulerUtils.resumeJob(scheduler, jobId);
    			} catch (RRException e) {
    				e.printStackTrace();
    				return ResultModel.success(false);
    			}
    	    }
    	    Map<String, Object> map = new HashMap<>();
    	    map.put("list", jobIds);
    	    map.put("status", Constant.ScheduleStatus.NORMAL.getValue());
    	    scheduleJobMapper.updateBatch(map);
    	    return ResultModel.success(true);
    	}
    
    	@Override
    	@Transactional(propagation = Propagation.REQUIRED)
    	public ResultModel<Boolean> run(Long[] jobIds) {
    		for(Long jobId : jobIds){
    	        try {
    				SchedulerUtils.run(scheduler, jobId);
    			} catch (RRException e) {
    				e.printStackTrace();
    				return ResultModel.success(false);
    			}
    	    }
    		return ResultModel.success(true);
    	}
    
    	@SuppressWarnings({ "rawtypes", "resource" })
    	@Override
    	public ResultModel<Map<String, Object>> selectList(ScheduleJobRequest request) {
    		ScheduleJob model = new ScheduleJob();
            if (request != null) {
                BeanUtils.copyProperties(request, model);
            }
            PageHelper.startPage(request.getPageNum(), request.getPageSize());
            List<ScheduleJob> list = scheduleJobMapper.selectList(model);
            if (list == null || list.size() <= 0) {
            	return ResultModel.noData();
            }
            PageInfo<ScheduleJob> pageInfo = new PageInfo<>(list);
            Map<String, Object> map = new HashMap<>(1);
            Page page = (Page) list;
            pageInfo.setTotal(page.getTotal());
            map.put("pageInfo", pageInfo);
            return ResultModel.success(map);
    	}
    
    }
    

      

    7.2 ScheduleJobLogServiceImpl.java

    package one.stand.service.task.impl;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.github.pagehelper.Page;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    
    import one.stand.entity.ScheduleJobLog;
    import one.stand.mapper.ScheduleJobLogMapper;
    import one.stand.request.ScheduleJobLogRequest;
    import one.stand.service.task.ScheduleJobLogService;
    
    @Service
    public class ScheduleJobLogServiceImpl implements ScheduleJobLogService{
    
    	@Autowired
    	private ScheduleJobLogMapper scheduleJobLogMapper;
    	
    	@Override
    	@Transactional(propagation = Propagation.REQUIRED)
    	public void save(ScheduleJobLog scheduleJobLog) {
    		scheduleJobLogMapper.save(scheduleJobLog);
    	}
    
    	@SuppressWarnings({ "rawtypes", "resource" })
    	@Override
    	public Map<String, Object> selectList(ScheduleJobLogRequest request) {
    		ScheduleJobLog model = new ScheduleJobLog();
            if (request != null) {
                BeanUtils.copyProperties(request, model);
            }
            PageHelper.startPage(request.getPageNum(), request.getPageSize());
            List<ScheduleJobLog> list = scheduleJobLogMapper.selectList(model);
            if (list == null || list.size() <= 0) {
                return null;
            }
            PageInfo<ScheduleJobLog> pageInfo = new PageInfo<>(list);
            Map<String, Object> map = new HashMap<>(1);
            Page page = (Page) list;
            pageInfo.setTotal(page.getTotal());
            map.put("pageInfo", pageInfo);
            return map;
    	}
    
    	@Override
    	public ScheduleJobLog selectByPrimaryKey(Long logId) {
    		return scheduleJobLogMapper.selectByPrimaryKey(logId);
    	}
    
    	@Override
    	public void updateByPrimaryKey(ScheduleJobLog scheduleJobLog) {
    		scheduleJobLogMapper.updateByPrimaryKey(scheduleJobLog);
    	}
    
    	@Override
    	public void deleteBatch(Long[] logIds) {
    		scheduleJobLogMapper.deleteBatch(logIds);
    	}
    
    }
    

      

    8.TaskController(Web接口)

    package one.stand.controller.task;
    
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
    import com.github.xiaoymin.knife4j.annotations.ApiSort;
    
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiOperation;
    import one.stand.entity.ScheduleJob;
    import one.stand.model.ResultModel;
    import one.stand.request.ScheduleJobLogRequest;
    import one.stand.request.ScheduleJobRequest;
    import one.stand.service.task.ScheduleJobLogService;
    import one.stand.service.task.ScheduleJobService;
    
    @Api(value = "task-定时任务",tags = "Auction-定时任务")
    @ApiSort(3)
    @RestController
    @RequestMapping("task")
    public class TaskController {
    	
    	@Autowired
    	private ScheduleJobService scheduleJobService;
    	@Autowired
    	private ScheduleJobLogService scheduleJobLogService;
    	
    	/**
         * 查询定时任务列表
         *
         * @param request
         * @return
         */
    	@ApiOperation("查询定时任务列表")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="ScheduleJobRequest",paramType="body")
    	@PostMapping("selectList")
        public ResultModel<Map<String, Object>> selectList(@RequestBody ScheduleJobRequest request) {
            return scheduleJobService.selectList(request);
        }
    	/**
    	* 保存定时任务
    	*/
    	@ApiOperation("保存定时任务")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="ScheduleJob",paramType="body")
    	@PostMapping("save")
    	public ResultModel<Boolean> save(@RequestBody ScheduleJob scheduleJob){
    		return scheduleJobService.save(scheduleJob);
    	}
    	
    	/**
    	* 定时任务信息
    	*/
    	@ApiOperation("查询定时任务信息")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="Long",paramType="query")
    	@GetMapping("info/{jobId}")
    	public ResultModel<ScheduleJob> info(@PathVariable("jobId") Long jobId){
    	    return scheduleJobService.queryObject(jobId);
    	}
    
    	/**
    	* 修改定时任务
    	*/
    	@ApiOperation("修改定时任务")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="ScheduleJob",paramType="body")
    	@PostMapping("update")
    	public ResultModel<Boolean> update(@RequestBody ScheduleJob scheduleJob){
    		return scheduleJobService.update(scheduleJob);
    	}
    	
    	/**
    	 * 删除定时任务
    	 */
    	@ApiOperation("删除定时任务")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="Long[]",paramType="body")
    	@PostMapping("del")
    	public ResultModel<Boolean> delete(@RequestBody Long[] jobIds){
    	    return scheduleJobService.deleteBatch(jobIds);
    	}
    	
    	/**
    	 * 暂停定时任务
    	 */
    	@ApiOperation("暂停定时任务")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="Long[]",paramType="body")
    	@PostMapping("pause")
    	public ResultModel<Boolean> pause(@RequestBody Long[] jobIds){
    	    return scheduleJobService.pause(jobIds);
    	}
    	
    	/**
    	 * 恢复定时任务
    	 */
    	@ApiOperation("恢复定时任务")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="Long[]",paramType="body")
    	@PostMapping("resume")
    	public ResultModel<Boolean> resume(@RequestBody Long[] jobIds){
    		return scheduleJobService.resume(jobIds);
    	}
    	
    	/**
    	 * 立即执行定时任务
    	 */
    	@ApiOperation("立即执行定时任务")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="Long[]",paramType="body")
    	@PostMapping("run")
    	public ResultModel<Boolean> run(@RequestBody Long[] jobIds){
    	    return scheduleJobService.run(jobIds);
    	}
    	
    	/**
         * 查询定时任务日志列表
         *
         * @param request
         * @return
         */
    	@SuppressWarnings("unchecked")
    	@ApiOperation("查询定时任务日志列表")
    	@ApiOperationSupport(order=1, author="zgc")
    	@ApiImplicitParam(name = "请求参数", value = "request", required = true, dataType="ScheduleJobLogRequest",paramType="body")
    	@PostMapping("log/selectList")
        public ResultModel<Map<String, Object>> logSelectList(@RequestBody ScheduleJobLogRequest request) {
            return ResultModel.success(scheduleJobLogService.selectList(request));
        }
    }
    

      

    9.RyTask(测试定时任务类)

    package one.stand.service.task;
    
    import org.springframework.stereotype.Component;
    
    /**
     * 定时任务调度测试
     * 
     */
    @Component("ryTask")
    public class RyTask {
        public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i){
            System.out.println("执行多参方法:");
        }
    
        public void ryParams(String param){
            System.out.println("执行有参方法:" + param);
        }
    
        public void ryNoParams(){
            System.out.println("执行无参方法");
        }
        
    }
    

      

    测试定时任务说明:

    (1)beanName为@Component("ryTask")中的ryTask,methodName为对应的方法名,例如:ryParams.实际处理定时任务在上面的定时任务类中处理.

    (2)添加定时任务时,如果quartz报错,请检查是否是定时任务开始时间或结束时间不可达,即输入了一个已经过去的时间.

    10.SQL文件(schedule_jobschedule_job_logquartz相关表)

    下载链接:https://files.cnblogs.com/files/mituxiaogaoyang/quartz.zip

  • 相关阅读:
    Simple Microservices Architecture on AWS
    信封加密 Envelope
    AWS::Serverless::Application
    API Gateway Stage variables
    重新开始继续准备AWS Dev认证考试:AWS Lambda 环境变量
    MXnet 转 OpenVino,在树莓派上做的图片推理
    OpenVino的MXnet模型转换
    Grafana 6.3.3发布 系统指标监控与分析平台
    【小工具】鼠标右键 图片转文字
    【Shiro】Shiro登录验证失败问题
  • 原文地址:https://www.cnblogs.com/mituxiaogaoyang/p/15338652.html
Copyright © 2011-2022 走看看