Spring-Boot+Neo4j☞创建多点关系网

时间:2022-09-25 18:01:53

基于前两篇的简单实战后,本篇我们继续讲Neo4j的应用,模拟公司内部员工之间的关系,当然,关系可能是上下级(管理),也可能是同级(同事),甚至也有可能是其他一些特殊的关系,比如说,互相喜欢啊...etc


本文参考地址:https://spring.io/guides/gs/accessing-data-neo4j/



一、Spring-Boot目录结构图



Spring-Boot+Neo4j☞创建多点关系网



二、先有节点(顶点)才有关系(边)



(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)



Spring-Boot+Neo4j☞创建多点关系网



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





Spring-Boot+Neo4j☞创建多点关系网




(3)Neo4j图库-- Employee员工关系图谱查询(ALL)



Spring-Boot+Neo4j☞创建多点关系网




四、查询关系(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)



Spring-Boot+Neo4j☞创建多点关系网



(3)



Spring-Boot+Neo4j☞创建多点关系网