使用 Spring Boot 和 Neo4j 通过 REST API 插入实体时出错

Posted

技术标签:

【中文标题】使用 Spring Boot 和 Neo4j 通过 REST API 插入实体时出错【英文标题】:Error inserting an entity through a REST API with Spring Boot and Neo4j 【发布时间】:2019-03-03 20:29:54 【问题描述】:

我正在使用 Spring Boot 测试 Neo4j,当我尝试使用 Rest API 插入元素时发现以下问题,我收到无法将 JSON 序列化为实体的错误。如果有人可以帮助我或解释如何更改我的代码或如何序列化该实体,我将非常感激。 我的课是... 用户实体

@NodeEntity
public class User extends AbstractEntity

    @Id
    @GeneratedValue
    private Long id;

    private String firstname, lastname;


    @NotNull @NotBlank @Email
    @Index(unique = true)
    private String email;

    @Index(unique = true)
    private String phone;

    @Relationship(type = "ADDRESS")
    private Set<Address> addresses = new HashSet<>();

    public User() 
    
    //get & set & const....
    

地址实体

@NodeEntity
public class Address extends AbstractEntity
    /*Update the OMG [https://neo4j.com/developer/neo4j-ogm] and remove de id.
     Keep the id in AbstractEntity*/
    @Id
    @GeneratedValue
    private Long id;

    private String street, city;

    @Relationship(type = "COUNTRY")
    private Country country;

    public Address(String street, String city, Country country) 
        this.street = street;
        this.city = city;
        this.country = country;
    

    public Address() 
    
    //get & set & const...
    

国家实体

@NodeEntity
public class Country extends AbstractEntity 
    /*Update the OMG [https://neo4j.com/developer/neo4j-ogm] and remove de id.
     Keep the id in AbstractEntity*/
    @Id
    @GeneratedValue
    private Long id;

    @Index(unique=true)
    private String code;

    private String name;

    public Country(String code, String name) 
        this.code = code;
        this.name = name;
    

    public Country() 
     
  

抽象实体

@EnableNeo4jAuditing
public abstract class AbstractEntity 

    public abstract Long getId();

    @Transient
    private SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");

    private Date created = new Date();

    public Date getCreated() 
        return created;
    

    public void setCreated(Date created) 
        this.created = created;
    

    @Override
    public boolean equals(Object obj) 

        if (this == obj) 
            return true;
        

        if (getId() == null || obj == null || !getClass().equals(obj.getClass())) 
            return false;
        
        return getId().equals(((AbstractEntity) obj).getId());

    

    @Override
    public int hashCode() 
        return getId() == null ? 0 : getId().hashCode();
    

我的商店用户的简单存储库类

public interface UserRepository extends Neo4jRepository<User, Long> 

    User findByFirstname(String name);

    @Override
    void delete(User deleted);

我的服务类

@Service
public class UserService 
     private UserRepository userRepository;
    @Autowired
    public UserService(UserRepository userRepository) 
        this.userRepository = userRepository;
    
    public Iterable<User> contact() 
        return userRepository.findAll();
    
    public User save(User user) 
            userRepository.save(user);
            return user;
    
    public User show(Long id) 
        return userRepository.findById(id).get();
    
    public User update(Long id, User user) 
        User c = userRepository.findById(id).get();
        if(user.getFirstname()!=null && !user.getFirstname().trim().isEmpty())
            c.setFirstname(user.getFirstname().trim());
        if(user.getLastname()!=null && !user.getLastname().trim().isEmpty())
            c.setLastname(user.getLastname().trim());
        if(user.getEmail()!=null && !user.getEmail().trim().isEmpty())
            c.setEmail(user.getEmail().trim());
        userRepository.save(c);
        return user;
    
    public String delete(Long id) 
        User user = userRepository.findById(id).get();
        userRepository.delete(user);

        return "";
    

我的控制器类

