本文简单讲解Springboot整合neo4j的过程,非常简单的demo,后续还需要更多的完善。本文将简单将demo的背景需求,安装neo4j、springboot整合和实践来说明。
软件版本:
springboot:2.3.7.release
neo4j:3.5.26
一、背景
本文做一个人与人之间的关系图谱,应用在某个领域,在此做个简单的模块。例如A的基本信息,他是被谁(B)推荐过来,以此来展现他们的关系。有几种做法,例如使用关系型数据库,然后添加个字段说明,但是如果常此以往,找更多关系时,那么面临的性能问题就相当严重。因此,有个图数据库neo4j则可以满足。
neo4j的介绍,可以到官网https://neo4j.com/ 或者中国区代理http://we-yun.com/查看,下载安装,里面的教程展现的东西正是我们想要的,在此简单说明一下。
二、安装neo4j
neo4j是一款开源的图数据库,但是也是分社区版和企业版,其中对我们简单来说,社区版是免费的,但是不支持分布式集群。本文安装了neo4j的版本是:neo4j-chs-community-3.5.26-windows。
2.1 下载地址
如果在官网下载,在国内的下载速度很慢,要做好准备,但是也可以在国内的镜像下载,即在we-yun代理商下载,也提供社区版下载,而且还提供中文文档,这对像我这样英文小白来说最合适不过了。
下载地址:http://doc.we-yun.com:1008/neo4j/3.5.26
注:如果下载4.x版本,那么jdk应该至少是11.x版本以上,而3.x还是支持jdk1.8的。
2.2 在windows10下安装
- 下载:
easy!鼠标点点,环境到手,下载eo4j-community-3.5.26-windows.zip直接解压即可。我把它放在我的D盘目录下:D:\ProgramFiles\neo4j-chs-community-3.5.26-windows。
几个目录结构:
bin:命令目录
conf: 一些配置目录,neo4j.conf,配置项视自己情况而定
data: 存放数据目录,有databases目录,存放数据库;dbms目录,有auth文件,如果忘记用户名等,暴力的话则可以直接删除auth文件即可。
plugin:存放neo4j插件的目录
-
添加系统环境变量:
添加环境变量
变量名:NEO4J_HOME
变量值:D:\ProgramFiles\neo4j-chs-community-3.5.26-windows
3.注册服务
在bin目录下(添加系统变量还没有重启),注册服务
bin\ neo4j install-service
或者卸载已经注册的服务
bin\ neo4j uninstall-service
- 启动或者查看
如果注册服务已经成功,那就可以查看状态或者启动服务
bin\ neo4j start # 启动
bin\ neo4j stop # 停止
bin\ neo4j status # 查看状态
bin\ neo4j restart
5.可以在浏览器查看
默认地址:http://localhost:7474/browser/

默认用户名:neo4j
默认密码:neo4j
登录后会让我们修改密码。
如果想测试是否安装成功,则可以根据教程运行示例,在此不做介绍。
三、Springboot整合neo4j
整合springboot,在springboot操作和调用neo4j对数据操作,新建springboot项目,项目目录结构如下:

