Spring Boot调用外部API存入JPA数据库返回空值问题
问题:Spring Boot调用外部API后保存实体到MySQL,除ID外所有字段为null
在Spring Boot应用中调用OpenLibrary的API获取书籍数据,尝试将响应保存到MySQL数据库,但最终保存的Book实体除自动生成的id外,所有字段均为null。
实体类代码
public class Book { @Id @GeneratedValue( strategy = GenerationType.AUTO ) private Long id; private String bookName; private LocalDate publishYear; private Integer stock; private String ISBN; private String bib_key; private String info_url; private String preview; private String preview_url; private String thumbnail_url; }
原服务层代码
public Book getExternal(String isbn) { String uri = "https://openlibrary.org/api/books?bibkeys=ISBN:" + isbn + "&format=json"; String ISBNCode = "ISBN:" + isbn; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> externalBook = restTemplate.getForEntity(uri, String.class); JSONObject jsonObject = new JSONObject(externalBook); Book entity = new Book(); jsonObject.put(ISBNCode, entity); bookRepository.saveAndFlush(entity); return entity; }
API响应示例
{ "ISBN:1931498717": { "bib_key": "ISBN:1931498717", "info_url": "https://openlibrary.org/books/OL34424821M/Don't_Think_of_an_Elephant!", "preview": "borrow", "preview_url": "https://archive.org/details/dontthinkofeleph0000lako", "thumbnail_url": "https://covers.openlibrary.org/b/id/12039210-S.jpg" } }
保存后的实体示例
{ "id": 42, "bookName": null, "publishYear": null, "stock": null, "bib_key": null, "info_url": null, "preview": null, "preview_url": null, "thumbnail_url": null, "kind": null, "isbn": null }
解决方案
1. 修复核心逻辑错误
原代码中jsonObject.put(ISBNCode, entity)是将空的Book对象存入JSON,完全搞反了数据流向——应该是从JSON响应中提取数据赋值给Book实体,而非反过来。
2. 修正RestTemplate响应处理
直接将ResponseEntity传入JSONObject构造器是错误的,需要先获取响应体内容:externalBook.getBody()。
3. 补充实体类Getter/Setter方法
JPA和JSON数据映射都需要实体类具备对应的Getter/Setter方法,否则无法完成字段赋值。可以手动编写,也可以用Lombok的@Data注解自动生成:
import lombok.Data; import javax.persistence.*; import java.time.LocalDate; @Data @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String bookName; private LocalDate publishYear; private Integer stock; private String ISBN; private String bib_key; private String info_url; private String preview; private String preview_url; private String thumbnail_url; }
4. 正确映射API响应数据
API返回的是外层以ISBN为key的嵌套结构,需要先提取内层的书籍对象,再逐个字段赋值。推荐使用Jackson的ObjectMapper来处理JSON解析:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import java.io.IOException; public Book getExternal(String isbn) { String uri = "https://openlibrary.org/api/books?bibkeys=ISBN:" + isbn + "&format=json"; String ISBNCode = "ISBN:" + isbn; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class); ObjectMapper objectMapper = new ObjectMapper(); Book book = new Book(); book.setISBN(isbn); book.setStock(0); // 初始化库存字段 try { JsonNode rootNode = objectMapper.readTree(response.getBody()); JsonNode bookNode = rootNode.get(ISBNCode); if (bookNode != null) { book.setBib_key(bookNode.get("bib_key").asText()); book.setInfo_url(bookNode.get("info_url").asText()); book.setPreview(bookNode.get("preview").asText()); book.setPreview_url(bookNode.get("preview_url").asText()); book.setThumbnail_url(bookNode.get("thumbnail_url").asText()); } } catch (IOException e) { e.printStackTrace(); } bookRepository.saveAndFlush(book); return book; }
注意事项
当前调用的OpenLibrary API返回结果中不包含bookName和publishYear字段,如果需要这两个数据,需要额外调用书籍详情接口(比如info_url指向的页面对应的API)来获取。
内容的提问来源于stack exchange,提问作者Levent Kaya
相关产品推荐
相关产品推荐

