全部
常见问题
产品动态
精选推荐
功能建议

分析中 已回复 待规划 {{opt.name}}
分析中 已回复 待规划
Java 实现京东商品分类查询、图片上传与铺货上架完整指南

管理 管理 编辑 删除

在电商多平台运营时代,商家需要将商品从货源平台(如1688、淘宝)同步上架至京东。传统手动铺货模式效率低下、错误率高,而通过京东开放平台(JOS)提供的标准化接口,可以实现从分类查询 → 图片上传 → 商品发布的全流程自动化。本文将详细介绍如何使用 Java 调用京东相关接口完成铺货上架。



一、整体流程概览


┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  1.类目查询  │ → │  2.图片上传  │ → │  3.商品发布  │ → │  4.状态查询  │
│ 获取类目ID   │    │ 上传主图/详情 │    │ 填写商品信息 │    │ 确认上架成功 │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘


二、准备工作

1. 注册京东开放平台开发者账号

  1. 注册开发者账号
  2. 完成企业认证,创建应用获取凭证:
凭证说明
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 依赖配置


<dependencies>
    <!-- HTTP 请求 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.14</version>
    </dependency>
    
    <!-- JSON 解析 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>2.0.43</version>
    </dependency>
    
    <!-- MD5 加密 -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.16.0</version>
    </dependency>
    
    <!-- 图片处理 -->
    <dependency>
        <groupId>javax.imageio</groupId>
        <artifactId>imageio-core</artifactId>
        <version>3.8.3</version>
    </dependency>
    
    <!-- Base64编码 -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.16.0</version>
    </dependency>
</dependencies>


三、核心代码实现

1. 签名工具类(MD5 算法)

京东JOS签名规则:参数按key ASCII升序排列,拼接为 key1+value1+key2+value2 格式,首尾追加 AppSecret,最后进行 MD5 加密并转大写。


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();
    }
}

2. 基础请求工具类


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());
    }
}

3. 类目查询服务

京东商品发布必须先确定类目,通过类目查询接口获取类目ID和属性信息。


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<Category> 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<Category> 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<CategoryAttribute> 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<CategoryAttribute> 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<AttrValue> 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<Category> 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<Category> parseCategories(JSONObject response) {
        List<Category> 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<AttrValue> 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<AttrValue> getValues() { return values; }
        public void setValues(List<AttrValue> 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; }
    }
}

4. 图片上传服务

京东要求商品图片先上传到京东服务器,获取图片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<String> batchUploadImages(List<String> imagePaths) {
        List<String> 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"));
        }
    }
}

5. 商品发布服务

商品发布是铺货的核心环节,需要组装完整的商品信息并调用发布接口。

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<String> 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<String> imageUrls) {
        StringBuilder html = new StringBuilder();
        html.append("<div style='width:750px;margin:0 auto;'>");
        
        // 商品描述
        html.append("<p>").append(product.getDescription()).append("</p>");
        
        // 详情图片
        for (String url : imageUrls) {
            html.append("<img src='").append(url).append("' style='width:100%;'/>");
        }
        
        // 规格参数表
        html.append("<table style='width:100%;border-collapse:collapse;'>");
        html.append("<tr><th style='border:1px solid #ddd;padding:8px;'>参数</th>");
        html.append("<th style='border:1px solid #ddd;padding:8px;'>值</th></tr>");
        for (ProductAttribute attr : product.getAttributes()) {
            html.append("<tr>");
            html.append("<td style='border:1px solid #ddd;padding:8px;'>")
                .append(attr.getAttrName()).append("</td>");
            html.append("<td style='border:1px solid #ddd;padding:8px;'>")
                .append(attr.getAttrValues()).append("</td>");
            html.append("</tr>");
        }
        html.append("</table>");
        
        html.append("</div>");
        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<ProductAttribute> attributes;
        private List<SkuInfo> skus;
        private List<String> 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<ProductAttribute> getAttributes() { return attributes; }
        public void setAttributes(List<ProductAttribute> attributes) { this.attributes = attributes; }
        public List<SkuInfo> getSkus() { return skus; }
        public void setSkus(List<SkuInfo> skus) { this.skus = skus; }
        public List<String> getSourceImageUrls() { return sourceImageUrls; }
        public void setSourceImageUrls(List<String> 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<SkuProperty> 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<SkuProperty> getProperties() { return properties; }
        public void setProperties(List<SkuProperty> 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; }
    }
}

