在电商系统开发中,对接 1688 开放平台的商品 API 实现信息实时同步是常见需求。本文将详细介绍接入流程,并提供完整代码示例,帮助开发者快速实现商品数据的实时获取与同步功能。
一、准备工作:1688 接入前置条件
1. 注册与认证
登录注册开发账号
完成认证(个人开发者部分 API 权限受限)
获取
apiKey和apiSecret(应用密钥)
2. 了解 API 基础信息
接口文档地址:
核心接口:
alibaba.product.get(获取商品详情)、alibaba.product.list(商品列表)调用方式:HTTP/HTTPS POST,支持 JSON 格式
签名机制:基于 HMAC-SHA1 的签名算法
二、核心技术实现:签名生成与 API 调用
1. 签名生成工具类
1688 API 要求所有请求必须包含合法签名,以下是签名生成的 Java 实现:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
public class SignUtils {
private static final String SIGN_METHOD = "HMAC-SHA1";
private static final String FORMAT = "json";
private static final String VERSION = "1.0";
/**
* 生成API请求参数(包含签名)
*/
public static Map<String, String> generateParams(String appKey, String appSecret,
String method, Map<String, String> bizParams) {
Map<String, String> params = new TreeMap<>();
// 系统参数
params.put("app_key", appKey);
params.put("method", method);
params.put("format", FORMAT);
params.put("v", VERSION);
params.put("sign_method", SIGN_METHOD);
params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// 业务参数
if (bizParams != null) {
params.putAll(bizParams);
}
// 生成签名
String sign = generateSign(params, appSecret);
params.put("sign", sign);
return params;
}
/**
* 生成签名
*/
private static String generateSign(Map<String, String> params, String appSecret) {
try {
// 1. 拼接待签名字符串
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (key != null && value != null && !key.equals("sign")) {
sb.append(key).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8.name()))
.append("&");
}
}
String signSource = sb.substring(0, sb.length() - 1);
// 2. HMAC-SHA1加密
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
mac.init(keySpec);
byte[] signBytes = mac.doFinal(signSource.getBytes(StandardCharsets.UTF_8));
// 3. Base64编码
return Base64.getEncoder().encodeToString(signBytes);
} catch (Exception e) {
throw new RuntimeException("生成签名失败", e);
}
}
}三、商品信息同步服务实现
1. 数据模型定义
定义商品实体类,映射 1688 返回的核心字段:
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
public class Product {
private String productId; // 商品ID
private String title; // 商品标题
private String description; // 商品描述
private BigDecimal price; // 价格
private String currency; // 货币单位
private List<String> imageUrls; // 商品图片
private String categoryId; // 类目ID
private int stock; // 库存
private Date gmtCreate; // 创建时间
private Date gmtModified; // 修改时间
}2. 同步服务实现
实现商品信息的拉取与本地存储同步:
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ProductSyncService {
private final Ali1688Client ali1688Client;
private final ProductRepository productRepository; // 本地数据库操作接口
@Autowired
public ProductSyncService(Ali1688Client ali1688Client, ProductRepository productRepository) {
this.ali1688Client = ali1688Client;
this.productRepository = productRepository;
}
/**
* 同步单个商品信息
*/
public Product syncSingleProduct(String productId) {
JSONObject result = ali1688Client.getProductDetail(productId);
// 验证API返回是否成功
if (!"0".equals(result.getString("code"))) {
throw new RuntimeException("获取商品信息失败: " + result.getString("msg"));
}
// 解析商品数据
Product product = parseProduct(result.getJSONObject("data"));
// 保存到本地数据库
return productRepository.save(product);
}
/**
* 批量同步商品列表
*/
public int batchSyncProducts(int page, int pageSize) {
JSONObject result = ali1688Client.getProductList(page, pageSize);
if (!"0".equals(result.getString("code"))) {
throw new RuntimeException("获取商品列表失败: " + result.getString("msg"));
}
// 解析商品列表
JSONArray productArray = result.getJSONObject("data").getJSONArray("products");
List<Product> products = new ArrayList<>();
for (int i = 0; i < productArray.size(); i++) {
products.add(parseProduct(productArray.getJSONObject(i)));
}
// 批量保存
productRepository.saveAll(products);
return products.size();
}
/**
* 解析API返回的商品数据
*/
private Product parseProduct(JSONObject productJson) {
Product product = new Product();
product.setProductId(productJson.getString("productId"));
product.setTitle(productJson.getString("title"));
product.setDescription(productJson.getString("description"));
product.setPrice(productJson.getBigDecimal("price"));
product.setCurrency(productJson.getString("currency"));
product.setImageUrls(productJson.getJSONArray("imageUrls").toJavaList(String.class));
product.setCategoryId(productJson.getString("categoryId"));
product.setStock(productJson.getIntValue("stock"));
// 更多字段映射...
return product;
}
}四、定时同步与异常处理
1. 定时任务配置
使用 Spring Scheduler 实现定时同步:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ProductSyncTask {
private final ProductSyncService syncService;
public ProductSyncTask(ProductSyncService syncService) {
this.syncService = syncService;
}
/**
* 每小时同步一次商品数据
*/
@Scheduled(cron = "0 0 * * * ?")
public void scheduledSyncProducts() {
// 分页同步所有商品
int page = 1;
int pageSize = 50;
while (true) {
int syncCount = syncService.batchSyncProducts(page, pageSize);
if (syncCount < pageSize) {
break; // 没有更多数据
}
page++;
}
}
}2. 异常处理与重试机制
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
@Component
public class RetryableProductSync {
private final ProductSyncService syncService;
public RetryableProductSync(ProductSyncService syncService) {
this.syncService = syncService;
}
/**
* 带重试机制的商品同步
*/
@Retryable(
value = {Exception.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2)
)
public void syncWithRetry(String productId) {
syncService.syncSingleProduct(productId);
}
}五、接入注意事项
接口权限:部分高级接口需要单独申请权限,需在开放平台完成权限开通
调用频率限制:1688 API 有严格的限流策略,需合理控制调用频率(默认 100 次 / 分钟)
数据缓存:建议对商品数据进行本地缓存,减少 API 调用次数
签名有效期:timestamp 参数需使用当前时间,且请求需在 15 分钟内发送
错误处理:针对不同错误码(如 401、429)进行专门处理,实现优雅降级
通过以上步骤,即可完成 1688 商品 API 的接入与商品信息实时同步功能。实际开发中可根据业务需求扩展字段映射和同步策略,建议结合消息队列实现异步处理,提升系统稳定性和响应速度。