个人开发者接入京东联盟开放平台

63 阅读5分钟

大家好,我是小悟。

京东联盟开放平台是京东集团旗下的电商广告联盟平台,主要业务模式为CPS(按成交订单支付佣金),个人开发者可通过社交APP、聊天工具等进行推广并赚取佣金。

图片

平台依托京东的海量商家和大数据能力,提供精准的营销解决方案。

下面将实现SpringBoot接入京东联盟开放平台,包括环境准备、核心步骤、代码实现和注意事项。

图片

一、前期准备:注册与配置

1、注册京东开放平台账号:

访问京东开放平台官网,完成个人实名认证。

在开发者中心创建应用,填写使用场景(如“商品推广工具”),平台将审核技术能力与业务匹配度。

审核通过后,获取 AppKey(应用标识)和 AppSecret(签名密钥),这两个参数是API调用的核心凭证。

2、开发环境准备:

技术栈:SpringBoot 2.7+、JDK 8+、Maven 3.6+。

依赖:在 pom.xml 中添加必要的依赖(HTTP客户端、JSON处理工具等)。

<dependencies>
    <!-- SpringBoot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- HTTP客户端 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    <!-- JSON处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <!-- 签名工具 -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
    </dependency>
</dependencies>

3、配置参数:

在 application.yml 中配置京东联盟参数(参考实际项目的配置方式):

jd:
  union:
    app-key: "你的AppKey"
    app-secret: "你的AppSecret"
    api-url: "https://api.jd.com/routerjson"
    # 联盟商品ID示例:动态字符串如 "VgDXlT9hVVVmDDiCbofTFhV7_VIfTFhV7VVyGGPNs"[citation:6]

二、核心步骤:接口调用与实现

接入流程主要包括:签名生成 → 请求发送 → 数据解析 → 业务处理。下面以查询商品详情接口(jd.union.open.goods.detail.query)为例,分步说明。

步骤1:签名生成

京东API要求对所有请求参数进行签名验证,推荐使用更安全的 HMAC-SHA256算法。签名步骤如下:

1、将所有请求参数(除 sign 外)按ASCII码升序排序。

2、将排序后的参数键值对拼接成字符串

(格式:key1=value1&key2=value2),并进行URL编码。

3、使用 AppSecret 对拼接字符串进行HMAC-SHA256加密,结果转为大写作为最终签名。

SpringBoot代码实现:

import org.springframework.stereotype.Component;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Component
public class JdSignatureUtil {
    /**
     * 生成京东API签名(HMAC-SHA256)
     * @param params 请求参数Map(需包含app_key、method、timestamp等公共参数)
     * @param appSecret 应用密钥
     * @return 大写签名字符串
     */
    public static String generateSign(Map<String, String> params, String appSecret) {
        try {
            // 1. 参数按ASCII升序排序
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);

            // 2. 拼接键值对(URL编码)
            StringBuilder signStr = new StringBuilder();
            for (String key : keys) {
                if ("sign".equals(key)) continue; // 签名参数不参与签名
                String value = params.get(key);
                signStr.append(key)
                       .append("=")
                       .append(URLEncoder.encode(value, StandardCharsets.UTF_8.name()))
                       .append("&");
            }
            if (signStr.length() > 0) {
                signStr.deleteCharAt(signStr.length() - 1); // 移除最后一个"&"
            }

            // 3. HMAC-SHA256加密
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            byte[] hash = mac.doFinal(signStr.toString().getBytes(StandardCharsets.UTF_8));

            // 4. 转为大写十六进制
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString().toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("生成签名失败: " + e.getMessage(), e);
        }
    }
}

步骤2:发送HTTP请求

京东联盟API统一通过 api.jd.com/routerjson 地址调用,支持POST/GET方式。以下封装一个通用的请求工具类:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;

@Component
public class JdApiClient {
    @Value("${jd.union.app-key}")
    private String appKey;

    @Value("${jd.union.app-secret}")
    private String appSecret;

