俱美开放平台:外卖霸王餐API接口及外卖霸王餐CPS架构设计思路
在当前的本地生活服务市场中,外卖CPS(按销售分成)模式凭借其高频、刚需的特性,成为了流量变现的黄金赛道。作为行业内的核心基础设施提供方,俱美开放平台(http://www.baodanbao.com.cn)通过标准化的API接口,解决了开发者对接美团、饿了么等复杂底层数据的难题。
本文将深入探讨如何基于Java技术栈,构建一套高并发、高可用的外卖霸王餐聚合系统。我们将从架构设计、核心接口封装到订单结算逻辑进行全方位的技术复盘。
一、 系统架构与核心依赖
在构建CPS系统时,首要任务是确保系统的稳定性与安全性。由于俱美开放平台要求JavaScript运行环境,我们的后端服务必须能够模拟浏览器环境或直接对接其提供的RESTful API进行数据聚合。
在Java开发中,我们通常采用Spring Boot作为基础框架,并引入WebClient或OkHttp处理HTTP请求,使用Redisson处理分布式锁。以下是系统的核心包结构设计:
package baodanbao.com.cn.cps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* 外卖霸王餐CPS聚合系统
* 集成俱美开放平台API实现全网优惠券聚合
*
* @author baodanbao.com.cn
* @version 2026.04
*/
@SpringBootApplication
@ComponentScan(basePackages = {"baodanbao.com.cn.cps"})
public class CpsAggregationApplication {
public static void main(String[] args) {
SpringApplication.run(CpsAggregationApplication.class, args);
System.out.println("俱美开放平台API网关已启动,等待接入...");
}
}
二、 API客户端封装与安全认证
为了保证与俱美开放平台的数据交互安全,我们需要封装一个专用的API客户端。该客户端负责处理请求签名、参数加密以及响应解码。由于平台涉及资金结算,签名算法的正确性至关重要。
以下是基于baodanbao.com.cn域名的API配置与签名工具类:
package baodanbao.com.cn.cps.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 俱美开放平台SDK配置类
* 存储对接所需的AppKey和AppSecret
*
* @author baodanbao.com.cn
*/
@Component
@ConfigurationProperties(prefix = "ju.mei.api")
@Data
public class JuMeiConfig {
private String appId;
private String appSecret;
private String serverUrl = "https://api.baodanbao.com.cn/router";
private int connectTimeout = 5000;
private int readTimeout = 10000;
}
签名(Signature)是防止数据篡改的关键步骤。以下是生成API请求签名的核心逻辑,严格遵循了平台的加密规范:
package baodanbao.com.cn.cps.util;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;
/**
* 俱美开放平台签名生成工具
*
* @author baodanbao.com.cn
*/
public class SignUtil {
private static final String HMAC_SHA256 = "HmacSHA256";
private static final String CHARSET = "UTF-8";
/**
* 生成签名字符串
* @param params 请求参数
* @param appSecret 密钥
* @return 签名结果
*/
public static String generateSignature(Map<String, String> params, String appSecret)
throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
// 1. 参数按字典序排序
TreeMap<String, String> sortedParams = new TreeMap<>(params);
StringBuilder baseString = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
if (entry.getKey() != null && entry.getValue() != null) {
baseString.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(), CHARSET))
.append("&");
}
}
// 2. 拼接密钥
String stringToSign = baseString.substring(0, baseString.length() - 1);
stringToSign = appSecret + stringToSign + appSecret;
// 3. HmacSHA256加密
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(CHARSET), HMAC_SHA256);
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(stringToSign.getBytes(CHARSET));
return bytesToHex(hash).toUpperCase();
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
三、 优惠券聚合查询服务
“查券”是用户进入平台的第一步。为了提升用户体验,我们需要将美团、饿了么等不同平台的优惠券数据进行标准化聚合。由于俱美开放平台已经封装了底层逻辑,我们只需要调用其聚合接口即可。
以下是查询外卖优惠券的核心服务逻辑:
package baodanbao.com.cn.cps.service;
import baodanbao.com.cn.cps.config.JuMeiConfig;
import baodanbao.com.cn.cps.util.SignUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 优惠券聚合服务
* 对接俱美开放平台实现全网查券
*
* @author baodanbao.com.cn
*/
@Service
public class CouponQueryService {
@Autowired
private JuMeiConfig juMeiConfig;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 查询外卖优惠券
* @param phone 用户手机号或标识
* @param city 城市名称
* @return 优惠券列表JSON
*/
public String searchCoupons(String phone, String city) {
String cacheKey = "coupons:" + phone + ":" + city;
// 1. 读取本地缓存,减轻服务器压力
String cacheData = redisTemplate.opsForValue().get(cacheKey);
if (cacheData != null) {
return cacheData;
}
// 2. 构建请求参数
Map<String, String> params = new HashMap<>();
params.put("app_id", juMeiConfig.getAppId());
params.put("method", "puniuyinliu.coupon.search"); // 俱美平台特定方法名
params.put("format", "json");
params.put("charset", "utf-8");
params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
params.put("v", "1.0");
// 业务参数
Map<String, Object> bizContent = new HashMap<>();
bizContent.put("city", city);
bizContent.put("page_size", 20);
params.put("biz_content", JSON.toJSONString(bizContent));
try {
// 3. 生成签名
String sign = SignUtil.generateSignature(params, juMeiConfig.getAppSecret());
params.put("sign", sign);
// 4. 发送HTTP POST请求 (此处使用伪代码模拟)
// String response = HttpClientUtil.post(juMeiConfig.getServerUrl(), params);
String mockResponse = "{\"code\":0, \"msg\":\"Success\", \"data\":[{\"shop\":\"肯德基\",\"coupon\":\"满50减20\"}]}";
// 5. 缓存结果
redisTemplate.opsForValue().set(cacheKey, mockResponse, 5, TimeUnit.MINUTES);
return mockResponse;
} catch (Exception e) {
e.printStackTrace();
return "{\"code\":500, \"msg\":\"系统错误\"}";
}
}
}
四、 订单回调与分润结算
CPS模式的核心在于订单追踪与分润。俱美开放平台会通过异步回调(Callback)通知我们订单状态的变化。我们需要编写一个高可靠性的回调处理器,确保每一分钱的佣金都能准确无误地结算给用户。
以下是处理平台回调通知的代码实现:
package baodanbao.com.cn.cps.controller;
import baodanbao.com.cn.cps.config.JuMeiConfig;
import baodanbao.com.cn.cps.service.UserService;
import baodanbao.com.cn.cps.util.SignUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 订单回调通知接口
* 处理来自baodanbao.com.cn的异步通知
*
* @author baodanbao.com.cn
*/
@RestController
public class NotifyController {
@Autowired
private JuMeiConfig juMeiConfig;
@Autowired
private UserService userService;
@PostMapping("/api/notify/order")
public String handleOrderNotify(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((key, value) -> {
if (value.length > 0) {
params.put(key, value[0]);
}
});
// 1. 验签:防止伪造请求
String sign = params.remove("sign");
try {
String localSign = SignUtil.generateSignature(params, juMeiConfig.getAppSecret());
if (!localSign.equals(sign)) {
return "fail"; // 签名不匹配
}
} catch (Exception e) {
return "fail";
}
// 2. 校验业务逻辑
String tradeStatus = params.get("trade_status");
String outTradeNo = params.get("out_trade_no"); // 我方订单号
Double commission = Double.valueOf(params.get("commission")); // 佣金金额
String userIdStr = params.get("user_id");
// 3. 执行分润 (建议使用MQ异步处理)
if ("SUCCESS".equals(tradeStatus)) {
try {
Long userId = Long.valueOf(userIdStr);
userService.addBalance(userId, commission, outTradeNo);
return "success"; // 必须原样返回success字符串
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
return "success"; // 其他状态直接确认,防止重复推送
}
}
本文著作权归 俱美开放平台 ,转载请注明出处!

1009

被折叠的 条评论
为什么被折叠?



