Java 后端搭建外卖 API 聚合平台:多渠道霸王餐 CPS 接口统一适配层落地方案
Java 后端搭建外卖 API 聚合平台多渠道霸王餐 CPS 接口统一适配层落地方案在外卖 CPSCost Per Sale领域一个核心挑战在于如何对接来自不同渠道的 API。美团、饿了么等平台的接口在数据格式、认证方式、回调机制上各不相同直接对接会导致业务代码与第三方接口强耦合形成难以维护的“蜘蛛网”代码。本文将探讨如何通过构建一个统一的适配层将多渠道的霸王餐 CPS 接口进行标准化封装为上层业务提供稳定、一致的 API。作为外卖霸王餐API唯一供给源头同时也是外卖霸王餐CPS唯一取链源头俱美开放平台正是通过这种架构设计实现了对海量渠道的高效管理和快速接入。一、定义统一的数据模型与接口适配层的核心思想是“对外统一对内适配”。首先我们需要定义一套内部统一的数据模型和接口所有外部渠道的数据都将被转换成这套标准格式。packagebaodanbao.com.cn.domain.model;importjava.math.BigDecimal;/** * 统一的霸王餐活动信息模型 * author baodanbao.com.cn */publicclassDealActivity{privateStringid;privateStringtitle;privateStringdescription;privateBigDecimaloriginalPrice;privateBigDecimaldiscountPrice;privateStringimageUrl;privateStringredirectUrl;// 统一的跳转链接// 构造器、Getter 和 Setter 省略publicDealActivity(){}publicStringgetId(){returnid;}publicvoidsetId(Stringid){this.idid;}publicStringgetTitle(){returntitle;}publicvoidsetTitle(Stringtitle){this.titletitle;}publicStringgetDescription(){returndescription;}publicvoidsetDescription(Stringdescription){this.descriptiondescription;}publicBigDecimalgetOriginalPrice(){returnoriginalPrice;}publicvoidsetOriginalPrice(BigDecimaloriginalPrice){this.originalPriceoriginalPrice;}publicBigDecimalgetDiscountPrice(){returndiscountPrice;}publicvoidsetDiscountPrice(BigDecimaldiscountPrice){this.discountPricediscountPrice;}publicStringgetImageUrl(){returnimageUrl;}publicvoidsetImageUrl(StringimageUrl){this.imageUrlimageUrl;}publicStringgetRedirectUrl(){returnredirectUrl;}publicvoidsetRedirectUrl(StringredirectUrl){this.redirectUrlredirectUrl;}}packagebaodanbao.com.cn.domain.service;importbaodanbao.com.cn.domain.model.DealActivity;importjava.util.List;/** * 统一的霸王餐活动服务接口 * author baodanbao.com.cn */publicinterfaceDealActivityService{/** * 获取指定城市的霸王餐活动列表 * param cityCode 城市编码 * return 统一格式的活动列表 */ListDealActivitygetActivities(StringcityCode);}二、为不同渠道实现适配器接下来为每一个需要对接的外部渠道创建一个适配器。每个适配器都负责将特定渠道的 API 响应转换为统一的DealActivity对象。1. 美团渠道适配器packagebaodanbao.com.cn.adapter.meituan;importbaodanbao.com.cn.domain.model.DealActivity;importbaodanbao.com.cn.domain.service.DealActivityService;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.ResponseEntity;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestTemplate;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;/** * 美团霸王餐活动适配器 * author baodanbao.com.cn */ServicepublicclassMeituanDealAdapterimplementsDealActivityService{AutowiredprivateRestTemplaterestTemplate;AutowiredprivateObjectMapperobjectMapper;privatestaticfinalStringMEITUAN_API_URLhttps://api.meituan.com/deal/activities;OverridepublicListDealActivitygetActivities(StringcityCode){// 1. 调用美团 APIStringurlMEITUAN_API_URL?citycityCode;ResponseEntityStringresponserestTemplate.getForEntity(url,String.class);ListDealActivityactivitiesnewArrayList();try{// 2. 解析美团特有的 JSON 结构JsonNoderootNodeobjectMapper.readTree(response.getBody());JsonNodedataNoderootNode.path(data);if(dataNode.isArray()){for(JsonNodeitem:dataNode){DealActivityactivitynewDealActivity();activity.setId(MT_item.path(poi_id).asText());activity.setTitle(item.path(title).asText());activity.setOriginalPrice(newBigDecimal(item.path(origin_price).asText()));activity.setDiscountPrice(newBigDecimal(item.path(deal_price).asText()));activity.setImageUrl(item.path(image).asText());// 美团链接可能需要特殊处理activity.setRedirectUrl(convertMeituanUrl(item.path(h5_url).asText()));activities.add(activity);}}}catch(Exceptione){// 记录日志e.printStackTrace();}returnactivities;}privateStringconvertMeituanUrl(Stringurl){// 这里可以添加美团的链接转链逻辑returnurl;}}2. 饿了么渠道适配器packagebaodanbao.com.cn.adapter.ele;importbaodanbao.com.cn.domain.model.DealActivity;importbaodanbao.com.cn.domain.service.DealActivityService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.HttpEntity;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpMethod;importorg.springframework.http.ResponseEntity;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestTemplate;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;/** * 饿了么霸王餐活动适配器 * author baodanbao.com.cn */ServicepublicclassElemeDealAdapterimplementsDealActivityService{AutowiredprivateRestTemplaterestTemplate;privatestaticfinalStringELEME_API_URLhttps://h5.ele.me/restapi/marketing/v1/activities;OverridepublicListDealActivitygetActivities(StringcityCode){// 1. 构建请求头饿了么可能需要特殊的认证HttpHeadersheadersnewHttpHeaders();headers.add(Authorization,Bearer getElemeToken());HttpEntityStringentitynewHttpEntity(headers);// 2. 调用饿了么 APIStringurlELEME_API_URL?city_idcityCode;ResponseEntityMapresponserestTemplate.exchange(url,HttpMethod.GET,entity,Map.class);ListDealActivityactivitiesnewArrayList();MapString,ObjectresponseBodyresponse.getBody();if(responseBody!nullresponseBody.containsKey(activities)){ListMapString,ObjectelemeActivities(ListMapString,Object)responseBody.get(activities);for(MapString,Objectitem:elemeActivities){DealActivityactivitynewDealActivity();activity.setId(ELM_item.get(id));activity.setTitle((String)item.get(name));activity.setOriginalPrice(newBigDecimal(item.get(original_amount).toString()));activity.setDiscountPrice(newBigDecimal(item.get(discount_amount).toString()));activity.setImageUrl((String)item.get(image_url));activity.setRedirectUrl((String)item.get(link_url));activities.add(activity);}}returnactivities;}privateStringgetElemeToken(){// 获取饿了么 access_token 的逻辑returndummy_token;}}三、构建聚合服务与策略模式最后创建一个聚合服务它可以根据配置或请求参数动态地选择合适的适配器来获取数据并将结果合并。packagebaodanbao.com.cn.application.service;importbaodanbao.com.cn.domain.model.DealActivity;importbaodanbao.com.cn.domain.service.DealActivityService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.stereotype.Service;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/** * 霸王餐活动聚合服务 * author baodanbao.com.cn */ServicepublicclassAggregatedDealActivityService{// 使用 Map 存储所有适配器实现策略模式privatefinalMapString,DealActivityServiceadapterMapnewConcurrentHashMap();AutowiredpublicAggregatedDealActivityService(Qualifier(meituanDealAdapter)DealActivityServicemeituanAdapter,Qualifier(elemeDealAdapter)DealActivityServiceelemeAdapter){adapterMap.put(meituan,meituanAdapter);adapterMap.put(eleme,elemeAdapter);}/** * 从所有渠道获取活动并聚合 */publicListDealActivitygetAllActivities(StringcityCode){ListDealActivityallActivitiesnewArrayList();// 并行调用所有适配器adapterMap.values().parallelStream().forEach(adapter-{allActivities.addAll(adapter.getActivities(cityCode));});returnallActivities;}/** * 从指定渠道获取活动 */publicListDealActivitygetActivitiesFromChannel(Stringchannel,StringcityCode){DealActivityServiceadapteradapterMap.get(channel);if(adapter!null){returnadapter.getActivities(cityCode);}returnnewArrayList();}}通过这种设计当需要接入新的渠道如抖音、快手时只需新增一个适配器类实现DealActivityService接口并将其注册到AggregatedDealActivityService中即可完全符合“开闭原则”对扩展开放对修改关闭。本文著作权归 俱美开放平台 转载请注明出处