
如何快速實現REST API集成以優化業務流程
<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>
在Retrofit
框架中,構建與服務器的通信接口是通過定義清晰、結構化的API接口來實現的。這個過程涵蓋了詳細指定請求方式、路徑以及相關參數等關鍵信息。具體來說,每個接口方法代表了一種特定的HTTP交互模式,明確指示了請求類型(如GET
、POST
、PUT
或DELETE
)和目標URL
路徑。
請求方法
在接口方法上應用諸如?@GET
、@POST
、@PUT
?和@DELETE
等注解是為了精確映射到相應的HTTP動作。
@POST("user/add")
@GET("user/info/{id}")
// 也可以指定查詢參數
@GET("user/list?pageSize=50")
利用@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 = 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
的設置有一些注意事項:
/
結尾,否則匯報錯。http://localhost:8080/coderacademy/
, 方法url為test/add
,則最終的路徑為:localhost:8080/coderacademy/test/add
。baseUrl
中的路徑組件,只保留host部分,最終的URL
將只包含baseUrl
的主機部分和方法的路徑。如baseUrlhttp://localhost:8080/coderacademy/
, 方法url為/test/add
,則最終的路徑為:localhost:8080/test/add
。URL
,如果方法路徑是完整的URL,則會替換baseUrl
。如baseUrl為http://localhost:8080/coderacademy/
,而方法url為http://localhost:8081/coderacademy/test/add
,則最終的url為:http://localhost:8081/coderacademy/test/add
。Converter設置
Retrofit
默認只能將HTTP
響應主體反序列化為OkHttp
的ResponseBody
類型,并且只能接受其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
的一些高級功能。
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
類,重寫requestBodyConverter
與reponseBodyConverter
方法即可。
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
公司開源的一款面向Java
和Android
平臺的RESTful API
客戶端庫?;趶姶蟮?code>OkHttp網絡庫構建,Retrofit2
通過優雅的設計理念,將復雜的HTTP
請求抽象為類型安全且易于理解的接口調用。
在使用Retrofit2
時,開發者可以利用注解來定義API
接口以及配置請求方法、URL
路徑、參數等信息,大大簡化了網絡通信實現過程,提高了代碼可讀性和維護性。同時,Retrofit2
內置了多種數據轉換器(如GsonConverterFactory
),支持JSON
以及其他格式的數據自動序列化與反序列化,極大地降低了開發成本。
Retrofit2
不僅支持同步和異步兩種請求模式,還提供了豐富的擴展機制,包括自定義轉換器以適應不同數據格式,添加攔截器處理全局請求/響應邏輯,以及集成各種認證方式,滿足復雜網絡環境下的各類需求。
此外,本文還闡述了如何創建和配置Retrofit
實例,給出了具體的使用示例,并深入探討了如何利用高級功能如自定義轉換器、攔截器以及進行身份驗證等,進一步展示了?Retrofit2
?在實際項目中的強大靈活性和實用性。通過本文的學習,讀者將能夠更加熟練地使用Retrofit2
開發出高效、可靠的網絡請求功能。
本文章轉載微信公眾號@碼農Academy