<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>

<!-- 示例使用jackson的converter -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.9.0</version>
</dependency>

定義API接口

Retrofit框架中,構建與服務器的通信接口是通過定義清晰、結構化的API接口來實現的。這個過程涵蓋了詳細指定請求方式、路徑以及相關參數等關鍵信息。具體來說,每個接口方法代表了一種特定的HTTP交互模式,明確指示了請求類型(如GET、POST、PUTDELETE)和目標URL路徑。

請求方法

在接口方法上應用諸如?@GET、@POST@PUT?和@DELETE等注解是為了精確映射到相應的HTTP動作。

@POST("user/add")

@GET("user/info/{id}")

// 也可以指定查詢參數
@GET("user/list?pageSize=50")

URL操作

利用@Path@Query@Body注解能夠進一步細化接口描述,分別用于設定路徑中的動態變量、查詢字符串參數以及HTTP請求體內容。接口方法可以接受不同類型的參數,這些參數會根據注解類型被正確地插入到請求的不同部分。
使用@Path?注解的參數會在實際調用時將傳入值插入到URL路徑中相應的位置

@GET("group/{id}/users")  
Call<List<UserInfoResponse>> groupList(@Path("id") int groupId);

還可以通過@Query參數添加查詢參數。

@GET("group/{id}/users")  
Call<List<UserInfoResponse>> groupList(@Path("id") int groupId, @Query("pageSize") Integer pageSize);

對于復雜的查詢參數組合,可以使用Map

@GET("group/{id}/users")  
Call<List<UserInfoResponse>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

請求體

對于請求對象,可以使用@Body注解指定對象作為HTTP請求體。@Body注解通常用于指定將對象作為JSON格式的數據傳輸到服務器。當您在 Retrofit 接口方法中使用?@Body注解時,Retrofit將會使用內部的轉換器(如GsonConverter?或者?JacksonConverter)將對象轉換為JSON?格式的字符串,并將其作為請求的請求體發送到服務器。
通常情況下,@Body注解用于POST?或者PUT請求,其中請求的主體包含了要傳輸的對象的JSON表示形式。

@POST("users/new")  
Call<UserInfoResponse> createUser(@Body UserInfoRequest user);

通常情況下 @Body注解用于指定JSON格式的數據傳輸,但Retrofit并不會強制要求請求體的格式必須是JSON。您也可以使用其他格式的數據,例如XML或者純文本,只要在請求體中提供了正確的數據格式,并且服務器能夠正確地解析這種格式的數據。

表單數據和Multipart請求

方法還可以聲明發送表單數據和多部分請求數據
使用@FormUrlEncoded,@Field或者@FieldMap將發送表單數據。

@FormUrlEncoded
@POST("users/new")
Call<UserInfoResponse> createUser1(@Field("name") String name, @Field("passowrd") String password);

@FormUrlEncoded
@POST("users/new")
Call<UserInfoResponse> createUser2(@FieldMap Map<String, Object> paramMap);

同時他還支持發送多部分請求,例如文件上傳。在方法上使用@Multipart注解用于發送多部分請求,而參數要使用@Part注解。在Retrofit接口方法中使用@Multipart注解時,Retrofit將會使用multipart/form-data格式來發送請求,這種格式允許同時上傳文本數據和二進制文件數據。

@Multipart  
@POST("user/image")
Call<UserInfoResponse> updateUser(@Part("image") RequestBody userImage, @Part("imageDesc") RequestBody imageDesc);

@Part注解用于聲明每個部分的內容,其中可以是RequestBody類型的文本或者二進制數據,也可以是MultipartBody.Part類型的文件或者其他二進制數據。這樣的話,就可以通過多個@Part注解來聲明不同類型的部分,以滿足不同的上傳需求

Header信息

使用@Headers注解為方法設置靜態頭部。

@Headers({  
"Accept: application/json, text/plain, */*",
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"Cookie:xxxxxx"
})
@POST("users/new")
Call<UserInfoResponse> createUser(@Body UserInfoRequest user);

