首页 > Java > java教程 > 正文

Java REST API:高效获取JSON数组的教程

DDD
发布: 2025-10-15 11:19:23
原创
1017人浏览过

Java REST API:高效获取JSON数组的教程

本教程详细介绍了如何在java应用程序中从rest api获取json数组。文章探讨了两种主要方法:使用低级别的httpurlconnection进行直接http请求,以及利用更现代、功能强大的retrofit和rxjava库。教程提供了完整的代码示例,并强调了json解析、pojo定义以及错误处理等关键实践,旨在帮助开发者构建健壮的api客户端。

在现代应用开发中,从RESTful API获取数据是常见的任务。很多时候,API会返回一个对象列表,即JSON数组,例如搜索结果、商品列表或用户列表。正确地解析这些JSON数组并将其映射到Java对象是构建健壮API客户端的关键。本文将深入探讨两种主流的Java实现方式:使用标准库HttpURLConnection和更高级的Retrofit结合RxJava。

1. 理解从REST API获取JSON数组的需求

当API返回的数据结构是[...]而不是{...}时,意味着我们期望接收一个JSON对象数组。例如,一个查询化妆品列表的API可能会返回如下格式:

[
   {
      "_id":"6353e8fe5d63726919402cec",
      "code":"0000016615656",
      "name":"Lipstick",
      "brand":"BrandX"
   },
   {
      "_id":"6353e8fe5d63726919402ced",
      "code":"0000016615657",
      "name":"Mascara",
      "brand":"BrandY"
   }
]
登录后复制

我们的Java应用程序需要能够识别并解析这种数组结构,将其转换为List<YourObject>的形式。

2. 准备工作:定义数据模型(POJO)

无论是哪种API客户端,首先都需要定义一个Java Plain Old Java Object (POJO) 来映射JSON数据结构。这个POJO应该包含JSON对象中的所有字段。为了更好地与JSON字段匹配,特别是当Java字段名与JSON字段名不一致时,可以使用Gson库的@SerializedName注解。

立即学习Java免费学习笔记(深入)”;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

import java.io.Serializable;

public class Cosmetic implements Serializable {
    @SerializedName("_id")
    @Expose
    private String id;
    @SerializedName("code")
    @Expose
    private String code;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("brand")
    @Expose
    private String brand;

    // 构造函数
    public Cosmetic(String id, String code, String name, String brand) {
        this.id = id;
        this.code = code;
        this.name = name;
        this.brand = brand;
    }

    // Getters and Setters
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Cosmetic{" +
               "id='" + id + '\'' +
               ", code='" + code + '\'' +
               ", name='" + name + '\'' +
               ", brand='" + brand + '\'' +
               '}';
    }
}
登录后复制

3. 方法一:使用 HttpURLConnection 获取JSON数组

HttpURLConnection是Java标准库提供的一个低级别HTTP客户端,可以直接用于发送HTTP请求和接收响应。这种方法适用于简单的请求或不希望引入额外依赖的项目。

3.1 原理概述

使用HttpURLConnection获取JSON数组的基本流程包括:

  1. 构建URL对象。
  2. 打开HttpURLConnection连接。
  3. 设置请求方法(GET)。
  4. 获取输入流并读取服务器响应。
  5. 将响应内容(JSON字符串)解析为Java对象列表。

3.2 示例代码

为了解析JSON字符串,我们将使用Gson库。请确保在pom.xml或build.gradle中添加Gson依赖:

Maven:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>
登录后复制

Gradle:

implementation 'com.google.code.gson:gson:2.10.1'
登录后复制

以下是使用HttpURLConnection获取JSON数组的示例:

Find JSON Path Online
Find JSON Path Online

Easily find JSON paths within JSON objects using our intuitive Json Path Finder

Find JSON Path Online 30
查看详情 Find JSON Path Online
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.List;

public class HttpUrlConnectionApiExample {

    private static final String API_URL = "http://your-api-base-url/prod/beauty/search"; // 替换为你的API地址

