Java 实现京东商品分类查询、图片上传与铺货上架完整指南

在电商多平台运营时代,商家需要将商品从货源平台(如1688、淘宝)同步上架至京东。传统手动铺货模式效率低下、错误率高,而通过京东开放平台(JOS)提供的标准化接口,可以实现从分类查询 → 图片上传 → 商品发布的全流程自动化。本文将详细介绍如何使用 Java 调用京东相关接口完成铺货上架。
一、整体流程概览
plain
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 1.类目查询 │ → │ 2.图片上传 │ → │ 3.商品发布 │ → │ 4.状态查询 │
│ 获取类目ID │ │ 上传主图/详情 │ │ 填写商品信息 │ │ 确认上架成功 │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
二、准备工作

  1. 注册京东开放平台开发者账号
    访问 京东开放平台 注册开发者账号
    完成企业认证,创建应用获取凭证:
    表格
    凭证 说明
    App Key 应用唯一标识
    App Secret 应用密钥,用于签名
    Access Token 店铺授权令牌(OAuth2.0)

  2. 申请接口权限
    铺货上架需要申请以下接口权限:
    表格
    接口权限 用途
    jingdong.category.read.getAttrs 查询类目属性
    jingdong.image.write.upload 上传商品图片
    jingdong.seller.vender.info.get 获取商家信息
    jingdong.ware.write.add 发布新商品
    jingdong.ware.read.search 查询商品状态

  3. Maven 依赖配置
    xml

    org.apache.httpcomponents httpclient 4.5.14 com.alibaba fastjson 2.0.43 commons-codec commons-codec 1.16.0 javax.imageio imageio-core 3.8.3 commons-codec commons-codec 1.16.0
三、核心代码实现 1. 签名工具类(MD5 算法) 京东JOS签名规则:参数按key ASCII升序排列,拼接为 key1+value1+key2+value2 格式,首尾追加 AppSecret,最后进行 MD5 加密并转大写。 java import org.apache.commons.codec.digest.DigestUtils;

import java.util.Map;
import java.util.TreeMap;

/**

  • 京东JOS签名工具类
    */
    public class JdSignUtil {

    /**

    • 生成京东API签名

    • 规则:AppSecret + 按key升序拼接(key+value) + AppSecret → MD5 → 大写
      */
      public static String generateSign(Map<String, String> params, String appSecret) {
      // 1. 剔除sign和空值,按key升序排列
      TreeMap<String, String> sortedParams = new TreeMap<>();
      for (Map.Entry<String, String> entry : params.entrySet()) {
      String key = entry.getKey();
      String value = entry.getValue();
      if (!"sign".equals(key) && value != null && !value.trim().isEmpty()) {
      sortedParams.put(key, value);
      }
      }

      // 2. 按key升序拼接 key+value
      StringBuilder sb = new StringBuilder();
      for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
      sb.append(entry.getKey()).append(entry.getValue());
      }

      // 3. 首尾拼接AppSecret
      String toSign = appSecret + sb.toString() + appSecret;

      // 4. MD5加密,转大写
      return DigestUtils.md5Hex(toSign).toUpperCase();
      }
      }

  1. 基础请求工具类
    java
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    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 java.util.HashMap;
import java.util.Map;