使用用@Header或者HeaderMap注解動態更新請求頭。必須提供相應的參數給@Header。如果值為?null,則頭部將被省略。否則,將對值調用toString,并使用結果。

@POST("users/new")  
Call<UserInfoResponse> createUser(@Header("Cookie") String cookie, @Body UserInfoRequest user);

@POST("users/new")
Call<UserInfoResponse> createUser2(@HeaderMap Map<String, String> headerMap, @Body UserInfoRequest user);

關于Header參數,我們還可以通過OkHttp的攔截器進行操作。

方法返回值

API接口方法通常返回?Call<T>?類型的對象,這里的T代表期望從服務器接收的數據類型。這種方式使得開發者能方便地利用 Retrofit 提供的回調機制或其他響應式編程庫(如RxJava)來處理網絡請求的結果,從而確保了對異步操作的良好控制和管理。

public interface MyClientService {
@POST("test/add")
Call<TestResponse> addTest(@Body TestRequest testRequest);

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
}

創建Retrofit實例

Retrofit框架的核心組件是Retrofit實例。Retrofit實例作為整個框架的心臟,不僅負責搭建網絡請求所需的基礎設施,還承擔起發起請求、轉換數據和管理響應生命周期的任務。

Retrofit retrofit = new Retrofit.Builder()
// 設置 API 的基礎 URL
.baseUrl("http://localhost:8080/coderacademy/")
.addConverterFactory(JacksonConverterFactory.create())
.build();

baseUrl設置

其中baseUrl用于指定請求服務器的根地址或者API的基礎路徑。Retrofit會自動將baseUrl和方法注解中的相對路徑結合起來生成實際請求的完整URL。例如對上述示例中:

public interface MyClientService {
@POST("test/add")
Call<TestResponse> addTest(@Body TestRequest testRequest);
}

最終的請求url為:localhost:8080/coderacademy/test/add

關于baseUrl的設置有一些注意事項:

Converter設置

Retrofit默認只能將HTTP響應主體反序列化為OkHttpResponseBody類型,并且只能接受其RequestBody類型用于@Body注解。為了支持其他類型,可以添加轉換器。

官方提供了8種轉換器:

轉換器功能使用依賴
Gson將 JSON 數據轉換為 Java 對象,以及將 Java 對象轉換為 JSON 數據。com.squareup.retrofit2:converter-gson
Jackson將JSON數據轉換為 Java 對象,以及將 Java 對象轉換為 JSON 數據。com.squareup.retrofit2:converter-jackson
Moshi將 JSON 數據轉換為 Java 對象,以及將 Java 對象轉換為 JSON 數據。com.squareup.retrofit2:converter-moshi
Protobuf將 Protocol Buffers 數據轉換為 Java 對象,以及將 Java 對象轉換為 Protocol Buffers 數據。com.squareup.retrofit2:converter-protobuf
Wire將 Wire 數據轉換為 Java 對象,以及將 Java 對象轉換為 Wire 數據。com.squareup.retrofit2:converter-wire
Simple XML將 XML 數據轉換為 Java 對象,以及將 Java 對象轉換為 XML 數據。com.squareup.retrofit2:converter-simplexml
JAXB將 XML 數據轉換為 Java 對象,以及將 Java 對象轉換為 XML 數據。com.squareup.retrofit2:converter-jaxb
Scalars將原始類型、包裝類型和字符串轉換為 RequestBody,以及將 ResponseBody 轉換為原始類型、包裝類型和字符串。com.squareup.retrofit2:converter-scalars

除了官方提供的這幾種轉換器以外,如果使用了Retrofit默認不支持的內容格式的API進行通信(例如YAML、TXT、自定義格式),或者使用不同的庫來實現現有格式(請求與響應是不同的格式),我們也可以實現自定義轉換器。

除此之外Retrofit還可以跟OkHttpClient搭配使用,實現其高級功能,通過?OkHttpClient,您可以實現諸如網絡連接池、超時設置、重試機制、攔截器等高級功能。而Retrofit則提供了簡化的API,使得使用這些高級功能變得更加方便。

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 設置連接超時時間
.readTimeout(30, TimeUnit.SECONDS) // 設置讀取超時時間
.writeTimeout(30, TimeUnit.SECONDS) // 設置寫入超時時間
.addInterceptor(new LoggingInterceptor()) // 添加日志攔截器
.build();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/coderacademy/")
.client(okHttpClient) // 設置自定義的 OkHttpClient
.addConverterFactory(GsonConverterFactory.create())
.build();