    public static List<Cosmetic> getCosmeticsArray(String queryField, String queryValue) {
        HttpURLConnection connection = null;
        BufferedReader reader = null;
        try {
            // 1. 构建URL对象,添加查询参数
            URL url = new URL(API_URL + "?" + queryField + "=" + queryValue);
            connection = (HttpURLConnection) url.openConnection();

            // 2. 设置请求方法
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Accept", "application/json"); // 告知服务器我们期望JSON响应
            connection.setConnectTimeout(5000); // 连接超时
            connection.setReadTimeout(5000);    // 读取超时

            // 3. 获取响应码
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) { // 200 OK
                // 4. 读取响应流
                reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }

                // 5. 使用Gson解析JSON数组
                Gson gson = new Gson();
                // 对于泛型类型(如List<Cosmetic>),需要使用TypeToken来获取正确的Type
                Type cosmeticListType = new TypeToken<List<Cosmetic>>() {}.getType();
                return gson.fromJson(response.toString(), cosmeticListType);

            } else {
                System.err.println("API请求失败,响应码: " + responseCode);
                // 可以读取错误流并打印
                if (connection.getErrorStream() != null) {
                    reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
                    StringBuilder errorResponse = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        errorResponse.append(line);
                    }
                    System.err.println("错误详情: " + errorResponse.toString());
                }
            }
        } catch (IOException e) {
            System.err.println("网络连接或读取数据时发生错误: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // 确保关闭资源
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
        return Collections.emptyList(); // 返回空列表表示失败或无结果
    }

    public static void main(String[] args) {
        // 假设API查询参数是 "name" 和 "Lipstick"
        List<Cosmetic> cosmetics = getCosmeticsArray("name", "Lipstick");
        if (!cosmetics.isEmpty()) {
            System.out.println("成功获取到化妆品列表:");
            for (Cosmetic cosmetic : cosmetics) {
                System.out.println(cosmetic);
            }
        } else {
            System.out.println("未获取到化妆品或请求失败。");
        }
    }
}
登录后复制

3.3 注意事项

  • 手动资源管理: 需要手动管理连接的打开、关闭以及输入/输出流的关闭。
  • 错误处理: 必须显式检查HTTP响应码并处理各种IOException。
  • 同步阻塞: HttpURLConnection默认是同步阻塞的,在主线程中直接调用会阻塞UI。在实际应用中,应将其放在单独的线程或使用ExecutorService执行。
  • 安全性: HttpURLConnection本身是安全的,但如果处理不当(例如不验证SSL证书),可能会引入安全风险。这里的"安全"更多指的是代码的健壮性和对复杂场景的处理能力。

4. 方法二:利用 Retrofit 和 RxJava 获取JSON数组

Retrofit是一个类型安全的HTTP客户端,它将REST API转换为Java接口。结合RxJava,可以实现强大的异步和响应式编程模型,极大地简化API调用和结果处理。这是现代Java和Android应用中更推荐的方式。

4.1 原理概述

使用Retrofit和RxJava获取JSON数组的流程:

  1. 定义Retrofit服务接口: 声明一个方法,其返回类型为Single<List<Cosmetic>>或Call<List<Cosmetic>>。
  2. 构建Retrofit实例: 配置baseUrl、JSON转换器(如GsonConverterFactory)和Call Adapter(如RxJava2CallAdapterFactory)。
  3. 创建服务实例: 通过Retrofit实例创建服务接口的实现。
  4. 发起API调用: 调用服务方法并订阅其返回的Single或执行Call。

4.2 依赖配置

请确保在pom.xml或build.gradle中添加以下依赖:

Maven:

<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>retrofit</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>converter-gson</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>adapter-rxjava2</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>io.reactivex.rxjava2</groupId>
    <artifactId>rxjava</artifactId>
    <version>2.2.21</version>
</dependency>
<dependency>
    <groupId>io.reactivex.rxjava2</groupId>
    <artifactId>rxandroid</artifactId>
    <version>2.1.1</version>
</dependency>
登录后复制

Gradle:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' // 如果是Android项目
登录后复制

4.3 示例代码

首先,定义Retrofit服务接口:

import io.reactivex.Single;
import java.util.List;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface CosmeticsService {
    // 获取单个Cosmetic对象的方法 (如果API支持)
    @GET("/prod/beauty/{field}")
    Single<Cosmetic> getByName(@Query("name") String name);

    // 获取Cosmetic对象数组的方法
    // 注意返回类型是 List<Cosmetic>
    @GET("/prod/beauty/search") // 假设这是获取列表的API路径
    Single<List<Cosmetic>> searchCosmetics(@Query("queryField") String queryField, @Query("queryValue") String queryValue);
}
登录后复制

然后,进行API调用:

