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