@RestController
public class UserController 
    @Autowired
    UserService userService;

    @RequestMapping(method = RequestMethod.GET, value = "/users")
    public Iterable<User> user() 
        return userService.contact();
    

    @RequestMapping(method = RequestMethod.POST, value = "/users")
    public String save(@RequestBody User user) 
        try 
            userService.save(user);
        catch (org.neo4j.driver.v1.exceptions.ClientException ex)
            System.err.println("******||||||||||||[   The User exist with the same email   ]||||||||||||******");
        return "The User exist with the same email";
        
        return user.toString();
    
    @RequestMapping(method=RequestMethod.GET, value="/users/id")
    public User show(@PathVariable Long id) 
        try
        return userService.show(id);
        catch (java.util.NoSuchElementException ex)
            System.err.println("******||||||||||||[   The User do not exist    ]||||||||||||******");
        
        return null;
    
    @RequestMapping(method=RequestMethod.PUT, value="/users/id")
    public User update(@PathVariable Long id, @RequestBody User user) 
        return userService.update(id, user);
    
    @RequestMapping(method=RequestMethod.DELETE, value="/users/id")
    public String delete(@PathVariable Long id) 
        return userService.delete(id);
    


这是我尝试建模的简单方案(Neo4j 是一个 NoSQL 数据库,没有大纲,但我尝试建模一个简单的应用程序) enter image description here

当它尝试测试 api rest 的方法时,它适用于我,但 Country 实体未序列化为 json。

我已经将数据插入到数据库中,我使用测试方法声明了对象并使用方法保存它。当我使用 json 格式时会出现问题。 当我运行 curl 命令测试 Rest API 时,它不返回国家/地区

$ curl -i -H "Accept: application/json" localhost:8088/users/1
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 27 Sep 2018 20:38:31 GMT

"created":"2018-09-27T19:55:21.578+0000","id":1,"firstname":"Yuniel","lastname":"Acosta Pérez","email":"yuniel.acosta@someserver.com","phone":"+999999999999","addresses":["created":"2018-09-27T19:55:21.578+0000","id":0,"street":"Some Stree","city":"Some City","country":null]

如您所见,国家将其作为空值返回,如果它存在于数据库中。

当我尝试使用 API 插入一个元素时,它感叹一个错误,我无法将国家/地区对象序列化为 JSON。

$ curl -i -X POST -H "Content-Type: application/json" -d '"firstname":"Yuniel","lastname":"Acosta Pérez","email":"yuniel.acosta@someserver.com","phone":"+999999999999","addresses":["street":"Some Stree","city":"Some City","country":["code":"OO","name":"ANYCOUNTRY"]]' localhost:8088/users

下一个错误是我犯的错误

"timestamp":"2018-09-27T21:07:56.365+0000","status":400,"error":"Bad Request","message":"JSON 解析错误:无法反序列化com.syskayzen.hypercube.domain.Address 超出 START_ARRAY 令牌;嵌套异常是 com.fasterxml.jackson.databind.exc.MismatchedInputException:无法反序列化 com.syskayzen.hypercube.domain.Address 的实例,超出 [Source: (PushbackInputStream) 处的 START_ARRAY 令牌\n;行:1,列: 122](通过引用链:com.syskayzen.hypercube.domain.User[\"addresses\"])","path":"/users"

如果您能告诉我如何解决如何序列化 Country Entity 的问题,或者是由于其他原因导致的错误。

我正在使用 Spring Boot 2.0.5 和 Spring Data Neo4j

【问题讨论】:

【参考方案1】:

我相信 Country 在您的 curl 命令中返回 null 的原因是因为查询仅在数据库中深入 1 跳。因此,它正在拉用户,然后走 1 跳以拉地址节点,但随后它停止了。要让它沿路径拉更多的跃点,您需要指定深度。

您可以通过在 curl 命令中指定深度并为“int depth”添加参数来传递存储库调用来实现此目的。这将允许您拥有动态深度,以防您向要检索的应用程序添加更多跃点。

服务方法看起来像这样......

public User show(Long id, int depth) 
        return userRepository.findById(id, depth).get();

相关文档位于以下链接:https://docs.spring.io/spring-data/neo4j/docs/5.1.0.RELEASE/reference/html/#reference:session:persisting-entities:save-depth

【讨论】:

以上是关于使用 Spring Boot 和 Neo4j 通过 REST API 插入实体时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot 和嵌入式驱动程序测试 Neo4j

spring boot 2.0 neo4j 使用

如何使用Spring Boot获取节点链(Neo4j)

hello spring boot neo4j

Neo4j Spring Boot OGM - 保存关系中的对象列表

Hello World 之Spring Boot 调用图数据库Neo4j