
微店作为国内知名的移动电商平台为开发者提供了丰富的 API 接口其中micro.item_get接口用于获取商品详情数据。本文将详细介绍如何使用 Java 调用该接口包括环境准备、认证授权、签名生成、接口调用及数据解析等完整流程。一、接口概述micro.item_get是微店开放平台提供的核心接口用于获取指定商品的详细信息包括商品基本信息ID、标题、价格、库存商品图片与描述商品规格与属性销量与评价数据该接口采用 HTTP GET/POST 请求方式返回 JSON 格式数据。二、准备工作1. 注册开发者账号在调用接口前需前往微店开放平台注册开发者账号创建应用并获取以下凭证凭证说明app_key应用标识app_secret应用密钥用于签名access_token访问令牌用于身份验证2. 项目依赖使用 Maven 管理依赖在pom.xml中添加dependencies !-- HTTP 请求 -- dependency groupIdorg.apache.httpcomponents/groupId artifactIdhttpclient/artifactId version4.5.14/version /dependency !-- JSON 解析 -- dependency groupIdcom.google.code.gson/groupId artifactIdgson/artifactId version2.10.1/version /dependency !-- 日志 -- dependency groupIdorg.slf4j/groupId artifactIdslf4j-simple/artifactId version2.0.9/version /dependency /dependencies三、完整代码实现1. 签名工具类微店 API 要求对请求参数进行签名验证以下是基于 MD5 的签名实现import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; public class WeidianSignUtil { /** * 生成微店 API 签名 * 签名规则将参数按 key 升序排列拼接成 key1value1key2value2 格式末尾追加 app_secret最后进行 MD5 加密 */ public static String generateSign(MapString, String params, String appSecret) { // 1. 过滤空值按 key 升序排列 String sortedParams params.entrySet().stream() .filter(entry - entry.getValue() ! null !entry.getValue().isEmpty()) .sorted(Map.Entry.comparingByKey()) .map(entry - entry.getKey() entry.getValue()) .collect(Collectors.joining()); // 2. 拼接 app_secret String signStr sortedParams appSecret; // 3. MD5 加密 return md5(signStr).toLowerCase(); } private static String md5(String input) { try { MessageDigest md MessageDigest.getInstance(MD5); byte[] digest md.digest(input.getBytes(StandardCharsets.UTF_8)); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b)); } return sb.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(MD5 algorithm not found, e); } } }2. Access Token 获取点击测试import org.apache.http.client.methods.HttpPost; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.util.ArrayList; import java.util.List; public class WeidianAuthService { private static final String AUTH_URL https://open.weidian.com/api/oauth2/token; /** * 使用 client_credentials 模式获取 Access Token */ public static String getAccessToken(String clientId, String clientSecret) { try (CloseableHttpClient httpClient HttpClients.createDefault()) { HttpPost post new HttpPost(AUTH_URL); ListBasicNameValuePair params new ArrayList(); params.add(new BasicNameValuePair(grant_type, client_credentials)); params.add(new BasicNameValuePair(client_id, clientId)); params.add(new BasicNameValuePair(client_secret, clientSecret)); post.setEntity(new UrlEncodedFormEntity(params, UTF-8)); String response EntityUtils.toString(httpClient.execute(post).getEntity(), UTF-8); JsonObject json JsonParser.parseString(response).getAsJsonObject(); if (json.has(access_token)) { return json.get(access_token).getAsString(); } else { throw new RuntimeException(获取 Access Token 失败: response); } } catch (Exception e) { throw new RuntimeException(获取 Access Token 异常, e); } } }3. 商品详情服务类import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import com.google.gson.Gson; import com.google.gson.JsonObject; import java.util.HashMap; import java.util.Map; public class WeidianItemService { private static final String API_BASE_URL https://api.weidian.com/v1; private final String appKey; private final String appSecret; private final Gson gson new Gson(); public WeidianItemService(String appKey, String appSecret) { this.appKey appKey; this.appSecret appSecret; } /** * 获取商品详情 * param accessToken 访问令牌 * param itemId 商品ID * return 商品详情对象 */ public ItemDetail getItemDetail(String accessToken, String itemId) { // 构建请求参数 MapString, String params new HashMap(); params.put(app_key, appKey); params.put(access_token, accessToken); params.put(item_id, itemId); params.put(timestamp, String.valueOf(System.currentTimeMillis() / 1000)); // 生成签名 String sign WeidianSignUtil.generateSign(params, appSecret); params.put(sign, sign); // 构建 URL StringBuilder urlBuilder new StringBuilder(API_BASE_URL /items/details?); params.forEach((k, v) - urlBuilder.append(k).append().append(v).append()); String url urlBuilder.substring(0, urlBuilder.length() - 1); // 发送请求 try (CloseableHttpClient httpClient HttpClients.createDefault()) { HttpGet httpGet new HttpGet(url); httpGet.setHeader(User-Agent, Mozilla/5.0 (Windows NT 10.0; Win64; x64)); httpGet.setHeader(Accept, application/json); String response EntityUtils.toString(httpClient.execute(httpGet).getEntity(), UTF-8); JsonObject jsonResponse JsonParser.parseString(response).getAsJsonObject(); // 解析响应 return parseItemDetail(jsonResponse); } catch (Exception e) { throw new RuntimeException(获取商品详情失败, e); } } /** * 解析商品详情 JSON 响应 */ private ItemDetail parseItemDetail(JsonObject response) { if (!response.has(data) || response.get(data).isJsonNull()) { throw new RuntimeException(接口返回数据异常: response); } JsonObject data response.getAsJsonObject(data); ItemDetail item new ItemDetail(); item.setItemId(data.has(item_id) ? data.get(item_id).getAsString() : ); item.setName(data.has(item_name) ? data.get(item_name).getAsString() : ); item.setPrice(data.has(price) ? data.get(price).getAsDouble() : 0.0); item.setOriginalPrice(data.has(original_price) ? data.get(original_price).getAsDouble() : 0.0); item.setStock(data.has(stock) ? data.get(stock).getAsInt() : 0); item.setSoldCount(data.has(sold_count) ? data.get(sold_count).getAsInt() : 0); item.setDescription(data.has(description) ? data.get(description).getAsString() : ); item.setMainImage(data.has(main_image) ? data.get(main_image).getAsString() : ); // 解析图片列表 if (data.has(images) data.get(images).isJsonArray()) { ListString images new ArrayList(); data.getAsJsonArray(images).forEach(img - images.add(img.getAsString())); item.setImages(images); } return item; } }4. 商品详情实体类import java.util.List; public class ItemDetail { private String itemId; // 商品ID private String name; // 商品名称 private Double price; // 当前售价 private Double originalPrice; // 原价 private Integer stock; // 库存 private Integer soldCount; // 销量 private String description; // 商品描述 private String mainImage; // 主图 private ListString images; // 图片列表 private ListSku skus; // SKU 列表 // 构造方法、Getter 和 Setter public ItemDetail() {} // Getters and Setters public String getItemId() { return itemId; } public void setItemId(String itemId) { this.itemId itemId; } public String getName() { return name; } public void setName(String name) { this.name name; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price price; } public Double getOriginalPrice() { return originalPrice; } public void setOriginalPrice(Double originalPrice) { this.originalPrice originalPrice; } public Integer getStock() { return stock; } public void setStock(Integer stock) { this.stock stock; } public Integer getSoldCount() { return soldCount; } public void setSoldCount(Integer soldCount) { this.soldCount soldCount; } public String getDescription() { return description; } public void setDescription(String description) { this.description description; } public String getMainImage() { return mainImage; } public void setMainImage(String mainImage) { this.mainImage mainImage; } public ListString getImages() { return images; } public void setImages(ListString images) { this.images images; } public ListSku getSkus() { return skus; } public void setSkus(ListSku skus) { this.skus skus; } Override public String toString() { return ItemDetail{ itemId itemId \ , name name \ , price price , stock stock , soldCount soldCount }; } // SKU 内部类 public static class Sku { private String skuId; private String properties; private Double price; private Integer stock; // Getters and Setters... } }5. 主程序入口public class WeidianItemDemo { public static void main(String[] args) { // 配置信息请替换为实际值 String appKey your_app_key; String appSecret your_app_secret; String clientId your_client_id; String clientSecret your_client_secret; String itemId your_item_id; try { // 1. 获取 Access Token System.out.println(正在获取 Access Token...); String accessToken WeidianAuthService.getAccessToken(clientId, clientSecret); System.out.println(Access Token 获取成功: accessToken.substring(0, 10) ...); // 2. 调用商品详情接口 System.out.println(正在获取商品详情...); WeidianItemService itemService new WeidianItemService(appKey, appSecret); ItemDetail item itemService.getItemDetail(accessToken, itemId); // 3. 输出结果 System.out.println(\n 商品详情 ); System.out.println(商品ID: item.getItemId()); System.out.println(商品名称: item.getName()); System.out.println(当前售价: ¥ item.getPrice()); System.out.println(原价: ¥ item.getOriginalPrice()); System.out.println(库存: item.getStock()); System.out.println(销量: item.getSoldCount()); System.out.println(商品描述: item.getDescription()); System.out.println(主图: item.getMainImage()); if (item.getImages() ! null) { System.out.println(图片数量: item.getImages().size()); } } catch (Exception e) { System.err.println(程序执行异常: e.getMessage()); e.printStackTrace(); } } }四、接口返回数据示例调用成功后接口返回的 JSON 数据结构如下五、常见问题与解决方案问题原因解决方案403 权限不足未申请接口权限或凭证错误检查app_key和access_token是否正确确认已申请micro.item_get接口权限签名错误签名算法或参数排序有误确认参数按 key 升序排列签名字符串末尾正确追加app_secret429 请求频繁超出接口调用频率限制增加请求间隔使用限流策略或申请提升调用配额数据字段为空商品信息未设置或权限未开启检查商品是否已上架确认店铺开启了商品信息开放权限access_token 过期Token 有效期通常为 7200 秒实现 Token 自动刷新机制缓存 Token 并在过期前重新获取六、进阶优化建议1. Token 自动刷新与缓存public class TokenManager { private String accessToken; private long expireTime; public synchronized String getValidToken(String clientId, String clientSecret) { if (accessToken null || System.currentTimeMillis() expireTime - 60000) { // 提前 1 分钟刷新 accessToken WeidianAuthService.getAccessToken(clientId, clientSecret); expireTime System.currentTimeMillis() 7200 * 1000; } return accessToken; } }2. 连接池配置import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; public class HttpClientPool { private static final CloseableHttpClient httpClient; static { PoolingHttpClientConnectionManager cm new PoolingHttpClientConnectionManager(); cm.setMaxTotal(200); // 最大连接数 cm.setDefaultMaxPerRoute(50); // 每个路由最大连接数 httpClient HttpClients.custom() .setConnectionManager(cm) .setConnectionManagerShared(true) .build(); } public static CloseableHttpClient getClient() { return httpClient; } }3. 批量获取与异步处理对于需要批量获取商品详情的场景建议使用线程池配合 CompletableFuture 实现异步并行调用提升整体效率。七、总结本文完整介绍了使用 Java 调用微店micro.item_get商品详情接口的流程包括认证授权通过 OAuth2 获取access_token签名机制按规范生成 MD5 签名确保请求安全接口调用使用 Apache HttpClient 发送 HTTP 请求数据解析使用 Gson 解析 JSON 响应并映射为 Java 对象异常处理针对常见错误提供解决方案在实际开发中建议根据业务需求进一步完善异常处理、日志记录和性能优化。同时务必遵守微店开放平台的使用协议合理控制调用频率避免对平台造成过大压力