一、接口概述
京东开放平台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分钟缓存