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); // 批量保存整个列表
更优方案建议
- 用调度器替代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); } }
- 异常处理增强:添加重试机制或日志记录,避免单次请求失败导致任务中断
内容的提问来源于stack exchange,提问作者Jhonathan Mizrahi
相关产品推荐
相关产品推荐

