我们平时开发项目的时候,即使是单体应用,也免不了要调用其他服务提供的接口。这时候就要用到HTTP客户端工具了。我之前一直在Hutool中使用HttpUtil。虽然好用,但是用起来还是蛮麻烦的!最近发现了一个比较好的HTTP客户端工具Retrofit。只需声明接口即可发起HTTP请求,无需重复连接、结果解析等操作。用起来够优雅,推荐给大家!SpringBoot实战电商项目商城(50k+star)地址:https://github.com/macrozheng/mall简介Retrofit是Android和Java的类型安全的HTTP客户端工具。它在Github上已经有39k+Star。它最大的特点是支持通过接口进行HTTP请求,类似于我们使用Feign调用微服务接口的方式。SpringBoot是目前使用最广泛的Java开发框架,但是Retrofit官方并没有提供专门的Starter。于是有兄弟开发了retrofit-spring-boot-starter,实现了Retrofit和SpringBoot框架的快速集成,并且支持很多功能增强,大大简化了开发。今天我们就使用这个第三方的Starter来操作Retrofit。在SpringBoot中使用Retrofit非常简单,下面就来体验一下。依赖集成有了第三方Starter的支持,集成Retrofit只需一步,添加如下依赖即可。com.github.lianjiatechretrofit-spring-boot-starter2.2.18依赖>基本使用下面以调用mall-tiny-swagger中的接口为例,体验一下Retrofit的基本使用。首先,我们准备一个服务,方便远程调用。我们使用之前的mall-tiny-swaggerDemo。打开Swagger可以看到有一个登录界面和一个需要登录认证的产品品牌CRUD界面。项目地址:https://github.com/macrozheng...我们先尝试调用登录接口,在application.yml中配置mall-tiny-swagger的服务地址;remote:baseUrl:http://localhost:8088/然后通过@RetrofitClient声明一个Retrofit客户端,由于是通过POST形式调用登录界面,所以这里使用了@POST和@FormUrlEncoded注解;/***定义调用远程UmsAdmin服务的Http接口*宏创建于2022/1/19。*/@RetrofitClient(baseUrl="${remote.baseUrl}")publicinterfaceUmsAdminApi{@FormUrlEncoded@POST("admin/login")CommonResultlogin(@Field("username")Stringusername,@Field("password")Stringpassword);}如果你不是很明白这些注解是干什么用的,看下表基本就能明白了。更多细节,可以参考Retrofit官方文档;接下来,将UmsAdminApi注入到Controller中,然后调用它;/***Retrofit测试界面*宏创建于2022/1/19。*/@Api(tags="RetrofitController",description="Retrofit测试接口")@RestController@RequestMapping("/retrofit")publicclassRetrofitController{@Autowired私有UmsAdminApiumsAdminApi;@AutowiredprivateTokenHoldertokenHolder;@ApiOperation(value="调用远程登录接口获取token")@PostMapping(value="/admin/login")publicCommonResultlogin(@RequestParamStringusername,@RequestParamStringpassword){CommonResultresult=umsAdminApi.login(用户名,密码);登录信息loginInfo=result.getData();if(result.getData()!=null){tokenHolder.putToken(loginInfo.getTokenHead()+""+loginInfo.getToken());}返回结果;}}为了方便后续调用需要登录认证的接口,我创建了TokenHolder类,将token存放在Session中;/***登录令牌存储(会话中)*由宏创建于2022/1/19。*/@ComponentpublicclassTokenHolder{/***添加令牌*/publicvoidputToken(Stringtoken){RequestAttributesra=RequestContextHolder.getRequestAttributes();HttpServletRequest请求=((ServletRequestAttributes)ra).getRequest();request.getSession().setAttribute("token",token);}/***获取令牌*/publicStringgetToken(){RequestAttributesra=RequestContextHolder.getRequestAttributes();HttpServletRequest请求=((ServletRequestAttributes)ra).getRequest();对象令牌=request.getSession().getAttribute("token");如果(令牌!=空){返回(字符串)令牌;}返回空值;}}Next通过Swagger测试,可以通过调用接口获取远程服务返回的token。访问地址为:http://localhost:8086/swagger...注解拦截器商品品牌管理界面需要添加登录认证header才能正常访问,我们可以使用Retrofit中的注解拦截器来实现首先创建一个继承自BasePathMatchInterceptor的注解拦截器TokenInterceptor,然后在doIntercept方法中为请求添加Authorizationheader;/***将登录令牌标头添加到请求的拦截器*由宏创建于2022/1/19。*/@ComponentpublicclassTokenInterceptorextendsBasePathMatchInterceptor{@AutowiredprivateTokenHoldertokenHolder;@OverrideprotectedResponsedoIntercept(Chainchain)抛出IOException{Requestrequest=chain.request();如果(tokenHolder.getToken()!=null){请求=请求。).header("授权",tokenHolder.getToken()).build();}返回chain.proceed(请求);}}创建一个调用品牌管理接口的客户端PmsBrandApi,使用@Intercept注解配置拦截器和拦截路径;/***定义调用远程PmsBrand服务的Http接口*宏创建于2022/1/19.*/@RetrofitClient(baseUrl="${remote.baseUrl}")@Intercept(handler=TokenInterceptor.class,include="/brand/**")publicinterfacePmsBrandApi{@GET("brand/list")CommonResult>list(@Query("pageNum")IntegerpageNum,@Query("pageSize")IntegerpageSize);@GET("brand/{id}")CommonResultdetail(@Path("id")Longid);@POST("brand/create")CommonResultcreate(@BodyPmsBrandpmsBrand);@POST("brand/update/{id}")CommonResultupdate(@Path("id")Longid,@BodyPmsBrandpmsBrand);@GET("brand/delete/{id}")CommonResultdelete(@Path("id")Longid);}在Controller中注入PmsBrandApi实例,添加调用远程服务的方法即可;/***Retrofit测试界面*宏创建于2022/1/19。*/@Api(tags="RetrofitController",description="Retrofit测试接口")@RestController@RequestMapping("/retrofit")publicclassRetrofitController{@AutowiredprivatePmsBrandApipmsBrandApi;@ApiOperation("调用远程接口分页查询品牌列表")@GetMapping(value="/brand/list")publicCommonResult>listBrand(@RequestParam(value="pageNum",defaultValue="1")@ApiParam("pagenumber")IntegerpageNum,@RequestParam(value="pageSize",defaultValue="3")@ApiParam("每页页数")IntegerpageSize){returnpmsBrandApi.list(pageNum,pageSize);}@ApiOperation("调用远程接口获取指定id的品牌详情")@GetMapping(value="/brand/{id}")publicCommonResultbrand(@PathVariable("id")Longid){返回pmsBrandApi.detail(id);}@ApiOperation("调用远程接口添加品牌")@PostMapping(value="/brand/create")publicCommonResultcreateBrand(@RequestBodyPmsBrandpmsBrand){returnpmsBrandApi.create(pmsBrand);}@ApiOperation("调用远程接口更新指定id的品牌信息")@PostMapping(value="/brand/update/{id}")publicCommonResultupdateBrand(@PathVariable("id")Longid,@RequestBodyPmsBrandpmsBrand){returnpmsBrandApi.update(id,pmsBrand);}@ApiOperation("调用远程接口删除指定id的brand")@GetMapping(value="/delete/{id}")publicCommonResultdeleteBrand(@PathVariable("id")Longid){returnpmsBrandApi.delete(id);}}在Swagger中调用接口进行测试,发现可以成功调用全局拦截器。如果你想为所有的请求添加一个请求头,你可以使用全局拦截器。创建一个SourceInterceptor类继承BaseGlobalInterceptor接口,然后在Header中添加源请求头。/***全局拦截器,将源头添加到请求*由宏创建于2022/1/19。*/@ComponentpublicclassSourceInterceptorextendsBaseGlobalInterceptor{@OverrideprotectedResponsedoIntercept(Chainchain)throwsIOException{Requestrequest=chain.要求();RequestnewReq=request.newBuilder().addHeader("source","retrofit").build();返回chain.proceed(newReq);}}配置Retrofit的配置有很多,这里说说日志打印,全局超时和全局请求重试是最常用的三个配置。日志打印在默认配置下,Retrofit使用基本的日志策略,打印的日志非常简单;我们可以修改application.yml中的retrofit.global-log-strategy属性为body打印最完整的日志;retrofit:#日志打印配置log:#启用日志打印enable:true#日志打印拦截器logging-interceptor:com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor#全局日志打印级别global-log-level:info#全局日志打印策略global-log-strategy:body修改日志打印策略后,日志信息更全面;Retrofit支持四种日志打印策略;NONE:不打印日志;BASIC:只打印日志请求记录;HEADERS:打印日志请求记录、请求和响应头信息;BODY:打印日志请求记录、请求和响应头信息、请求和响应主体信息。全局超时有时候我们需要修改Retrofit的请求超时时间,可以通过如下配置来实现。retrofit:#全局连接超时global-connect-timeout-ms:3000#全局读取超时global-read-timeout-ms:3000#全局写入超时global-write-timeout-ms:35000#全局全调用超时global-call-timeout-ms:0全局请求重试retrofit-spring-boot-starter支持请求重试,可以通过如下配置实现。retrofit:#重试配置retry:#是否开启全局重试enable-global-retry:true#全局重试间隔global-interval-ms:100#全局最大重试次数global-max-retries:2#全局重试重试规则global-retry-rules:-response_status_not_2xx-occur_exception#重试拦截器retry-interceptor:com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor重试规则global-retry-rules支持以下三种配置。RESPONSE_STATUS_NOT_2XX:响应状态码不为2xx时重试;OCCUR_IO_EXCEPTION:发生IO异常时重试;OCCUR_EXCEPTION:发生任何异常时重试。综上所述,今天经历了一次Retrofit。与使用HttpUtil相比,确实优雅多了!通过接口发起HTTP请求不再是Feign的专属,我们仍然可以通过Retrofit在单体应用中使用这种方式。当然,retrofit-spring-boot-starter提供的功能远不止于此。它还可以支持微服务之间的调用和熔断降级。感兴趣的朋友可以研究一下!参考官方文档:https://github.com/LianjiaTec...项目源码地址https://github.com/macrozheng...本文的githubhttps://github.com/macrozheng/mall-learning有已收录,欢迎大家Star!