| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- /*
- * Copyright (c) 2018-2025, hnqz All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: hnqz
- */
- package net.yyc.quartz.util;
- import cn.hutool.core.util.StrUtil;
- import cn.hutool.http.HttpRequest;
- import cn.hutool.http.HttpUtil;
- import lombok.extern.slf4j.Slf4j;
- import net.yyc.common.core.constant.CommonConstants;
- import net.yyc.common.core.constant.SecurityConstants;
- import net.yyc.quartz.entity.SysJob;
- import net.yyc.quartz.exception.TaskException;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.cloud.client.ServiceInstance;
- import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
- import org.springframework.stereotype.Component;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * 定时任务 REST 反射实现
- * 支持 service-name 模式(http://service-name/path)和 host:port 模式(http://host:port/path)
- *
- * @author 郑健楠
- */
- @Slf4j
- @Component
- public class RestTaskInvok implements ITaskInvok {
- @Autowired
- private LoadBalancerClient loadBalancer;
- @Override
- public void invokMethod(SysJob sysJob) throws TaskException {
- try {
- String executePath = sysJob.getExecutePath();
- String resolvedUrl = resolveUrl(executePath);
- HttpRequest request = HttpUtil.createPost(resolvedUrl);
- // 租户 header
- if (sysJob.getTenantId() != null) {
- request.header(CommonConstants.TENANT_ID, sysJob.getTenantId().toString());
- }
- // 内部调用 header(绕过安全拦截器)
- request.header(SecurityConstants.FROM, SecurityConstants.FROM_IN);
- // 预留扩展 header(可由子类或配置覆盖)
- addExtraHeaders(request, sysJob);
- // 表单参数(params 对应 Controller @RequestParam)
- String methodParams = sysJob.getMethodParamsValue();
- if (StrUtil.isNotBlank(methodParams)) {
- Map<String, Object> formData = new HashMap<>();
- formData.put("params", methodParams);
- request.form(formData);
- }
- request.execute();
- log.debug("REST任务调用完成, url={}, params={}", resolvedUrl, methodParams);
- }
- catch (Exception e) {
- log.error("定时任务restTaskInvok异常,执行任务:{}", sysJob.getExecutePath());
- throw new TaskException("定时任务restTaskInvok业务执行失败,任务:" + sysJob.getExecutePath());
- }
- }
- /**
- * 解析 URL,支持两种模式:
- * 1. service-name 模式:http://service-name/path → 通过 LoadBalancer 解析为实际地址
- * 2. host:port 模式:http://host:port/path → 直接使用
- *
- * @param executePath 原始执行路径
- * @return 解析后的实际 URL
- */
- private String resolveUrl(String executePath) {
- if (executePath == null || !executePath.startsWith("http://")) {
- return executePath;
- }
- try {
- // 提取服务名和路径,例如: http://hnqz-upms-biz/admin/schedule-task/xxx
- String path = executePath.substring(7);
- int slashIndex = path.indexOf('/');
- if (slashIndex == -1) {
- return executePath;
- }
- String serviceName = path.substring(0, slashIndex);
- String servicePath = path.substring(slashIndex);
- // 尝试通过 LoadBalancer 解析服务名
- ServiceInstance instance = loadBalancer.choose(serviceName);
- if (instance != null) {
- return instance.getUri().toString() + servicePath;
- }
- } catch (Exception e) {
- log.warn("服务名解析失败,使用原路径: {}", executePath, e);
- }
- // host:port 模式直接返回原路径
- return executePath;
- }
- /**
- * 扩展点:子类可覆盖此方法添加额外的 header
- * 目前预留,未来可通过 SysJob 新增字段(如 invokeHeaders)实现动态配置
- *
- * @param request HTTP 请求
- * @param sysJob 任务实体
- */
- protected void addExtraHeaders(HttpRequest request, SysJob sysJob) {
- // 预留扩展点,可通过 sysJob.invokeHeaders 或配置文件动态添加 header
- }
- }
|