目录说明
controller:控制器,响应前端页面请求
doc:说明文档
entity: 实体类
mapper:操作数据库、mybatis的映射文件
pojo:图相关的实体
repository:使用jpa,操作neo4j的相关操作
service:服务层
3.1 使用maven来管理
本次使用springboot版本是2.3.7.release。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
</parent>
还需添加springboot-neo4j的相关依赖包和驱动包。
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jdbc-driver</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
具体的pom文件如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jdbc-driver</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
3.2 建实体类
使用jpa自动构建实体,减少代码量,需要lombok包。具体如下:
(1)定义节点CustomerNode
在pojo包下创建,定义CustomeNode节点,节点内容包括id(自增、名字、年龄),具体如下:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
@NodeEntity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerNode {
@Id
@GeneratedValue
private Long id;
private String name;
private Integer age;
}
(2) 定义关系信息CustomerRelation
在pojo目录下,创建定义关系CustomerRelation,节点内容包括id(自增)、标记关系remark、创建关系的时间createTime,具体如下:
@RelationshipEntity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomerRelation {
@Id
@GeneratedValue
private Long id;
private Date createTime;
private String remark;
@StartNode
private CustomerNode customerFrom;
@EndNode
private CustomerNode customerTo;
public CustomerRelation(CustomerNode customerFrom,CustomerNode customerTo,String remark){
this.customerFrom=customerFrom;
this.customerTo=customerTo;
this.remark=remark;
}
}
3.3 定义Repository
主要是继承Neo4jRepository,这里简单的分为关系和节点。
关系Repository如下:
public interface CustomerRelationRepository extends Neo4jRepository<CustomerRelation,Long> {
}
节点Repository
public interface CustomerNodeRepository extends Neo4jRepository<CustomerNode,Long> {
CustomerNode findByName(String name);
CustomerNode deleteByName(String name);
/**
* 根据节点名称查找关系
* @param name
* @return
*/
@Query("MATCH c=(cf:CustomerNode)-[r:CustomerRelation]->(ct:CustomerNode) WHERE ct.name=$name OR cf.name=$name RETURN cf")
List<CustomerNode> findRelationByCustomerNode(String name);
@Query("MATCH c=(cf:CustomerNode) WHERE cf.id=$id RETURN cf")
CustomerNode findNodeById(Long id);
}
3.4定义服务层
public interface GraphService {
void deleteNodeById(Long id);
void deleteNodeByName(String name);
void delete();
void addNode(String name,Integer age,String nameTo,String remark);
void updateNode(Long id,String name,Integer age);
Iterable<CustomerNode> queryNodes();
CustomerNode findByName(String name);
List<CustomerNode> queryNodes(String name);
}
实现GraphService,
@Service
public class GraphServiceImpl implements GraphService {
@Autowired
private CustomerNodeRelationRepository customerRelationRepository;
@Autowired
private CustomerNodeRepository customerRepository;
@Override
public void deleteNodeById(Long id) {
customerRepository.deleteById(id);
}
@Override
public void deleteNodeByName(String name) {
customerRepository.deleteByName(name);
}
@Override
public void delete() {
customerRepository.deleteAll();
}
@Override
public void addNode(String name, Integer age,String nameTo,String remark) {
CustomerNode customerNode=new CustomerNode();
customerNode.setName(name);
customerNode.setAge(age);
customerRepository.save(customerNode);
CustomerNode customerNodeTo=customerRepository.findByName(nameTo);
if(customerNodeTo !=null){
CustomerRelation customerRelation=new CustomerRelation(customerNode,customerNodeTo,remark);
customerRelationRepository.save(customerRelation);
}
//此处应该返回提示信息
}
/**
* 根据ID修改节点的值
* @param id
* @param name
* @param age
*/
@Override
public void updateNode(Long id,String name, Integer age) {
CustomerNode customerNode=customerRepository.findNodeById(id);
customerNode.setName(name);
customerNode.setAge(age);
customerRepository.save(customerNode);
}
@Override
public Iterable<CustomerNode> queryNodes() {
return customerRepository.findAll();
}
@Override
public CustomerNode findByName(String name) {
return customerRepository.findByName(name);
}
@Override
public List<CustomerNode> queryNodes(String name) {
return customerRepository.findRelationByCustomerNode(name);
}
}
3.5 控制层
主要是响应前端请求。
@RestController
@RequestMapping("/account")
public class GraphController {
private static Logger logger= LoggerFactory.getLogger(GraphController.class);
@Autowired
private GraphService graphService;
/**
* 添加节点,并添加关系,正常情况下应该由文件导入,此处仅是测试
* @param name 初始节点名称
* @param age
* @param nameTo 添加有关系节点的名称
* @param remark 关系说明
*/
@PostMapping(path = "/create")
public Result addNode(
@RequestParam(name = "name",defaultValue = "node1") String name,
@RequestParam(name = "age",defaultValue = "0")Integer age,
@RequestParam(name = "nameTo",defaultValue = "node2")String nameTo,
@RequestParam(name = "remark",defaultValue = "朋友") String remark,
HttpResponse response
){
logger.info("添加节点");
graphService.addNode(name,age,nameTo,remark);
return Result.ok();
}
/**
* 删除节点
* @param id 节点ID,非必须,如果不提供,那么默认全删,否则删除相对应的id
*/
@GetMapping(path = "/delete")
public Result deleteNode(
@RequestParam(name = "id",required = false)Long id,
@RequestParam(name = "name",required = false) String name
){
if (id !=null){
graphService.deleteNodeById(id);
}else if(name !=null and id==null){
graphService.deleteNodeByName(name);
}else {
graphService.delete();
}
return Result.ok();
}
/**
* 根据节点ID,更新节点信息
* @param id
* @param name
* @param age
*/
@GetMapping(path = "/update")
public Result updateNode(
@RequestParam(name = "id",required = false) Long id,
@RequestParam(name = "name",required = false) String name,
@RequestParam(name = "age",required = false) Integer age
){
logger.info("更新数据");
graphService.updateNode(id,name,age);
return Result.ok();
}
/**
* 根据名字查找相关的所有节点
* @param name
*/
@GetMapping(path = "/find")
public Result findNode(
@RequestParam(name = "name",required = true) String name
){
logger.info("查找所有的节点"+name);
List<CustomerNode> customerNodes=graphService.queryNodes(name);
logger.info(customerNodes.size()+" 返回的数据长度");
for (CustomerNode customerNode: customerNodes) {
logger.info("节点名 "+customerNode.getName()+"与节点 "+customerNode.getAge());
}
return Result.ok(customerNodes);
}
}
3.6 配置application.yml和application-dev.yml
spring:
profiles:
active: dev
配置application-dev.yml
spring:
datasource:
username: root
password: xxx
url: jdbc:mysql://localhost:3306/japp?serverTimeZone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
data:
neo4j:
uri: bolt://localhost:7687
username: neo4j
password: xxxx
3.7效果图


