SpringBoot-XXLJOB提供动态API调度任务

目录

一、项目版本

二、XXL-JOB提供动态API

controller层

service层

三、SpringBoot项目

pom

model

XxlJobUtil-工具类


       XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

分布式任务调度平台XXL-JOBXXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。icon-default.png?t=N7T8https://www.xuxueli.com/xxl-job/        一般我们都是在XXL-JOB提供的管理页面,进行任务调度的配置。如下图:

        也有在自己的项目中进行管理任务调度配置的需求。此篇文章将介绍如果通过API配置XXL-JOB的任务。

一、项目版本

工具版本
XXL-JOB2.4.1-SNAPSHOT
SpringBoot2.5.6.RELEASE

二、XXL-JOB提供动态API

主要实现依然是xxl-job底层的增删改查,需要在controller层去除框架权限校验的功能

controller层

package com.xxl.job.admin.controller;import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.util.GsonTool;
import com.xxl.job.core.util.XxlJobRemotingUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;/*** Created by meng*/
@Controller
@RequestMapping("/api")
public class JobApiController {@Resourceprivate AdminBiz adminBiz;@Resourceprivate XxlJobService xxlJobService;/*** api** @param uri* @param data* @return*/@RequestMapping("/{uri}")@ResponseBody@PermissionLimit(limit = false)public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {// validif (!"POST".equalsIgnoreCase(request.getMethod())) {return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");}if (uri == null || uri.trim().length() == 0) {return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");}if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0&& !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");}// services mappingif ("callback".equals(uri)) {List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);return adminBiz.callback(callbackParamList);} else if ("registry".equals(uri)) {RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);return adminBiz.registry(registryParam);} else if ("registryRemove".equals(uri)) {RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);return adminBiz.registryRemove(registryParam);} else if ("addJob".equals(uri)) {XxlJobInfo xxlJobInfo = GsonTool.fromJson(data, XxlJobInfo.class);return xxlJobService.add(xxlJobInfo);} else if ("updateJob".equals(uri)) {XxlJobInfo xxlJobInfo = GsonTool.fromJson(data, XxlJobInfo.class);return xxlJobService.update(xxlJobInfo);} else if ("jobInfo".equals(uri)) {XxlJobInfo xxlJobInfo = GsonTool.fromJson(data, XxlJobInfo.class);return xxlJobService.info(xxlJobInfo.getId());} else if ("removeJob".equals(uri)) {XxlJobInfo xxlJobInfo = GsonTool.fromJson(data, XxlJobInfo.class);return xxlJobService.remove(xxlJobInfo.getId());} else if ("startJob".equals(uri)) {XxlJobInfo xxlJobInfo = GsonTool.fromJson(data, XxlJobInfo.class);return xxlJobService.start(xxlJobInfo.getId());} else if ("stopJob".equals(uri)) {XxlJobInfo xxlJobInfo = GsonTool.fromJson(data, XxlJobInfo.class);return xxlJobService.stop(xxlJobInfo.getId());} else {return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");}}}

service层

XxlJobService:

package com.xxl.job.admin.service;import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.core.biz.model.ReturnT;import java.util.Date;
import java.util.Map;/*** core job action for xxl-job* * @author meng*/
public interface XxlJobService {/*** page list** @param start* @param length* @param jobGroup* @param jobDesc* @param executorHandler* @param author* @return*/public Map<String, Object> pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author);/*** add job** @param jobInfo* @return*/public ReturnT<String> add(XxlJobInfo jobInfo);/*** update job** @param jobInfo* @return*/public ReturnT<String> update(XxlJobInfo jobInfo);/*** remove job* 	 ** @param id* @return*/public ReturnT<String> remove(int id);/*** start job** @param id* @return*/public ReturnT<String> start(int id);/*** stop job** @param id* @return*/public ReturnT<String> stop(int id);/*** dashboard info** @return*/public Map<String,Object> dashboardInfo();/*** chart info** @param startDate* @param endDate* @return*/public ReturnT<Map<String,Object>> chartInfo(Date startDate, Date endDate);/*** info job** @param id* @return*/public ReturnT<String> info(int id);
}

XxlJobServiceImpl:

package com.xxl.job.admin.service.impl;import com.xxl.job.admin.core.cron.CronExpression;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
import com.xxl.job.admin.core.thread.JobScheduleHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.*;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.util.DateUtil;
import com.xxl.job.core.util.GsonTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.*;/*** core job action for xxl-job** @author meng*/
@Service
public class XxlJobServiceImpl implements XxlJobService {private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);@Resourceprivate XxlJobGroupDao xxlJobGroupDao;@Resourceprivate XxlJobInfoDao xxlJobInfoDao;@Resourcepublic XxlJobLogDao xxlJobLogDao;@Resourceprivate XxlJobLogGlueDao xxlJobLogGlueDao;@Resourceprivate XxlJobLogReportDao xxlJobLogReportDao;@Overridepublic Map<String, Object> pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {// page listList<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);// package resultMap<String, Object> maps = new HashMap<String, Object>();maps.put("recordsTotal", list_count);        // 总记录数maps.put("recordsFiltered", list_count);    // 过滤后的总记录数maps.put("data", list);                    // 分页列表return maps;}@Overridepublic ReturnT<String> add(XxlJobInfo jobInfo) {// valid baseXxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());if (group == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_field_jobgroup")));}if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc")));}if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author")));}// valid triggerScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);if (scheduleTypeEnum == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {return new ReturnT<String>(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid"));}} else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {if (jobInfo.getScheduleConf() == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")));}try {int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());if (fixSecond < 1) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}} catch (Exception e) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}}// valid jobif (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype") + I18nUtil.getString("system_unvalid")));}if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler() == null || jobInfo.getExecutorHandler().trim().length() == 0)) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + "JobHandler"));}// 》fix "\r" in shellif (GlueTypeEnum.GLUE_SHELL == GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource() != null) {jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));}// valid advancedif (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid")));}if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid")));}if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid")));}// 》ChildJobId validif (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) {String[] childJobIds = jobInfo.getChildJobId().split(",");for (String childJobIdItem : childJobIds) {if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) {XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));if (childJobInfo == null) {return new ReturnT<String>(ReturnT.FAIL_CODE,MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem));}} else {return new ReturnT<String>(ReturnT.FAIL_CODE,MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_unvalid")), childJobIdItem));}}// join , avoid "xxx,,"String temp = "";for (String item : childJobIds) {temp += item + ",";}temp = temp.substring(0, temp.length() - 1);jobInfo.setChildJobId(temp);}// add in dbjobInfo.setAddTime(new Date());jobInfo.setUpdateTime(new Date());jobInfo.setGlueUpdatetime(new Date());xxlJobInfoDao.save(jobInfo);if (jobInfo.getId() < 1) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add") + I18nUtil.getString("system_fail")));}return new ReturnT<String>(String.valueOf(jobInfo.getId()));}private boolean isNumeric(String str) {try {int result = Integer.valueOf(str);return true;} catch (NumberFormatException e) {return false;}}@Overridepublic ReturnT<String> update(XxlJobInfo jobInfo) {// valid baseif (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc")));}if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author")));}// valid triggerScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);if (scheduleTypeEnum == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {return new ReturnT<String>(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid"));}} else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {if (jobInfo.getScheduleConf() == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}try {int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());if (fixSecond < 1) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}} catch (Exception e) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}}// valid advancedif (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid")));}if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid")));}if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid")));}// 》ChildJobId validif (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) {String[] childJobIds = jobInfo.getChildJobId().split(",");for (String childJobIdItem : childJobIds) {if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) {XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));if (childJobInfo == null) {return new ReturnT<String>(ReturnT.FAIL_CODE,MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem));}} else {return new ReturnT<String>(ReturnT.FAIL_CODE,MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_unvalid")), childJobIdItem));}}// join , avoid "xxx,,"String temp = "";for (String item : childJobIds) {temp += item + ",";}temp = temp.substring(0, temp.length() - 1);jobInfo.setChildJobId(temp);}// group validXxlJobGroup jobGroup = xxlJobGroupDao.load(jobInfo.getJobGroup());if (jobGroup == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_jobgroup") + I18nUtil.getString("system_unvalid")));}// stage job infoXxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());if (exists_jobInfo == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_not_found")));}// next trigger time (5s后生效,避开预读周期)long nextTriggerTime = exists_jobInfo.getTriggerNextTime();boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf());if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) {try {Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));if (nextValidTime == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}nextTriggerTime = nextValidTime.getTime();} catch (Exception e) {logger.error(e.getMessage(), e);return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}}exists_jobInfo.setJobGroup(jobInfo.getJobGroup());exists_jobInfo.setJobDesc(jobInfo.getJobDesc());exists_jobInfo.setAuthor(jobInfo.getAuthor());exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());exists_jobInfo.setScheduleType(jobInfo.getScheduleType());exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf());exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy());exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());exists_jobInfo.setChildJobId(jobInfo.getChildJobId());exists_jobInfo.setTriggerNextTime(nextTriggerTime);exists_jobInfo.setUpdateTime(new Date());xxlJobInfoDao.update(exists_jobInfo);return ReturnT.SUCCESS;}@Overridepublic ReturnT<String> remove(int id) {XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);if (xxlJobInfo == null) {return ReturnT.SUCCESS;}xxlJobInfoDao.delete(id);xxlJobLogDao.delete(id);xxlJobLogGlueDao.deleteByJobId(id);return ReturnT.SUCCESS;}@Overridepublic ReturnT<String> start(int id) {XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);// validScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);if (ScheduleTypeEnum.NONE == scheduleTypeEnum) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type_none_limit_start")));}// next trigger time (5s后生效,避开预读周期)long nextTriggerTime = 0;try {Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));if (nextValidTime == null) {return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}nextTriggerTime = nextValidTime.getTime();} catch (Exception e) {logger.error(e.getMessage(), e);return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));}xxlJobInfo.setTriggerStatus(1);xxlJobInfo.setTriggerLastTime(0);xxlJobInfo.setTriggerNextTime(nextTriggerTime);xxlJobInfo.setUpdateTime(new Date());xxlJobInfoDao.update(xxlJobInfo);return ReturnT.SUCCESS;}@Overridepublic ReturnT<String> stop(int id) {XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);xxlJobInfo.setTriggerStatus(0);xxlJobInfo.setTriggerLastTime(0);xxlJobInfo.setTriggerNextTime(0);xxlJobInfo.setUpdateTime(new Date());xxlJobInfoDao.update(xxlJobInfo);return ReturnT.SUCCESS;}@Overridepublic Map<String, Object> dashboardInfo() {int jobInfoCount = xxlJobInfoDao.findAllCount();int jobLogCount = 0;int jobLogSuccessCount = 0;XxlJobLogReport xxlJobLogReport = xxlJobLogReportDao.queryLogReportTotal();if (xxlJobLogReport != null) {jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();jobLogSuccessCount = xxlJobLogReport.getSucCount();}// executor countSet<String> executorAddressSet = new HashSet<String>();List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();if (groupList != null && !groupList.isEmpty()) {for (XxlJobGroup group : groupList) {if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) {executorAddressSet.addAll(group.getRegistryList());}}}int executorCount = executorAddressSet.size();Map<String, Object> dashboardMap = new HashMap<String, Object>();dashboardMap.put("jobInfoCount", jobInfoCount);dashboardMap.put("jobLogCount", jobLogCount);dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);dashboardMap.put("executorCount", executorCount);return dashboardMap;}@Overridepublic ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {// processList<String> triggerDayList = new ArrayList<String>();List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();List<Integer> triggerDayCountSucList = new ArrayList<Integer>();List<Integer> triggerDayCountFailList = new ArrayList<Integer>();int triggerCountRunningTotal = 0;int triggerCountSucTotal = 0;int triggerCountFailTotal = 0;List<XxlJobLogReport> logReportList = xxlJobLogReportDao.queryLogReport(startDate, endDate);if (logReportList != null && logReportList.size() > 0) {for (XxlJobLogReport item : logReportList) {String day = DateUtil.formatDate(item.getTriggerDay());int triggerDayCountRunning = item.getRunningCount();int triggerDayCountSuc = item.getSucCount();int triggerDayCountFail = item.getFailCount();triggerDayList.add(day);triggerDayCountRunningList.add(triggerDayCountRunning);triggerDayCountSucList.add(triggerDayCountSuc);triggerDayCountFailList.add(triggerDayCountFail);triggerCountRunningTotal += triggerDayCountRunning;triggerCountSucTotal += triggerDayCountSuc;triggerCountFailTotal += triggerDayCountFail;}} else {for (int i = -6; i <= 0; i++) {triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i)));triggerDayCountRunningList.add(0);triggerDayCountSucList.add(0);triggerDayCountFailList.add(0);}}Map<String, Object> result = new HashMap<String, Object>();result.put("triggerDayList", triggerDayList);result.put("triggerDayCountRunningList", triggerDayCountRunningList);result.put("triggerDayCountSucList", triggerDayCountSucList);result.put("triggerDayCountFailList", triggerDayCountFailList);result.put("triggerCountRunningTotal", triggerCountRunningTotal);result.put("triggerCountSucTotal", triggerCountSucTotal);result.put("triggerCountFailTotal", triggerCountFailTotal);return new ReturnT<Map<String, Object>>(result);}@Overridepublic ReturnT<String> info(int id) {XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);return new ReturnT<String>(GsonTool.toJson(xxlJobInfo));}}
GsonTool:

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;/*** @author meng*/
public class GsonTool {private static Gson gson = null;static {GsonBuilder builder = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss");builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {return new Date(json.getAsJsonPrimitive().getAsLong());}});gson = builder.create();}/*** Object 转成 json** @param src* @return String*/public static String toJson(Object src) {return gson.toJson(src);}/*** json 转成 特定的cls的Object** @param json* @param classOfT* @return*/public static <T> T fromJson(String json, Class<T> classOfT) {return gson.fromJson(json, classOfT);}/*** json 转成 特定的 rawClass<classOfT> 的Object** @param json* @param classOfT* @param argClassOfT* @return*/public static <T> T fromJson(String json, Class<T> classOfT, Class argClassOfT) {Type type = new ParameterizedType4ReturnT(classOfT, new Class[]{argClassOfT});return gson.fromJson(json, type);}public static class ParameterizedType4ReturnT implements ParameterizedType {private final Class raw;private final Type[] args;public ParameterizedType4ReturnT(Class raw, Type[] args) {this.raw = raw;this.args = args != null ? args : new Type[0];}@Overridepublic Type[] getActualTypeArguments() {return args;}@Overridepublic Type getRawType() {return raw;}@Overridepublic Type getOwnerType() {return null;}}/*** json 转成 特定的cls的list** @param json* @param classOfT* @return*/public static <T> List<T> fromJsonList(String json, Class<T> classOfT) {return gson.fromJson(json,new TypeToken<List<T>>() {}.getType());}}

三、SpringBoot项目

pom

