You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何将嵌套JSON转换为JSON对象数组?

解决方案:解析LOL英雄JSON并转存MongoDB

核心问题分析

你获取的JSON中data字段是键值对结构(英雄ID为key,英雄详情为value),而非数组,直接转数组会失败;另外ChampionsData里的image字段定义为List是错误的——原JSON中image是嵌套对象,需要单独创建类映射。


步骤1:修复ChampionsData的image字段类型

先创建Image类匹配JSON中的image结构:

package DataHandlers;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Image {
    public final String full;
    public final String sprite;
    public final String group;
    public final int x;
    public final int y;
    public final int w;
    public final int h;

    public Image(@JsonProperty("full") String full,
                 @JsonProperty("sprite") String sprite,
                 @JsonProperty("group") String group,
                 @JsonProperty("x") int x,
                 @JsonProperty("y") int y,
                 @JsonProperty("w") int w,
                 @JsonProperty("h") int h) {
        this.full = full;
        this.sprite = sprite;
        this.group = group;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }
}

然后修改ChampionsData的image字段类型:

package DataHandlers;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public class ChampionsData {
    public final String id;
    public final String name;
    public final String blurb;
    public final Image image; // 替换原List类型
    public final String title;

    public ChampionsData(@JsonProperty("id") String id,
                @JsonProperty("name") String name,
                @JsonProperty("blurb") String blurb,
                @JsonProperty("image") Image image,
                @JsonProperty("title") String title) {
        this.id = id;
        this.name = name;
        this.title = title;
        this.blurb = blurb;
        this.image = image;
    }
}

步骤2:修改ChampionsJson直接映射键值对

不用JsonNode,让Jackson自动把data映射为Map<String, ChampionsData>:

package DataHandlers;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;

@JsonIgnoreProperties(ignoreUnknown = true)
public class ChampionsJson {
    public final Map<String, ChampionsData> championsData;

    public ChampionsJson(@JsonProperty("data") Map<String, ChampionsData> championsData) {
        this.championsData = championsData;
    }
}

步骤3:提取英雄对象数组

在请求代码中直接将Map的values转为List/数组:

import DataHandlers.ChampionsJson;
import DataHandlers.ChampionsData;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

public class ChampionsDataScheduler extends Thread{
    // 复用HttpClient,线程安全无需每次新建
    private static final HttpClient client = HttpClient.newHttpClient();

    @Override
    public void run(){
        while(true){
            try {
                var request = HttpRequest.newBuilder(
                                URI.create("http://ddragon.leagueoflegends.com/cdn/13.15.1/data/en_US/champion.json"))
                        .header("accept", "application/json")
                        .build();

                var responseFuture = client.sendAsync(request, new JsonBodyHandler<>(ChampionsJson.class));
                var response = responseFuture.get();
                var championsJson = response.body().get();
                
                // 转换为你需要的ChampionsData对象数组
                List<ChampionsData> championsList = new ArrayList<>(championsJson.championsData.values());
                
                System.out.println("获取到英雄数量:" + championsList.size());
                Thread.sleep(1000);

            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace(); // 替换RuntimeException,避免线程崩溃
            }
        }
    }
}

步骤4:用Morphia存入MongoDB

给ChampionsData添加Morphia实体注解,然后批量保存:

package DataHandlers;

import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@Entity("champions") // 指定MongoDB集合名
@JsonIgnoreProperties(ignoreUnknown = true)
public class ChampionsData {
    @Id // 将id设为MongoDB主键
    public final String id;
    public final String name;
    public final String blurb;
    public final Image image;
    public final String title;

    // 构造器不变
}

保存逻辑示例:

// 假设已初始化Morphia Datastore
datastore.save(championsList); // 批量保存整个列表

更优方案建议

  1. 用调度器替代Thread.sleep:避免线程阻塞,定时任务更优雅
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ChampionsDataScheduler {
    private static final HttpClient client = HttpClient.newHttpClient();
    private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    public static void start() {
        // 延迟0秒启动,每1秒执行一次
        scheduler.scheduleAtFixedRate(() -> {
            try {
                // 放入请求、解析、存库逻辑
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 1, TimeUnit.SECONDS);
    }
}
  1. 异常处理增强:添加重试机制或日志记录,避免单次请求失败导致任务中断

内容的提问来源于stack exchange,提问作者Jhonathan Mizrahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 02:47:03