俱美开放平台:外卖霸王餐API接口及外卖霸王餐CPS架构设计思路

俱美开放平台:外卖霸王餐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"; // 其他状态直接确认,防止重复推送
    }
}

本文著作权归 俱美开放平台 ,转载请注明出处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值