Java后端开发:基于美团开放平台规范构建高可用霸王餐API对接工程

在“霸王餐”业务中,需频繁调用美团开放平台的活动创建、用户资格校验、订单核销等接口。为保障系统稳定性与可维护性,必须遵循美团 API 规范(如签名算法、重试机制、幂等设计),并结合 Spring Boot 构建高可用对接工程。本文展示核心模块实现。

统一API请求客户端封装

使用 RestTemplate 封装带签名的 HTTP 客户端:

package baodanbao.com.cn.meituan.client;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
import java.util.TreeMap;

@Component
public class MeituanApiClient {

    private final RestTemplate restTemplate;
    private final String appKey;
    private final String appSecret;
    private final String baseUrl = "https://openapi.meituan.com";

    public MeituanApiClient(RestTemplate restTemplate,
                            @Value("${meituan.app-key}") String appKey,
                            @Value("${meituan.app-secret}") String appSecret) {
        this.restTemplate = restTemplate;
        this.appKey = appKey;
        this.appSecret = appSecret;
    }

    public <T> T post(String path, Map<String, Object> params, Class<T> responseType) {
        // 1. 添加公共参数
        params.put("appkey", appKey);
        params.put("timestamp", System.currentTimeMillis());

        // 2. 按字典序排序
        TreeMap<String, Object> sortedParams = new TreeMap<>(params);

        // 3. 构造待签名字符串
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : sortedParams.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        sb.append("secret=").append(appSecret);
        String sign = md5(sb.toString());

        // 4. 添加签名
        sortedParams.put("sign", sign);

        // 5. 发起请求
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(sortedParams, headers);
        return restTemplate.postForObject(baseUrl + path, entity, responseType);
    }

    private String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder hex = new StringBuilder();
            for (byte b : digest) {
                hex.append(String.format("%02x", b));
            }
            return hex.toString().toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("MD5计算失败", e);
        }
    }
}

在这里插入图片描述

定义领域模型与响应结构

package baodanbao.com.cn.meituan.model;

public class CreateActivityRequest {
    private String activityName;
    private Long startTime;
    private Long endTime;
    // getters/setters
}

public class MeituanResponse<T> {
    private Integer code;
    private String msg;
    private T data;
    // getters/setters
}

服务层实现——创建霸王餐活动

package baodanbao.com.cn.meituan.service;

import baodanbao.com.cn.meituan.client.MeituanApiClient;
import baodanbao.com.cn.meituan.model.CreateActivityRequest;
import baodanbao.com.cn.meituan.model.MeituanResponse;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class MeituanActivityService {

    private final MeituanApiClient apiClient;

    public MeituanActivityService(MeituanApiClient apiClient) {
        this.apiClient = apiClient;
    }

    public Long createFreeMealActivity(CreateActivityRequest request) {
        Map<String, Object> params = new HashMap<>();
        params.put("activity_name", request.getActivityName());
        params.put("start_time", request.getStartTime());
        params.put("end_time", request.getEndTime());
        params.put("meal_type", "FREE"); // 霸王餐类型

        MeituanResponse<Map<String, Object>> response =
            apiClient.post("/v1/activity/create", params, MeituanResponse.class);

        if (response.getCode() != 200) {
            throw new RuntimeException("创建活动失败: " + response.getMsg());
        }

        return (Long) response.getData().get("activity_id");
    }
}

高可用增强措施

1. 重试机制

配置 Spring Retry:

@Retryable(value = {RuntimeException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
public Long createFreeMealActivity(CreateActivityRequest request) {
    // ...
}

2. 熔断降级(Resilience4j)

@CircuitBreaker(name = "meituanApi", fallbackMethod = "createActivityFallback")
public Long createFreeMealActivity(CreateActivityRequest request) {
    // ...
}

public Long createActivityFallback(CreateActivityRequest request, Exception e) {
    // 记录日志,返回预设ID或抛出友好异常
    throw new ServiceException("美团服务暂时不可用,请稍后再试");
}

3. 幂等性保障

对核销等写操作,生成唯一 out_biz_no 并缓存结果:

public boolean writeOffOrder(String orderId, String outBizNo) {
    // 先查本地是否已处理
    if (writeOffRecordRepository.existsByOutBizNo(outBizNo)) {
        return true; // 已成功,直接返回
    }

    Map<String, Object> params = new HashMap<>();
    params.put("order_id", orderId);
    params.put("out_biz_no", outBizNo); // 美团支持该字段做幂等

    // 调用API...
    // 成功后保存记录
    writeOffRecordRepository.save(new WriteOffRecord(outBizNo, orderId));
    return true;
}

配置管理

敏感信息通过 Spring Cloud Config 管理:

# meituan-service-prod.yml
meituan:
  app-key: MT2025BAODAN
  app-secret: '{cipher}AQEeGzK...xyz'
  connect-timeout: 5000
  read-timeout: 10000

日志与监控

  • 记录完整请求/响应(脱敏后);
  • 上报关键指标(如调用耗时、失败率)到 Prometheus;
  • code != 200 的响应触发告警。

通过规范化的签名、重试、熔断、幂等设计,霸王餐系统与美团开放平台的对接具备生产级高可用能力。

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

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