6. 铺货主程序入口

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<String> 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.titletitletitle
销售价格item.pricepricejdPrice
库存数量item.stocknumstockNum
商品主图item.pic_urlpic_urlwareImage
详情图片item.desc_imgdesc_imgintroduction
类目路径item.category_pathcidcid(需映射)
SKU规格item.skuskusskus
品牌item.brandbrandbrandId
重量item.weightweightweight
类目映射示例





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属性不匹配属性值不在类目允许范围内查询类目属性可选值
价格低于最低价低于类目最低限价调整价格或更换类目
库存必须为整数传入小数四舍五入取整
商品审核不通过信息不完整或违规根据审核意见修改后重新提交


七、进阶优化建议

1. 异步批量铺货


import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

public class BatchPublishService {
    
    public List<String> batchPublish(List<ProductInfo> 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. 铺货结果监控


public class PublishMonitor {
    
    // 记录铺货日志
    public void logPublishResult(String sourceId, String jdWareId, boolean success, String message) {
        // 写入数据库或发送通知
    }
    
    // 定时同步库存
    public void syncStock(String sourceId, String jdWareId) {
        // 从货源平台获取最新库存,同步到京东
    }
}


八、总结

本文完整介绍了使用 Java 实现京东商品铺货上架的流程:

  1. 类目查询:通过关键词搜索或层级遍历获取正确的三级类目ID
  2. 图片上传:将货源图片预处理(尺寸、格式、白底)后上传至京东服务器
  3. 商品发布:组装完整的商品信息(标题、价格、SKU、属性、详情页)调用发布接口
  4. 状态查询:确认商品审核状态,处理异常
  5. 在实际开发中,建议建立类目映射表品牌映射表,实现跨平台数据的标准化转换。同时,务必遵守京东开放平台的使用协议,合理控制调用频率,确保铺货操作的合规性和稳定性。

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

{{voteData.voteSum}} 人已参与
支持
反对
请登录后查看

123c001fa85d 最后编辑于2026-07-13 18:23:30

快捷回复
回复
回复
回复({{post_count}}) {{!is_user ? '我的回复' :'全部回复'}}
排序 默认正序 回复倒序 点赞倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理员 企业

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推荐': '推荐'}}
{{item.is_suggest == 1? '取消推荐': '推荐'}} 【已收集】
{{item.floor}}# 沙发 板凳 地板 {{item.floor}}# 【已收集】
{{item.user_info.title || '暂无简介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打赏
已打赏¥{{item.reward_price}}
{{item.like_count}}
分享
{{item.showReply ? '取消回复' : '回复'}}
删除
回复
回复

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回复 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打赏
已打赏¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回复' : '回复'}}
删除
回复
回复
收起 展开更多
查看更多
打赏
已打赏¥{{reward_price}}
23
{{like_count}}
{{collect_count}}
添加回复 ({{post_count}})

相关推荐

快速安全登录

使用微信扫码登录
回复
回复
问题:
问题自动获取的帖子内容,不准确时需要手动修改. [获取答案]
答案:
提交
bug 需求 取 消 确 定
打赏金额
当前余额:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
请输入 0.1-{{reward_max_price}} 范围内的数值
打赏成功
¥{{price}}
完成 确认打赏

微信登录/注册

切换手机号登录

{{ bind_phone ? '绑定手机' : '手机登录'}}

{{codeText}}
切换微信登录/注册
暂不绑定
CRMEB客服
CRMEB咨询热线 400-8888-794

扫码领取产品资料

功能清单
思维导图
安装教程
CRMEB开源商城下载 源码下载 CRMEB帮助文档 帮助文档
返回顶部 返回顶部
CRMEB客服