如何在foreach循环中填充List并生成可导入MySQL的JSON文件?
将POJO转换为JSON文件导入MySQL的问题与解决方案
问题描述
我尝试把抓取到的HackerNews数据封装成POJO,通过Jackson转成JSON文件后导入MySQL,遇到两个问题:
- 用
mapper.writeValue(Paths.get("hackernewsitem2.json").toFile(), fullList.add(hnItem))时,控制台能输出正确的JSON字符串,JSON文件也生成了,但MySQL Workbench报错unhandled exception: object of type bool() has no length.,且文件里只有一行"true"。 - 用
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(); }
关键修改点
- 复用ObjectMapper:把
ObjectMapper的创建移到循环外部,避免每次循环重复实例化,提升性能。 - 正确写入列表:循环内只执行
fullList.add(hnItem),循环结束后再将整个列表传入writeValue,生成标准的JSON数组格式。 - 避免文件覆盖:一次性写入所有数据,不会覆盖之前的内容,确保文件包含所有抓取到的条目。
导入注意事项
确保MySQL导入时:
- 选择正确的JSON文件格式(JSON数组)。
- 数据库列名与POJO中
@JsonProperty指定的字段名对应。
内容的提问来源于stack exchange,提问作者FacundoGB
相关产品推荐
相关产品推荐

