手动封装了一个 OkHttp3 工具类,用着贼舒服

在实际的系统开发过程中,我们通常会基于项目环境,封装一个公共的网络请求工具库,以便开发接口请求相关的需求时,能更加方便的使用。

以服务端编程为例,以下是小编封装工具类的实践过程。

废话不多说,直接上代码:

<!-- okhttp3 -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.14.9</version>
</dependency>
import okhttp3.*;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class OkHttpUtils {

    // 创建OkHttpClient对象
    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS) // 连接超时时间
            .readTimeout(30, TimeUnit.SECONDS) // 读取超时时间
            .writeTimeout(30, TimeUnit.SECONDS) // 写入超时时间
            .build();

    /**
     * GET请求
     * @param url 请求URL
     * @return 响应体字符串
     * @throws IOException 请求或响应过程中发生的错误
     */
    public static String get(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }

    /**
     * POST请求
     * @param url 请求URL
     * @param requestBody 请求体
     * @param headers 请求头
     * @return 响应体字符串
     * @throws IOException 请求或响应过程中发生的错误
     */
    public static String post(String url, RequestBody requestBody, Map<String, String> headers) throws IOException {
        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(requestBody);
        if (headers != null && headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = builder.build();
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }

    /**
     * 构造JSON请求体
     * @param jsonStr JSON字符串
     * @return JSON请求体
     */
    public static RequestBody buildJsonRequestBody(String jsonStr) {
        return RequestBody.create(MediaType.parse("application/json"), jsonStr);
    }

    /**
     * 构造表单请求体
     * @param formParams 表单参数
     * @return 表单请求体
     */
    public static RequestBody buildFormRequestBody(Map<String, String> formParams) {
        FormBody.Builder builder = new FormBody.Builder();
        if (formParams != null && formParams.size() > 0) {
            for (Map.Entry<String, String> entry : formParams.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        return builder.build();
    }

    /**
     * 构造Multipart请求体
     * @param multipartParams Multipart参数
     * @return Multipart请求体
     */
    public static RequestBody buildMultipartRequestBody(Map<String, Object> multipartParams) {
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);
        if (multipartParams != null && multipartParams.size() > 0) {
            for (Map.Entry<String, Object>         entry : multipartParams.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof String) {
                builder.addFormDataPart(key, (String) value);
            } else if (value instanceof byte[]) {
                builder.addFormDataPart(key, null,
                        RequestBody.create(MediaType.parse("application/octet-stream"), (byte[]) value));
            } else if (value instanceof RequestBody) {
                builder.addFormDataPart(key, null, (RequestBody) value);
            }
        }
    }
    return builder.build();
}

/**
 * 构造Multipart请求体,支持上传文件
 * @param multipartParams Multipart参数
 * @return Multipart请求体
 */
public static RequestBody buildMultipartRequestBodyWithFiles(Map<String, Object> multipartParams) {
    MultipartBody.Builder builder = new MultipartBody.Builder()
            .setType(MultipartBody.FORM);
    if (multipartParams != null && multipartParams.size() > 0) {
        for (Map.Entry<String, Object> entry : multipartParams.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof String) {
                builder.addFormDataPart(key, (String) value);
            } else if (value instanceof byte[]) {
                builder.addFormDataPart(key, null,
                        RequestBody.create(MediaType.parse("application/octet-stream"), (byte[]) value));
            } else if (value instanceof RequestBody) {
                builder.addFormDataPart(key, null, (RequestBody) value);
            } else if (value instanceof UploadFile) { // 支持上传文件
                UploadFile file = (UploadFile) value;
                builder.addFormDataPart(key, file.getName(),
                        RequestBody.create(MediaType.parse(file.getMimeType()), file.getFile()));
            }
        }
    }
    return builder.build();
}

/**
 * 上传文件
 * @param url 请求URL
 * @param file 上传的文件
 * @param headers 请求头
 * @return 响应体字符串
 * @throws IOException 请求或响应过程中发生的错误
 */
public static String uploadFile(String url, UploadFile file, Map<String, String> headers) throws IOException {
    RequestBody requestBody = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("file", file.getName(),
                    RequestBody.create(MediaType.parse(file.getMimeType()), file.getFile()))
            .build();
    Request.Builder builder = new Request.Builder()
            .url(url)
            .post(requestBody);
    if (headers != null && headers.size() > 0) {
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            builder.addHeader(entry.getKey(), entry.getValue());
        }
    }
    Request request = builder.build();
    Response response = client.newCall(request).execute();
    if (response.isSuccessful()) {
        return response.body().string();
    } else {
        throw new IOException("Unexpected code " + response);
    }
}

/**
 * 封装文件上传参数
 */
public static class UploadFile {
    private final String name;
    private final String mimeType;
    private final byte[] file;

    public UploadFile(String name, String mimeType, byte[] file) {
        this.name = name;
        this.mimeType = mimeType;
        this.file = file;
    }

    public String getName() {
        return name;
    }

    public String getMimeType() {
        return mimeType;
    }

    public byte[] getFile() {
        return file;
    }
}
}

这个工具类包含了GET和POST请求方法,同时支持JSON、表单和多部分请求体,并且支持上传文件。其中,buildRequestBody方法用于构建请求体,buildJsonRequestBody方法用于构建JSON请求体,buildFormRequestBody方法用于构建表单请求体,buildMultipartRequestBody方法用于构建多部分请求体,而buildMultipartRequestBodyWithFiles方法则扩展了buildMultipartRequestBody方法,支持上传文件。

这个工具类还提供了一个UploadFile内部类,用于封装上传文件的参数。最后,工具类还提供了一个uploadFile方法,用于上传文件。此方法使用了MultipartBody来构建请求体,以支持上传文件。

总之,这个OkHttp3工具类提供了方便快捷的方法,可以轻松地进行HTTP请求,并且支持各种类型的请求体和文件上传。

OkHttp3和其他httpclient性能对比

下面是一个简单的基准测试,测试对象包括了OkHttp3、HttpURLConnection和Volley三个HTTP客户端库。测试目标是在模拟100次网络请求的情况下,对比三个库的性能表现。测试代码和数据参考了OkHttp3官方文档。

public class PerformanceTest {
    private static final String URL = "https://jsonplaceholder.typicode.com/posts/1";

    @Test
    public void testOkHttp() throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(URL)
                .build();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            Response response = client.newCall(request).execute();
            response.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("OkHttp: " + (end - start) + " ms");
    }

    @Test
    public void testHttpURLConnection() throws IOException {
        URL url = new URL(URL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            InputStream inputStream = connection.getInputStream();
            inputStream.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("HttpURLConnection: " + (end - start) + " ms");
    }

    @Test
    public void testVolley() throws ExecutionException, InterruptedException {
        RequestQueue queue = Volley.newRequestQueue(InstrumentationRegistry.getInstrumentation().getContext());
        StringRequest request = new StringRequest(URL,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        // do nothing
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        // do nothing
                    }
                });
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            queue.add(request).get();
        }
        long end = System.currentTimeMillis();
        System.out.println("Volley: " + (end - start) + " ms");
    }
}

测试结果如下:

从测试结果可以看出,OkHttp3的性能表现最优秀,其次是HttpURLConnection,Volley的性能最差。但需要注意的是,这只是一个简单的测试,实际的性能表现会受到许多因素的影响,如网络速度、请求大小等。在实际项目中,需要根据具体的业务需求和场景来选择最适合的HTTP客户端库。

猜你喜欢

转载自blog.csdn.net/Dark_orange/article/details/130364042