当前位置: 首页 > news >正文

在Java项目中使用OkHttp构建高可用的外卖霸王餐API客户端

在Java项目中使用OkHttp构建高可用的外卖霸王餐API客户端

在对接美团外卖霸王餐这类高并发、强时效性的第三方服务时,API客户端的稳定性至关重要。本文将基于OkHttp客户端,通过连接池管理、统一拦截器、异步回调及熔断降级策略,构建一个健壮且易于维护的Java API客户端。

1. 项目依赖与基础配置

首先,确保pom.xml中引入了OkHttp和相关工具库。

<dependencies><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.10.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version></dependency></dependencies>
2. 定义核心数据模型

baodanbao.com.cn.model包下定义通用的响应结构和业务请求体。

通用响应类:

packagecom.baodanbao.cn.model;publicclassApiResponse<T>{privateintstatus;privateStringmsg;privateTresult;publicbooleanisSuccess(){returnthis.status==200;}// Getter和Setter省略}

霸王餐活动查询请求:

packagecom.baodanbao.cn.model.request;publicclassQueryCampaignRequest{privateStringpartnerId;privateStringtimestamp;privateStringtoken;privateStringshopPoiId;privateIntegerpage;privateIntegerpageSize;// Getter和Setter}

3. 构建OkHttpClient实例

利用OkHttp的连接池和拦截器机制,统一处理日志、重试和头部信息。

packagecom.baodanbao.cn.config;importokhttp3.ConnectionPool;importokhttp3.Interceptor;importokhttp3.OkHttpClient;importokhttp3.Response;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.io.IOException;importjava.util.concurrent.TimeUnit;@ConfigurationpublicclassOkHttpConfig{@BeanpublicOkHttpClientbawangcanHttpClient(){returnnewOkHttpClient.Builder().connectTimeout(5,TimeUnit.SECONDS).readTimeout(10,TimeUnit.SECONDS).writeTimeout(10,TimeUnit.SECONDS).connectionPool(newConnectionPool(5,5,TimeUnit.MINUTES))// 添加日志拦截器.addInterceptor(newLoggingInterceptor())// 添加公共参数拦截器.addInterceptor(newCommonHeaderInterceptor()).build();}// 日志拦截器staticclassLoggingInterceptorimplementsInterceptor{@OverridepublicResponseintercept(Chainchain)throwsIOException{Requestrequest=chain.request();longstartTime=System.nanoTime();Responseresponse=chain.proceed(request);longendTime=System.nanoTime();// 实际项目中应使用loggerSystem.out.println(String.format("API调用: %s 耗时: %.1fms",request.url(),(endTime-startTime)/1e6d));returnresponse;}}// 公共头部拦截器staticclassCommonHeaderInterceptorimplementsInterceptor{@OverridepublicResponseintercept(Chainchain)throwsIOException{Requestoriginal=chain.request();Requestrequest=original.newBuilder().header("Content-Type","application/json").header("User-Agent","Baodanbao-Client/1.0").method(original.method(),original.body()).build();returnchain.proceed(request);}}}
4. 封装业务客户端

创建专门的服务类来处理具体的API调用逻辑。

packagecom.baodanbao.cn.service;importcom.alibaba.fastjson.JSON;importcom.baodanbao.cn.config.OkHttpConfig;importcom.baodanbao.cn.model.ApiResponse;importcom.baodanbao.cn.model.request.QueryCampaignRequest;importcom.baodanbao.cn.util.SignatureUtil;importokhttp3.*;importjava.io.IOException;importjava.util.concurrent.CompletableFuture;publicclassMeituanBawangcanService{privatefinalOkHttpClientclient;privatefinalStringbaseUrl="https://api.meituan.com/bawangcan";privatefinalStringpartnerId="your_partner_id";privatefinalStringpartnerSecret="your_secret_key";publicMeituanBawangcanService(){this.client=newOkHttpConfig().bawangcanHttpClient();}/** * 异步查询霸王餐活动列表 */publicCompletableFuture<ApiResponse<String>>queryCampaignsAsync(StringshopPoiId){returnCompletableFuture.supplyAsync(()->{try{QueryCampaignRequestrequest=buildQueryRequest(shopPoiId);Stringjson=JSON.toJSONString(request);Stringsign=SignatureUtil.sign(json,partnerSecret);RequestBodybody=RequestBody.create(json,MediaType.get("application/json; charset=utf-8"));RequesthttpRequest=newRequest.Builder().url(baseUrl+"/query").post(body).addHeader("X-PARTNER-ID",partnerId).addHeader("X-SIGNATURE",sign).build();try(Responseresponse=client.newCall(httpRequest).execute()){if(response.isSuccessful()&&response.body()!=null){StringresponseBody=response.body().string();returnJSON.parseObject(responseBody,newcom.alibaba.fastjson.TypeReference<ApiResponse<String>>(){});}else{thrownewIOException("API调用失败,状态码: "+(response!=null?response.code():"null"));}}}catch(Exceptione){// 在实际项目中,这里应该集成熔断器(如Hystrix或Sentinel)System.err.println("调用异常: "+e.getMessage());ApiResponse<String>errorResponse=newApiResponse<>();errorResponse.setStatus(500);errorResponse.setMsg("服务调用异常");returnerrorResponse;}});}privateQueryCampaignRequestbuildQueryRequest(StringshopPoiId){QueryCampaignRequestreq=newQueryCampaignRequest();req.setPartnerId(partnerId);req.setTimestamp(String.valueOf(System.currentTimeMillis()/1000));req.setShopPoiId(shopPoiId);req.setPage(1);req.setPageSize(10);// Token可以基于时间戳生成req.setToken(java.util.UUID.randomUUID().toString());returnreq;}}
5. 签名工具类

确保请求的安全性。

packagecom.baodanbao.cn.util;importjava.security.MessageDigest;publicclassSignatureUtil{publicstaticStringsign(Stringcontent,Stringsecret){try{MessageDigestmd=MessageDigest.getInstance("MD5");md.update((content+secret).getBytes());byte[]digest=md.digest();StringBuildersb=newStringBuilder();for(byteb:digest){sb.append(String.format("%02x",b&0xff));}returnsb.toString().toUpperCase();}catch(Exceptione){thrownewRuntimeException("签名生成失败",e);}}}
6. 使用示例
publicclassApplication{publicstaticvoidmain(String[]args){MeituanBawangcanServiceservice=newMeituanBawangcanService();service.queryCampaignsAsync("shop_123456").whenComplete((result,throwable)->{if(throwable!=null){System.err.println("异步调用发生错误: "+throwable.getMessage());}else{System.out.println("API响应状态: "+result.getStatus());System.out.println("API响应数据: "+result.getResult());}});// 保持主线程存活以观察异步结果try{Thread.sleep(5000);}catch(InterruptedExceptione){e.printStackTrace();}}}

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

http://www.jsqmd.com/news/567549/

相关文章:

  • Windows 10下TESLA P40显卡CUDA 12.9.1环境搭建全攻略(含Ollama-GPU配置)
  • intv_ai_mk11效果实测:在中文长文本理解任务(>3000字技术文档)中摘要准确率与人工对比达92%
  • 万象视界灵坛部署案例:GPU算力优化的开源多模态感知平台
  • 技术赋能B端拓客:号码核验行业的迭代升级与价值深耕,
  • Lychee-Rerank-MM部署案例:智慧农业病虫害图-防治方案-农技知识排序
  • 告别FuLID-Flux报错:在Ubuntu 22.04 + RTX4090环境下,从源码层面搞定insightface模型加载
  • PDF.js在React中的5个高级用法:从基础渲染到性能优化
  • Hunyuan-OCR-WEBUI新手入门:手把手教你搭建OCR识别环境
  • 如何实现丝滑拖拽交互?React-Grid-Layout高级功能开发指南
  • 基于MPC的六自由度机械臂与倒立摆及二自由度机械臂协同控制策略研究
  • OpenCV+Python纹理分割避坑指南:暗斑检测的形态学参数调优技巧
  • 终极本地语音转文字方案:AnythingLLM完全离线部署指南
  • Ubuntu下Kea DHCP Server高级配置:Option 43与日志调优实战
  • 第5章 变量类型-5.7 列表
  • dropbear交叉编译移植记录
  • 通过信道优化数据传输的通信链路的实现附Matlab代码
  • 199.Vue3 + OpenLayers 实现:点击 / 拖动地图播放音频
  • 射频电路设计中的阻抗匹配原理与实践
  • 每周一个开源项目 #6:LlamaEdge 轻量本地大模型部署工具
  • 深求·墨鉴保姆级教程:从安装到使用,打造你的个人数字文房
  • 视觉感知升维:RGB+EVS 硬件融合的新基准
  • Janus-Pro-7B开发环境搭建:Ubuntu20.04系统配置全攻略
  • ”测试开发全日制学徒班7期第2天“-Linux常用命令之帮助命令
  • FUTURE POLICE语音模型Java八股文实践:设计模式在语音服务中的应用
  • 深入解析Apk安装后桌面图标缺失的CATEGORY_LAUNCHER与LEANBACK_LAUNCHER机制
  • HarmonyOS6 ArkTS ListItemGroup设置Header/Footer
  • 别再买错千元投影! 哈趣Q1Pro藏看越级体验
  • 突破Web墨卡托限制:Mapbox-gl.js v2.15.0 自定义坐标系扩展实战
  • 避坑指南:PyTorch模型保存时选torch.save还是state_dict?5个实际项目经验总结
  • 低噪声放大器设计中的常见误区与优化技巧:如何避免噪声系数飙升