        <!-- hutool --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.22</version></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

model

job类:

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;/*** job参数*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class JobVo {/*** job描述*/private String jobDesc;/*** job调度配置*/private String scheduleConf;/*** 设备ID*/private String equid;/*** wvp-设备ID*/private String deviceId;/*** wvp-通道ID*/private String channelId;
}

XxlJobInfo类: 

package com.yunhoutech.aiel.backend.model;import lombok.Data;import java.util.Date;/*** xxl-job info** @author xuxueli  2016-1-12 18:25:49*/
@Data
public class XxlJobInfo {private int id;				// 主键IDprivate int jobGroup;		// 执行器主键IDprivate String jobDesc;private Date addTime;private Date updateTime;private String author;		// 负责人private String alarmEmail;	// 报警邮件private String scheduleType;			// 调度类型private String scheduleConf;			// 调度配置,值含义取决于调度类型private String misfireStrategy;			// 调度过期策略private String executorRouteStrategy;	// 执行器路由策略private String executorHandler;		    // 执行器,任务Handler名称private String executorParam;		    // 执行器,任务参数private String executorBlockStrategy;	// 阻塞处理策略private int executorTimeout;     		// 任务执行超时时间,单位秒private int executorFailRetryCount;		// 失败重试次数private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnumprivate String glueSource;		// GLUE源代码private String glueRemark;		// GLUE备注private Date glueUpdatetime;	// GLUE更新时间private String childJobId;		// 子任务ID,多个逗号分隔private int triggerStatus;		// 调度状态:0-停止,1-运行private long triggerLastTime;	// 上次调度时间private long triggerNextTime;	// 下次调度时间
}

XxlJobUtil-工具类

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.demo.backend.model.JobVo;
import com.demo.backend.model.XxlJobInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;/*** @Author: meng* @Description:* @Date: 2023/7/10 11:00* @Version: 1.0*/
@Component
public class XxlJobUtil {private Logger logger = LoggerFactory.getLogger(this.getClass());public static final String CODE = "code";public static final String XXL_JOB_ACCESS_TOKEN = "XXL-JOB-ACCESS-TOKEN";private static final String ADD_URL = "/api/addJob";private static final String INFO_URL = "/api/jobInfo";private static final String UPDATE_URL = "/api/updateJob";private static final String REMOVE_URL = "/api/removeJob";private static final String PAUSE_URL = "/api/pauseJob";private static final String START_URL = "/api/startJob";private static final String STOP_URL = "/api/stopJob";private static final String ADD_START_URL = "/api/addAndStart";private static final String GET_GROUP_ID = "/api/getGroupId";/*** 新增job* {\"jobGroup\":\"1\",\"jobDesc\":\"test_des\",\"author\":\"admin\",\"alarmEmail\":\"\",\"scheduleType\":\"CRON\",\"scheduleConf\":\"0 0 0 * * ? *\",* \"cronGen_display\":\"0 0 0 * * ? *\",\"schedule_conf_CRON\":\"0 0 0 * * ? *\",\"schedule_conf_FIX_RATE\":\"\",\"schedule_conf_FIX_DELAY\":\"\",* \"glueType\":\"BEAN\",\"executorHandler\":\"demoJobHandler\",\"executorParam\":\"\",\"executorRouteStrategy\":\"FIRST\",\"childJobId\":\"\",* \"misfireStrategy\":\"DO_NOTHING\",\"executorBlockStrategy\":\"SERIAL_EXECUTION\",\"executorTimeout\":\"0\",\"executorFailRetryCount\":\"1\",* \"glueRemark\":\"GLUE%E4%BB%A3%E7%A0%81%E5%88%9D%E5%A7%8B%E5%8C%96\",\"glueSource\":\"\"}*/public Integer addJob(JobVo jobVo) {if (StrUtil.hasBlank(jobVo.getJobDesc(), jobVo.getScheduleConf(), jobVo.getEquid(), jobVo.getDeviceId(), jobVo.getChannelId())) {logger.info("jobVo-参数都不能为空");return null;}JSONObject requestInfo = new JSONObject();requestInfo.put("jobGroup", 3);requestInfo.put("jobDesc", jobVo.getJobDesc());requestInfo.put("author", "admin");requestInfo.put("alarmEmail", "");requestInfo.put("scheduleType", "CRON");requestInfo.put("scheduleConf", jobVo.getScheduleConf());requestInfo.put("cronGen_display", jobVo.getScheduleConf());requestInfo.put("schedule_conf_CRON", jobVo.getScheduleConf());requestInfo.put("schedule_conf_FIX_RATE", "");requestInfo.put("schedule_conf_FIX_DELAY", "");requestInfo.put("glueType", "BEAN");requestInfo.put("executorHandler", "pollPresetJobHandler");requestInfo.put("executorParam", String.format("%s,%s,%s", jobVo.getEquid(), jobVo.getDeviceId(), jobVo.getChannelId()));// 一致性hashrequestInfo.put("executorRouteStrategy", "CONSISTENT_HASH");requestInfo.put("childJobId", "");requestInfo.put("misfireStrategy", "DO_NOTHING");requestInfo.put("executorBlockStrategy", "SERIAL_EXECUTION");requestInfo.put("executorTimeout", "0");requestInfo.put("executorFailRetryCount", "1");requestInfo.put("glueRemark", "GLUE代码初始化");requestInfo.put("glueSource", "");String body = getRequestBody(requestInfo.toJSONString(), ADD_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("addJob error:{}", JSON.parseObject(body));return null;}logger.info("addJob success");return jsonObject.getInteger("content");}return null;}/*** job详情*/public XxlJobInfo infoJob(int id) {XxlJobInfo xxlJobInfo = new XxlJobInfo();xxlJobInfo.setId(id);String body = getRequestBody(JSONObject.toJSONString(xxlJobInfo), INFO_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("infoJob error:{}", JSON.parseObject(body));return null;}logger.info("infoJob success");return JSONObject.parseObject(jsonObject.getString("content"), XxlJobInfo.class);}return null;}/*** 更新job*/public boolean updateJob(XxlJobInfo xxlJobInfo) {if (ObjectUtil.isNull(xxlJobInfo)) {logger.info("updateJob xxlJobInfo is null");return false;}String body = getRequestBody(JSONObject.toJSONString(xxlJobInfo), UPDATE_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("updateJob error:{}", JSON.parseObject(body));return false;}}logger.info("updateJob success");return true;}/*** 更新job*/public boolean updateJob(String jobId, String scheduleConf) {if (StrUtil.hasBlank(jobId, scheduleConf)) {logger.info("jobVo-参数都不能为空");return false;}XxlJobInfo xxlJobInfo = infoJob(Integer.valueOf(jobId));if (ObjectUtil.isNull(xxlJobInfo)) {logger.info("updateJob xxlJobInfo is null");return false;}xxlJobInfo.setScheduleConf(scheduleConf);String body = getRequestBody(JSONObject.toJSONString(xxlJobInfo), UPDATE_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("updateJob error:{}", JSON.parseObject(body));return false;}}logger.info("updateJob success");return true;}/*** 启动job*/public boolean startJob(int id) {XxlJobInfo xxlJobInfo = new XxlJobInfo();xxlJobInfo.setId(id);String body = getRequestBody(JSONObject.toJSONString(xxlJobInfo), START_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("startJob error:{}", JSON.parseObject(body));return false;}}logger.info("startJob success");return true;}/*** 停止job*/public boolean stopJob(int id) {XxlJobInfo xxlJobInfo = new XxlJobInfo();xxlJobInfo.setId(id);String body = getRequestBody(JSONObject.toJSONString(xxlJobInfo), STOP_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("stopJob error:{}", JSON.parseObject(body));return false;}}logger.info("stopJob success");return true;}/*** 删除job*/public boolean removeJob(int id) {XxlJobInfo xxlJobInfo = new XxlJobInfo();xxlJobInfo.setId(id);// 先停止job,再删除jobif (!stopJob(id)) {return false;}String body = getRequestBody(JSONObject.toJSONString(xxlJobInfo), REMOVE_URL);if (StrUtil.isNotBlank(body)) {JSONObject jsonObject = JSON.parseObject(body);if (jsonObject.getInteger(CODE) != 200) {logger.info("removeJob error:{}", JSON.parseObject(body));return false;}}logger.info("removeJob success");return true;}/*** 接口请求* XXL_JOB_URL:请求链接* XXL_JOB_TOKEN:权限token*/private String getRequestBody(String dateStr, String uri) {HttpResponse httpResponse = HttpRequest.post(XXL_JOB_URL).body(dateStr).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE).header(XXL_JOB_ACCESS_TOKEN, XXL_JOB_TOKEN).execute();return httpResponse.body();}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/234583.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能监测/检测系统/摄像头监控系统EasyCVR大华云台控制问题的解决方法

GB28181视频集中存储/云存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园…

Java研学-Tomcat服务器

一 Web资源 1 概述 浏览器网页上看到的所有内容都称为web资源&#xff0c;比如文字&#xff0c;图片&#xff0c;音频&#xff0c;视频&#xff0c;链接等等内容。 2 Web资源分类 分类概述使用的技术静态资源静态资源是相对于动态资源而言&#xff0c;是指没有后台数据库、不…

在.NET 应用程序中使用DSN-GBASE南大通用

在.NET 应用程序中使用GBASE南大通用 machine.config 文件中的资源时&#xff0c;首先需在工程中 引用 .NET Framework 的组件GBASE南大通用 System.configuration&#xff0c;然后使用 using 语句将GBASE南大通用System.configuration 命名空间中的类引入到工程中。 1) 在工…

LeetCode:162. 寻找峰值、1901. 寻找峰值 II(二分 C++)

目录 162. 寻找峰值 题目描述&#xff1a; 实现代码与解析&#xff1a; 二分 原理思路&#xff1a; 1901. 寻找峰值 II 题目描述&#xff1a; 实现代码与解析&#xff1a; 二分 原理思路&#xff1a; 162. 寻找峰值 题目描述&#xff1a; 峰值元素是指其值严格大于左…

内网穿透工具frp安装使用

摘要&#xff1a;之前使用的 nps 目前没有维护更新了&#xff0c;和在使用的过程中做内网穿透的的网速应该有限制&#xff0c;不论云服务器带宽是多少&#xff0c;下载速度都比较慢。这里切换到 frp 试试&#xff0c;对安装和使用简单记录&#xff0c;其和 nps 有很大的操作配置…

03-数据结构-栈与队列

1.栈 栈和队列是两种操作受限的线性表。如上图所示显示栈的结构 栈&#xff1a;先进后出&#xff0c;入栈&#xff08;数据进入&#xff09; 和出栈&#xff08;数据出去&#xff09;均在栈顶操作。 常见栈的应用场景包括括号问题的求解&#xff0c;表达式的转换和求值&#…

wvp gb28181 pro 统一编码规则

统一编码规则 D.1 编码规则 A 编码规则 A 由中心编码(8位)、行业编码(2位)、类型编码(3位)和序号(7位)四个码段共20位十 进制数字字符构成,即系统编码 中心编码 行业编码 类型编码 序号。   编码规则 A 的详细说明见表 D.1。其中,中心编码指用户或设备所归属的监控中心的…

Go语言字符串综合指南:函数、方法和最佳实践

Go语言字符串综合指南&#xff1a;函数、方法和最佳实践 引言Go语言字符串基础声明和初始化不可变性字符串长度 字符串操作函数常用字符串操作转换与解析示例连接分割包含关系替换大小写转换整数与字符串的转换字符串到整数的转换格式化与解析 字符串与字符切片字符串和字符切片…

create-react-app 打包去掉 map文件

前言&#xff1a; 在使用 create-react-app 创建的React应用中&#xff0c;默认情况下会生成带有.map文件的打包文件&#xff0c;这些.map文件包含了源代码和调试信息&#xff0c;用于开发和调试过程中进行错误跟踪。然而&#xff0c;在生产环境中&#xff0c;这些.map文件通常…

SQL学习笔记+MySQL+SQLyog工具教程

文章目录 1、前言2、SQL基本语言及其操作2.1、CREATE TABLE – 创建表2.2、DROP TABLE – 删除表2.3、INSERT – 插入数据2.4、SELECT – 查询数据2.5、SELECTDISTINCT – 去除重复值后查询数据2.6、SELECTWHERE – 条件过滤2.7、AND & OR – 运算符2.8、ORDER BY – 排序2…

SAP 采购订单暂存 EKKO-MEMORY 做标识

ME21N创建采购订单的时候可以点击 暂存 按钮保存订单 ME22N进去修改的时候会提示这个订单是暂存的 在表EKKO里字段 MEMORY 打上了标识则标识这个是暂存的 MEMORYTYPE 字段则记录了暂存的状态

理解pom.xml中的parent标签

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

【TI毫米波雷达】上电时序、串口回环BUG及SOP模式不正常工作的解决方案(LP87524电源PMIC芯片的BUCK供电时序配置)

【TI毫米波雷达】雷达上电时序及SOP模式不正常工作的解决方案&#xff08;LP87524电源PMIC芯片的BUCK供电时序配置&#xff09; 文章目录 上电时序上电以后的雷达串口回环问题延迟上电时序LP87524电源PMIC芯片的BUCK供电时序LP87524电源PMIC芯片的BUCK默认供电输出附录&#x…

w3af安装(处理python2和3,pip2和3混乱的问题)

git clone --depth 1 https://github.com/andresriancho/w3af.git cd w3af ./w3af_gui报错 打开w3af_gui看一下 要求必须是python2 但我的/usr/bin/env中的python是python3 我们将/usr/bin/env中的python换成python2 which python2 #/usr/bin/python2rm /usr/bin/pythonsud…

探索数据宇宙之飞船 -- python进阶函数numpy

导读&#xff1a;NumPy以其强大的多维数组对象和广泛的数学函数库著称。这些特性使得NumPy成为不仅在学术研究&#xff0c;也在工业界广泛应用的工具。无论是机器学习算法的开发、数据分析、还是复杂的数学模型的构建&#xff0c;NumPy都扮演着举足轻重的角色。 目录 Numpy简…

node.js mongoose aggregate

目录 官方文档 简述 Aggregate的原型方法 aggregate进行操作 官方文档 Mongoose v8.0.3: Aggregate 简述 在 Mongoose 中&#xff0c;Aggregate 是用于执行 MongoDB 聚合操作的类。MongoDB 聚合操作是一种强大的数据处理工具&#xff0c;可以用于对集合中的文档进行变换和…

星融元中标华夏银行项目,助力金融数据中心可视网建设工作

近日&#xff0c;星融元成功入围华夏银行国产品牌网络流量汇聚分流器&#xff08;TAP&#xff09;设备供应商&#xff0c;在助力头部金融机构构建数据中心可视网络的建设工作中&#xff0c;星融元又一次获得全国性股份制银行客户的青睐。 华夏银行作为全国性股份制商业银行积极…

2-负载均衡、反向代理

负载均衡、反向代理 upstream server即上游服务器&#xff0c;指Nginx负载均衡到的处理业务的服务器&#xff0c;也可以称之为real server,即真实处理业务的服务器。 对于负载均衡我们要关心的几个方面如下&#xff1a; 上游服务器配置&#xff1a;使用upstream server配置上…

ansible的脚本------playbook剧本

playbook组成部分&#xff1a; 1.task 任务&#xff1a;包含要在目标主机上执行的操作&#xff0c;使用模块定义这些操作。每个都是一个模块的调用。2.variables 变量&#xff1a;存储和传递数据。变量可以自定义&#xff0c;可以在playbook当中定义为全局变量&#xff0c;也可…

Navicat16的下载与安装

Navicat16的下载与安装 1、官网下载地址&#xff1a;https://www.navicat.com.cn/download/navicat-premium 当然有的朋友在官网下载比较慢&#xff0c;我也为大家准备好了百度网盘链接 链接&#xff1a;https://pan.baidu.com/s/1dUcTSHr3761Oayh0-WfolA?pwdwfpl 提取码&am…