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

如何在foreach循环中填充List并生成可导入MySQL的JSON文件?

将POJO转换为JSON文件导入MySQL的问题与解决方案

问题描述

我尝试把抓取到的HackerNews数据封装成POJO,通过Jackson转成JSON文件后导入MySQL,遇到两个问题:

  1. 用mapper.writeValue(Paths.get("hackernewsitem2.json").toFile(), fullList.add(hnItem))时,控制台能输出正确的JSON字符串,JSON文件也生成了,但MySQL Workbench报错unhandled exception: object of type bool() has no length.,且文件里只有一行"true"。
  2. 用mapper.writeValue(Paths.get("hackernewsitem.json").toFile(), hnItem)时,文件能正常导入但数据库无数据,且文件仅保留最后一行内容。

抓取与序列化代码

try {
        //HtmlPage object contains the html code
        HtmlPage page = client.getPage(baseUrl);
        //System.out.println(page.asXml());

        //Selecting nodes with xpath
        List<HtmlElement> itemList = page.getByXPath("//tr[@class='athing']");

        List<HackerNewsItem> fullList = new ArrayList<>();

        if(itemList.isEmpty()) {
            System.out.println("No item found");
        }else {
            for(HtmlElement htmlItem : itemList){
                int position = Integer.parseInt(((HtmlElement) htmlItem.getFirstByXPath("./td/span")).asText().replace(".", ""));
                int id = Integer.parseInt(htmlItem.getAttribute("id"));
                String title =  ((HtmlElement) htmlItem.getFirstByXPath("./td[not(@valign='top')][@class='title']")).asText();
                String url = ((HtmlAnchor) htmlItem.getFirstByXPath("./td[not(@valign='top')][@class='title']/a")).getHrefAttribute();
                String author =  ((HtmlElement) htmlItem.getFirstByXPath("./following-sibling::tr/td[@class='subtext']/a[@class='hnuser']")).asText();
                int score = Integer.parseInt(((HtmlElement) htmlItem.getFirstByXPath("./following-sibling::tr/td[@class='subtext']/span[@class='score']")).asText().replace(" points", ""));

                HackerNewsItem hnItem = new HackerNewsItem(title, url, author, score, position, id);

                ObjectMapper mapper = new ObjectMapper();

                String jsonString = mapper.writeValueAsString(hnItem) ;


                System.out.println(jsonString);
                mapper.writeValue(Paths.get("hackernewsitem2.json").toFile(), fullList.add(hnItem));

            }
          
        }

    }catch (Exception e) {
        e.printStackTrace();
    }

POJO代码

@Getter@Setter@AllArgsConstructor
public class HackerNewsItem {

    @JsonProperty("item_title")
    private String title;

    @JsonProperty("item_url")
    private String url;

    @JsonProperty("item_author")
    private String author;

    @JsonProperty("item_score")
    private int score;

    @JsonProperty("item_position")
    private int position;

    @JsonProperty("item_id")
    private int id;

}

问题分析与解决方案

问题1根源

fullList.add(hnItem)的返回值是布尔值(添加成功返回true),Jackson会直接把这个布尔值序列化为字符串"true",导致生成的JSON文件完全不符合MySQL的解析要求。

问题2根源

每次循环调用writeValue写入单个hnItem时,会覆盖之前的文件内容,最终文件只保留最后一个对象。同时,单个JSON对象可能不符合MySQL导入时对JSON数组的格式要求,导致导入后无数据。

修改后的代码

try {
    HtmlPage page = client.getPage(baseUrl);
    List<HtmlElement> itemList = page.getByXPath("//tr[@class='athing']");
    List<HackerNewsItem> fullList = new ArrayList<>();
    // 将ObjectMapper实例化移到循环外,避免重复创建
    ObjectMapper mapper = new ObjectMapper();

    if(itemList.isEmpty()) {
        System.out.println("No item found");
    } else {
        for(HtmlElement htmlItem : itemList){
            // 数据解析逻辑保持不变
            int position = Integer.parseInt(((HtmlElement) htmlItem.getFirstByXPath("./td/span")).asText().replace(".", ""));
            int id = Integer.parseInt(htmlItem.getAttribute("id"));
            String title =  ((HtmlElement) htmlItem.getFirstByXPath("./td[not(@valign='top')][@class='title']")).asText();
            String url = ((HtmlAnchor) htmlItem.getFirstByXPath("./td[not(@valign='top')][@class='title']/a")).getHrefAttribute();
            String author =  ((HtmlElement) htmlItem.getFirstByXPath("./following-sibling::tr/td[@class='subtext']/a[@class='hnuser']")).asText();
            int score = Integer.parseInt(((HtmlElement) htmlItem.getFirstByXPath("./following-sibling::tr/td[@class='subtext']/span[@class='score']")).asText().replace(" points", ""));

            HackerNewsItem hnItem = new HackerNewsItem(title, url, author, score, position, id);
            String jsonString = mapper.writeValueAsString(hnItem);
            System.out.println(jsonString);
            // 仅将对象添加到列表,不在这里写入文件
            fullList.add(hnItem);
        }
        // 循环结束后,一次性将整个列表写入文件,生成JSON数组
        mapper.writeValue(Paths.get("hackernewsitem2.json").toFile(), fullList);
    }
} catch (Exception e) {
    e.printStackTrace();
}

关键修改点

  1. 复用ObjectMapper:把ObjectMapper的创建移到循环外部,避免每次循环重复实例化,提升性能。
  2. 正确写入列表:循环内只执行fullList.add(hnItem),循环结束后再将整个列表传入writeValue,生成标准的JSON数组格式。
  3. 避免文件覆盖:一次性写入所有数据,不会覆盖之前的内容,确保文件包含所有抓取到的条目。

导入注意事项

确保MySQL导入时:

  • 选择正确的JSON文件格式(JSON数组)。
  • 数据库列名与POJO中@JsonProperty指定的字段名对应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 13:54:22