/**

  • 京东API基础请求工具
    */
    public class JdApiClient {

    private static final String API_URL = "https://api.jd.com/routerjson";
    private static final String VERSION = "2.0";

    private final String appKey;
    private final String appSecret;
    private final String accessToken;

    public JdApiClient(String appKey, String appSecret, String accessToken) {
    this.appKey = appKey;
    this.appSecret = appSecret;
    this.accessToken = accessToken;
    }

    /**

    • 发送API请求

    • @param method 接口方法名

    • @param paramJson 业务参数JSON

    • @return 响应JSON
      */
      public JSONObject execute(String method, String paramJson) {
      try {
      Map<String, String> params = new HashMap<>();
      params.put("method", method);
      params.put("app_key", appKey);
      params.put("access_token", accessToken);
      params.put("timestamp", getCurrentTimestamp());
      params.put("v", VERSION);
      params.put("format", "json");
      params.put("360buy_param_json", paramJson);

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

      // 发送POST请求
      try (CloseableHttpClient client = HttpClients.createDefault()) {
      HttpPost httpPost = new HttpPost(API_URL);
      httpPost.setHeader("Content-Type", "application/json");
      httpPost.setEntity(new StringEntity(JSON.toJSONString(params), "UTF-8"));

      String response = EntityUtils.toString(
      client.execute(httpPost).getEntity(), "UTF-8");

      return JSON.parseObject(response);
      }
      } catch (Exception e) {
      throw new RuntimeException("API请求失败: " + e.getMessage(), e);
      }
      }

    /**

    • 获取当前时间戳(格式:yyyy-MM-dd HH:mm:ss)
      */
      private String getCurrentTimestamp() {
      return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
      .format(new java.util.Date());
      }
      }
  1. 类目查询服务
    京东商品发布必须先确定类目,通过类目查询接口获取类目ID和属性信息。
    java
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**

  • 京东类目查询服务
    */
    public class JdCategoryService {

    private final JdApiClient apiClient;

    public JdCategoryService(JdApiClient apiClient) {
    this.apiClient = apiClient;
    }

    /**

    • 获取一级类目列表
      */
      public List getTopCategories() {
      JSONObject param = new JSONObject();
      param.put("fields", "cid,name,isParent");

      JSONObject response = apiClient.execute(
      "jingdong.category.read.findFirstLevelCategories",
      param.toJSONString());

      return parseCategories(response);
      }

    /**

    • 获取子类目列表

    • @param parentCid 父类目ID
      */
      public List getChildCategories(long parentCid) {
      JSONObject param = new JSONObject();
      param.put("parentCid", parentCid);
      param.put("fields", "cid,name,isParent");

      JSONObject response = apiClient.execute(
      "jingdong.category.read.findByPId",
      param.toJSONString());

      return parseCategories(response);
      }

    /**

    • 获取类目属性(发布商品前必须调用)

    • @param cid 三级类目ID
      */
      public List getCategoryAttributes(long cid) {
      JSONObject param = new JSONObject();
      param.put("cid", cid);
      param.put("type", 0); // 0=销售属性,1=关键属性,2=非关键属性

      JSONObject response = apiClient.execute(
      "jingdong.category.read.getAttrs",
      param.toJSONString());

      List attrs = new ArrayList<>();
      if (response.containsKey("category_attrs")) {
      JSONArray attrArray = response.getJSONArray("category_attrs");
      for (int i = 0; i < attrArray.size(); i++) {
      JSONObject attr = attrArray.getJSONObject(i);
      CategoryAttribute attribute = new CategoryAttribute();
      attribute.setAttrId(attr.getLong("aid"));
      attribute.setAttrName(attr.getString("name"));
      attribute.setRequired(attr.getBoolean("is_required"));
      attribute.setInputType(attr.getString("input_type")); // text/select/checkbox

      // 解析属性值选项
      if (attr.containsKey("attrValues")) {
      JSONArray values = attr.getJSONArray("attrValues");
      List valueList = new ArrayList<>();
      for (int j = 0; j < values.size(); j++) {
      JSONObject v = values.getJSONObject(j);
      AttrValue av = new AttrValue();
      av.setValueId(v.getLong("vid"));
      av.setValueName(v.getString("name"));
      valueList.add(av);
      }
      attribute.setValues(valueList);
      }
      attrs.add(attribute);
      }
      }
      return attrs;
      }

    /**

    • 根据关键词搜索类目(辅助选类目)

    • @param keyword 类目关键词
      */
      public List searchCategory(String keyword) {
      JSONObject param = new JSONObject();
      param.put("keyword", keyword);

      JSONObject response = apiClient.execute(
      "jingdong.category.read.search",
      param.toJSONString());

      return parseCategories(response);
      }

    private List parseCategories(JSONObject response) {
    List categories = new ArrayList<>();
    if (response.containsKey("categories")) {
    JSONArray array = response.getJSONArray("categories");
    for (int i = 0; i < array.size(); i++) {
    JSONObject obj = array.getJSONObject(i);
    Category cat = new Category();
    cat.setCid(obj.getLong("cid"));
    cat.setName(obj.getString("name"));
    cat.setParent(obj.getBooleanValue("isParent"));
    categories.add(cat);
    }
    }
    return categories;
    }

    // 实体类
    public static class Category {
    private long cid;
    private String name;
    private boolean isParent;

    // Getters and Setters
    public long getCid() { return cid; }
    public void setCid(long cid) { this.cid = cid; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public boolean isParent() { return isParent; }
    public void setParent(boolean parent) { isParent = parent; }
    }

    public static class CategoryAttribute {
    private long attrId;
    private String attrName;
    private boolean required;
    private String inputType;
    private List values;

    // Getters and Setters...
    public long getAttrId() { return attrId; }
    public void setAttrId(long attrId) { this.attrId = attrId; }
    public String getAttrName() { return attrName; }
    public void setAttrName(String attrName) { this.attrName = attrName; }
    public boolean isRequired() { return required; }
    public void setRequired(boolean required) { this.required = required; }
    public String getInputType() { return inputType; }
    public void setInputType(String inputType) { this.inputType = inputType; }
    public List getValues() { return values; }
    public void setValues(List values) { this.values = values; }
    }

    public static class AttrValue {
    private long valueId;
    private String valueName;

    // Getters and Setters...
    public long getValueId() { return valueId; }
    public void setValueId(long valueId) { this.valueId = valueId; }
    public String getValueName() { return valueName; }
    public void setValueName(String valueName) { this.valueName = valueName; }
    }
    }

  1. 图片上传服务
    京东要求商品图片先上传到京东服务器,获取图片URL后再用于商品发布。图片需满足:白底、800×800像素、≤2MB、JPG/PNG格式。
    java
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import org.apache.commons.codec.binary.Base64;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;

/**

  • 京东图片上传服务
    */
    public class JdImageService {

    private final JdApiClient apiClient;

    public JdImageService(JdApiClient apiClient) {
    this.apiClient = apiClient;
    }

    /**

    • 上传本地图片到京东

    • @param imagePath 本地图片路径

    • @return 京东图片URL
      */
      public String uploadLocalImage(String imagePath) {
      try {
      File file = new File(imagePath);
      BufferedImage image = ImageIO.read(file);

      // 图片预处理:调整尺寸、压缩
      BufferedImage processedImage = processImage(image);

      // 转为Base64
      String base64Image = imageToBase64(processedImage);

      // 调用上传接口
      return uploadToJd(base64Image);

      } catch (Exception e) {
      throw new RuntimeException("图片上传失败: " + e.getMessage(), e);
      }
      }

    /**

    • 上传网络图片到京东

    • @param imageUrl 图片URL

    • @return 京东图片URL
      */
      public String uploadRemoteImage(String imageUrl) {
      try {
      URL url = new URL(imageUrl);
      BufferedImage image = ImageIO.read(url);

      BufferedImage processedImage = processImage(image);
      String base64Image = imageToBase64(processedImage);

      return uploadToJd(base64Image);

      } catch (Exception e) {
      throw new RuntimeException("网络图片上传失败: " + e.getMessage(), e);
      }
      }

    /**

    • 批量上传图片
    • @param imagePaths 图片路径列表
    • @return 京东图片URL列表
      */
      public List batchUploadImages(List imagePaths) {
      List urls = new ArrayList<>();
      for (String path : imagePaths) {
      String jdUrl = uploadLocalImage(path);
      urls.add(jdUrl);
      // 控制上传频率,避免触发限流
      try { Thread.sleep(500); } catch (InterruptedException ignored) {}
      }
      return urls;
      }

    /**

    • 图片预处理:调整尺寸、白底、压缩
      */
      private BufferedImage processImage(BufferedImage source) {
      // 1. 调整尺寸为800x800
      BufferedImage resized = new BufferedImage(800, 800, BufferedImage.TYPE_INT_RGB);
      Graphics2D g = resized.createGraphics();
      g.setColor(Color.WHITE);
      g.fillRect(0, 0, 800, 800);
      g.drawImage(source, 0, 0, 800, 800, null);
      g.dispose();

      // 2. 压缩质量(后续在Base64编码时控制)
      return resized;
      }

    /**

    • 图片转Base64
      */
      private String imageToBase64(BufferedImage image) throws IOException {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ImageIO.write(image, "jpg", baos);
      byte[] bytes = baos.toByteArray();
      return Base64.encodeBase64String(bytes);
      }

    /**

    • 调用京东图片上传接口
      */
      private String uploadToJd(String base64Image) {
      JSONObject param = new JSONObject();
      param.put("imageData", base64Image);

      JSONObject response = apiClient.execute(
      "jingdong.image.write.upload",
      param.toJSONString());

      if (response.getIntValue("code") == 0) {
      return response.getJSONObject("url").getString("url");
      } else {
      throw new RuntimeException("上传失败: " + response.getString("message"));
      }
      }
      }

  1. 商品发布服务
    商品发布是铺货的核心环节,需要组装完整的商品信息并调用发布接口。
    java
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**

  • 京东商品发布服务
    */
    public class JdPublishService {

    private final JdApiClient apiClient;
    private final JdImageService imageService;

    public JdPublishService(JdApiClient apiClient, JdImageService imageService) {
    this.apiClient = apiClient;
    this.imageService = imageService;
    }

    /**

    • 发布新商品

    • @param product 商品信息

    • @return 商品ID
      */
      public String publishProduct(ProductInfo product) {
      try {
      // 1. 上传图片并获取京东图片URL
      List jdImageUrls = new ArrayList<>();
      for (String imgUrl : product.getSourceImageUrls()) {
      String jdUrl = imageService.uploadRemoteImage(imgUrl);
      jdImageUrls.add(jdUrl);
      }

      // 2. 构建商品发布参数
      JSONObject ware = new JSONObject();
      ware.put("title", product.getTitle()); // 商品标题
      ware.put("secondTitle", product.getSubTitle()); // 副标题
      ware.put("cid", product.getCategoryId()); // 类目ID(三级类目)
      ware.put("brandId", product.getBrandId()); // 品牌ID
      ware.put("shopCategorys", product.getShopCategoryIds()); // 店内分类
      ware.put("wrap", product.getPackaging()); // 包装清单
      ware.put("weight", product.getWeight()); // 重量(kg)
      ware.put("prodectArea", product.getOrigin()); // 产地
      ware.put("upc", product.getUpc()); // UPC码
      ware.put("wareStatus", 1); // 1=上架,2=下架

      // 3. 商品属性
      JSONArray attributes = new JSONArray();
      for (ProductAttribute attr : product.getAttributes()) {
      JSONObject attrObj = new JSONObject();
      attrObj.put("attrId", attr.getAttrId());
      attrObj.put("attrValues", attr.getAttrValues());
      attributes.add(attrObj);
      }
      ware.put("attributes", attributes);

      // 4. SKU信息
      JSONArray skus = new JSONArray();
      for (SkuInfo sku : product.getSkus()) {
      JSONObject skuObj = new JSONObject();
      skuObj.put("skuId", sku.getSkuId());
      skuObj.put("outerId", sku.getOuterId()); // 商家编码
      skuObj.put("jdPrice", sku.getJdPrice()); // 京东价
      skuObj.put("costPrice", sku.getCostPrice()); // 成本价
      skuObj.put("stockNum", sku.getStockNum()); // 库存
      skuObj.put("skuName", sku.getSkuName()); // SKU名称

      // SKU图片
      if (sku.getImageUrl() != null) {
      skuObj.put("imagePath", sku.getImageUrl());
      }

      // SKU属性(颜色、尺码等)
      JSONArray skuProps = new JSONArray();
      for (SkuProperty prop : sku.getProperties()) {
      JSONObject propObj = new JSONObject();
      propObj.put("propId", prop.getPropId());
      propObj.put("propValues", prop.getPropValues());
      skuProps.add(propObj);
      }
      skuObj.put("skuProps", skuProps);

      skus.add(skuObj);
      }
      ware.put("skus", skus);

      // 5. 商品主图
      ware.put("wareImage", jdImageUrls.get(0)); // 主图
      JSONArray imageList = new JSONArray();
      for (int i = 0; i < jdImageUrls.size() && i < 10; i++) {
      imageList.add(jdImageUrls.get(i));
      }
      ware.put("wareImageList", imageList); // 轮播图

      // 6. 详情页(HTML格式)
      ware.put("introduction", buildDetailHtml(product, jdImageUrls));

      // 7. 售后服务
      ware.put("afterSaleDesc", product.getAfterSaleDesc());
      ware.put("mobileDesc", product.getMobileDesc()); // 移动端详情

      // 8. 物流信息
      ware.put("transportId", product.getTransportId()); // 运费模板ID

      // 调用发布接口
      JSONObject param = new JSONObject();
      param.put("ware", ware.toJSONString());

      JSONObject response = apiClient.execute(
      "jingdong.ware.write.add",
      param.toJSONString());

      if (response.getIntValue("code") == 0) {
      return response.getJSONObject("ware_id").getString("wareId");
      } else {
      throw new RuntimeException("发布失败: " + response.getString("message"));
      }

      } catch (Exception e) {
      throw new RuntimeException("商品发布异常: " + e.getMessage(), e);
      }
      }

    /**

    • 构建详情页HTML
      */
      private String buildDetailHtml(ProductInfo product, List imageUrls) {
      StringBuilder html = new StringBuilder();
      html.append("

      ");

      // 商品描述
      html.append("

      ").append(product.getDescription()).append("

      ");

      // 详情图片
      for (String url : imageUrls) {
      html.append("");
      }

      // 规格参数表
      html.append("

      ");
      html.append("");
      html.append("");
      for (ProductAttribute attr : product.getAttributes()) {
      html.append("");
      html.append("");
      html.append("");
      html.append("");
      }
      html.append("
      参数
      ")
      .append(attr.getAttrName()).append("
      ")
      .append(attr.getAttrValues()).append("
      ");

      html.append("

      ");
      return html.toString();
      }

    /**

    • 查询商品发布状态
      */
      public String getProductStatus(String wareId) {
      JSONObject param = new JSONObject();
      param.put("wareId", wareId);
      param.put("fields", "wareId,title,wareStatus,stockNum");

      JSONObject response = apiClient.execute(
      "jingdong.ware.read.get",
      param.toJSONString());

      return response.toJSONString();
      }

    // 商品信息实体类
    public static class ProductInfo {
    private String title;
    private String subTitle;
    private long categoryId;
    private long brandId;
    private String[] shopCategoryIds;
    private String packaging;
    private double weight;
    private String origin;
    private String upc;
    private List attributes;
    private List skus;
    private List sourceImageUrls;
    private String description;
    private String afterSaleDesc;
    private String mobileDesc;
    private long transportId;

    // Getters and Setters...
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String getSubTitle() { return subTitle; }
    public void setSubTitle(String subTitle) { this.subTitle = subTitle; }
    public long getCategoryId() { return categoryId; }
    public void setCategoryId(long categoryId) { this.categoryId = categoryId; }
    public long getBrandId() { return brandId; }
    public void setBrandId(long brandId) { this.brandId = brandId; }
    public String[] getShopCategoryIds() { return shopCategoryIds; }
    public void setShopCategoryIds(String[] shopCategoryIds) { this.shopCategoryIds = shopCategoryIds; }
    public String getPackaging() { return packaging; }
    public void setPackaging(String packaging) { this.packaging = packaging; }
    public double getWeight() { return weight; }
    public void setWeight(double weight) { this.weight = weight; }
    public String getOrigin() { return origin; }
    public void setOrigin(String origin) { this.origin = origin; }
    public String getUpc() { return upc; }
    public void setUpc(String upc) { this.upc = upc; }
    public List getAttributes() { return attributes; }
    public void setAttributes(List attributes) { this.attributes = attributes; }
    public List getSkus() { return skus; }
    public void setSkus(List skus) { this.skus = skus; }
    public List getSourceImageUrls() { return sourceImageUrls; }
    public void setSourceImageUrls(List sourceImageUrls) { this.sourceImageUrls = sourceImageUrls; }
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    public String getAfterSaleDesc() { return afterSaleDesc; }
    public void setAfterSaleDesc(String afterSaleDesc) { this.afterSaleDesc = afterSaleDesc; }
    public String getMobileDesc() { return mobileDesc; }
    public void setMobileDesc(String mobileDesc) { this.mobileDesc = mobileDesc; }
    public long getTransportId() { return transportId; }
    public void setTransportId(long transportId) { this.transportId = transportId; }
    }

    public static class ProductAttribute {
    private long attrId;
    private String attrName;
    private String attrValues;

    // Getters and Setters...
    public long getAttrId() { return attrId; }
    public void setAttrId(long attrId) { this.attrId = attrId; }
    public String getAttrName() { return attrName; }
    public void setAttrName(String attrName) { this.attrName = attrName; }
    public String getAttrValues() { return attrValues; }
    public void setAttrValues(String attrValues) { this.attrValues = attrValues; }
    }

    public static class SkuInfo {
    private String skuId;
    private String outerId;
    private double jdPrice;
    private double costPrice;
    private int stockNum;
    private String skuName;
    private String imageUrl;
    private List properties;

    // Getters and Setters...
    public String getSkuId() { return skuId; }
    public void setSkuId(String skuId) { this.skuId = skuId; }
    public String getOuterId() { return outerId; }
    public void setOuterId(String outerId) { this.outerId = outerId; }
    public double getJdPrice() { return jdPrice; }
    public void setJdPrice(double jdPrice) { this.jdPrice = jdPrice; }
    public double getCostPrice() { return costPrice; }
    public void setCostPrice(double costPrice) { this.costPrice = costPrice; }
    public int getStockNum() { return stockNum; }
    public void setStockNum(int stockNum) { this.stockNum = stockNum; }
    public String getSkuName() { return skuName; }
    public void setSkuName(String skuName) { this.skuName = skuName; }
    public String getImageUrl() { return imageUrl; }
    public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
    public List getProperties() { return properties; }
    public void setProperties(List properties) { this.properties = properties; }
    }

    public static class SkuProperty {
    private long propId;
    private String propValues;

    // Getters and Setters...
    public long getPropId() { return propId; }
    public void setPropId(long propId) { this.propId = propId; }
    public String getPropValues() { return propValues; }
    public void setPropValues(String propValues) { this.propValues = propValues; }
    }
    }

  1. 铺货主程序入口
    java
    public class JdPublishingDemo {

    public static void main(String[] args) {
    // 配置信息
    String appKey = "your_app_key";
    String appSecret = "your_app_secret";
    String accessToken = "your_access_token";

    try {
    // 初始化服务
    JdApiClient apiClient = new JdApiClient(appKey, appSecret, accessToken);
    JdImageService imageService = new JdImageService(apiClient);
    JdCategoryService categoryService = new JdCategoryService(apiClient);
    JdPublishService publishService = new JdPublishService(apiClient, imageService);

    // ========== Step 1: 查询类目 ==========
    System.out.println("【Step 1】查询类目...");
    System.out.println("=".repeat(50));

    // 搜索类目
    List<JdCategoryService.Category> categories =
    categoryService.searchCategory("手机");
    System.out.println("找到类目:");
    for (JdCategoryService.Category cat : categories) {
    System.out.println(" " + cat.getCid() + " - " + cat.getName());
    }

    // 假设选择三级类目ID为 9987(手机)
    long categoryId = 9987L;

    // 获取类目属性
    List<JdCategoryService.CategoryAttribute> attrs =
    categoryService.getCategoryAttributes(categoryId);
    System.out.println("\n类目必填属性:");
    for (JdCategoryService.CategoryAttribute attr : attrs) {
    if (attr.isRequired()) {
    System.out.println(" [必填] " + attr.getAttrName()
    + " (" + attr.getInputType() + ")");
    }
    }

    // ========== Step 2: 准备商品数据 ==========
    System.out.println("\n【Step 2】准备商品数据...");
    System.out.println("=".repeat(50));

    JdPublishService.ProductInfo product = new JdPublishService.ProductInfo();
    product.setTitle("Apple iPhone 16 Pro Max 256GB 钛金属");
    product.setSubTitle("A18芯片 4800万像素 超长续航");
    product.setCategoryId(categoryId);
    product.setBrandId(14026L); // Apple品牌ID
    product.setWeight(0.227);
    product.setOrigin("中国");
    product.setDescription("iPhone 16 Pro Max 搭载全新A18芯片...");

    // 设置商品属性
    List<JdPublishService.ProductAttribute> attributes = new ArrayList<>();
    JdPublishService.ProductAttribute attr1 = new JdPublishService.ProductAttribute();
    attr1.setAttrId(100000); // 颜色属性ID
    attr1.setAttrValues("钛金属");
    attributes.add(attr1);
    product.setAttributes(attributes);

    // 设置SKU
    List<JdPublishService.SkuInfo> skus = new ArrayList<>();
    JdPublishService.SkuInfo sku1 = new JdPublishService.SkuInfo();
    sku1.setOuterId("IP16PM-256-TITAN");
    sku1.setJdPrice(9999.00);
    sku1.setCostPrice(8500.00);
    sku1.setStockNum(100);
    sku1.setSkuName("256GB 钛金属");

    List<JdPublishService.SkuProperty> skuProps = new ArrayList<>();
    JdPublishService.SkuProperty prop1 = new JdPublishService.SkuProperty();
    prop1.setPropId(100000);
    prop1.setPropValues("钛金属");
    skuProps.add(prop1);
    sku1.setProperties(skuProps);
    skus.add(sku1);
    product.setSkus(skus);

    // 设置图片(从货源平台获取的图片URL)
    List imageUrls = new ArrayList<>();
    imageUrls.add("https://img.example.com/iphone16-main.jpg");
    imageUrls.add("https://img.example.com/iphone16-detail1.jpg");
    imageUrls.add("https://img.example.com/iphone16-detail2.jpg");
    product.setSourceImageUrls(imageUrls);

    // ========== Step 3: 发布商品 ==========
    System.out.println("\n【Step 3】发布商品到京东...");
    System.out.println("=".repeat(50));

    String wareId = publishService.publishProduct(product);
    System.out.println("商品发布成功!商品ID: " + wareId);

    // ========== Step 4: 查询状态 ==========
    System.out.println("\n【Step 4】查询商品状态...");
    System.out.println("=".repeat(50));

    String status = publishService.getProductStatus(wareId);
    System.out.println("商品状态: " + status);

    } catch (Exception e) {
    System.err.println("铺货失败: " + e.getMessage());
    e.printStackTrace();
    }
    }
    }
    四、跨平台铺货数据映射
    当从其他平台(如1688、淘宝)采集商品数据铺货到京东时,需要进行字段映射和转换:
    表格
    业务字段 1688数据源 淘宝数据源 京东目标字段
    商品标题 item.title title title
    销售价格 item.price price jdPrice
    库存数量 item.stock num stockNum
    商品主图 item.pic_url pic_url wareImage
    详情图片 item.desc_img desc_img introduction
    类目路径 item.category_path cid cid(需映射)
    SKU规格 item.sku skus skus
    品牌 item.brand brand brandId
    重量 item.weight weight weight
    类目映射示例:
    java
    public class CategoryMapping {

    // 类目映射表:源平台类目 → 京东类目
    private static final Map<String, Long> CATEGORY_MAP = new HashMap<>();

    static {
    CATEGORY_MAP.put("tb:50008165", 9987L); // 淘宝手机 → 京东手机
    CATEGORY_MAP.put("tb:50013864", 652L); // 淘宝女装 → 京东女装
    CATEGORY_MAP.put("1688:7", 9987L); // 1688手机 → 京东手机
    // ... 更多映射
    }

    public static Long mapToJdCategory(String sourceCategory) {
    return CATEGORY_MAP.getOrDefault(sourceCategory, 0L);
    }
    }
    五、图片处理规范
    京东对商品图片有严格要求,铺货前需进行预处理:
    表格
    要求项 规范 处理方式
    主图尺寸 800×800像素 强制缩放至800×800
    主图背景 白底(RGB 255,255,255) 自动填充白色背景
    图片格式 JPG/PNG 统一转为JPG
    图片大小 ≤2MB 压缩至2MB以内
    图片数量 主图5张,详情图≤20张 自动截取前5张为主图
    水印 不得有第三方平台水印 自动去除或覆盖
    六、常见问题与解决方案
    表格
    问题 原因 解决方案
    类目不存在 类目ID错误或已下线 重新查询最新类目树
    品牌未授权 品牌ID未在店铺授权 申请品牌授权或选择其他品牌
    图片上传失败 图片格式/大小不符 按规范预处理图片
    SKU属性不匹配 属性值不在类目允许范围内 查询类目属性可选值
    价格低于最低价 低于类目最低限价 调整价格或更换类目
    库存必须为整数 传入小数 四舍五入取整
    商品审核不通过 信息不完整或违规 根据审核意见修改后重新提交
    七、进阶优化建议

  2. 异步批量铺货
    java
    import java.util.concurrent.CompletableFuture;
    import java.util.stream.Collectors;

public class BatchPublishService {

public List batchPublish(List products) {
return products.stream()
.map(p -> CompletableFuture.supplyAsync(() -> {
try {
return publishService.publishProduct(p);
} catch (Exception e) {
return "FAILED: " + p.getTitle();
}
}))
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
}
2. 铺货结果监控
java
public class PublishMonitor {

// 记录铺货日志
public void logPublishResult(String sourceId, String jdWareId, boolean success, String message) {
// 写入数据库或发送通知
}

// 定时同步库存
public void syncStock(String sourceId, String jdWareId) {
// 从货源平台获取最新库存,同步到京东
}
}
八、总结
本文完整介绍了使用 Java 实现京东商品铺货上架的流程:
类目查询:通过关键词搜索或层级遍历获取正确的三级类目ID
图片上传:将货源图片预处理(尺寸、格式、白底)后上传至京东服务器
商品发布:组装完整的商品信息(标题、价格、SKU、属性、详情页)调用发布接口
状态查询:确认商品审核状态,处理异常
在实际开发中,建议建立类目映射表和品牌映射表,实现跨平台数据的标准化转换。同时,务必遵守京东开放平台的使用协议,合理控制调用频率,确保铺货操作的合规性和稳定性。

如遇任何疑问或有进一步的需求,请随时与我私信或者评论联系。

posted @ 2026-07-13 18:19  爱专研的技术土狗  阅读(10)  评论(0)    收藏  举报