    @Value("${jd.union.api-url}")
    private String apiUrl;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 调用京东联盟API
     * @param method 接口方法名(如 jd.union.open.goods.detail.query)
     * @param bizParams 业务参数(如商品ID、场景ID等)
     * @return API响应结果(JSON字符串)
     */
    public String callApi(String method, Map<String, String> bizParams) {
        try {
            // 1. 构建公共参数
            Map<String, String> params = new HashMap<>();
            params.put("app_key", appKey);
            params.put("method", method);
            params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            params.put("format", "json");
            params.put("v", "1.0");
            if (bizParams != null) {
                params.putAll(bizParams); // 添加业务参数
            }

            // 2. 生成签名
            String sign = JdSignatureUtil.generateSign(params, appSecret);
            params.put("sign", sign);

            // 3. 发送POST请求
            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpPost httpPost = new HttpPost(apiUrl);
                httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

                // 构建表单参数
                List<String> paramList = new ArrayList<>();
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    paramList.add(entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()));
                }
                StringEntity entity = new StringEntity(String.join("&", paramList), StandardCharsets.UTF_8);
                httpPost.setEntity(entity);

                // 4. 解析响应
                String response = EntityUtils.toString(httpClient.execute(httpPost).getEntity(), StandardCharsets.UTF_8);
                return response;
            }
        } catch (Exception e) {
            throw new RuntimeException("调用京东API失败: " + e.getMessage(), e);
        }
    }
}

步骤3:处理联盟商品ID

2025年联盟商品ID升级为动态字符串格式

(如 VgDXlT9hVVVmDDiCbofTFhV7_VIfTFhV7VVyGGPNs),由A段(动态变化)和B段(相对稳定)组成,需配合场景ID(sceneId)使用。常规推广场景使用 sceneId=1,比价场景使用 sceneId=2。

ID解析工具类:

@Component
public class UnionIdParser {
    /**
     * 解析联盟商品ID
     * @param unionId 动态ID(格式:A段_B段)
     * @return 解析结果,包含A段、B段和有效性标志
     */
    public Map<String, Object> parseUnionId(String unionId) {
        Map<String, Object> result = new HashMap<>();
        if (unionId == null || !unionId.contains("_") || unionId.length() > 50) {
            result.put("isValid", false);
            result.put("error", "无效的联盟商品ID格式");
            return result;
        }

        String[] segments = unionId.split("_", 2);
        result.put("fullId", unionId);
        result.put("aSegment", segments[0]); // 动态部分
        result.put("bSegment", segments[1]); // 稳定部分(用于商品去重)
        result.put("isValid", true);
        return result;
    }
}

步骤4:完整接口调用示例(查询商品详情)

创建SpringBoot Controller 或 Service 调用商品详情接口:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;

@RestController
@RequestMapping("/api/jd")
public class JdUnionController {
    @Autowired
    private JdApiClient jdApiClient;

    @Autowired
    private UnionIdParser unionIdParser;

    /**
     * 查询商品详情(联盟接口)
     * @param unionId 联盟商品ID(动态字符串)
     * @param sceneId 场景ID(默认1-常规推广)
     * @return 商品详情JSON
     */
    @GetMapping("/goods/detail")
    public String getGoodsDetail(@RequestParam String unionId, 
                                 @RequestParam(defaultValue = "1") String sceneId) {
        // 1. 验证联盟ID格式
        Map<String, Object> idInfo = unionIdParser.parseUnionId(unionId);
        if (!Boolean.TRUE.equals(idInfo.get("isValid"))) {
            return "{"error": "联盟商品ID格式无效"}";
        }

        // 2. 构建业务参数
        Map<String, String> bizParams = new HashMap<>();
        bizParams.put("unionId", unionId);
        bizParams.put("sceneId", sceneId);
        // fields参数:指定返回字段(减少数据传输)[citation:5]
        bizParams.put("fields", "skuId,title,price,stock,shopName,originalPrice,specs");

        // 3. 调用API
        String response = jdApiClient.callApi("jd.union.open.goods.detail.query", bizParams);

        // 4. 可在此添加业务处理(如解析JSON、存储数据库等)
        // 示例:解析价格和库存
        try {
            Map<String, Object> data = new ObjectMapper().readValue(response, Map.class);
            // 根据实际响应结构提取数据(通常嵌套在"data"字段下)
            System.out.println("API响应: " + data);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return response;
    }
}

步骤5:接收京东推送(如订单通知)

京东联盟可能向你的服务器推送订单成交等异步通知(Webhook),你需要提供公网可访问的API接口。以下是一个接收推送的示例:

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@RestController
public class JdWebhookController {
    @Value("${jd.union.app-secret}")
    private String appSecret;

