基于前两篇的简单实战后,本篇我们继续讲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)
五、项目GitHub地址
SpringBoot集成neo4j实现关系网创建和查询