When we develop a project, even a single application will have to call the interface provided by other services. HttpUtil from Hutool is easy to use but cumbersome to use! Retrofit is a new HTTP client that allows you to make HTTP requests by simply declaring an interface, without having to rework the connection, result parsing, and so on.
SpringBoot e-commerce project mall (50K + STAR) address: github.com/macrozheng/…
Introduction to the
Retrofit is a type-safe HTTP client tool for Android and Java, available on Github with 39K +Star. Its biggest feature is that it supports HTTP requests via interfaces, similar to the way we used Feign to invoke the microservice interface.
SpringBoot is the most widely used Java development framework, but Retrofit does not officially provide a dedicated Starter. One of my friends developed Retrofit-Spring-boot-Starter, which quickly integrates Retrofit with the SpringBoot framework and supports enhancements that greatly simplify development. Today we will use this third party Starter to operate Retrofit.
use
Using Retrofit in SpringBoot is pretty simple, so let’s try it out.
Relying on the integration
With third-party Starter support, integrating Retrofit is a one-step process by adding the following dependencies.
<! - Retrofit dependence - >
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.2.18</version>
</dependency>
Copy the code
The basic use
Let’s take a look at the basic use of Retrofit using the example of calling the interface in mall-Tiny-Swagger.
- First we prepare a service to facilitate remote invocation, using the previous one
mall-tiny-swagger
In this Demo, open Swagger and have a look. There is a login interface and CRUD interface of commodity brand that requires login authentication. The project address is:Github.com/macrozheng/…
- Let’s try calling the login interface first, in
application.yml
The configuredmall-tiny-swagger
The service address of;
remote:
baseUrl: http://localhost:8088/
Copy the code
- through
@RetrofitClient
Declare a Retrofit client, which is used here since the login interface is invoked via a POST form@POST
and@FormUrlEncoded
Annotations;
/** * Created by macro on 2022/1/19
@RetrofitClient(baseUrl = "${remote.baseUrl}")
public interface UmsAdminApi {
@FormUrlEncoded
@POST("admin/login")
CommonResult<LoginInfo> login(@Field("username") String username, @Field("password") String password);
}
Copy the code
- If you’re not sure what these notes are for, look at the table below to get a sense of what they are, and more specifically refer to Retrofit’s official documentation;
- Next inject it into the Controller
UmsAdminApi
, and then call it;
/** * Retrofit test interface * Created by macro on 2022/1/19
@API (Tags = "RetrofitController", Description = "Retrofit test interface ")
@RestController
@RequestMapping("/retrofit")
public class RetrofitController {
@Autowired
private UmsAdminApi umsAdminApi;
@Autowired
private TokenHolder tokenHolder;
@apiOperation (value = "Call remote login interface to obtain token")
@PostMapping(value = "/admin/login")
public CommonResult<LoginInfo> login(@RequestParam String username, @RequestParam String password) {
CommonResult<LoginInfo> result = umsAdminApi.login(username, password);
LoginInfo loginInfo = result.getData();
if(result.getData() ! =null) {
tokenHolder.putToken(loginInfo.getTokenHead() + "" + loginInfo.getToken());
}
returnresult; }}Copy the code
- To facilitate subsequent calls to interfaces that require login authentication, I created
TokenHolder
This class stores tokens in the Session;
/** * Created by macro on 2022/1/19. */
@Component
public class TokenHolder {
/** * Add token */
public void putToken(String token) {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
request.getSession().setAttribute("token", token);
}
/** * obtain token */
public String getToken(a) {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
Object token = request.getSession().getAttribute("token");
if(token! =null) {return (String) token;
}
return null; }}Copy the code
- Then tested through Swagger, call interface can get to the remote service returns a token, access address: http://localhost:8086/swagger-ui/
Annotated interceptors
The merchandise brand management interface, which requires a login authentication header to be accessed, can be implemented using annotated interceptors in Retrofit.
- Start by creating an annotated interceptor
TokenInterceptor
inheritanceBasePathMatchInterceptor
And then indoIntercept
Method to add to the requestAuthorization
Head;
/** * Created by macro on 2022/1/19
@Component
public class TokenInterceptor extends BasePathMatchInterceptor {
@Autowired
private TokenHolder tokenHolder;
@Override
protected Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
if(tokenHolder.getToken() ! =null) {
request = request.newBuilder()
.header("Authorization", tokenHolder.getToken())
.build();
}
returnchain.proceed(request); }}Copy the code
- Create a client that invokes the brand management interface
PmsBrandApi
, the use of@Intercept
Annotations configure interceptors and interception paths;
/** * Created by macro on 2022/1/19. */
@RetrofitClient(baseUrl = "${remote.baseUrl}")
@Intercept(handler = TokenInterceptor.class, include = "/brand/**")
public interface PmsBrandApi {
@GET("brand/list")
CommonResult<CommonPage<PmsBrand>> list(@Query("pageNum") Integer pageNum, @Query("pageSize") Integer pageSize);
@GET("brand/{id}")
CommonResult<PmsBrand> detail(@Path("id") Long id);
@POST("brand/create")
CommonResult create(@Body PmsBrand pmsBrand);
@POST("brand/update/{id}")
CommonResult update(@Path("id") Long id, @Body PmsBrand pmsBrand);
@GET("brand/delete/{id}")
CommonResult delete(@Path("id") Long id);
}
Copy the code
- Inject it into the Controller
PmsBrandApi
Instance and add methods to call the remote service;
/** * Retrofit test interface * Created by macro on 2022/1/19
@API (Tags = "RetrofitController", Description = "Retrofit test interface ")
@RestController
@RequestMapping("/retrofit")
public class RetrofitController {
@Autowired
private PmsBrandApi pmsBrandApi;
@apiOperation (" Call remote interface paging query brand list ")
@GetMapping(value = "/brand/list")
public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(value = "pageNum", defaultValue = "1")
@ ApiParam (" page ") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "3")
@apiparam (" number per page ") Integer pageSize) {
return pmsBrandApi.list(pageNum, pageSize);
}
@apiOperation (" Call remote interface to get brand details for specified ID ")
@GetMapping(value = "/brand/{id}")
public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
return pmsBrandApi.detail(id);
}
@apiOperation (" Call remote interface to add brand ")
@PostMapping(value = "/brand/create")
public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) {
return pmsBrandApi.create(pmsBrand);
}
@apiOperation (" Call remote interface to update brand information of specified ID ")
@PostMapping(value = "/brand/update/{id}")
public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrand) {
return pmsBrandApi.update(id,pmsBrand);
}
@apiOperation (" Call remote interface to delete brand with specified ID ")
@GetMapping(value = "/delete/{id}")
public CommonResult deleteBrand(@PathVariable("id") Long id) {
returnpmsBrandApi.delete(id); }}Copy the code
- Call the interface in Swagger to test and find that it can be called successfully.
Global interceptor
If you want to add a header to all requests, you can use a global interceptor.
Create the SourceInterceptor class that inherits the BaseGlobalInterceptor interface and then add the Source request Header to the Header.
* Created by macro on 2022/1/19. */
@Component
public class SourceInterceptor extends BaseGlobalInterceptor {
@Override
protected Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
Request newReq = request.newBuilder()
.addHeader("source"."retrofit")
.build();
returnchain.proceed(newReq); }}Copy the code
configuration
Retrofit has many configurations, but let’s talk about log printing, global timeout, and global request retries as the three most common configurations.
Log print
- Retrofit is used under default configuration
basic
Log policy, printing logs is very simple;
- We can put
application.yml
In theretrofit.global-log-strategy
Change the property tobody
To print the most complete log;
retrofit:
Log print configuration
log:
# Enable log printing
enable: true
# log print interceptor
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
# global log print level
global-log-level: info
# Global log printing policy
global-log-strategy: body
Copy the code
- After the log printing policy is modified, the log information is more comprehensive.
- Retrofit supports four log printing strategies;
- NONE: Logs are not printed.
- BASIC: Only log request records are printed.
- HEADERS: prints log request records, request HEADERS, and response HEADERS.
- BODY: Displays log request records, request and response headers, and request and response BODY information.
Global timeout
Sometimes we need to modify Retrofit’s request timeout through the following configuration.
retrofit:
Global connection timeout
global-connect-timeout-ms: 3000
Global read timeout
global-read-timeout-ms: 3000
# global write timeout
global-write-timeout-ms: 35000
Global complete call timeout
global-call-timeout-ms: 0
Copy the code
Global request retry
retrofit-spring-boot-starter
Request retry is supported by the following configuration.
retrofit:
Retry configuration
retry:
# Whether to enable global retry
enable-global-retry: true
Global retry interval
global-interval-ms: 100
# Maximum number of global retries
global-max-retries: 2
# global retry rule
global-retry-rules:
- response_status_not_2xx
- occur_exception
Retry interceptor
retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
Copy the code
- Retry rules
global-retry-rules
The following three configurations are supported.- RESPONSE_STATUS_NOT_2XX: Retry if the response status code is not 2XX;
- OCCUR_IO_EXCEPTION: Retry is performed when I/O exceptions occur.
- OCCUR_EXCEPTION: Retries are performed when any exception occurs.
conclusion
I tried out Retrofit today, and compared to HttpUtil, it was pretty elegant! Making HTTP requests through the interface is no longer the exclusive domain of Feign, but with Retrofit we can use it in standalone applications. Retrofit-spring-boot-starter does a lot more than that. It also supports calls between microservices and fuse downscaling.
The resources
Official documentation: github.com/LianjiaTech…
Project source code address
Github.com/macrozheng/…
In this paper, making github.com/macrozheng/… Already included, welcome everyone Star!