import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers; // 仅限Android
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import java.util.List;
import java.util.concurrent.CountDownLatch; // 用于桌面应用模拟异步等待

public class RetrofitRxJavaApiExample {

    private static final String BASE_URL = "http://your-api-base-url/"; // 替换为你的API基础URL
    private Retrofit retrofit;
    private CosmeticsService service;
    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    public RetrofitRxJavaApiExample() {
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        service = retrofit.create(CosmeticsService.class);
    }

    public void fetchCosmeticsList(String queryField, String queryValue) {
        // 调用获取Cosmetic列表的方法
        Single<List<Cosmetic>> callSync = service.searchCosmetics(queryField, queryValue);

        callSync.subscribeOn(Schedulers.io()) // 在IO线程执行网络请求
                // .observeOn(AndroidSchedulers.mainThread()) // 如果是Android应用,切换到主线程更新UI
                .observeOn(Schedulers.computation()) // 对于非Android应用,可以切换到其他线程处理结果
                .onErrorReturn(throwable -> {
                    System.err.println("API请求发生错误: " + throwable.getMessage());
                    throwable.printStackTrace();
                    return Collections.emptyList(); // 错误时返回空列表
                })
                .subscribe(new SingleObserver<List<Cosmetic>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        compositeDisposable.add(d); // 管理Disposable,防止内存泄漏
                    }

                    @Override
                    public void onSuccess(List<Cosmetic> cosmetics) {
                        if (!cosmetics.isEmpty()) {
                            System.out.println("成功获取到化妆品列表:");
                            for (Cosmetic cosmetic : cosmetics) {
                                System.out.println(cosmetic);
                            }
                        } else {
                            System.out.println("未获取到化妆品或结果为空。");
                        }
                        // 如果是桌面应用,需要某种机制来通知主线程操作完成
                        // 例如使用CountDownLatch
                        // latch.countDown();
                    }

                    @Override
                    public void onError(Throwable e) {
                        System.err.println("订阅处理中发生错误: " + e.getMessage());
                        e.printStackTrace();
                        // latch.countDown(); // 同样通知完成
                    }
                });
    }

    // 在应用程序退出或组件销毁时调用,以清理资源
    public void dispose() {
        compositeDisposable.clear();
    }

    public static void main(String[] args) throws InterruptedException {
        RetrofitRxJavaApiExample apiExample = new RetrofitRxJavaApiExample();
        CountDownLatch latch = new CountDownLatch(1); // 用于模拟异步等待,在桌面应用中

        // 假设API查询参数是 "name" 和 "Lipstick"
        apiExample.fetchCosmeticsList("name", "Lipstick");

        // 在桌面应用中,主线程可能需要等待异步操作完成
        // 在Android中,通常不需要显式等待,因为UI会在回调中更新
        latch.await(10, java.util.concurrent.TimeUnit.SECONDS); // 等待最多10秒
        apiExample.dispose(); // 清理资源
    }
}
登录后复制

4.4 注意事项

  • 类型安全: Retrofit通过接口定义提供了强大的类型安全,减少了运行时错误。
  • 异步处理: RxJava提供了强大的异步编程模型,通过subscribeOn和observeOn可以轻松管理线程切换。
  • 错误处理: RxJava操作符(如onErrorReturn)使得错误处理更加优雅和链式化。
  • 资源管理: 使用CompositeDisposable管理Disposable对象,以防止内存泄漏,尤其是在Android应用中。
  • 可测试性: 接口化的设计使得API服务更易于进行单元测试和集成测试。

5. JSON解析库的选择与使用

本文示例中均使用了Google的Gson库进行JSON解析。Gson是一个功能强大且易于使用的Java库,可以将Java对象序列化为JSON,反之亦然。

  • 单个对象解析: gson.fromJson(jsonString, Cosmetic.class)
  • 对象列表解析: gson.fromJson(jsonString, new TypeToken<List<Cosmetic>>() {}.getType())

TypeToken是处理Java泛型类型擦除的关键。由于Java在运行时会擦除泛型信息,List<Cosmetic>.class无法直接获取到List中元素的具体类型。TypeToken通过匿名内部类的方式保留了泛型类型信息,使得Gson能够正确地解析JSON数组。

6. 错误处理与健壮性

无论是哪种方法,健壮的API客户端都必须妥善处理各种错误情况:

  • 网络连接错误: `IOException

以上就是Java REST API:高效获取JSON数组的教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号