1.需求背景:微信小程序秒杀模块有个订阅功能,当用户点击完订阅后,要在活动开始的前10分钟调用微信接口发送订阅消息给用户
2.思路:本地创建秒杀订阅表,当用户添加或者取消时对应表中数据的增删,添加数据时动态创建一条xxljob的定时任务,取消时删除它
xxl-job有两种创建任务的方式,第一种就是我们使用xxl-job的图形化页面,第二种直接调用xxl-job的接口(其实图形化页面也是使用了调用接口的方式)
废话少说,下面是工具类和示例代码以供参考
@Component
public class XxlJobUtil {
public static final int SUCCESS_CODE = 200;
private static String adminAddresses;
private static String appname;
private static Integer groupId;
private static String accessToken;
@Value("${xxl.job.admin.addresses}")
public void setAdminAddresses(String adminAddresses) {
XxlJobUtil.adminAddresses = adminAddresses;
}
@Value("${xxl.job.accessToken}")
public void setAccessToken(String accessToken) {
XxlJobUtil.accessToken = accessToken;
}
@Value("${xxl.job.executor.appname}")
public void setAppname(String appname) {
XxlJobUtil.appname = appname;
}
@PostConstruct
public void init() {
initGroupId();
}
private static final String ADD_URL = "/ext/jobinfo/add";
private static final String UPDATE_URL = "/ext/jobinfo/update";
private static final String REMOVE_URL = "/ext/jobinfo/remove";
private static final String PAUSE_URL = "/ext/jobinfo/stop";
private static final String START_URL = "/ext/jobinfo/start";
private static final String ADD_AND_START_URL = "/ext/jobinfo/add-and-start";
private static final String GET_GROUP_ID = "/ext/jobgroup/get-group-id";
/**
* 添加任务
* @param jobInfo 任务信息
* @return {@link String} 任务id
* @author kritofgo
* @date 2022/05/27 17:37
**/
public static String add(XxlJobInfo jobInfo) {
jobInfo.setJobGroup(groupId);
return doPost(adminAddresses + ADD_URL, jobInfo, String.class);
}
/**
* 初始化获取执行器id
* @author kritofgo
* @date 2022/05/27 17:37
**/
public static void initGroupId() {
// 查询对应groupId:
Map<String, Object> param = new HashMap<>(4);
param.put("appname", appname);
Integer groupId = doPost(adminAddresses + GET_GROUP_ID, param, Integer.class);
if (groupId == null) {
throw new XllJobRemoteException(String.format("【xxl-job】接口调用未获取到分组id,appname:%s", appname));
}
XxlJobUtil.groupId = groupId;
}
/**
* 修改执行时间
* @param id 任务id
* @param cron cron表达式
* @return {@link String}
* @author kritofgo
* @date 2022/05/27 17:38
**/
public static String update(int id, String cron) {
Map<String, Object> param = new HashMap<>(4);
param.put("id", id);
param.put("jobCron", cron);
return doPost(adminAddresses + UPDATE_URL, param, String.class);
}
/**
* 删除任务
* @param id 任务id
* @return {@link String}
* @author kritofgo
* @date 2022/05/27 17:39
**/
public static String remove(int id) {
Map<String, Object> param = new HashMap<>(4);
param.put("id", id);
return doPost(adminAddresses + REMOVE_URL, param, String.class);
}
/**
* 暂停任务
* @param id 任务id
* @return {@link String}
* @author kritofgo
* @date 2022/05/27 17:40
**/
public static String pause(int id) {
Map<String, Object> param = new HashMap<>(4);
param.put("id", id);
return doPost(adminAddresses + PAUSE_URL, param, String.class);
}
/**
* 开始任务
* @param id 任务id
* @return {@link String}
* @author kritofgo
* @date 2022/05/27 17:40
**/
public static String start(int id) {
Map<String, Object> param = new HashMap<>();
param.put("id", id);
return doPost(adminAddresses + START_URL, param, String.class);
}
/**
* 添加并启动
* @param jobInfo 任务信息
* @return {@link String}
* @author kritofgo
* @date 2022/05/27 20:10
**/
public static String addAndStart(XxlJobInfo jobInfo) {
jobInfo.setJobGroup(groupId);
return doPost(adminAddresses + ADD_AND_START_URL, jobInfo, String.class);
}
@SuppressWarnings("unchecked")
public static <T> T doPost(String url, Object json, Class<T> clazz) {
ReturnT<T> returnT = XxlJobRemotingUtil.postBody(url, accessToken, 3, json, clazz);
if (returnT.getCode() != SUCCESS_CODE) {
throw new XllJobRemoteException(String.format("【xxl-job】接口调用失败,错误码:%s,原因:%s",
returnT.getCode(), returnT.getMsg()));
}
return returnT.getContent();
}
}
cron生成器的工具类
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
/**
* @description:
* @author kritofgo
* @date 2022/8/10 14:08
*/
public class CronUtil {
private static final SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
/**
* 年 (可选) 留空
* 允许的特殊字符:留空, 1970-2099 , - * /
*/
private String year;
/**
* 星期 可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
* 允许的特殊字符:1-7 或者 SUN-SAT , - * ? / L C #
*/
private String week;
/**
* 月 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* 允许的特殊字符:1-12 或者 JAN-DEC , - * /
*/
private String month;
/**
* 日 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* 允许的特殊字符:1-31 , - * ? / L W C
*/
private String day;
/**
* 时 可以用数字0-23表示
* 允许的特殊字符:0-23, - * /
*/
private String hour;
/**
* 分 可以用数字0-59 表示
* 允许的特殊字符:0-59,- * /
*/
private String minutes;
/**
* 秒 可以用数字0-59 表示
* 允许的特殊字符:0-59,- * /
*/
private String seconds ;
/***
* 日期转换cron表达式 例如 "0 07 10 15 1 ? 2016"
* @param date 时间点
* @return
*/
public static String getCron(Date date) {
String formatTimeStr = null;
if (Objects.nonNull(date)) {
formatTimeStr = sdf.format(date);
}
return formatTimeStr;
}
/**
* 获取指定日期的cron表达式
* @param year 年
* @param week 星期 可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
* @param month 月 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* @param day 日 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* @param hour 时 可以用数字0-23表示
* @param minutes 分 可以用数字0-59 表示
* @param seconds 秒 可以用数字0-59 表示
* @return
*/
public static String getCron(String year,String week,String month,String day,String hour,String minutes,String seconds) {
return seconds+" "+minutes+" "+hour+" "+day+" "+month+" "+week+" "+year;
}
/**
* 获取指定日期的cron表达式
* @param week 星期 可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
* @param month 月 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* @param day 日 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* @param hour 时 可以用数字0-23表示
* @param minutes 分 可以用数字0-59 表示
* @param seconds 秒 可以用数字0-59 表示
* @return
*/
public static String getCron(String week,String month,String day,String hour,String minutes,String seconds) {
return getCron("*",week,month,day,hour,minutes,seconds);
}
/**
* 获取指定日期的cron表达式
* @param month 月 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* @param day 日 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* @param hour 时 可以用数字0-23表示
* @param minutes 分 可以用数字0-59 表示
* @param seconds 秒 可以用数字0-59 表示
* @return
*/
static String getCron(String month,String day,String hour,String minutes,String seconds) {
return getCron("?",month,day,hour,minutes,seconds);
}
/**
* 获取指定范围的Cron表达式 例如 13-14 30-31 11-12 20-21 04-05 1-2 2021-2022
* @param year 年 使用(year1-year2) year1<=year2
* @param week 星期 使用(week1-week2) 可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
* @param month 月 使用(month1-month2) 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* @param day 日 使用(day1-day2) 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* @param hour 时 使用(hour1-hour2) 可以用数字0-23表示
* @param minutes 分 使用(minutes1-minutes2) 可以用数字0-59 表示
* @param seconds 秒 使用(seconds1-seconds2) 可以用数字0-59 表示
* @return
*/
public static String getCronByRange(String year,String week,String month,String day,String hour,String minutes,String seconds) {
return seconds+" "+minutes+" "+hour+" "+day+" "+month+" "+week+" "+year;
}
/**
* 获取指定范围的Cron表达式 例如 13-14 30-31 11-12 20-21 04-05 1-2
* @param week 星期 使用(week1-week2) 可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
* @param month 月 使用(month1-month2) 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* @param day 日 使用(day1-day2) 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* @param hour 时 使用(hour1-hour2) 可以用数字0-23表示
* @param minutes 分 使用(minutes1-minutes2) 可以用数字0-59 表示
* @param seconds 秒 使用(seconds1-seconds2) 可以用数字0-59 表示
* @return
*/
public static String getCronByRange(String week,String month,String day,String hour,String minutes,String seconds) {
return getCron("*",week,month,day,hour,minutes,seconds);
}
/**
* 获取指定范围的Cron表达式 例如 13-14 30-31 11-12 20-21 04-05
* @param month 月 使用(month1-month2) 可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
* @param day 日 使用(day1-day2) 可以用数字1-31 中的任一一个值,但要注意一些特别的月份
* @param hour 时 使用(hour1-hour2) 可以用数字0-23表示
* @param minutes 分 使用(minutes1-minutes2) 可以用数字0-59 表示
* @param seconds 秒 使用(seconds1-seconds2) 可以用数字0-59 表示
* @return
*/
static String getCronByRange(String month,String day,String hour,String minutes,String seconds) {
return getCron("?",month,day,hour,minutes,seconds);
}
}
下面是项目中用到的代码示例:
...
//执行器cron表达式
String cron = CronUtil.getCron(wxSubscription.getReminderTime());
log.info("当前cron表达式:----" + cron);
//执行器任务参数,
String mId = String.valueOf(wxSubscription.getId());
//执行器,任务Handler名称
String handler = "";
String jobDesc = "秒杀活动订阅消息:" + wxSubscription.getId();
XxlJobInfo jobInfo = new XxlJobInfo(jobDesc, "admin", handler, mId);
jobInfo.setSchedule(ScheduleTypeEnum.CRON, cron);
//创建定时任务提醒用户
XxlJobUtil.addAndStart(jobInfo);
...