基于前两篇的简单实战后,本篇我们继续讲Neo4j的应用,模拟公司内部员工之间的关系,当然,关系可能是上下级(管理),也可能是同级(同事),甚至也有可能是其他一些特殊的关系,比如说,互相喜欢啊...etc
本文参考地址:https://spring.io/guides/gs/accessing-data-neo4j/
一、Spring-Boot目录结构图
二、先有节点(顶点)才有关系(边)
(1)创建Employee(员工)节点实体--【包含两个关系】
package com.appleyk.data.nodeentity; import java.util.Collections; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.neo4j.ogm.annotation.GraphId; import org.neo4j.ogm.annotation.NodeEntity; import org.neo4j.ogm.annotation.Relationship; @NodeEntity public class Employee { @GraphId private Long id; private String name; public Employee(String name) { this.name = name; } /** * Neo4j 并没有真正的双向关系,我们只有在查询的时候忽略关系的方向 * 可以参考下面这个链接对neo4j的关系作出正确的理解: * https://dzone.com/articles/modelling-data-neo4j */ @Relationship(type = "同事", direction = Relationship.UNDIRECTED) //@Relationship(type = "同事") public Set<Employee> colleagues; @Relationship(type = "管理") public Set<Employee> manages; /* * 指定同事关系 ---> */ public void worksWith(Employee person) { if (colleagues == null) { colleagues = new HashSet<>(); } colleagues.add(person); } /* * 指定管理关系 ---> */ public void management(Employee person) { if (manages == null) { manages = new HashSet<>(); } manages.add(person); } /** * 列出该节点(Employee)的关系网 */ public String toString() { /* java8新特新 * Optional.ofNullable(arg) 参数可以是null * 如果值不为null,orElse方法返回Optional实例(关系)的值 * Collections.emptySet():防止空指针出现 * | * | * V * 当代码需要一个集合而这个集合可能不存在,此时尽量使用空集合而不是null */ return this.name + " 同事 => " + Optional.ofNullable(this.colleagues).orElse( Collections.emptySet()).stream().map( person -> person.getName()).collect(Collectors.toList()) + " 管理 => " + Optional.ofNullable(this.manages).orElse( Collections.emptySet()).stream().map( person -> person.getName()).collect(Collectors.toList()); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
(2)创建Employee增删改查接口
package com.appleyk.data.Repository; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.stereotype.Repository; import com.appleyk.data.nodeentity.Employee; @Repository public interface EmployeeRepository extends GraphRepository<Employee>{ Employee findByName(String name); }
三、Spring-Boot启动时即创建节点及节点之间的关系
(1)
package com.appleyk; import java.util.Arrays; import java.util.List; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; import com.appleyk.data.Repository.EmployeeRepository; import com.appleyk.data.nodeentity.Employee; /** * * 下面是一个典型的结构: * * com +- example +- myproject +- Application.java -- * 注意这个位置,习惯性的放在项目的一开始,也就是根包的第一层 | + - domain | +- Customer.java | +- * CustomerRepository.java | + - service | +- CustomerService.java | + - web +- * CustomerController.java * * * 文件将声明 main 方法, 还有基本的 @Configuration * * @author yukun24@126.com * @date 2017年12月1日08:46:41 */ @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan public class Application extends SpringBootServletInitializer{ /** * SpringApplication类提供了一种从main()方法启动Spring应用的便捷方式。 在很多情况下, 你只需委托给 * SpringApplication.run这个静态方法: * * @param args */ public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } /** * Spring-Boot启动的时候,加载、创建、初始化数据 * @param personRepository * @return */ @Bean CommandLineRunner demo(EmployeeRepository employeeRepository) { return args -> { //先删除Employees节点,再创建 employeeRepository.deleteAll(); Employee boss = new Employee("总裁"); Employee manager= new Employee("项目经理"); Employee p1 = new Employee("员工1"); Employee p2 = new Employee("员工2"); List<Employee> team = Arrays.asList(boss,manager,p1,p2); System.err.println("连接neo4j图库没创建关系节点之前..."); team.stream().forEach(person -> System.err.println("\t" + person.toString())); employeeRepository.save(boss); employeeRepository.save(manager); employeeRepository.save(p1); employeeRepository.save(p2); boss = employeeRepository.findByName(boss.getName()); /* * Boss管理经理(一级直属关系) */ boss.management(manager); /* * 同时 Boss和其他人是同事关系,反之亦成立 */ boss.worksWith(manager); boss.worksWith(p1); boss.worksWith(p2); //建立关系 employeeRepository.save(boss); /* * 经理管理员工1和2(直接关系) * 先查节点,再添加关系(边) */ manager = employeeRepository.findByName(manager.getName()); manager.management(p1); manager.management(p2); /* * 由于上面我们已经知道了Boss和经理是同事,反之亦然,下面只添加经理和其他人的同事关系 */ manager.worksWith(p1); manager.worksWith(p2); employeeRepository.save(manager); /* * 员工1和员工2是同事关系,此层关系不考虑方向,因此创建一个就Ok */ p1 = employeeRepository.findByName(p1.getName()); p1.worksWith(p2); employeeRepository.save(p1); System.out.println("创建关系节点之后,通过人名查找节点查询节点信息..."); team.stream().forEach(person -> System.out.println( "\t" + employeeRepository.findByName(person.getName()).toString())); }; } }
(2)启动Spring-Boot
(3)Neo4j图库-- Employee员工关系图谱查询(ALL)
四、查询关系(findByName)
(1)
package com.appleyk.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.appleyk.data.Repository.EmployeeRepository; import com.appleyk.data.nodeentity.Employee; import com.appleyk.result.ResponseMessage; import com.appleyk.result.ResponseResult; @RestController @RequestMapping("/rest/v1.0.1/database/employee") public class EmployeeController { @Autowired EmployeeRepository employeeRepository; @RequestMapping("/get") public ResponseResult GetEmployees(@RequestParam(value = "name") String name) { Employee employee = employeeRepository.findByName(name); if (employee != null) { /* * 打印下name的关系,以下关系!=null,就是一个set集合,集合未做处理! */ System.out.println(employee.getManages()); System.out.println("========上管理【" + employee.getName() + "】下同事============"); System.out.println(employee.getColleagues()); return new ResponseResult(ResponseMessage.OK); } return new ResponseResult(ResponseMessage.INTERNAL_SERVER_ERROR); } }
(2)
(3)