主要是想实现这个功能,用户注册时,自定义开始时间(date)和时长(time),当开始时间(date)一到,将用户的status从0变为1,当开始时间(date)+时长(time)一到即结束时间(date),将用户的status从1变为2。如下图所示
注册用户,输入自定义的开始日期,以及时长
当时间到达开始时间,将用户状态变为1
当时间到达结束时间,将用户状态变为2
一、 Quartz 的4个核心概念
1. Job 表示一个工作,要执行的具体内容。此接口中只有一个方法,如下
execute(JobExecutionContext context)
2. JobDetail 表示一个具体的可执行的调度程序,Job是这个可执行程调度程序索要执行的内容,另外JobDetail还包含了这个任务调度的方 案和策略。
3. Trigger 代表一个调度参数的配置,什么时候去调。
4. Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器 调度了。
二、项目目录结构
三、pom.xml 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.xej</groupId>
<artifactId>springboot-quartz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-quartz</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
四、在数据库中运行,创建11张qrtz表
CREATE TABLE QRTZ_JOB_DETAILS
(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(200) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CALENDARS
(
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
五、添加quartz.properties文件(我是存放在resources下)
#=======================================================
#调度器配置
#=======================================================
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=project1QuartzScheduler
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
#=======================================================
#线程池配置
#=======================================================
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=5
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
#=======================================================
#JobStore配置
#=======================================================
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.isClustered=false
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dataSource=myDS
#=======================================================
#数据库配置
#=======================================================
org.quartz.dataSource.myDS.driver= com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL= jdbc:mysql:///db_quartz?characterEncoding=utf8&serverTimezone=UTC
org.quartz.dataSource.myDS.user= root
org.quartz.dataSource.myDS.password=123456
org.quartz.dataSource.myDS.maxConnections=5
六、自定义JobFactory
原因
因为定时任务Job对象的实例化过程是在Quartz中进行的,QuartzService Bean是由Spring容器管理的,Quartz根本察觉不 到QuartzService Bean的存在,所以无法将 QuartzService Bean装配到Job对象中
Job对象的实例化,是由SchedulerFactoryBean使用AdaptableJobFactory创建的,如果未指定,会自动创建
解决步骤
将Job Bean也加入Spring 容器管理之中,Spring容器能够为Job Bean自动装配好所需的依赖,因此需要重写JobFactory,然后 创建SchedulerFactoryBean,并指定创建Job实例为自定义的JobFactory工厂
1. 创建一个自定义的JobFactory,使用Spring容器管理的Quartz的Bean(Job)
创建一个MyJobFactory 类,@Component,表示该类是由Spring管理的一个组件
package cn.xej.config;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
/**
* 创建Job实例
*/
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 实例化对象
Object jobInstance = super.createJobInstance(bundle);
// 进行注入(Spring管理该Bean)
capableBeanFactory.autowireBean(jobInstance);
// 返回对象
return jobInstance;
}
}
2. 创建一个SchedulerFactoryBean 实例,并将其Job实例化的工厂指定为一个Spring容器中的自定义MyJobFactory实例,创建 一个SchedulerConfig 配 置类
package cn.xej.config;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@Configuration // 表示该类是 配置类
public class SchedulerConfig {
@Autowired
private MyJobFactory myJobFactory; //一个由Spring管理的自定义创建Job实例的工厂
/**
* 配置SchedulerFactoryBean //创建一个SchedulerFactoryBean 实例
*/
@Bean // 将一个方法产生为Bean并交给Spring容器管理
public SchedulerFactoryBean schedulerFactoryBean(){
// Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
// 延时启动(秒)
schedulerFactoryBean.setStartupDelay(1);
// 设置quartz的配置文件
schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
// 设置自定义Job Factory,用于Spring管理Job Bean
schedulerFactoryBean.setJobFactory(myJobFactory);
return schedulerFactoryBean;
}
@Bean
public Scheduler scheduler(){
// 创建一个调度容器,并由Spring管理
return schedulerFactoryBean().getScheduler();
}
}
七、 编写定时任务(1个开始,1个结束)
1. 创建一个开始任务StartUserJob
package cn.xej.job;
import cn.xej.service.UserService;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class StartUserJob extends QuartzJobBean {
@Autowired
private UserService userService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("开始将用户status改为1");
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
String userId = (String) jobDataMap.get("userId");
Integer time = (Integer) jobDataMap.get("time");
String date = (String) jobDataMap.get("date");
System.out.println("用户注册开始id: "+userId+" 时长: "+time+" 开始日期: "+date);
// 写自己的方法
userService.startUpdateUserStatus(userId,time,date);
}
}
2. 创建一个结束任务CloseUserJob
package cn.xej.job;
import cn.xej.service.UserService;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class CloseUserJob extends QuartzJobBean {
@Autowired
private UserService userService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("结束将用户status改为2");
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
String userId = (String) jobDataMap.get("userId");
System.out.println("用户注册结束id: "+userId);
// 写自己的方法
userService.closeUpdateUserStatus(userId);
}
}
八、创建一个具有添加定时任务、移除、暂停、恢复,QuartzService接口,以及QuartzServiceimpl实现接口
package cn.xej.service;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public interface QuartzService {
/**
* 添加定时任务
*/
void addJob(String jobName, String jobGroup, String cron, Class<? extends QuartzJobBean> jobClass, JobDataMap jobDataMap) throws SchedulerException;
/**
* 删除定时任务
*/
void delJob(String jobName, String jobGroup);
/**
* 暂停定时任务
*/
void pauseJob(String jobName, String jobGroup);
/**
* 继续定时任务
*/
void resumeJob(String jobName, String jobGroup);
}
package cn.xej.service.impl;
import cn.xej.service.QuartzService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;
@Service
public class QuartzServiceimpl implements QuartzService {
@Autowired
private Scheduler scheduler; // 在SchedulerConfig配置类中 已经由Spring管理,所以这里可以自动注入
/**
* jobName 任务名 自定义
* jobGroup 任务组 自定义
* cron 时间表达式
* jobClass 任务实现类 如 StartUserJob 或 CloseUserJob
* jobDataMap 自定义参数
**/
// 添加定时任务
@Override
public void addJob(String jobName, String jobGroup, String cron, Class<? extends QuartzJobBean> jobClass, JobDataMap jobDataMap) {
try {
/**
* 构建JobDetail (表示一个具体的可执行的调度程序,Job是这个可执行调度程序所要执行的内容)
*/
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName,jobGroup)
.usingJobData(jobDataMap)
.build();
/**
* 构建出发去Trigger (调度参数的配置,代表何时出发该任务)
*/
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName,jobGroup)
.startNow()
.withSchedule(scheduleBuilder)
.build();
scheduler.scheduleJob(jobDetail,trigger);
scheduler.start();
System.out.println("添加定时任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
// 删除定时任务
@Override
public void delJob(String jobName, String jobGroup) {
try {
// TriggerKey 定义了trigger的名称和组别 ,通过任务名和任务组名获取TriggerKey
TriggerKey triggerKey = TriggerKey.triggerKey(jobName,jobGroup);
// 停止触发器
scheduler.resumeTrigger(triggerKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 移除任务
scheduler.deleteJob(JobKey.jobKey(jobName,jobGroup));
System.out.println("删除定时任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
// 暂停定时任务
@Override
public void pauseJob(String jobName, String jobGroup) {
try {
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
// 暂停任务
scheduler.pauseJob(jobKey);
System.out.println("暂停定时任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
// 继续定时任务
@Override
public void resumeJob(String jobName, String jobGroup) {
try {
// 通过任务名和任务组名获取jobKey
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
// 继续任务
scheduler.resumeJob(jobKey);
System.out.println("继续定时任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
九、注册页面 register.html
<form>
账号 <input type="text" name="userId" id="userId"><br/>
密码 <input type="password" name="password" id="password"><br/>
性名 <input type="text" name="name" id="name"><br/>
日期 <input type="text" name="date" id="date"><br/>
时长 <input type="text" name="time" id="time"><br/>
<button type="button" onclick="register()">注册</button>
</form>
<script>
function register() {
var userId = $('#userId').val();
var password = $('#password').val();
var name = $('#name').val();
var date = $('#date').val();
var time = $('#time').val();
$.ajax({
url: '/user/toRegister',
type: 'post',
data: {
userId: userId,
password: password,
name: name,
date: date,
time: time
},
success: function (dt) {
if(dt.code===200){
alert('注册成功');
}
}
})
}
</script>
十、UserController控制器
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/toRegister")
@ResponseBody
public RespObj toRegister(String userId, String password, String name, String date, Integer time) {
return userService.addUser(userId, password, name, date, time);
}
}
十一、UserService接口以及UserServiceimpl实现类
当用户注册时,首先获取前端注册页面获得的参数(userId,password,name,date,time),然后要将date装换成cron表达式,添加定时器
执行顺序为: UserController --》UserServiceimpl --》QuartzServiceimpl --》(等待自定义开始日期到达然后执行自定义的Job)StartUserJob
--》 UserServiceimpl 的 startUpdateUserStatus方法(删除开始的定时任务,新增结束的定时任务),同理结束任务流程。
package cn.xej.service;
import cn.xej.common.RespObj;
import cn.xej.pojo.User;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface UserService {
public User findByUserId(String userId);
public List<User> getAllUser();
public RespObj addUser(String userId, String password, String name, String date, Integer time);
public RespObj startUpdateUserStatus(String userId, Integer time, String date);
public RespObj closeUpdateUserStatus(String userId);
public RespObj stopJob(String userId);
public RespObj resumeJob(String userId);
public RespObj delJob(String userId);
}
package cn.xej.service.impl;
import cn.xej.common.RespObj;
import cn.xej.common.Utils;
import cn.xej.job.CloseUserJob;
import cn.xej.job.StartUserJob;
import cn.xej.mapper.UserDao;
import cn.xej.pojo.User;
import cn.xej.service.QuartzService;
import cn.xej.service.UserService;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
@Service
public class UserServiceimpl implements UserService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private UserDao userDao;
@Autowired
private QuartzService quartzService;
@Override
public User findByUserId(String userId) {
return userDao.findByUserId(userId);
}
@Override
public List<User> getAllUser() {
return userDao.getAllUser();
}
// 用户注册时,添加定时任务
@Override
public RespObj addUser(String userId, String password, String name, String date, Integer time) {
User user = new User();
user.setUserId(userId);
user.setPassword(password);
user.setName(name);
user.setStatus(0);
/*
//获得SimpleDateFormat类,我们转换为yyyy-MM-dd的时间格式
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
//使用SimpleDateFormat的parse()方法生成Date
Date date1 = sf.parse(date);
//打印Date
System.out.println(date1);
user.setDate(date1);
} catch (ParseException e) {
e.printStackTrace();
}
*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
GregorianCalendar calendar = new GregorianCalendar();
try{
calendar.setTime(sdf.parse(date));
Date date1 = calendar.getTime();
user.setDate(date1);
}catch (ParseException e) {
e.printStackTrace();
}
user.setTime(time);
// 添加注册的用户
userDao.addUser(user);
// 添加定时任务,jobDataMap为自定义要的传参的内容,将在StartUserJob中获取
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("userId",userId);
jobDataMap.put("time",time);
jobDataMap.put("date",date);
// 将页面传的date 装换成 cron表达式
String cronExpression = Utils.dateStrConvertCronExpression(date,null);
System.out.println("开始日期: "+cronExpression);
try {
quartzService.addJob("START_USER"+userId,"USER",cronExpression, StartUserJob.class,jobDataMap);
} catch (SchedulerException e) {
e.printStackTrace();
}
return RespObj.build(200,"success",null);
}
@Override
public RespObj startUpdateUserStatus(String userId, Integer time, String date) {
log.info("开始改变用户status为1:"+userId);
// 修改用户状态为:1
userDao.startUpdateUserStatus(userId);
// 删除开始注册的定时任务
quartzService.delJob("START_USER"+userId,"USER");
// 新增一个注册结束的定时任务
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("userId",userId);
String cronExpression = Utils.dateStrConvertCronExpression(date, time);
try {
quartzService.addJob("CLOSE_USER"+userId,"USER",cronExpression, CloseUserJob.class,jobDataMap);
} catch (SchedulerException e) {
e.printStackTrace();
}
return RespObj.build(200,"success",null);
}
@Override
public RespObj closeUpdateUserStatus(String userId) {
log.info("用户注册结束用户状态为2.:"+userId);
// 修改用户状态为:2
userDao.closeUpdateUserStatus(userId);
// 删除考试结束的定时任务
quartzService.delJob("CLOSE_USER"+userId,"USER");
return RespObj.build(200,"success",null);
}
// 暂停任务
@Override
public RespObj stopJob(String userId) {
User user = userDao.findByUserId(userId);
if(user.getStatus()==2){
return RespObj.build(400,"fail","任务已结束");
}
quartzService.pauseJob("CLOSE_USER"+userId,"USER"); // 实现暂停
return RespObj.build(200,"success",null);
}
// 恢复任务
@Override
public RespObj resumeJob(String userId) {
User user = userDao.findByUserId(userId);
if(user.getStatus()==2){
return RespObj.build(400,"fail","任务已结束");
}
quartzService.resumeJob("CLOSE_USER"+userId,"USER");
return RespObj.build(200,"success",null);
}
// 移除任务
@Override
public RespObj delJob(String userId) {
User user = userDao.findByUserId(userId);
if(user.getStatus()==2){
return RespObj.build(400,"fail","任务已结束");
}else if(user.getStatus()==0){
return RespObj.build(400,"fail","任务未开始");
}
quartzService.delJob("CLOSE_USER"+userId,"USER");
return RespObj.build(200,"success",null);
}
}
十二、将时间日期字符串转换成cron表达式
package cn.xej.common;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Utils {
/**
* 将时间日期字符串转换成cron表达式
* @param dateStr
* @return
*/
public static String dateStrConvertCronExpression(String dateStr,Integer minute){
DateTimeFormatter localDateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = LocalDateTime.parse(dateStr, localDateTimeFormat);
if(minute != null)
date = date.plusMinutes(minute);
StringBuilder sb = new StringBuilder();
sb.append(date.getSecond()).append(" ")
.append(date.getMinute()).append(" ")
.append(date.getHour()).append(" ")
.append(date.getDayOfMonth()).append(" ")
.append(date.getMonthValue()).append(" ")
.append("?");
return sb.toString();
}
}