场景背景
在电商运营中,商品发布是一项重复性高、耗时耗力的工作。特别是对于拥有大量商品需要同步到闲鱼平台的商家而言,手动逐一发布不仅效率低下,还容易出现操作失误。
本文将介绍一个基于Java的自动化解决方案,通过轮询待发布商品列表,自动构建闲鱼商品发布参数,并调用发布接口实现批量上架。整个流程包括:定时拉取待发布商品 → 数据格式转换 → 调用发布接口 → 更新商品状态,形成完整的自动化闭环。
一、技术选型与依赖
本方案使用以下核心技术和库:
| 技术/库 | 用途 |
|---|---|
| Java 8+ | 基础开发语言 |
| Fastjson | JSON对象构建与处理 |
| Gson | JSON解析与实体映射 |
| HttpURLConnection | 原生HTTP请求发送 |
| Thread.sleep | 定时轮询控制 |
Maven依赖
<dependencies>
<!-- Fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<!-- Gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
</dependencies>
二、整体架构设计
┌─────────────────────────────────────────────────────────────┐
│ 主循环(每10秒) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Step1 │ -> │ Step3 │ -> │ Step2 │ │
│ │ 获取待发布 │ │ 调用发布接口 │ │ 更新状态 │ │
│ │ 商品列表 │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
三、核心代码实现
1. 定义数据实体类
static class JsonParse {
List<Data> data;
}
static class Data {
String id; // 商品唯一标识
String goodsName; // 商品名称
String licenseImageFront; // 行驶证正面
String licenseImageBack; // 行驶证背面
String overallImage; // 整体照
String numberImage; // 号码牌照
String planeImage; // 平面照
String goodsVideo; // 商品视频
double expectPrice; // 期望价格
int stock; // 库存
String goodsDetail; // 商品详情
// ... 其他字段
}
2. 构建带参数的请求URL
public static String buildUrlWithParams(String baseUrl) {
StringBuilder urlBuilder = new StringBuilder(baseUrl);
urlBuilder.append("?");
// 可根据实际需求添加参数,如分页、筛选条件等
return urlBuilder.toString();
}
3. 发送GET请求获取商品列表
public static String sendGetRequest(String fullUrl) throws Exception {
URL url = new URL(fullUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
connection.setDoInput(true);
connection.setDoOutput(false);
int responseCode = connection.getResponseCode();
StringBuilder response = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(responseCode >= 200 && responseCode < 300 ?
connection.getInputStream() : connection.getErrorStream(),
StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
}
System.out.println("请求URL:" + fullUrl);
System.out.println("响应码:" + responseCode);
return response.toString();
} finally {
connection.disconnect();
}
}
4. 构建闲鱼发布参数
闲鱼发布接口需要特定的JSON结构,核心字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| item_biz_type | int | 商品业务类型,2表示普通商品 |
| sp_biz_type | int | 子业务类型,33表示闲鱼 |
| channel_cat_id | String | 渠道类目ID |
| price | int | 售价(单位:分) |
| original_price | int | 原价(单位:分) |
| stock | int | 库存数量 |
| publish_shop | array | 发布店铺信息 |
JSONObject root = new JSONObject();
// 基础配置
root.put("item_biz_type", 2);
root.put("sp_biz_type", 33);
root.put("channel_cat_id", "c460d6051481dbad28d88a08a19453dc");
root.put("price", (int) (tempData.expectPrice * 100)); // 元转分
root.put("original_price", (int) (tempData.expectPrice * 150)); // 原价=期望价*1.5
root.put("stock", 1);
root.put("outer_id", "CAR_SERVICE_001");
root.put("stuff_status", 0); // 0表示全新
// 店铺信息
JSONArray publishShopArray = new JSONArray();
JSONObject shop = new JSONObject();
shop.put("province", 330000); // 浙江省
shop.put("city", 330100); // 杭州市
shop.put("district", 330110); // 余杭区
shop.put("title", tempData.goodsName);
shop.put("content", tempData.goodsDetail);
shop.put("user_name", "tb31852548");
shop.put("white_images", null);
// 图片数组
JSONArray images = new JSONArray();
images.add(tempData.overallImage);
images.add(tempData.numberImage);
images.add(tempData.planeImage);
images.add(tempData.licenseImageFront);
images.add(tempData.licenseImageBack);
shop.put("images", images);
publishShopArray.add(shop);
root.put("publish_shop", publishShopArray);
5. 主循环:轮询处理
public static void main(String[] args) throws Exception {
while (true) {
Thread.sleep(10000); // 10秒轮询一次
// Step1: 获取待发布商品列表
String apiUrl = HOST + "/api/app/wxClue/getGoodsList";
String fullUrl = buildUrlWithParams(apiUrl);
String result = sendGetRequest(fullUrl);
// 解析响应
JsonParse jsonParse = gson.fromJson(result, JsonParse.class);
List<Data> dataList = jsonParse.data;
System.err.println("待发布商品:" + dataList.size() + "条。");
int numFlag = 0;
for (Data tempData : dataList) {
numFlag++;
// 构建发布参数
String publishJson = buildPublishParams(tempData);
// Step3: 调用发布接口
Step3_PublishAll.doWork(publishJson);
System.out.println("本轮已发布:" + numFlag + "条。剩余:" +
(dataList.size() - numFlag) + "条。");
// Step2: 更新商品发布状态
String updateInput = "{\"id\":\"" + tempData.id + "\"}";
Step2_ChangeStatus.updateGoodsStatus(updateInput);
}
}
}
四、关键技术点详解
1. 价格单位转换
闲鱼接口的价格单位是分 ,而数据库中存储的是元:
// 元 → 分
root.put("price", (int) (tempData.expectPrice * 100));
// 原价通常设置为售价的1.5倍,营造折扣感
root.put("original_price", (int) (tempData.expectPrice * 150));
2. 图片数组处理
闲鱼商品需要多张图片,包括整体照、号码牌、平面照、行驶证正反面等:
JSONArray images = new JSONArray();
images.add(tempData.overallImage); // 整体照
images.add(tempData.numberImage); // 号码牌
images.add(tempData.planeImage); // 平面照
images.add(tempData.licenseImageFront); // 行驶证正面
images.add(tempData.licenseImageBack); // 行驶证背面
shop.put("images", images);
3. 地区编码
使用国家统计局标准的地区编码:
shop.put("province", 330000); // 浙江省
shop.put("city", 330100); // 杭州市
shop.put("district", 330110); // 余杭区
4. 请求异常处理
通过HttpURLConnection的响应码判断使用InputStream还是ErrorStream:
try (BufferedReader br = new BufferedReader(
new InputStreamReader(responseCode >= 200 && responseCode < 300 ?
connection.getInputStream() : connection.getErrorStream(),
StandardCharsets.UTF_8))) {
// 读取响应
}
五、优化建议
1. 添加重试机制
public static String sendGetRequestWithRetry(String fullUrl, int maxRetries) {
for (int i = 0; i < maxRetries; i++) {
try {
return sendGetRequest(fullUrl);
} catch (Exception e) {
System.err.println("请求失败,第" + (i+1) + "次重试...");
if (i == maxRetries - 1) throw e;
Thread.sleep(2000);
}
}
return null;
}
2. 使用线程池并发处理
ExecutorService executor = Executors.newFixedThreadPool(5);
for (Data tempData : dataList) {
executor.submit(() -> {
// 处理单个商品发布
});
}
executor.shutdown();
3. 添加日志记录
建议使用Slf4j + Logback替代System.out.println,便于生产环境排查:
private static final Logger logger = LoggerFactory.getLogger(Step1_XianyuGoodsListApi.class);
logger.info("待发布商品数量:{}", dataList.size());
logger.error("发布失败,商品ID:{}", tempData.id, exception);
4. 配置化参数
将API地址、类目ID、用户信息等抽离到配置文件:
properties
# application.properties
api.host=http://8.149.245.18:8807
api.channel.cat.id=c460d6051481dbad28d88a08a19453dc
api.user.name=tb31852548
六、总结
本文实现了一套完整的闲鱼商品自动发布系统,核心功能包括:
-
定时轮询:每10秒自动获取待发布商品列表
-
数据转换:将内部商品数据转换为闲鱼API所需的JSON格式
-
批量发布:循环调用发布接口,支持批量上架
-
状态同步:发布成功后更新商品状态,避免重复发布
这套方案有效解决了电商运营中商品发布效率低下的问题,将人工操作转化为自动化流程,大大提升了运营效率。