×

Java获取京东商品详情接口(item_get)实战指南

admin admin 发表于2026-04-02 15:29:09 浏览2 评论0

抢沙发发表评论

一、接口概述

京东开放平台API体系

表格
接口名称功能说明应用场景
jd.item.get获取单个商品详情商品信息同步、详情展示
jd.item.search关键词搜索商品选品、比价系统
jd.item.sku获取SKU信息库存管理、价格监控
jd.item.price实时价格查询动态定价、促销监控
jd.item.comment商品评价获取口碑分析、选品参考

item_get接口核心价值

plain
复制
┌─────────────────────────────────────────┐
│         京东商品详情数据维度              │
├─────────────────────────────────────────┤
│  基础信息:标题、副标题、品牌、类目        │
│  销售信息:价格、促销、库存、销量          │
│  图文内容:主图、详情图、视频、360°展示    │
│  规格信息:SKU矩阵、属性组合、重量尺寸      │
│  服务信息:物流、售后、质保、发票          │
│  店铺信息:店铺评分、资质、客服            │
│  评价数据:好评率、标签、晒单             │
└─────────────────────────────────────────┘

二、接口技术规格

基本信息

表格
属性
接口名称jd.item.get / item_get
协议HTTPS/REST
请求方式GET/POST
数据格式JSON
字符编码UTF-8
认证方式OAuth 2.0 + AppKey/Secret签名
频率限制5000次/天(基础版),可申请提升

请求参数

java
复制
@Data@Builderpublic class JdItemGetRequest {
    
    /** 商品SKU ID(京东商品唯一标识) */
    @NotBlank(message = "SKU ID不能为空")
    private String skuId;
    
    /** 是否需要实时价格(默认true) */
    @Builder.Default
    private Boolean needPrice = true;
    
    /** 是否需要库存信息(默认true) */
    @Builder.Default
    private Boolean needStock = true;
    
    /** 是否需要促销信息(默认true) */
    @Builder.Default
    private Boolean needPromotion = true;
    
    /** 是否需要评价数据(默认false,节省流量) */
    @Builder.Default
    private Boolean needComments = false;
    
    /** 是否需要详情HTML(默认false,数据量大) */
    @Builder.Default
    private Boolean needDetailHtml = false;
    
    /** 指定返回字段(减少数据传输) */
    private String fields;
    
    /** 版本号(默认2.0) */
    @Builder.Default
    private String version = "2.0";}

三、核心代码实现

1. 配置类

java
复制
package com.example.jd.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;@Data@Component@ConfigurationProperties(prefix = "jd.open")public class JdOpenConfig {
    
    /** AppKey */
    private String appKey;
    
    /** AppSecret */
    private String appSecret;
    
    /** 接入方式:sandbox/production */
    private String env = "sandbox";
    
    /** 网关地址 */
    private String gatewayUrl = "https://api.jd.com/routerjson";
    
    /** 沙箱地址 */
    private String sandboxUrl = "https://gw.api.sandbox.jd.com/routerjson";
    
    /** 默认超时(秒) */
    private Integer timeout = 30;
    
    /** 连接池大小 */
    private Integer poolSize = 20;
    
    public String getActualGatewayUrl() {
        return "sandbox".equals(env) ? sandboxUrl : gatewayUrl;
    }}

2. 签名工具类(京东TOP协议)