    /**
     * 接收京东推送(如订单成交通知)
     * 注意:需配置公网域名(如使用Ngrok或云服务器)[citation:2]
     * @param request HTTP请求(包含签名参数)
     * @return 固定格式响应[citation:2]
     */
    @PostMapping("/jd/webhook/order")
    public Map<String, Object> handleOrderWebhook(HttpServletRequest request) {
        try {
            // 1. 获取参数(京东推送参数包含:app_key、method、sign、timestamp等)[citation:2]
            String appKey = request.getParameter("app_key");
            String sign = request.getParameter("sign");
            String timestamp = request.getParameter("timestamp");
            // 业务参数(如订单信息)可能通过360buy_param_json传递[citation:2]
            String bizJson = request.getParameter("360buy_param_json");

            // 2. 签名验证(防止伪造请求)
            Map<String, String> params = new HashMap<>();
            for (String key : request.getParameterMap().keySet()) {
                if (!"sign".equals(key)) {
                    params.put(key, request.getParameter(key));
                }
            }
            boolean isValid = JdSignatureUtil.generateSign(params, appSecret).equals(sign);
            if (!isValid) {
                throw new RuntimeException("签名验证失败");
            }

            // 3. 处理业务逻辑(如解析订单、发送邮件通知等[citation:9])
            System.out.println("收到京东推送: " + bizJson);
            // 示例:发送邮件通知(可参考实际项目[citation:9])
            // emailService.sendOrderNotification(bizJson);

            // 4. 返回成功响应(格式必须符合京东要求[citation:2])
            return Map.of(
                "reponse", Map.of(
                    "code", "0000",
                    "data", true,
                    "uuid", UUID.randomUUID().toString()
                )
            );
        } catch (Exception e) {
            return Map.of(
                "reponse", Map.of(
                    "code", "5000",
                    "errMsg", "处理失败: " + e.getMessage(),
                    "uuid", UUID.randomUUID().toString()
                )
            );
        }
    }
}

三、注意事项

错误处理:

签名错误(返回码1001):检查参数排序、URL编码和AppSecret是否正确。

频率超限:实现动态限流(如缓冲30%空间)。

性能优化:

缓存策略:使用Redis缓存商品静态信息(如标题、品牌),设置5分钟过期。

字段筛选:始终通过 fields 参数指定所需字段,减少网络传输。

实时性处理:京东API价格更新延迟≤3秒,库存≤15秒,适合实时监控场景。

安全与合规:

敏感信息:AppSecret 必须存储在服务器环境变量或配置中心,禁止硬编码在代码中。

推送接口:接收京东推送的服务器需配置HTTPS,并使用签名验证确保安全性。

四、总结

接入京东联盟开放平台,核心在于签名生成、API调用和数据处理。流程上,需要先完成实名认证并获取AppKey/AppSecret。

开发时,应用层面,可利用商品详情接口构建推广工具,或通过订单推送实现自动化通知,采用缓存、限流策略提升性能。

通过以上步骤,开发者可快速搭建一个京东联盟集成应用,实现商品推广、订单跟踪等功能。

图片

谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。

您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海