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

news2024/9/25 11:16:46

目录

一、项目版本

二、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 {

    @Resource
    private AdminBiz adminBiz;

    @Resource
    private 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) {

        // valid
        if (!"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 mapping
        if ("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);

    @Resource
    private XxlJobGroupDao xxlJobGroupDao;
    @Resource
    private XxlJobInfoDao xxlJobInfoDao;
    @Resource
    public XxlJobLogDao xxlJobLogDao;
    @Resource
    private XxlJobLogGlueDao xxlJobLogGlueDao;
    @Resource
    private XxlJobLogReportDao xxlJobLogReportDao;

    @Override
    public Map<String, Object> pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {

        // page list
        List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
        int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);

        // package result
        Map<String, Object> maps = new HashMap<String, Object>();
        maps.put("recordsTotal", list_count);        // 总记录数
        maps.put("recordsFiltered", list_count);    // 过滤后的总记录数
        maps.put("data", list);                    // 分页列表
        return maps;
    }

    @Override
    public ReturnT<String> add(XxlJobInfo jobInfo) {

        // valid base
        XxlJobGroup 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 trigger
        ScheduleTypeEnum 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 job
        if (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 shell
        if (GlueTypeEnum.GLUE_SHELL == GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource() != null) {
            jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
        }

        // valid advanced
        if (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 valid
        if (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 db
        jobInfo.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;
        }
    }

    @Override
    public ReturnT<String> update(XxlJobInfo jobInfo) {

        // valid base
        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 trigger
        ScheduleTypeEnum 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 advanced
        if (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 valid
        if (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 valid
        XxlJobGroup 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 info
        XxlJobInfo 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;
    }

    @Override
    public 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;
    }

    @Override
    public ReturnT<String> start(int id) {
        XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);

        // valid
        ScheduleTypeEnum 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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 count
        Set<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;
    }

    @Override
    public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {

        // process
        List<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);
    }

    @Override
    public 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];
        }

        @Override
        public Type[] getActualTypeArguments() {
            return args;
        }

        @Override
        public Type getRawType() {
            return raw;
        }

        @Override
        public 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;				// 主键ID
	
	private int jobGroup;		// 执行器主键ID
	private 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.GlueTypeEnum
	private 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()));
		// 一致性hash
        requestInfo.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,再删除job
        if (!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.coloradmin.cn/o/1324233.html

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

相关文章

java注意项--更新中

前言&#xff1a; 1.大小写规定 1.1.类名和接口名&#xff1a;每个单词首字母大写。如GoodStudent&#xff1b; 是一个单词的时候首字母大写。如Student&#xff1b; 1.2.变量和方法名&#xff1a;第一个首字母小写&#xff0c;后序首字母大写。如firstName&#xff1b; 是一…

Web请求与响应

目录 Postman Postman简介 Postman的使用 请求 简单参数 实体参数 数组参数 集合参数 日期参数 Json参数 路径参数 响应 ResponseBody 统一响应结果 Postman Postman简介 postman是一款功能强大的网页调试与发送网页http请求的Chrome插件&#xff0c;常用于进行…

JavaSE 搜索树

目录 1 概念2 操作2.1 查找2.2 插入2.3 删除 3 性能分析4 和 java 类集的关系 1 概念 二叉搜索树 又称 二叉排序树&#xff0c;它是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值&#xff1b;若它…

MyBatis的ORM映射

目录 什么是ORM 一&#xff0c;列的别名 二&#xff0c;结果映射 三&#xff0c;总结 什么是ORM ORM&#xff1a;对象关系映射&#xff08;Object Relational Mapping&#xff0c;简称ORM&#xff09;模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简…

【六大排序详解】开篇 :插入排序 与 希尔排序

插入排序 与 希尔排序 六大排序之二 插入排序 与 希尔排序1 排序1.1排序的概念 2 插入排序2.1 插入排序原理2.2 排序步骤2.3 代码实现 3 希尔排序3.1 希尔排序原理3.2 排序步骤3.3 代码实现 4 时间复杂度分析 Thanks♪(&#xff65;ω&#xff65;)&#xff89;下一篇文章见&am…

统计分析绘图软件 GraphPad Prism 10 mac功能介绍

GraphPad Prism mac是一款专业的统计和绘图软件&#xff0c;主要用于生物医学研究、实验设计和数据分析。 GraphPad Prism mac功能和特点 数据导入和整理&#xff1a;GraphPad Prism 可以导入各种数据格式&#xff0c;并提供直观的界面用于整理、编辑和管理数据。用户可以轻松地…

MySQL——表的增删查改

目录 一.Create&#xff08;创建&#xff09; 1.单行数据 全列插入 2.多行数据 指定列插入 3.插入否则更新 4. 替换 二.Retrieve&#xff08;读取&#xff09; 1. select 列 查询 2.where 条件 3.结果排序 4.筛选分页结果 三.Update &#xff08;修改&#xff09;…

ROS学习笔记(七)---参数服务器

ROS学习笔记文章目录 01. ROS学习笔记(一)—Linux安装VScode 02. ROS学习笔记(二)—使用 VScode 开发 ROS 的Python程序&#xff08;简例&#xff09; 03. ROS学习笔记(三)—好用的终端Terminator 04. ROS学习笔记(四)—使用 VScode 启动launch文件运行多个节点 05. ROS学习笔…

SMARTFORMS打印问题

一、问题概述 项目中碰到EPSON针式打印机&#xff0c;SAP打印出来的三单合一&#xff0c;是想横向打印&#xff0c;结果不管怎么设置打印出来都是纵向的&#xff1b; 二、调整 1、首先调整SMARTFORMS的打印方向&#xff0c;使用T-CODE:SMARTFORMS&#xff0c;如下图&#xf…

嵌入式串口输入详细实例

学习目标 掌握串口初始化流程掌握串口输出单个字符掌握串口输出字符串掌握通过串口printf熟练掌握串口开发流程学习内容 需求 串口循环输出内容到PC机。 串口数据发送 添加Usart功能。 首先,选中Firmware,鼠标右键,点击Manage Project Items 接着,将gd32f4xx_usart.c添…

Dokit 开源库:简化 Android 应用开发的利器

Dokit 开源库&#xff1a;简化 Android 应用开发的利器 一、Dokit 简介二、Dokit 功能三、Dokit 使用3.1 DoKit Android 最新版本3.2 DoKit Android 接入步骤 四、总结 在 Android 应用开发过程中&#xff0c;我们经常需要处理调试、性能优化和用户体验等方面的问题。然而&…

【python】进阶--->并发编程之协程

一、协程 是另外一种实现多任务的方式,只不过比线程占用更小的执行单元(需要的资源).因为它自带cpu上下文,就可以在合适的时机,从一个协程切换到另一个协程. (任务数量多于cpu时)系统在很短的时间内,将cpu轮流分配给不同的任务执行,造成了多任务同时运行的错觉.而每个任务在运行…

全面解析找不到xinput1_3.dll无法继续执行代码的多种解决方案(实用教程)

xinput1_3.dll文件是什么&#xff1f; xinput1_3.dll是一个动态链接库文件&#xff0c;它是DirectInput的组件之一。DirectInput是微软公司开发的一种输入设备驱动程序&#xff0c;用于处理游戏控制器、键盘、鼠标等输入设备的信号。xinput1_3.dll文件主要负责处理游戏控制器的…

年终汇报这么写,升值加薪必有你!

#01 你这么能干&#xff0c; 老板知道吗&#xff1f; — 打工人最怕什么&#xff1f; 最怕你忙前忙后&#xff0c;干活一大堆&#xff0c;气出一身结节&#xff0c;锅还没少背&#xff0c;最后升职加薪没有你&#xff0c;出国旅游不带你&#xff1b;更怕你日常996&#xf…

C语言归并排序(合并排序)算法以及代码

合并排序是采用分治法&#xff0c;先将无序序列划分为有序子序列&#xff0c;再将有序子序列合并成一个有序序列的有效的排序算法。 原理&#xff1a;先将无序序列利用二分法划分为子序列&#xff0c;直至每个子序列只有一个元素(单元素序列必有序)&#xff0c;然后再对有序子序…

HTML5+CSS3小实例:纯CSS实现锚点平滑过渡

实例:纯CSS实现锚点平滑过渡 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"&…

宠物干货类软文怎么写?媒介盒子分享

虽然近年来生育率有所减少&#xff0c;但是养宠物的人却大大增加&#xff0c;随之而来的宠物经济也是一个值得关注的点。做宠物生意想要脱颖而出&#xff0c;可以依靠软文营销&#xff0c;其中宠物干货类软文由于其价值性能够带来较高的转化率今天媒介盒子主要来和大家聊聊宠物…

QT 前端技术 QSS(1)

伪装态是指当鼠标悬停在按钮上的时候&#xff0c;按钮的字体背景颜色等会发生改变。 这句话意思在this里面找到QTextEdit控件#后面表示指定的控件名称就是从所有QTextEdit中选出叫做lbsize的QTextEdit并对其进行后面的操作。 如果将QTextEdit#lbsize删除的话就是将this中全部的…

c语言编写http服务器(Linux下运行)

参考文章&#xff1a;https://blog.csdn.net/baixingyubxy/article/details/125964986?spm1001.2014.3001.5506 上面是详细讲解&#xff0c;我这篇是总结了他的代码&#xff0c;因为他没给整体代码 所有代码&#xff1a; #include <stdio.h> #include <stdlib.h&g…

echarts地图map点击某一区域设置选中颜色/select选中文字颜色设置无效

选中区域为红色&#xff0c;字体为白色 1.selectedMode: ‘single’,设置单选&#xff0c;多选&#xff0c;不选中 2.series/map/select属性 series: [{type: map,map: area,//单选selectedMode: single,aspectScale: 0.73,layoutCenter: [50%, 51%], //地图位置layoutSize: …