java
复制
package com.example.jd.util;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.*;@Slf4j@Componentpublic class JdSignUtil {
    
    private static final DateTimeFormatter TIMESTAMP_FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    /**
     * 构建通用请求参数
     */
    public Map<String, String> buildCommonParams(String appKey, String method) {
        Map<String, String> params = new HashMap<>();
        params.put("app_key", appKey);
        params.put("method", method);
        params.put("v", "2.0");
        params.put("format", "json");
        params.put("timestamp", LocalDateTime.now().format(TIMESTAMP_FORMATTER));
        params.put("sign_method", "md5");
        return params;
    }
    
    /**
     * 生成签名(京东TOP协议)
     * 规则:按参数名ASCII排序,拼接成字符串,首尾加Secret,MD5加密
     */
    public String generateSign(Map<String, String> params, String appSecret) {
        // 1. 过滤空值和sign字段
        Map<String, String> filtered = new HashMap<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (value != null && !value.isEmpty() && !"sign".equals(key)) {
                filtered.put(key, value);
            }
        }
        
        // 2. 按ASCII排序
        List<String> keys = new ArrayList<>(filtered.keySet());
        Collections.sort(keys);
        
        // 3. 拼接字符串
        StringBuilder sb = new StringBuilder();
        sb.append(appSecret); // 开头加Secret
        for (String key : keys) {
            sb.append(key).append(filtered.get(key));
        }
        sb.append(appSecret); // 结尾加Secret
        
        // 4. MD5加密,转大写
        return md5(sb.toString()).toUpperCase();
    }
    
    private String md5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
            
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1) {
                    sb.append("0");
                }
                sb.append(hex);
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5加密失败", e);
        }
    }}

3. API客户端

java
复制
package com.example.jd.client;import com.alibaba.fastjson2.JSON;import com.alibaba.fastjson2.JSONObject;import com.example.jd.config.JdOpenConfig;import com.example.jd.util.JdSignUtil;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.apache.hc.client5.http.classic.methods.HttpPost;import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;import org.apache.hc.client5.http.impl.classic.HttpClients;import org.apache.hc.core5.http.HttpEntity;import org.apache.hc.client5.http.config.RequestConfig;import org.apache.hc.core5.http.NameValuePair;import org.apache.hc.core5.http.io.entity.EntityUtils;import org.apache.hc.core5.http.message.BasicNameValuePair;import org.apache.hc.core5.util.Timeout;import org.springframework.stereotype.Component;import java.nio.charset.StandardCharsets;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.concurrent.TimeUnit;@Slf4j@Component@RequiredArgsConstructorpublic class JdApiClient {
    
    private final JdOpenConfig config;
    private final JdSignUtil signUtil;
    
    private final CloseableHttpClient httpClient;
    
    public JdApiClient(JdOpenConfig config, JdSignUtil signUtil) {
        this.config = config;
        this.signUtil = signUtil;
        
        // 配置连接池和超时
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(Timeout.ofSeconds(config.getTimeout()))
            .setResponseTimeout(Timeout.ofSeconds(config.getTimeout()))
            .build();
        
        this.httpClient = HttpClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .setMaxConnTotal(config.getPoolSize())
            .setMaxConnPerRoute(config.getPoolSize())
            .build();
    }
    
    /**
     * 执行API调用
     */
    public JSONObject execute(String method, Map<String, String> bizParams) {
        try {
            // 1. 构建公共参数
            Map<String, String> params = signUtil.buildCommonParams(
                config.getAppKey(), method);
            
            // 2. 添加业务参数(JSON格式)
            if (bizParams != null && !bizParams.isEmpty()) {
                params.put("360buy_param_json", JSON.toJSONString(bizParams));
            }
            
            // 3. 生成签名
            String sign = signUtil.generateSign(params, config.getAppSecret());
            params.put("sign", sign);
            
            // 4. 构建HTTP请求
            HttpPost httpPost = new HttpPost(config.getActualGatewayUrl());
            
            List<NameValuePair> formParams = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            
            httpPost.setEntity(new UrlEncodedFormEntity(formParams, StandardCharsets.UTF_8));
            
            // 5. 执行请求
            log.debug("调用京东API: method={}, params={}", method, params);
            
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                HttpEntity entity = response.getEntity();
                String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                
                log.debug("API响应: {}", result);
                
                JSONObject jsonResult = JSON.parseObject(result);
                
                // 6. 检查错误
                if (jsonResult.containsKey("error_response")) {
                    JSONObject error = jsonResult.getJSONObject("error_response");
                    String code = error.getString("code");
                    String msg = error.getString("zh_desc");
                    throw new JdApiException(code, msg);
                }
                
                return jsonResult;
            }
            
        } catch (Exception e) {
            log.error("调用京东API失败: method={}", method, e);
            throw new RuntimeException("京东API调用失败: " + e.getMessage(), e);
        }
    }}

