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

基于前两篇的简单实战后,本篇我们继续讲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实现关系网创建和查询

 

 

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
首先,需要创建一个Spring Boot项目,并添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-neo4j</artifactId> </dependency> ``` 接下来,需要定义实体类和Repository接口。例如,我们要创建一个搜索系统,需要定义一个节点实体类`SearchNode`和一个关系实体类`SearchRelation`,并分别创建对应的Repository接口`SearchNodeRepository`和`SearchRelationRepository`。 ```java @NodeEntity public class SearchNode { @Id @GeneratedValue private Long id; @Indexed private String title; @Indexed private String content; @Relationship(type = "RELATED_TO", direction = Relationship.OUTGOING) private Set<SearchRelation> relations = new HashSet<>(); // getters and setters } @RelationshipEntity(type = "RELATED_TO") public class SearchRelation { @Id @GeneratedValue private Long id; @StartNode private SearchNode fromNode; @EndNode private SearchNode toNode; // getters and setters } public interface SearchNodeRepository extends Neo4jRepository<SearchNode, Long> { List<SearchNode> findByTitleContainingIgnoreCase(String title); } public interface SearchRelationRepository extends Neo4jRepository<SearchRelation, Long> { List<SearchRelation> findByFromNode(SearchNode fromNode); } ``` 在上述代码中,`SearchNode`和`SearchRelation`分别用`@NodeEntity`和`@RelationshipEntity`注解标记为节点关系实体类。`SearchNode`中包含了`@Relationship`注解,用于描述和`SearchRelation`的关系,其中`type`表示关系类型,`direction`表示关系方向。`SearchNodeRepository`和`SearchRelationRepository`继承自`Neo4jRepository`,可以使用Spring Data Neo4j提供的各种查询方法。 接下来,在`application.properties`文件中配置Neo4j数据库连接信息: ```properties spring.data.neo4j.uri=bolt://localhost:7687 spring.data.neo4j.username=neo4j spring.data.neo4j.password=123456 ``` 最后,可以在Controller中使用上述Repository接口来实现搜索功能,例如: ```java @RestController public class SearchController { @Autowired private SearchNodeRepository searchNodeRepository; @GetMapping("/search") public List<SearchNode> search(@RequestParam String keyword) { return searchNodeRepository.findByTitleContainingIgnoreCase(keyword); } } ``` 在上述代码中,通过`searchNodeRepository.findByTitleContainingIgnoreCase(keyword)`方法来查询包含关键词的节点信息。可以根据具体需求,使用更复杂的查询方法来实现更丰富的搜索功能。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值