diff --git a/mhd-modules/mhd-system/pom.xml b/mhd-modules/mhd-system/pom.xml
index cb2dcc86f..b88cb5ba2 100644
--- a/mhd-modules/mhd-system/pom.xml
+++ b/mhd-modules/mhd-system/pom.xml
@@ -116,6 +116,11 @@
xxl-job-core
2.4.0
+
+ org.jsoup
+ jsoup
+ 1.17.2
+
diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java
index a66ed0d6c..cfcd73da3 100644
--- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java
+++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/contractManage/ContractManageApplicationService.java
@@ -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);
diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobBusinessConfig.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobBusinessConfig.java
new file mode 100644
index 000000000..3e4e6508e
--- /dev/null
+++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobBusinessConfig.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobOpenApiUtil.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobOpenApiUtil.java
index 5edcdea53..ffbd10e16 100644
--- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobOpenApiUtil.java
+++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManage/repository/util/XxlJobOpenApiUtil.java
@@ -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 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;
}
}
\ No newline at end of file
diff --git a/mhd_bms/pom.xml b/mhd_bms/pom.xml
index fa731f470..0ed437df8 100644
--- a/mhd_bms/pom.xml
+++ b/mhd_bms/pom.xml
@@ -100,6 +100,11 @@
xxl-job-core
2.4.0
+
+ org.jsoup
+ jsoup
+ 1.17.2
+
com.alibaba
diff --git a/mhd_bms/src/main/java/com/mhd/bms/application/server/settlementCustomers/SettlementCustomersApplicationService.java b/mhd_bms/src/main/java/com/mhd/bms/application/server/settlementCustomers/SettlementCustomersApplicationService.java
index 5d64df651..51b5077e4 100644
--- a/mhd_bms/src/main/java/com/mhd/bms/application/server/settlementCustomers/SettlementCustomersApplicationService.java
+++ b/mhd_bms/src/main/java/com/mhd/bms/application/server/settlementCustomers/SettlementCustomersApplicationService.java
@@ -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);
diff --git a/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobBusinessConfig.java b/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobBusinessConfig.java
new file mode 100644
index 000000000..d66a61ff2
--- /dev/null
+++ b/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobBusinessConfig.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobOpenApiUtil.java b/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobOpenApiUtil.java
index 41953d8c4..791df0538 100644
--- a/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobOpenApiUtil.java
+++ b/mhd_bms/src/main/java/com/mhd/bms/domain/settlementCustomers/repository/util/XxlJobOpenApiUtil.java
@@ -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 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;
}
}
\ No newline at end of file