4. 商品服务层(核心)

java
复制
package com.example.jd.service;import com.alibaba.fastjson2.JSON;import com.alibaba.fastjson2.JSONObject;import com.example.jd.client.JdApiClient;import com.example.jd.config.JdOpenConfig;import com.example.jd.model.*;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Service;import java.math.BigDecimal;import java.time.LocalDateTime;import java.util.*;import java.util.stream.Collectors;@Slf4j@Service@RequiredArgsConstructorpublic class JdItemService {
    
    private static final String API_METHOD = "jd.item.get";
    private static final String CACHE_NAME = "jd:item";
    
    private final JdApiClient apiClient;
    private final JdOpenConfig config;
    
    /**
     * 获取商品详情(带缓存)
     */
    @Cacheable(value = CACHE_NAME, key = "#skuId", unless = "#result == null")
    public JdItemDetail getItemDetail(String skuId) {
        return getItemDetail(skuId, JdItemGetRequest.builder().build());
    }
    
    /**
     * 获取商品详情(自定义参数)
     */
    public JdItemDetail getItemDetail(String skuId, JdItemGetRequest request) {
        log.info("获取京东商品详情, skuId: {}", skuId);
        
        try {
            // 构建业务参数
            Map<String, String> bizParams = new HashMap<>();
            bizParams.put("skuId", skuId);
            
            // 可选字段控制
            if (!request.getNeedPrice()) {
                bizParams.put("fields", "basic,sku,shop"); // 排除价格
            }
            
            // 调用API
            JSONObject response = apiClient.execute(API_METHOD, bizParams);
            
            // 解析响应
            JSONObject result = response.getJSONObject(API_METHOD.replace(".", "_") + "_responce");
            if (result == null) {
                result = response.getJSONObject("jingdong_item_get_responce");
            }
            
            if (result == null || result.getJSONObject("item") == null) {
                throw new RuntimeException("商品不存在或已下架");
            }
            
            JSONObject itemJson = result.getJSONObject("item");
            
            return parseItemDetail(itemJson);
            
        } catch (Exception e) {
            log.error("获取商品详情失败, skuId: {}", skuId, e);
            throw new RuntimeException("获取商品详情失败: " + e.getMessage());
        }
    }
    
    /**
     * 批量获取商品详情
     */
    public List<JdItemDetail> getItemDetailsBatch(List<String> skuIds) {
        return skuIds.parallelStream()
            .map(skuId -> {
                try {
                    return getItemDetail(skuId);
                } catch (Exception e) {
                    log.error("批量获取失败, skuId: {}", skuId, e);
                    return null;
                }
            })
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
    }
    
    /**
     * 解析商品详情JSON
     */
    private JdItemDetail parseItemDetail(JSONObject json) {
        JdItemDetail item = new JdItemDetail();
        
        // ========== 基础信息 ==========
        item.setSkuId(json.getString("skuId"));
        item.setSpuId(json.getString("spuId"));
        item.setName(json.getString("name"));
        item.setSubTitle(json.getString("subTitle"));
        item.setBrandName(json.getString("brandName"));
        item.setBrandId(json.getString("brandId"));
        item.setCategoryId(json.getString("catId"));
        item.setCategoryName(json.getString("category"));
        
        // ========== 价格信息 ==========
        PriceInfo priceInfo = new PriceInfo();
        priceInfo.setOriginalPrice(json.getBigDecimal("marketPrice"));
        priceInfo.setCurrentPrice(json.getBigDecimal("jdPrice"));
        priceInfo.setPlusPrice(json.getBigDecimal("plusPrice")); // Plus会员价
        priceInfo.setPromotionPrice(json.getBigDecimal("pPrice")); // 促销价
        
        // 计算折扣
        if (priceInfo.getOriginalPrice() != null && 
            priceInfo.getCurrentPrice() != null &&
            priceInfo.getOriginalPrice().compareTo(BigDecimal.ZERO) > 0) {
            priceInfo.setDiscountRate(priceInfo.getCurrentPrice()
                .divide(priceInfo.getOriginalPrice(), 2, BigDecimal.ROUND_HALF_UP));
        }
        
        item.setPriceInfo(priceInfo);
        
        // ========== 库存信息 ==========
        StockInfo stockInfo = new StockInfo();
        stockInfo.setStockState(json.getInteger("stockState")); // 33-现货 34-无货 40-可配货
        stockInfo.setStockStateName(json.getString("stockStateName"));
        stockInfo.setStockNum(json.getInteger("stockNum"));
        stockInfo.setIsStock(json.getBoolean("isStock"));
        
        item.setStockInfo(stockInfo);
        
        // ========== 图片信息 ==========
        Images images = new Images();
        images.setMainImage(json.getString("image"));
        images.setImageList(json.getList("imageList", String.class));
        images.setDetailImages(json.getList("detailImages", String.class));
        images.setVideoUrl(json.getString("videoUrl"));
        
        item.setImages(images);
        
        // ========== SKU规格 ==========
        if (json.containsKey("skuInfo")) {
            JSONObject skuJson = json.getJSONObject("skuInfo");
            SkuInfo skuInfo = new SkuInfo();
            
            skuInfo.setSkuId(skuJson.getString("skuId"));
            skuInfo.setSkuName(skuJson.getString("skuName"));
            
            // 规格属性
            List<SkuProp> props = new ArrayList<>();
            if (skuJson.containsKey("propCodeList")) {
                JSONArray propArray = skuJson.getJSONArray("propCodeList");
                for (int i = 0; i < propArray.size(); i++) {
                    JSONObject prop = propArray.getJSONObject(i);
                    props.add(SkuProp.builder()
                        .propId(prop.getString("propId"))
                        .propName(prop.getString("propName"))
                        .propValue(prop.getString("propValue"))
                        .build());
                }
            }
            skuInfo.setProps(props);
            
            item.setSkuInfo(skuInfo);
        }
        
        // ========== 店铺信息 ==========
        ShopInfo shopInfo = new ShopInfo();
        shopInfo.setShopId(json.getString("shopId"));
        shopInfo.setShopName(json.getString("shopName"));
        shopInfo.setShopScore(json.getBigDecimal("shopScore"));
        shopInfo.setShopLevel(json.getString("shopLevel"));
        
        item.setShopInfo(shopInfo);
        
        // ========== 服务信息 ==========
        ServiceInfo serviceInfo = new ServiceInfo();
        serviceInfo.setIsSelfSupport(json.getBoolean("isSelf")); // 是否自营
        serviceInfo.setIsGlobalPurchase(json.getBoolean("isGlobalPurchase")); // 是否全球购
        serviceInfo.setIsFresh(json.getBoolean("isFresh")); // 是否生鲜
        serviceInfo.setIsSevenDayReturn(json.getBoolean("is7ToReturn")); // 7天无理由
        
        item.setServiceInfo(serviceInfo);
        
        // ========== 销售数据 ==========
        SalesData salesData = new SalesData();
        salesData.setCommentCount(json.getInteger("commentCount"));
        salesData.setGoodRate(json.getBigDecimal("goodRate"));
        salesData.setSalesCount(json.getInteger("salesCount"));
        
        item.setSalesData(salesData);
        
        // ========== 物流信息 ==========
        item.setWeight(json.getBigDecimal("weight"));
        item.setProductArea(json.getString("productArea")); // 产地
        
        // ========== 时间戳 ==========
        item.setFetchTime(LocalDateTime.now());
        
        return item;
    }}

