Springboot整合neo4j

  本文简单讲解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下安装

  1. 下载:
     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插件的目录
  1. 添加系统环境变量:


    添加环境变量
变量名:NEO4J_HOME
变量值:D:\ProgramFiles\neo4j-chs-community-3.5.26-windows

3.注册服务
在bin目录下(添加系统变量还没有重启),注册服务

bin\ neo4j install-service

或者卸载已经注册的服务

bin\ neo4j uninstall-service
  1. 启动或者查看
    如果注册服务已经成功,那就可以查看状态或者启动服务
bin\  neo4j start  # 启动
bin\  neo4j stop # 停止
bin\  neo4j status # 查看状态
bin\  neo4j restart

5.可以在浏览器查看
默认地址:http://localhost:7474/browser/

neo4j登录界面

默认用户名: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效果图

添加截图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容