創建請求接口實例,發起請求

在創建完Retrofit實例之后,接下來就需要通過調用Retrofit實例的create()?方法來創建API接口的實例。然后就可以使用該實例調用定義在接口中的方法來發起網絡請求。

MyClientService myClientService = retrofit.create(MyClientService.class);

TestRequest testRequest = new TestRequest();
testRequest.setName("碼農Academy");
testRequest.setPassword("12131");
// 發起請求
Call<TestResponse> call = myClientService.addTest(testRequest);
try {
Response<TestResponse> response = call.execute();
System.out.println("是否請求成功:"+response.isSuccessful());
System.out.println("響應:"+ response.toString());
TestResponse testResponse = response.body();
System.out.println("請求結果:"+ testResponse.toString());
}catch (Exception e){
e.printStackTrace();
}

Retrofit中,Call對象代表了一個待執行的網絡請求。它是一個表示單個異步或同步執行的請求的對象。Call接口定義了執行網絡請求和處理響應的方法。Call接口的泛型類型參數表示了該網絡請求的響應類型。例如,Call<TestResponse> 表示該網絡請求的響應是一個TestResponse對象響應。

execute()方法用于同步執行網絡請求,并返回一個Response對象。當調用execute()方法時,請求將立即發出,當前線程將被阻塞直到請求完成并返回響應。Response對象包含了網絡請求的響應數據,可以通過調用body()方法來獲取響應主體。

另外,還可以使用Call對象來發起異步網絡請求。異步請求允許您在發出請求后繼續執行其他代碼,而不必等待網絡請求完成。當請求完成后,Retrofit將在后臺線程上調用您提供的回調方法,以處理響應數據。

Call<TestResponse> call = myClientService.addTest(testRequest);

try {
call.enqueue(new Callback<TestResponse>() {
@Override
public void onResponse(Call<TestResponse> call, Response<TestResponse> response) {
System.out.println("是否請求成功:"+response.isSuccessful());
System.out.println("響應:"+ response.toString());
TestResponse testResponse = response.body();
System.out.println("請求結果:"+ testResponse.toString());
}

@Override
public void onFailure(Call<TestResponse> call, Throwable t) {
// 請求失敗結果
}
});

}catch (Exception e){
e.printStackTrace();
}

異步請求時,需要實現Callback接口,該接口定義了處理成功和失敗響應的方法。在 onResponse方法中處理成功響應,在onFailure方法中處理失敗響應。

然后使用Call對象的enqueue()方法來執行異步網絡請求,并傳入Callback。Retrofit將在后臺線程上執行網絡請求,并在請求完成后調用相應的回調方法。

到此一個使用Retrofit2發起請求的功能就完成了。接下來我們看一下Retrofit2的一些高級功能。

Retrofit2的高級功能

攔截器

Retrofit的高級功能通常需要與OkHttpClient結合使用才能實現。OkHttpClient是一個強大的HTTP客戶端庫,Retrofit是基于它構建的,并且Retrofit默認使用 OkHttpClient作為其底層的網絡請求庫。

通過OkHttpClient,您可以實現諸如網絡連接池、超時設置、重試機制、攔截器等高級功能。而Retrofit則提供了簡化的API,使得使用這些高級功能變得更加方便。

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 設置連接超時時間
.readTimeout(30, TimeUnit.SECONDS) // 設置讀取超時時間
.writeTimeout(30, TimeUnit.SECONDS) // 設置寫入超時時間
.addInterceptor(new LoggingInterceptor()) // 添加日志攔截器
.build();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/coderacademy/")
.client(okHttpClient) // 設置自定義的 OkHttpClient
.addConverterFactory(GsonConverterFactory.create())
.build();