5. 数据模型类

java
复制
package com.example.jd.model;import com.alibaba.fastjson2.annotation.JSONField;import lombok.Builder;import lombok.Data;import java.math.BigDecimal;import java.time.LocalDateTime;import java.util.List;@Datapublic class JdItemDetail {
    
    /** ========== 基础信息 ========== */
    private String skuId;           // SKU ID
    private String spuId;           // SPU ID
    private String name;            // 商品名称
    private String subTitle;        // 副标题
    private String brandName;       // 品牌名
    private String brandId;         // 品牌ID
    private String categoryId;      // 类目ID
    private String categoryName;    // 类目名称
    
    /** ========== 价格信息 ========== */
    private PriceInfo priceInfo;
    
    /** ========== 库存信息 ========== */
    private StockInfo stockInfo;
    
    /** ========== 图片信息 ========== */
    private Images images;
    
    /** ========== SKU规格 ========== */
    private SkuInfo skuInfo;
    
    /** ========== 店铺信息 ========== */
    private ShopInfo shopInfo;
    
    /** ========== 服务信息 ========== */
    private ServiceInfo serviceInfo;
    
    /** ========== 销售数据 ========== */
    private SalesData salesData;
    
    /** ========== 物流信息 ========== */
    private BigDecimal weight;      // 重量(kg)
    private String productArea;     // 产地
    
    /** ========== 元数据 ========== */
    @JSONField(serialize = false)
    private LocalDateTime fetchTime;
    
    // ========== 子类定义 ==========
    
    @Data
    public static class PriceInfo {
        private BigDecimal originalPrice;   // 市场价
        private BigDecimal currentPrice;    // 京东价
        private BigDecimal plusPrice;       // Plus会员价
        private BigDecimal promotionPrice;  // 促销价
        private BigDecimal discountRate;    // 折扣率
    }
    
    @Data
    public static class StockInfo {
        private Integer stockState;         // 库存状态码
        private String stockStateName;      // 库存状态名
        private Integer stockNum;           // 库存数量
        private Boolean isStock;            // 是否有库存
    }
    
    @Data
    public static class Images {
        private String mainImage;           // 主图
        private List<String> imageList;     // 图片列表
        private List<String> detailImages;  // 详情图
        private String videoUrl;            // 视频地址
    }
    
    @Data
    public static class SkuInfo {
        private String skuId;
        private String skuName;
        private List<SkuProp> props;        // 规格属性
    }
    
    @Data
    @Builder
    public static class SkuProp {
        private String propId;
        private String propName;
        private String propValue;
    }
    
    @Data
    public static class ShopInfo {
        private String shopId;
        private String shopName;
        private BigDecimal shopScore;       // 店铺评分
        private String shopLevel;           // 店铺等级
    }
    
    @Data
    public static class ServiceInfo {
        private Boolean isSelfSupport;      // 京东自营
        private Boolean isGlobalPurchase;   // 全球购
        private Boolean isFresh;            // 生鲜
        private Boolean isSevenDayReturn;   // 7天无理由
    }
    
    @Data
    public static class SalesData {
        private Integer commentCount;       // 评价数
        private BigDecimal goodRate;        // 好评率
        private Integer salesCount;         // 销量
    }}

