自动添加xxl任务;
This commit is contained in:
@@ -116,6 +116,11 @@
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>2.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.17.2</version>
|
||||
</dependency>
|
||||
<!-- JPush推送 -->
|
||||
<!-- jpush极光推送导入start -->
|
||||
<!-- <dependency>-->
|
||||
|
||||
+30
-12
@@ -98,7 +98,8 @@ public class ContractManageApplicationService {
|
||||
private ContractManageParametersMapper contractManageParametersMapper;
|
||||
@Autowired
|
||||
private IContractManageParametersService contractManageParametersService;
|
||||
|
||||
@Resource
|
||||
private XxlJobOpenApiUtil apiUtil;
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
private static final String token = "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjozNTYzLCJ0b3BPcmdhbml6YXRpb25JZCI6MjgyNywidXNlcl9rZXkiOiI0N2MzY2U4My0wMmFjLTQ0NTQtOTdiYS1lYmQwMDc2MzNiNDMiLCJ1c2VybmFtZSI6ImNhbmdtYSJ9.tnZyywwburfBo3Kizdhfk5eYdXbrrZ9976Z0W7GrS6UqSpKwfI2RwdRwfYx7DbD7Ri1Fdj_eOVxBkjvdFF226Q";
|
||||
@@ -984,27 +985,44 @@ public class ContractManageApplicationService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建夜间23点定时任务
|
||||
* @param shipperId 结算对象id,作为任务参数
|
||||
* @return xxlJobId 保存到业务表,后续用于删除/暂停
|
||||
*/
|
||||
public Integer addXxlJob(String shipperId) {
|
||||
//1.实例化工具类,建议交给Spring管理
|
||||
XxlJobOpenApiUtil apiUtil = new XxlJobOpenApiUtil(adminAddresses,token);
|
||||
|
||||
//2.构建新增任务参数
|
||||
XxlJobOpenApiUtil.JobInfoAddReq req = new XxlJobOpenApiUtil.JobInfoAddReq();
|
||||
req.setJobGroup(5); //你的执行器组id
|
||||
req.setJobGroup(5);
|
||||
req.setJobDesc("整租推送计费单据/流水任务,结算对象id:" + shipperId);
|
||||
req.setJobCron("0 0 1 * * ?");
|
||||
req.setAuthor("system");
|
||||
req.setAlarmEmail("");
|
||||
req.setScheduleType("CRON");
|
||||
// 每天晚上23点执行
|
||||
req.setScheduleConf("0 0 1 * * ?");
|
||||
req.setGlueType("BEAN");
|
||||
req.setExecutorHandler("pushContractManageToBms");
|
||||
req.setExecutorParam(shipperId); //传入业务单号
|
||||
req.setExecutorParam(shipperId);
|
||||
req.setGlueRemark("");
|
||||
req.setGlueSource("");
|
||||
req.setExecutorRouteStrategy("FIRST");
|
||||
req.setChildJobId(null);
|
||||
req.setMisfireStrategy("DO_NOTHING");
|
||||
req.setExecutorBlockStrategy("SERIAL_EXECUTION");
|
||||
req.setExecutorTimeout(0);
|
||||
req.setExecutorFailRetryCount(0);
|
||||
|
||||
//3.调用创建任务接口 ,返回任务ID
|
||||
Integer xxlJobId = apiUtil.addJob(req);
|
||||
if(xxlJobId == null){
|
||||
// 创建定时任务失败,抛异常/重试,不要让单据直接保存成功
|
||||
boolean addOk = apiUtil.addJob(req);
|
||||
if (!addOk) {
|
||||
throw new RuntimeException("创建夜间定时任务失败");
|
||||
}
|
||||
Integer xxlJobId = apiUtil.queryJobIdByDescAndParam(req.getJobDesc(), shipperId);
|
||||
if (xxlJobId == null) {
|
||||
throw new RuntimeException("定时任务创建成功,但查询jobId失败");
|
||||
}
|
||||
return xxlJobId;
|
||||
}
|
||||
|
||||
|
||||
public void stopXxlJob(Integer shipperId) {
|
||||
//1.实例化工具类,建议交给Spring管理
|
||||
XxlJobOpenApiUtil apiUtil = new XxlJobOpenApiUtil(adminAddresses,token);
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.mhd.basic.domain.contractManage.repository.util;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class XxlJobBusinessConfig {
|
||||
|
||||
@Value("${xxl.job.admin.address}")
|
||||
private String adminAddress;
|
||||
|
||||
@Value("${xxl.job.admin.cookie}")
|
||||
private String adminCookie;
|
||||
|
||||
@Bean
|
||||
public XxlJobOpenApiUtil xxlJobOpenApiUtil() {
|
||||
return new XxlJobOpenApiUtil(adminAddress, adminCookie);
|
||||
}
|
||||
}
|
||||
+130
-84
@@ -1,138 +1,184 @@
|
||||
package com.mhd.basic.domain.contractManage.repository.util;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* XXL‑JOB OpenApi 工具类
|
||||
* 调用XXL‑JOB后台页面接口(抓包获取 /jobinfo/*)
|
||||
* 鉴权依赖JSESSIONID Cookie,非官方openapi;老版本xxl‑job无新增任务openapi
|
||||
*/
|
||||
@Slf4j
|
||||
public class XxlJobOpenApiUtil {
|
||||
|
||||
/** xxl‑job admin地址,例:http://127.0.0.1:8080/xxl‑job‑admin */
|
||||
private final String adminUrl;
|
||||
/** 系统配置里的AccessToken */
|
||||
private final String accessToken;
|
||||
private final String cookie;
|
||||
|
||||
public XxlJobOpenApiUtil(String adminUrl, String accessToken) {
|
||||
this.adminUrl = adminUrl.endsWith("/") ? adminUrl.substring(0, adminUrl.length() -1) : adminUrl;
|
||||
this.accessToken = accessToken;
|
||||
/**
|
||||
* @param adminUrl xxl‑job admin地址 示例:http://127.0.0.1:8080/xxl-job-admin
|
||||
* @param cookie 浏览器登录后的完整Cookie(JSESSIONID=xxx)
|
||||
*/
|
||||
public XxlJobOpenApiUtil(String adminUrl, String cookie) {
|
||||
this.adminUrl = StrUtil.removeSuffix(adminUrl, "/");
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增定时任务
|
||||
* @param addReq 请求参数
|
||||
* @return jobId 任务ID,返回null代表调用失败
|
||||
* 新增定时任务 POST /jobinfo/add
|
||||
* @param addReq 请求实体,与浏览器payload字段完全对齐
|
||||
* @return true=新增成功,false=失败
|
||||
*/
|
||||
public Integer addJob(JobInfoAddReq addReq) {
|
||||
String url = adminUrl + "/api/jobinfo/add";
|
||||
public boolean addJob(JobInfoAddReq addReq) {
|
||||
String url = adminUrl + "/jobinfo/add";
|
||||
try {
|
||||
// 实体对象转map,解决form不能传bean的爆红
|
||||
Map<String, Object> formMap = BeanUtil.beanToMap(addReq);
|
||||
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Authorization", accessToken)
|
||||
.form(formMap) //传入map,不再传实体
|
||||
.header("Cookie", cookie)
|
||||
.form(formMap)
|
||||
.execute();
|
||||
int status = response.getStatus();
|
||||
log.info("[XxlJob] addJob status:{}", status);
|
||||
// 新增成功302重定向到列表页
|
||||
return status == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("[XxlJob] addJob异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String body = response.body();
|
||||
log.info("xxl‑job addJob resp:{}", body);
|
||||
XxlApiResp resp = JSONUtil.toBean(body, XxlApiResp.class);
|
||||
if (resp != null && resp.getCode() == 200) {
|
||||
return Integer.valueOf(resp.getContent().toString());
|
||||
/**
|
||||
* 根据【任务描述+执行器参数】查询jobId
|
||||
* @param jobDesc 任务描述
|
||||
* @param executorParam 任务参数(业务shipperId)
|
||||
* @return jobId,查不到返回null
|
||||
*/
|
||||
public Integer queryJobIdByDescAndParam(String jobDesc, String executorParam) {
|
||||
String url = adminUrl + "/jobinfo/pageList";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("jobGroup", "")
|
||||
.form("jobDesc", jobDesc)
|
||||
.form("executorHandler", "")
|
||||
.form("executorParam", executorParam)
|
||||
.form("triggerStatus", "-1")
|
||||
.execute();
|
||||
String html = response.body();
|
||||
if (StrUtil.isBlank(html)) {
|
||||
return null;
|
||||
}
|
||||
Document doc = Jsoup.parse(html);
|
||||
Elements trList = doc.select("tr");
|
||||
for (Element tr : trList) {
|
||||
String dataId = tr.attr("data-id");
|
||||
if (StrUtil.isBlank(dataId)) {
|
||||
continue;
|
||||
}
|
||||
return Integer.parseInt(dataId);
|
||||
}
|
||||
log.error("新增xxl‑job任务失败,resp:{}", body);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("调用xxl‑job addJob异常", e);
|
||||
log.error("[XxlJob] queryJobId异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停任务 POST /jobinfo/pause
|
||||
* @param jobId xxl任务id
|
||||
* @return true成功
|
||||
*/
|
||||
public boolean pauseJob(Integer jobId) {
|
||||
if (jobId == null) {
|
||||
return false;
|
||||
}
|
||||
String url = adminUrl + "/jobinfo/pause";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("id", jobId)
|
||||
.execute();
|
||||
return response.getStatus() == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("[XxlJob] pauseJob jobId:{}异常", jobId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
* @param jobId 任务id
|
||||
* 开启任务 POST /jobinfo/start
|
||||
* @param jobId xxl任务id
|
||||
* @return true成功
|
||||
*/
|
||||
public boolean startJob(Integer jobId) {
|
||||
if (jobId == null) {
|
||||
return false;
|
||||
}
|
||||
String url = adminUrl + "/jobinfo/start";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("id", jobId)
|
||||
.execute();
|
||||
return response.getStatus() == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("[XxlJob] startJob jobId:{}异常", jobId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务 POST /jobinfo/remove
|
||||
* @param jobId xxl任务id
|
||||
* @return true成功
|
||||
*/
|
||||
public boolean removeJob(Integer jobId) {
|
||||
String url = adminUrl + "/api/jobinfo/remove";
|
||||
try (HttpResponse response = HttpRequest.post(url)
|
||||
.header("Authorization", accessToken)
|
||||
.form("id", jobId)
|
||||
.execute()) {
|
||||
String body = response.body();
|
||||
XxlApiResp resp = JSONUtil.toBean(body, XxlApiResp.class);
|
||||
if (resp != null && resp.getCode() == 200) {
|
||||
return true;
|
||||
}
|
||||
log.error("删除xxl‑job任务失败 jobId:{},resp:{}", jobId, body);
|
||||
if (jobId == null) {
|
||||
return false;
|
||||
}
|
||||
String url = adminUrl + "/jobinfo/remove";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("id", jobId)
|
||||
.execute();
|
||||
return response.getStatus() == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("调用xxl‑job removeJob异常", e);
|
||||
log.error("[XxlJob] removeJob jobId:{}异常", jobId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停任务
|
||||
* 请求实体,与浏览器F12抓包payload字段一一对应
|
||||
*/
|
||||
public boolean pauseJob(Integer jobId) {
|
||||
String url = adminUrl + "/api/jobinfo/pause";
|
||||
try (HttpResponse response = HttpRequest.post(url)
|
||||
.header("Authorization", accessToken)
|
||||
.form("id", jobId)
|
||||
.execute()) {
|
||||
String body = response.body();
|
||||
XxlApiResp resp = JSONUtil.toBean(body, XxlApiResp.class);
|
||||
return resp != null && resp.getCode() == 200;
|
||||
} catch (Exception e) {
|
||||
log.error("pauseJob异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------- 实体 ----------------
|
||||
|
||||
@Data
|
||||
public static class JobInfoAddReq {
|
||||
/** 执行器组ID xxl_job_group.id */
|
||||
private Integer jobGroup;
|
||||
/** 任务描述 */
|
||||
private String jobDesc;
|
||||
/** 路由策略 ROUND:轮询 */
|
||||
private String executorRouteStrategy = "ROUND";
|
||||
/** cron表达式 23点 0 0 23 * * ? */
|
||||
private String jobCron;
|
||||
/** @XxlJob 注解handler名称 */
|
||||
private String author;
|
||||
private String alarmEmail;
|
||||
private String scheduleType;
|
||||
private String scheduleConf;
|
||||
private String glueType;
|
||||
private String executorHandler;
|
||||
/** 任务参数,这里存业务单号 */
|
||||
private String executorParam;
|
||||
/** 阻塞策略 SERIAL_EXECUTION单机串行 */
|
||||
private String executorBlockStrategy = "SERIAL_EXECUTION";
|
||||
/** 超时时间 0不限制 */
|
||||
private Integer executorTimeout = 0;
|
||||
/** 失败重试次数 */
|
||||
private Integer executorFailRetryCount = 0;
|
||||
/** BEAN模式 */
|
||||
private String glueType = "BEAN";
|
||||
private String glueSource = "";
|
||||
private String glueRemark = "";
|
||||
/** 1启用 0停止 */
|
||||
private Integer triggerStatus = 1;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class XxlApiResp {
|
||||
private Integer code;
|
||||
private Object content;
|
||||
private String msg;
|
||||
private String glueRemark;
|
||||
private String glueSource;
|
||||
private String executorRouteStrategy;
|
||||
private Integer childJobId;
|
||||
private String misfireStrategy;
|
||||
private String executorBlockStrategy;
|
||||
private Integer executorTimeout;
|
||||
private Integer executorFailRetryCount;
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,11 @@
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>2.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.17.2</version>
|
||||
</dependency>
|
||||
<!--添加druid连接池 依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
|
||||
+59
-23
@@ -44,6 +44,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
@@ -78,7 +79,8 @@ public class SettlementCustomersApplicationService {
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
private static final String token = "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjozNTYzLCJ0b3BPcmdhbml6YXRpb25JZCI6MjgyNywidXNlcl9rZXkiOiI0N2MzY2U4My0wMmFjLTQ0NTQtOTdiYS1lYmQwMDc2MzNiNDMiLCJ1c2VybmFtZSI6ImNhbmdtYSJ9.tnZyywwburfBo3Kizdhfk5eYdXbrrZ9976Z0W7GrS6UqSpKwfI2RwdRwfYx7DbD7Ri1Fdj_eOVxBkjvdFF226Q";
|
||||
|
||||
@Resource
|
||||
private XxlJobOpenApiUtil apiUtil;
|
||||
/**
|
||||
* 分页查询结算对象列表
|
||||
*/
|
||||
@@ -352,48 +354,82 @@ public class SettlementCustomersApplicationService {
|
||||
return settlementCustomersDomainService.update(settlementCustomersDO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建夜间23点定时任务
|
||||
* @param shipperId 结算对象id,作为任务参数
|
||||
* @return xxlJobId 保存到业务表,后续用于删除/暂停
|
||||
*/
|
||||
public Integer addXxlJob(String shipperId) {
|
||||
//1.实例化工具类,建议交给Spring管理
|
||||
XxlJobOpenApiUtil apiUtil = new XxlJobOpenApiUtil(adminAddresses,token);
|
||||
|
||||
//2.构建新增任务参数
|
||||
XxlJobOpenApiUtil.JobInfoAddReq req = new XxlJobOpenApiUtil.JobInfoAddReq();
|
||||
req.setJobGroup(3); //你的执行器组id
|
||||
req.setJobGroup(5);
|
||||
req.setJobDesc("散租推送计费单据/流水任务,结算对象id:" + shipperId);
|
||||
req.setJobCron("0 0 1 * * ?");
|
||||
req.setAuthor("system");
|
||||
req.setAlarmEmail("");
|
||||
req.setScheduleType("CRON");
|
||||
// 每天晚上23点执行
|
||||
req.setScheduleConf("0 0 1 * * ?");
|
||||
req.setGlueType("BEAN");
|
||||
req.setExecutorHandler("pushBillingRecord");
|
||||
req.setExecutorParam(shipperId); //传入业务单号
|
||||
req.setExecutorParam(shipperId);
|
||||
req.setGlueRemark("");
|
||||
req.setGlueSource("");
|
||||
req.setExecutorRouteStrategy("FIRST");
|
||||
req.setChildJobId(null);
|
||||
req.setMisfireStrategy("DO_NOTHING");
|
||||
req.setExecutorBlockStrategy("SERIAL_EXECUTION");
|
||||
req.setExecutorTimeout(0);
|
||||
req.setExecutorFailRetryCount(0);
|
||||
|
||||
//3.调用创建任务接口 ,返回任务ID
|
||||
Integer xxlJobId = apiUtil.addJob(req);
|
||||
if(xxlJobId == null){
|
||||
// 创建定时任务失败,抛异常/重试,不要让单据直接保存成功
|
||||
boolean addOk = apiUtil.addJob(req);
|
||||
if (!addOk) {
|
||||
throw new RuntimeException("创建夜间定时任务失败");
|
||||
}
|
||||
Integer xxlJobId = apiUtil.queryJobIdByDescAndParam(req.getJobDesc(), shipperId);
|
||||
if (xxlJobId == null) {
|
||||
throw new RuntimeException("定时任务创建成功,但查询jobId失败");
|
||||
}
|
||||
return xxlJobId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建夜间23点定时任务
|
||||
* @param shipperId 结算对象id,作为任务参数
|
||||
* @return xxlJobId 保存到业务表,后续用于删除/暂停
|
||||
*/
|
||||
public Integer addXxlJob1(String shipperId) {
|
||||
//1.实例化工具类,建议交给Spring管理
|
||||
XxlJobOpenApiUtil apiUtil = new XxlJobOpenApiUtil(adminAddresses,token);
|
||||
|
||||
//2.构建新增任务参数
|
||||
XxlJobOpenApiUtil.JobInfoAddReq req = new XxlJobOpenApiUtil.JobInfoAddReq();
|
||||
req.setJobGroup(6); //你的执行器组id
|
||||
req.setJobGroup(5);
|
||||
req.setJobDesc("计费单据/流水生成发票任务,结算对象id:" + shipperId);
|
||||
req.setJobCron("0 0 1 * * ?");
|
||||
req.setAuthor("system");
|
||||
req.setAlarmEmail("");
|
||||
req.setScheduleType("CRON");
|
||||
// 每天晚上23点执行
|
||||
req.setScheduleConf("0 0 1 * * ?");
|
||||
req.setGlueType("BEAN");
|
||||
req.setExecutorHandler("pushBillManage");
|
||||
req.setExecutorParam(shipperId); //传入业务单号
|
||||
req.setExecutorParam(shipperId);
|
||||
req.setGlueRemark("");
|
||||
req.setGlueSource("");
|
||||
req.setExecutorRouteStrategy("FIRST");
|
||||
req.setChildJobId(null);
|
||||
req.setMisfireStrategy("DO_NOTHING");
|
||||
req.setExecutorBlockStrategy("SERIAL_EXECUTION");
|
||||
req.setExecutorTimeout(0);
|
||||
req.setExecutorFailRetryCount(0);
|
||||
|
||||
//3.调用创建任务接口 ,返回任务ID
|
||||
Integer xxlJobId = apiUtil.addJob(req);
|
||||
if(xxlJobId == null){
|
||||
// 创建定时任务失败,抛异常/重试,不要让单据直接保存成功
|
||||
boolean addOk = apiUtil.addJob(req);
|
||||
if (!addOk) {
|
||||
throw new RuntimeException("创建夜间定时任务失败");
|
||||
}
|
||||
Integer xxlJobId = apiUtil.queryJobIdByDescAndParam(req.getJobDesc(), shipperId);
|
||||
if (xxlJobId == null) {
|
||||
throw new RuntimeException("定时任务创建成功,但查询jobId失败");
|
||||
}
|
||||
return xxlJobId;
|
||||
}
|
||||
|
||||
|
||||
public void stopXxlJob(Integer shipperId) {
|
||||
//1.实例化工具类,建议交给Spring管理
|
||||
XxlJobOpenApiUtil apiUtil = new XxlJobOpenApiUtil(adminAddresses,token);
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.mhd.bms.domain.settlementCustomers.repository.util;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class XxlJobBusinessConfig {
|
||||
|
||||
@Value("${xxl.job.admin.address}")
|
||||
private String adminAddress;
|
||||
|
||||
@Value("${xxl.job.admin.cookie}")
|
||||
private String adminCookie;
|
||||
|
||||
@Bean
|
||||
public XxlJobOpenApiUtil xxlJobOpenApiUtil() {
|
||||
return new XxlJobOpenApiUtil(adminAddress, adminCookie);
|
||||
}
|
||||
}
|
||||
+130
-85
@@ -1,139 +1,184 @@
|
||||
package com.mhd.bms.domain.settlementCustomers.repository.util;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* XXL‑JOB OpenApi 工具类
|
||||
* 调用XXL‑JOB后台页面接口(抓包获取 /jobinfo/*)
|
||||
* 鉴权依赖JSESSIONID Cookie,非官方openapi;老版本xxl‑job无新增任务openapi
|
||||
*/
|
||||
@Slf4j
|
||||
public class XxlJobOpenApiUtil {
|
||||
|
||||
/** xxl‑job admin地址,例:http://127.0.0.1:8080/xxl‑job‑admin */
|
||||
private final String adminUrl;
|
||||
/** 系统配置里的AccessToken */
|
||||
private final String accessToken;
|
||||
private final String cookie;
|
||||
|
||||
public XxlJobOpenApiUtil(String adminUrl, String accessToken) {
|
||||
this.adminUrl = adminUrl.endsWith("/") ? adminUrl.substring(0, adminUrl.length() -1) : adminUrl;
|
||||
this.accessToken = accessToken;
|
||||
/**
|
||||
* @param adminUrl xxl‑job admin地址 示例:http://127.0.0.1:8080/xxl-job-admin
|
||||
* @param cookie 浏览器登录后的完整Cookie(JSESSIONID=xxx)
|
||||
*/
|
||||
public XxlJobOpenApiUtil(String adminUrl, String cookie) {
|
||||
this.adminUrl = StrUtil.removeSuffix(adminUrl, "/");
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增定时任务
|
||||
* @param addReq 请求参数
|
||||
* @return jobId 任务ID,返回null代表调用失败
|
||||
* 新增定时任务 POST /jobinfo/add
|
||||
* @param addReq 请求实体,与浏览器payload字段完全对齐
|
||||
* @return true=新增成功,false=失败
|
||||
*/
|
||||
public Integer addJob(JobInfoAddReq addReq) {
|
||||
String url = adminUrl + "/api/jobinfo/add";
|
||||
public boolean addJob(JobInfoAddReq addReq) {
|
||||
String url = adminUrl + "/jobinfo/add";
|
||||
try {
|
||||
// 实体对象转map,解决form不能传bean的爆红
|
||||
Map<String, Object> formMap = BeanUtil.beanToMap(addReq);
|
||||
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Authorization", accessToken)
|
||||
.form(formMap) //传入map,不再传实体
|
||||
.header("Cookie", cookie)
|
||||
.form(formMap)
|
||||
.execute();
|
||||
int status = response.getStatus();
|
||||
log.info("[XxlJob] addJob status:{}", status);
|
||||
// 新增成功302重定向到列表页
|
||||
return status == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("[XxlJob] addJob异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String body = response.body();
|
||||
log.info("xxl‑job addJob resp:{}", body);
|
||||
XxlApiResp resp = JSONUtil.toBean(body, XxlApiResp.class);
|
||||
if (resp != null && resp.getCode() == 200) {
|
||||
return Integer.valueOf(resp.getContent().toString());
|
||||
/**
|
||||
* 根据【任务描述+执行器参数】查询jobId
|
||||
* @param jobDesc 任务描述
|
||||
* @param executorParam 任务参数(业务shipperId)
|
||||
* @return jobId,查不到返回null
|
||||
*/
|
||||
public Integer queryJobIdByDescAndParam(String jobDesc, String executorParam) {
|
||||
String url = adminUrl + "/jobinfo/pageList";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("jobGroup", "")
|
||||
.form("jobDesc", jobDesc)
|
||||
.form("executorHandler", "")
|
||||
.form("executorParam", executorParam)
|
||||
.form("triggerStatus", "-1")
|
||||
.execute();
|
||||
String html = response.body();
|
||||
if (StrUtil.isBlank(html)) {
|
||||
return null;
|
||||
}
|
||||
Document doc = Jsoup.parse(html);
|
||||
Elements trList = doc.select("tr");
|
||||
for (Element tr : trList) {
|
||||
String dataId = tr.attr("data-id");
|
||||
if (StrUtil.isBlank(dataId)) {
|
||||
continue;
|
||||
}
|
||||
return Integer.parseInt(dataId);
|
||||
}
|
||||
log.error("新增xxl‑job任务失败,resp:{}", body);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("调用xxl‑job addJob异常", e);
|
||||
log.error("[XxlJob] queryJobId异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停任务 POST /jobinfo/pause
|
||||
* @param jobId xxl任务id
|
||||
* @return true成功
|
||||
*/
|
||||
public boolean pauseJob(Integer jobId) {
|
||||
if (jobId == null) {
|
||||
return false;
|
||||
}
|
||||
String url = adminUrl + "/jobinfo/pause";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("id", jobId)
|
||||
.execute();
|
||||
return response.getStatus() == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("[XxlJob] pauseJob jobId:{}异常", jobId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
* @param jobId 任务id
|
||||
* 开启任务 POST /jobinfo/start
|
||||
* @param jobId xxl任务id
|
||||
* @return true成功
|
||||
*/
|
||||
public boolean startJob(Integer jobId) {
|
||||
if (jobId == null) {
|
||||
return false;
|
||||
}
|
||||
String url = adminUrl + "/jobinfo/start";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("id", jobId)
|
||||
.execute();
|
||||
return response.getStatus() == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("[XxlJob] startJob jobId:{}异常", jobId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务 POST /jobinfo/remove
|
||||
* @param jobId xxl任务id
|
||||
* @return true成功
|
||||
*/
|
||||
public boolean removeJob(Integer jobId) {
|
||||
String url = adminUrl + "/api/jobinfo/remove";
|
||||
try (HttpResponse response = HttpRequest.post(url)
|
||||
.header("Authorization", accessToken)
|
||||
.form("id", jobId)
|
||||
.execute()) {
|
||||
String body = response.body();
|
||||
XxlApiResp resp = JSONUtil.toBean(body, XxlApiResp.class);
|
||||
if (resp != null && resp.getCode() == 200) {
|
||||
return true;
|
||||
}
|
||||
log.error("删除xxl‑job任务失败 jobId:{},resp:{}", jobId, body);
|
||||
if (jobId == null) {
|
||||
return false;
|
||||
}
|
||||
String url = adminUrl + "/jobinfo/remove";
|
||||
try {
|
||||
HttpResponse response = HttpRequest.post(url)
|
||||
.header("Cookie", cookie)
|
||||
.form("id", jobId)
|
||||
.execute();
|
||||
return response.getStatus() == 302;
|
||||
} catch (Exception e) {
|
||||
log.error("调用xxl‑job removeJob异常", e);
|
||||
log.error("[XxlJob] removeJob jobId:{}异常", jobId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停任务
|
||||
* 请求实体,与浏览器F12抓包payload字段一一对应
|
||||
*/
|
||||
public boolean pauseJob(Integer jobId) {
|
||||
String url = adminUrl + "/api/jobinfo/pause";
|
||||
try (HttpResponse response = HttpRequest.post(url)
|
||||
.header("Authorization", accessToken)
|
||||
.form("id", jobId)
|
||||
.execute()) {
|
||||
String body = response.body();
|
||||
XxlApiResp resp = JSONUtil.toBean(body, XxlApiResp.class);
|
||||
return resp != null && resp.getCode() == 200;
|
||||
} catch (Exception e) {
|
||||
log.error("pauseJob异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------- 实体 ----------------
|
||||
|
||||
@Data
|
||||
public static class JobInfoAddReq {
|
||||
/** 执行器组ID xxl_job_group.id */
|
||||
private Integer jobGroup;
|
||||
/** 任务描述 */
|
||||
private String jobDesc;
|
||||
/** 路由策略 ROUND:轮询 */
|
||||
private String executorRouteStrategy = "ROUND";
|
||||
/** cron表达式 23点 0 0 23 * * ? */
|
||||
private String jobCron;
|
||||
/** @XxlJob 注解handler名称 */
|
||||
private String author;
|
||||
private String alarmEmail;
|
||||
private String scheduleType;
|
||||
private String scheduleConf;
|
||||
private String glueType;
|
||||
private String executorHandler;
|
||||
/** 任务参数,这里存业务单号 */
|
||||
private String executorParam;
|
||||
/** 阻塞策略 SERIAL_EXECUTION单机串行 */
|
||||
private String executorBlockStrategy = "SERIAL_EXECUTION";
|
||||
/** 超时时间 0不限制 */
|
||||
private Integer executorTimeout = 0;
|
||||
/** 失败重试次数 */
|
||||
private Integer executorFailRetryCount = 0;
|
||||
/** BEAN模式 */
|
||||
private String glueType = "BEAN";
|
||||
private String glueSource = "";
|
||||
private String glueRemark = "";
|
||||
/** 1启用 0停止 */
|
||||
private Integer triggerStatus = 1;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class XxlApiResp {
|
||||
private Integer code;
|
||||
private Object content;
|
||||
private String msg;
|
||||
private String glueRemark;
|
||||
private String glueSource;
|
||||
private String executorRouteStrategy;
|
||||
private Integer childJobId;
|
||||
private String misfireStrategy;
|
||||
private String executorBlockStrategy;
|
||||
private Integer executorTimeout;
|
||||
private Integer executorFailRetryCount;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user