對于攔截器,在實際開發中有較多需要使用的場景,比如第三方服務需要使用一些簽名驗證手段,請求數據進行加密等,我們都可以統一在攔截器中進行處理。自定義攔截器,我們需要實現Interceptor接口,實現intercept()方法。

@Slf4j
public class MyAuthInterceptor implements Interceptor {

@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {

String appKey = "MyKey";
String appToken = "MyToken";

Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder.addHeader("Api-Key", appKey).addHeader("Api-Secret", appToken);
request = builder.build();
return chain.proceed(request);
}
}

傳入攔截器:

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 設置連接超時時間
.readTimeout(30, TimeUnit.SECONDS) // 設置讀取超時時間
.writeTimeout(30, TimeUnit.SECONDS) // 設置寫入超時時間
.addInterceptor(new LoggingInterceptor()) // 添加日志攔截器
.addInterceptor(new MyAuthInterceptor())
.build();

轉換器

前面內容已經提到對于轉換器,出了Retrofit2提供的8種轉換器以外,有些特別的請求體這幾種轉換器不能滿足,此時,我們可以自定義轉換器。需要繼承Converter.Factory類,重寫requestBodyConverterreponseBodyConverter方法即可。

public class CustomBodyConverterFactory extends Converter.Factory {

@Nullable
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new CustomResponseBodyConverter(type);
}

@Nullable
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new CustomRequestBodyConverter(type);
}
}

然后我們在分別實現CustomResponseBodyConverter以及CustomRequestBodyConverter,實現請求與響應不同的轉換器。

@Slf4j
public class CustomRequestBodyConverter implements Converter<CustomRequest, RequestBody> {

private final ObjectMapper objectMapper;

public CustomRequestBodyConverter() {

this.objectMapper = new ObjectMapper(new JsonFactoryBuilder().build());
this.objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
this.objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

@Nullable
@Override
public RequestBody convert(CustomRequest CustomRequest) throws IOException {
// 具體轉換邏輯
}
}

/**
*響應轉換器
*/
public class CustomResponseBodyConverter implements Converter<ResponseBody, Object> {

private final Type type;
/**
* 對象映射器
*/
private final Gson gson;

public CustomResponseBodyConverter(Type type) {
this.type = type;
GsonBuilder gsonBuilder = new GsonBuilder();
this.gson = gsonBuilder.create();
}

@Override
public Object convert(ResponseBody value) throws IOException {
// 具體處理邏輯
}
}

使用自定義轉換器

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/coderacademy/")
.client(okHttpClient) // 設置自定義的 OkHttpClient
.addConverterFactory(new CustomBodyConverterFactory())
.build();

總結

本文深入介紹了Retrofit2,這是由Square公司開源的一款面向JavaAndroid平臺的RESTful API客戶端庫?;趶姶蟮?code>OkHttp網絡庫構建,Retrofit2通過優雅的設計理念,將復雜的HTTP請求抽象為類型安全且易于理解的接口調用。

在使用Retrofit2時,開發者可以利用注解來定義API接口以及配置請求方法、URL路徑、參數等信息,大大簡化了網絡通信實現過程,提高了代碼可讀性和維護性。同時,Retrofit2內置了多種數據轉換器(如GsonConverterFactory),支持JSON以及其他格式的數據自動序列化與反序列化,極大地降低了開發成本。

Retrofit2不僅支持同步和異步兩種請求模式,還提供了豐富的擴展機制,包括自定義轉換器以適應不同數據格式,添加攔截器處理全局請求/響應邏輯,以及集成各種認證方式,滿足復雜網絡環境下的各類需求。

此外,本文還闡述了如何創建和配置Retrofit實例,給出了具體的使用示例,并深入探討了如何利用高級功能如自定義轉換器、攔截器以及進行身份驗證等,進一步展示了?Retrofit2?在實際項目中的強大靈活性和實用性。通過本文的學習,讀者將能夠更加熟練地使用Retrofit2開發出高效、可靠的網絡請求功能。

本文章轉載微信公眾號@碼農Academy

上一篇:

11 個期貨數據 API

下一篇:

SQL Server API:它是什么以及如何創建它
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費