四、API响应示例

成功响应

JSON
复制
{
    "jingdong_item_get_responce": {
        "item": {
            "skuId": "100012043978",
            "spuId": "100009077475",
            "name": "Apple iPhone 15 Pro Max (256GB) 蓝色钛金属",
            "subTitle": "支持移动联通电信5G 双卡双待手机",
            "brandName": "Apple",
            "brandId": "15126",
            "catId": "9987,653,655",
            "category": "手机通讯>手机>5G手机",
            "marketPrice": 9999.00,
            "jdPrice": 8999.00,
            "plusPrice": 8899.00,
            "pPrice": 8799.00,
            "stockState": 33,
            "stockStateName": "现货",
            "stockNum": 5000,
            "isStock": true,
            "image": "https://img10.360buyimg.com/n1/...jpg",
            "imageList": [
                "https://img10.360buyimg.com/n1/...jpg",
                "https://img10.360buyimg.com/n1/...jpg"
            ],
            "shopId": "1000000127",
            "shopName": "京东自营",
            "shopScore": 9.8,
            "isSelf": true,
            "isGlobalPurchase": false,
            "is7ToReturn": true,
            "commentCount": 500000,
            "goodRate": 0.98,
            "weight": 0.221,
            "productArea": "中国",
            "skuInfo": {
                "skuId": "100012043978",
                "skuName": "256GB 蓝色钛金属",
                "propCodeList": [
                    {
                        "propId": "100004",
                        "propName": "机身颜色",
                        "propValue": "蓝色钛金属"
                    },
                    {
                        "propId": "100005",
                        "propName": "存储容量",
                        "propValue": "256GB"
                    }
                ]
            }
        }
    }}

