Tạo ứng dụng Java RESTful Client với thư viện OkHttp
Bài viết được sự cho phép của tác giả Giang Phan
Trong các bài viết trước chúng ta sử dụng thư viện Jersey client để gọi các RESTful API. Trong bài này, tôi sẽ giới thiệu với các bạn thư viện khác, rất mạnh mẽ để gọi các RESTful API là OkHttp.
Giới thiệu OkHttp
OkHttp là một thư viện Java mã nguồn mở, được thiết kế để trở thành một HTTP Client hiệu quả với tốc độ tải nhanh và giảm băng thông đường truyền.
Một số đặc điểm nỗi bật của OkHttp:
- Hỗ trợ Http/2 protocol.
- Connection pooling : giúp giảm độ trợ của các request.
- GZIP compression : hỗ trợ nén dữ liệu khi truyền tải.
- Cache : tránh lặp lại một request nhiều lần.
- Hỗ trợ synchronous và asynchronous.
Xem thêm nhiều việc làm Java hấp dẫn trên TopDev
OkHttp được sử dụng để gửi và nhận kết quả từ các ứng dụng Restful web service.
Một số thành phần của OkHttp:
- Request.Builder : hỗ trợ tạo request bao gồm : HTTP Method, header, cookie, media type, …
- RestClient : chịu trách nhiệm giao tiếp với REST service bao gồm gửi Request và nhận Response.
Ví dụ CRUD Restful Client với OkHttp
Tạo project
Tạo maven project và khai báo dependency sau trong file pom.xml.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion >4.0.0</ modelVersion > < groupId >com.gpcoder</ groupId > < artifactId >RestfulClientWithOkHttpExample</ artifactId > < version >0.0.1-SNAPSHOT</ version > < packaging >jar</ packaging > < name >RestfulClientWithOkHttpExample</ name > < properties > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < maven.compiler.source >1.8</ maven.compiler.source > < maven.compiler.target >1.8</ maven.compiler.target > < lombok.version >1.16.20</ lombok.version > </ properties > < dependencies > < dependency > < groupId >com.squareup.okhttp3</ groupId > < artifactId >okhttp</ artifactId > < version >3.14.2</ version > </ dependency > </ dependencies > </ project > |
Tạo CRUD Restful Client với OkHttp
Trong ví dụ này, chúng ta sẽ gọi lại các Restful API chúng ta đã tạo ở bài viết trước “JWT – Token-based Authentication trong Jersey 2.x“.
Đầu tiên, chúng ta cần gọi API /auth để lấy token và sau đó chúng ta sẽ attach token này vào mỗi request để truy cập resource.
AuthenticationClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package com.gpcoder.service; import java.io.IOException; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** * This is a first step in restful flow. We must authorize first and use the token for other request. */ public class AuthenticationClient { public static final String TOKEN = getToken(); /** * Get Json Web Token (JWT) * */ private static String getToken() { RequestBody requestBody = new FormBody.Builder() .add( "username" , "gpcoder" ) .add( "password" , "gpcoder" ) .build(); Request request = new Request.Builder() .url(AUTH_URL) .post(requestBody) .build(); OkHttpClient client = new OkHttpClient(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException( "Unexpected code: " + response); } String token = response.body().string(); System.out.println( "Token: " + token); return token; } catch (IOException e) { e.printStackTrace(); } return null ; } } |
OkHttpClientExample.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
package com.gpcoder; import java.io.IOException; import com.gpcoder.service.AuthenticationClient; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class OkHttpClientExample { public static final MediaType JSON = MediaType.parse( "application/json; charset=utf-8" ); private static OkHttpClient client; public static void main(String[] args) throws IOException { client = new OkHttpClient(); String token = AuthenticationClient.TOKEN; createOrder(token); retrieveOrder(token); updateOrder(token); deleteOrder(token); } /** */ private static void createOrder(String token) throws IOException { RequestBody requestBody = RequestBody.create(JSON, createJsonData()); Request request = new Request.Builder() .header( "Authorization" , "Bearer " + token) .url(API_URL) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "createOrder: " + result); } } /** */ private static void retrieveOrder(String token) throws IOException { HttpUrl.Builder urlBuilder = HttpUrl.parse(API_URL).newBuilder(); urlBuilder.addPathSegment( "1" ); String url = urlBuilder.build().toString(); Request request = new Request.Builder() .header( "Authorization" , "Bearer " + token) .url(url) .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "retrieveOrder: " + result); } } /** */ private static void updateOrder(String token) throws IOException { RequestBody requestBody = RequestBody.create(JSON, createJsonData()); Request request = new Request.Builder() .header( "Authorization" , "Bearer " + token) .url(API_URL) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "updateOrder: " + result); } } /** */ private static void deleteOrder(String token) throws IOException { HttpUrl.Builder urlBuilder = HttpUrl.parse(API_URL).newBuilder(); urlBuilder.addPathSegment( "1" ); String url = urlBuilder.build().toString(); Request request = new Request.Builder() .header( "Authorization" , "Bearer " + token) .url(url) .delete() .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "deleteOrder: " + result); } } private static String createJsonData() { return "{\"id\": 1, \"name\": \"gpcoder\"}" ; } } |
Sử dụng Interceptor với OkHttp
Interceptor là một tính năng rất hữu ích nó giúp chúng ta có thể chỉnh sửa request/response, retry call, monitor ứng dụng.
OkHttp hỗ trợ 2 loại Interceptor:
- Application Interceptor : loại interceptor này thường được sử dụng để thay đổi headers/query cho cả request/ response. Loại interceptor này chắc chắn được gọi 1 lần ngay cả khi nó được truy xuất từ bộ nhớ đệm (Cache).
- Network Interceptor : được sử dụng để giám sát yêu cầu giống như được truyền qua mạng. Nó rất hữu ích để theo dõi chuyển hướng (redirect) , thử lại (retry) và cung cấp quyền truy cập vào các resource của request. Loại interceptor này sẽ KHÔNG được gọi nếu nó được truy xuất từ bộ nhớ đệm (Cache).
Bây giờ chúng ta sẽ sử dụng Interceptor để tự động thêm Token vào mỗi request, chúng ta không cần thêm nó một cách thủ công trong từng request. Ví dụ bên dưới sử dụng 2 Interceptor:
- AuthInterceptor : thêm Token vào mỗi request.
- LoggingInterceptor : log trước khi gửi request và sau khi nhận response.
AuthInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package com.gpcoder.interceptor; import java.io.IOException; import com.gpcoder.service.AuthenticationClient; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; public class AuthInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { /* * chain.request() returns original request that you can work with(modify, * rewrite) */ Request originalRequest = chain.request(); // Here we can rewrite the request // We add an Authorization header if the request is not an authorize request and already had a token Request authRequest = originalRequest; if (!originalRequest.url().toString().contains( "/auth" ) && AuthenticationClient.TOKEN != null ) { authRequest = originalRequest.newBuilder() .header( "Authorization" , "Bearer " + AuthenticationClient.TOKEN) .build(); } /* * chain.proceed(request) is the call which will initiate the HTTP work. This * call invokes the request and returns the response as per the request. */ Response response = chain.proceed(authRequest); // Here we can rewrite/modify the response return response; } } |
Tương tự chúng ta sẽ tạo LoggingInterceptor
LoggingInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.gpcoder.interceptor; import java.io.IOException; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; public class LoggingInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request request = chain.request(); long t1 = System.nanoTime(); System.out.println( String.format( "Sending request %s on %s%n%s" , request.url(), chain.connection(), request.headers())); Response response = chain.proceed(request); long t2 = System.nanoTime(); System.out.println(String.format( "Received response for %s in %.1fms%n%s" , response.request().url(), (t2 - t1) / 1e6d, response.headers())); return response; } } |
Để sử dụng Interceptor, chúng ta cần đăng ký với Client thông qua phương thức addInterceptor() hoặc addNetworkInterceptor(). Chương trình bên dưới, tôi đăng ký AuthInterceptor ở mức Application và LoggingInterceptor cho cả 2 mức Application và Network.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
package com.gpcoder; import java.io.IOException; import com.gpcoder.interceptor.AuthInterceptor; import com.gpcoder.interceptor.LoggingInterceptor; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class OkHttpClientWithInterceptorExample { public static final MediaType JSON = MediaType.parse( "application/json; charset=utf-8" ); private static OkHttpClient client; public static void main(String[] args) throws IOException { client = new OkHttpClient.Builder() .addInterceptor( new LoggingInterceptor()) .addInterceptor( new AuthInterceptor()) .addNetworkInterceptor( new LoggingInterceptor()) .build(); createOrder(); retrieveOrder(); updateOrder(); deleteOrder(); } /** */ private static void createOrder() throws IOException { RequestBody requestBody = RequestBody.create(JSON, createJsonData()); Request request = new Request.Builder() .url(API_URL) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "createOrder: " + result); } } /** */ private static void retrieveOrder() throws IOException { HttpUrl.Builder urlBuilder = HttpUrl.parse(API_URL).newBuilder(); urlBuilder.addPathSegment( "1" ); String url = urlBuilder.build().toString(); Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "retrieveOrder: " + result); } } /** */ private static void updateOrder() throws IOException { RequestBody requestBody = RequestBody.create(JSON, createJsonData()); Request request = new Request.Builder() .url(API_URL) .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "updateOrder: " + result); } } /** */ private static void deleteOrder() throws IOException { HttpUrl.Builder urlBuilder = HttpUrl.parse(API_URL).newBuilder(); urlBuilder.addPathSegment( "1" ); String url = urlBuilder.build().toString(); Request request = new Request.Builder() .url(url) .delete() .build(); try (Response response = client.newCall(request).execute()) { String result = response.body().string(); System.out.println( "deleteOrder: " + result); } } private static String createJsonData() { return "{\"id\": 1, \"name\": \"gpcoder\"}" ; } } |
Chạy ứng dụng, các bạn sẽ thấy nó có cùng kết quả với ví dụ đầu tiên. Tuy nhiên, chúng ta không cần quan tâm đến token nữa. Mọi thứ đã được handle trong AuthInterceptor.
Trên đây là những thông tin cơ bản về OkHttp, ngoài ra chúng ta có thể upload, download file khi sử dụng retrofit. Trong java thường nếu xử lý trên web thì ít khi dùng đến thư viện OkHttp, thư viện này được sử dụng chủ yếu trong các ứng dụng Android để thao tác từ client đến server. Hy vọng bài viết giúp ích cho các bạn, hẹn gặp lại ở các bài viết tiếp theo.
Tài liệu tham khảo:
Bài viết gốc được đăng tải tại gpcoder.com
Có thể bạn quan tâm:
- Tạo ứng dụng Java RESTful Client với thư viện Retrofit
- Giới thiệu Feign – Tạo ứng dụng Java RESTful Client không thể đơn giản hơn
- Retrofit là gì? Những kiến thức cần nắm về Retrofit trong Android
Xem thêm tuyển dụng IT hấp dẫn trên TopDev
- T Từ khóa final trong Java
- R RxJava – Thời đại lập trình Reactive programming ứng dụng Android đã tới
- J Java roadmap cho newbie – Từ số 0 đến chuyên nghiệp
- T Top các Framework Java Backend phổ biến cho anh em Developer
- T Tìm hiểu về lớp HashMap trong Java: Các hoạt động và cách dùng
- L Lập trình Android bằng Java: Hướng dẫn toàn diện
- J Java Super là gì? Sự khác biệt giữa Java Super và Java thông thường
- K Khai báo phương thức overloading trong Java
- J Java Sleep: Kỹ thuật ngủ luồng trong lập trình Java
- S Sử dụng subString trong xử lý văn bản trong Java