我们平时开发项目时,就算是单体应用,也免不了要调用一下其他服务提供的接口。此时就会用到HTTP客户端工具,之前一直使用的是Hutool中的HttpUtil,虽然容易上手,但用起来颇为麻烦!最近发现一款更好用的HTTP客户端工具Retrofit,你只需声明接口就可发起HTTP请求,无需进行连接、结果解析之类的重复操作,用起来够优雅,推荐给大家!简介 Retrofit是适用于Android和Java且类型安全的HTTP客户端工具,在Github上已经有39kStar。其最大的特性的是支持通过接口的方式发起HTTP请求,类似于我们用Feign调用微服务接口的那种方式。 SpringBoot是使用最广泛的Java开发框架,但是Retrofit官方并没有提供专门的Starter。于是有位老哥就开发了retrofitspringbootstarter,它实现了Retrofit与SpringBoot框架的快速整合,并且支持了诸多功能增强,极大简化开发。今天我们将使用这个第三方Starter来操作Retrofit。 使用 在SpringBoot中使用Retrofit是非常简单的,下面我们就来体验下。依赖集成 有了第三方Starter的支持,集成Retrofit仅需一步,添加如下依赖即可。!Retrofit依赖dependencygroupIdcom。github。lianjiatechgroupIdretrofitspringbootstarterartifactIdversion2。2。18versiondependency基本使用 下面以调用malltinyswagger中的接口为例,我们来体验下Retrofit的基本使用。首先我们准备一个服务来方便远程调用,使用的是之前的malltinyswagger这个Demo,打开Swagger看下,里面有一个登录接口和需要登录认证的商品品牌CRUD接口,项目地址:https:github。commacrozhengmalllearningtreemastermalltinyswagger 我们先来调用下登录接口试试,在application。yml中配置好malltinyswagger的服务地址;remote:baseUrl:http:localhost:8088再通过RetrofitClient声明一个Retrofit客户端,由于登录接口是通过POST表单形式调用的,这里使用到了POST和FormUrlEncoded注解;定义Http接口,用于调用远程的UmsAdmin服务Createdbymacroon2022119。RetrofitClient(baseUrl{remote。baseUrl})publicinterfaceUmsAdminApi{FormUrlEncodedPOST(adminlogin)CommonResultLoginInfologin(Field(username)Stringusername,Field(password)Stringpassword);}如果你不太明白这些注解是干嘛的,看下下面的表基本就懂了,更具体的话可以参考Retrofit官方文档; 接下来在Controller中注入UmsAdminApi,然后进行调用即可;Retrofit测试接口Createdbymacroon2022119。Api(tagsRetrofitController,descriptionRetrofit测试接口)RestControllerRequestMapping(retrofit)publicclassRetrofitController{AutowiredprivateUmsAdminApiumsAdminApi;AutowiredprivateTokenHoldertokenHolder;ApiOperation(value调用远程登录接口获取token)PostMapping(valueadminlogin)publicCommonResultLoginInfologin(RequestParamStringusername,RequestParamStringpassword){CommonResultLoginInforesultumsAdminApi。login(username,password);LoginInfologinInforesult。getData();if(result。getData()!null){tokenHolder。putToken(loginInfo。getTokenHead()loginInfo。getToken());}returnresult;}}为方便后续调用需要登录认证的接口,我创建了TokenHolder这个类,把token存储到了Session中;登录token存储(在Session中)Createdbymacroon2022119。ComponentpublicclassTokenHolder{添加tokenpublicvoidputToken(Stringtoken){RequestAttributesraRequestContextHolder。getRequestAttributes();HttpServletRequestrequest((ServletRequestAttributes)ra)。getRequest();request。getSession()。setAttribute(token,token);}获取tokenpublicStringgetToken(){RequestAttributesraRequestContextHolder。getRequestAttributes();HttpServletRequestrequest((ServletRequestAttributes)ra)。getRequest();Objecttokenrequest。getSession()。getAttribute(token);if(token!null){return(String)token;}returnnull;}}接下来通过Swagger进行测试,调用接口就可以获取到远程服务返回的token了,访问地址:http:localhost:8086swaggerui 注解式拦截器 商品品牌管理接口,需要添加登录认证头才可以正常访问,我们可以使用Retrofit中的注解式拦截器来实现。首先创建一个注解式拦截器TokenInterceptor继承BasePathMatchInterceptor,然后在doIntercept方法中给请求添加Authorization头;给请求添加登录Token头的拦截器Createdbymacroon2022119。ComponentpublicclassTokenInterceptorextendsBasePathMatchInterceptor{AutowiredprivateTokenHoldertokenHolder;OverrideprotectedResponsedoIntercept(Chainchain)throwsIOException{Requestrequestchain。request();if(tokenHolder。getToken()!null){requestrequest。newBuilder()。header(Authorization,tokenHolder。getToken())。build();}returnchain。proceed(request);}}创建调用品牌管理接口的客户端PmsBrandApi,使用Intercept注解配置拦截器和拦截路径;定义Http接口,用于调用远程的PmsBrand服务Createdbymacroon2022119。RetrofitClient(baseUrl{remote。baseUrl})Intercept(handlerTokenInterceptor。class,includebrand)publicinterfacePmsBrandApi{GET(brandlist)CommonResultCommonPagePmsBrandlist(Query(pageNum)IntegerpageNum,Query(pageSize)IntegerpageSize);GET(brand{id})CommonResultPmsBranddetail(Path(id)Longid);POST(brandcreate)CommonResultcreate(BodyPmsBrandpmsBrand);POST(brandupdate{id})CommonResultupdate(Path(id)Longid,BodyPmsBrandpmsBrand);GET(branddelete{id})CommonResultdelete(Path(id)Longid);}再在Controller中注入PmsBrandApi实例,并添加方法调用远程服务即可;Retrofit测试接口Createdbymacroon2022119。Api(tagsRetrofitController,descriptionRetrofit测试接口)RestControllerRequestMapping(retrofit)publicclassRetrofitController{AutowiredprivatePmsBrandApipmsBrandApi;ApiOperation(调用远程接口分页查询品牌列表)GetMapping(valuebrandlist)publicCommonResultCommonPagePmsBrandlistBrand(RequestParam(valuepageNum,defaultValue1)ApiParam(页码)IntegerpageNum,RequestParam(valuepageSize,defaultValue3)ApiParam(每页数量)IntegerpageSize){returnpmsBrandApi。list(pageNum,pageSize);}ApiOperation(调用远程接口获取指定id的品牌详情)GetMapping(valuebrand{id})publicCommonResultPmsBrandbrand(PathVariable(id)Longid){returnpmsBrandApi。detail(id);}ApiOperation(调用远程接口添加品牌)PostMapping(valuebrandcreate)publicCommonResultcreateBrand(RequestBodyPmsBrandpmsBrand){returnpmsBrandApi。create(pmsBrand);}ApiOperation(调用远程接口更新指定id品牌信息)PostMapping(valuebrandupdate{id})publicCommonResultupdateBrand(PathVariable(id)Longid,RequestBodyPmsBrandpmsBrand){returnpmsBrandApi。update(id,pmsBrand);}ApiOperation(调用远程接口删除指定id的品牌)GetMapping(valuedelete{id})publicCommonResultdeleteBrand(PathVariable(id)Longid){returnpmsBrandApi。delete(id);}}在Swagger中调用接口进行测试,发现已经可以成功调用。 全局拦截器 如果你想给所有请求都加个请求头的话,可以使用全局拦截器。 创建SourceInterceptor类继承BaseGlobalInterceptor接口,然后在Header中添加source请求头。全局拦截器,给请求添加source头Createdbymacroon2022119。ComponentpublicclassSourceInterceptorextendsBaseGlobalInterceptor{OverrideprotectedResponsedoIntercept(Chainchain)throwsIOException{Requestrequestchain。request();RequestnewReqrequest。newBuilder()。addHeader(source,retrofit)。build();returnchain。proceed(newReq);}}配置 Retrofit的配置很多,下面我们讲讲日志打印、全局超时时间和全局请求重试这三种最常用的配置。日志打印默认配置下Retrofit使用basic日志策略,打印的日志非常简单; 我们可以将application。yml中的retrofit。globallogstrategy属性修改为body来打印最全日志;retrofit:日志打印配置log:启用日志打印enable:true日志打印拦截器logginginterceptor:com。github。lianjiatech。retrofit。spring。boot。interceptor。DefaultLoggingInterceptor全局日志打印级别globalloglevel:info全局日志打印策略globallogstrategy:body修改日志打印策略后,日志信息更全面了; Retrofit支持四种日志打印策略;NONE:不打印日志;BASIC:只打印日志请求记录;HEADERS:打印日志请求记录、请求和响应头信息;BODY:打印日志请求记录、请求和响应头信息、请求和响应体信息。全局超时时间 有时候我们需要修改一下Retrofit的请求超时时间,可以通过如下配置实现。retrofit:全局连接超时时间globalconnecttimeoutms:3000全局读取超时时间globalreadtimeoutms:3000全局写入超时时间globalwritetimeoutms:35000全局完整调用超时时间globalcalltimeoutms:0全局请求重试retrofitspringbootstarter支持请求重试,可以通过如下配置实现。retrofit:重试配置retry:是否启用全局重试enableglobalretry:true全局重试间隔时间globalintervalms:100全局最大重试次数globalmaxretries:2全局重试规则globalretryrules:responsestatusnot2xxoccurexception重试拦截器retryinterceptor:com。github。lianjiatech。retrofit。spring。boot。retry。DefaultRetryInterceptor重试规则globalretryrules支持如下三种配置。RESPONSESTATUSNOT2XX:响应状态码不是2xx时执行重试;OCCURIOEXCEPTION:发生IO异常时执行重试;OCCUREXCEPTION:发生任意异常时执行重试。总结 今天体验了一把Retrofit,对比使用HttpUtil,确实优雅不少!通过接口发起HTTP请求已不再是Feign的专属,通过Retrofit我们在单体应用中照样可以使用这种方式。当然retrofitspringbootstarter提供的功能远不止于此,它还能支持微服务间的调用和熔断降级,感兴趣的朋友可以研究下!