错误响应

JSON
复制
{
    "error_response": {
        "code": "100",
        "zh_desc": "商品不存在或已下架",
        "en_desc": "Item not found"
    }}

五、使用示例

Controller层

java
复制
package com.example.jd.controller;import com.example.jd.model.JdItemDetail;import com.example.jd.model.JdItemGetRequest;import com.example.jd.service.JdItemService;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController@RequestMapping("/api/jd/item")@RequiredArgsConstructorpublic class JdItemController {
    
    private final JdItemService itemService;
    
    /**
     * 获取商品详情
     * GET /api/jd/item/100012043978
     */
    @GetMapping("/{skuId}")
    public JdItemDetail getItem(@PathVariable String skuId) {
        return itemService.getItemDetail(skuId);
    }
    
    /**
     * 批量获取商品详情
     * POST /api/jd/item/batch
     */
    @PostMapping("/batch")
    public List<JdItemDetail> getItemsBatch(@RequestBody List<String> skuIds) {
        return itemService.getItemDetailsBatch(skuIds);
    }
    
    /**
     * 获取商品详情(自定义参数)
     * GET /api/jd/item/100012043978?needPrice=false&needStock=true
     */
    @GetMapping("/{skuId}/custom")
    public JdItemDetail getItemCustom(
            @PathVariable String skuId,
            @RequestParam(defaultValue = "true") Boolean needPrice,
            @RequestParam(defaultValue = "true") Boolean needStock) {
        
        JdItemGetRequest request = JdItemGetRequest.builder()
            .needPrice(needPrice)
            .needStock(needStock)
            .build();
        
        return itemService.getItemDetail(skuId, request);
    }}

六、进阶应用场景

1. 价格监控与预警

java
复制
@Servicepublic class JdPriceMonitorService {
    
    @Autowired
    private JdItemService itemService;
    
    @Autowired
    private AlertService alertService;
    
    /**
     * 价格监控任务
     */
    @Scheduled(fixedRate = 3600000) // 每小时
    public void monitorPriceChanges() {
        List<MonitoredItem> items = monitorRepository.findAll();
        
        items.parallelStream().forEach(item -> {
            try {
                JdItemDetail current = itemService.getItemDetail(item.getSkuId());
                BigDecimal currentPrice = current.getPriceInfo().getCurrentPrice();
                
                // 价格变动检测
                BigDecimal changeRate = currentPrice.subtract(item.getLastPrice())
                    .divide(item.getLastPrice(), 4, RoundingMode.HALF_UP);
                
                if (changeRate.abs().compareTo(new BigDecimal("0.05")) > 0) {
                    alertService.sendPriceAlert(PriceAlert.builder()
                        .skuId(item.getSkuId())
                        .name(current.getName())
                        .oldPrice(item.getLastPrice())
                        .newPrice(currentPrice)
                        .changeRate(changeRate)
                        .type(changeRate.signum() > 0 ? "涨价" : "降价")
                        .build());
                }
                
                // 库存预警
                if (!current.getStockInfo().getIsStock()) {
                    alertService.sendStockAlert(StockAlert.builder()
                        .skuId(item.getSkuId())
                        .name(current.getName())
                        .message("商品已断货")
                        .build());
                }
                
                // 更新记录
                item.setLastPrice(currentPrice);
                item.setLastCheckTime(LocalDateTime.now());
                monitorRepository.save(item);
                
            } catch (Exception e) {
                log.error("监控失败: {}", item.getSkuId(), e);
            }
        });
    }}

2. 竞品分析与选品

java
复制
@Servicepublic class JdCompetitorAnalysisService {
    
    /**
     * 竞品分析
     */
    public CompetitorReport analyzeCompetitor(String skuId) {
        JdItemDetail item = itemService.getItemDetail(skuId);
        
        return CompetitorReport.builder()
            .skuId(skuId)
            .name(item.getName())
            .pricePosition(analyzePricePosition(item))
            .competitiveIndex(calculateCompetitiveIndex(item))
            .marketGap(identifyMarketGap(item))
            .suggestedPricing(generatePricingSuggestion(item))
            .build();
    }
    
    /**
     * 计算竞争力指数
     */
    private double calculateCompetitiveIndex(JdItemDetail item) {
        double score = 0;
        
        // 价格竞争力(30%)
        if (item.getPriceInfo().getDiscountRate() != null) {
            score += item.getPriceInfo().getDiscountRate().doubleValue() * 0.3;
        }
        
        // 口碑竞争力(30%)
        if (item.getSalesData().getGoodRate() != null) {
            score += item.getSalesData().getGoodRate().doubleValue() * 0.3;
        }
        
        // 库存竞争力(20%)
        score += (item.getStockInfo().getIsStock() ? 1.0 : 0.0) * 0.2;
        
        // 自营背书(20%)
        score += (item.getServiceInfo().getIsSelfSupport() ? 1.0 : 0.5) * 0.2;
        
        return score;
    }}

3. 与ERP/电商系统对接

java
复制
@Servicepublic class JdErpIntegrationService {
    
    /**
     * 同步商品到ERP
     */
    public void syncToErp(String skuId) {
        JdItemDetail jdItem = itemService.getItemDetail(skuId);
        
        // 转换为ERP商品模型
        ErpProduct erpProduct = ErpProduct.builder()
            .externalSkuId(jdItem.getSkuId())
            .externalSpuId(jdItem.getSpuId())
            .name(jdItem.getName())
            .brand(jdItem.getBrandName())
            .categoryPath(jdItem.getCategoryName())
            .purchasePrice(jdItem.getPriceInfo().getCurrentPrice())
            .suggestedRetailPrice(jdItem.getPriceInfo().getOriginalPrice())
            .weight(jdItem.getWeight())
            .origin(jdItem.getProductArea())
            .mainImage(jdItem.getImages().getMainImage())
            .specifications(convertSpecs(jdItem.getSkuInfo()))
            .supplierType(jdItem.getServiceInfo().getIsSelfSupport() ? 
                "JD_SELF" : "JD_POP")
            .build();
        
        erpProductService.saveOrUpdate(erpProduct);
    }}

七、关键注意事项

表格
注意点解决方案
频率限制本地缓存+队列削峰,避免触发限流
数据一致性京东价格实时变动,关键场景需实时查询
SKU vs SPU京东以SKU为最小单位,注意区分
自营vsPOP自营商品API数据更完整,POP店铺数据可能缺失
区域库存库存分仓,需指定地区查询
促销复杂性价格可能含多重促销,需解析promotion字段

八、配置示例(application.yml)

yaml
复制
jd:
  open:
    app-key: ${JD_APP_KEY}
    app-secret: ${JD_APP_SECRET}
    env: production  # sandbox/production
    gateway-url: https://api.jd.com/routerjson    sandbox-url: https://gw.api.sandbox.jd.com/routerjson    timeout: 30
    pool-size: 20spring:
  cache:
    type: redis    redis:
      time-to-live: 600000  # 10分钟缓存


群贤毕至

访客