SpringBoot该怎么使用Neo4j - 优化篇

文章目录

  • 前言
  • 实体工具
  • 使用

前言

上一篇中,我们的Cypher都用的是字符串,字符串拼接简单,但存在写错的风险,对于一些比较懒的开发者,甚至觉得之间写字符串还更自在快速,也确实,但如果在后期需要修改,如更高字段名或者一些级联的变动,会导致维护难,所以,这里这里我们模仿Mybatis-Plus写一个实体字段工具之间替换哪些字符串,以提高项目可维护性。

实体工具

我们以这篇的工具为基础进行下面的开发:Lambda表达式提取字段名-CSDN博客

然后我们再增加对于与Neo4j的实体工具:

  1. 实体缓存对象信息,保存实体必要信息

    public class EntityCache {private String className;private List<String> labels;private Map<String, String> fieldNameMap;public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public List<String> getLabels() {return labels;}public void setLabels(List<String> labels) {this.labels = labels;}public Map<String, String> getFieldNameMap() {return fieldNameMap;}public void setFieldNameMap(Map<String, String> fieldNameMap) {this.fieldNameMap = fieldNameMap;}
    }
  2. 解析工具,也就是反射解析

    public class EntityUtil {/*** 实体缓存*/private static final Map<String, EntityCache> ENTITY_MAP = new ConcurrentHashMap<>();public static void main(String[] args) {Job job = new Job();String column = column(Job::getName);System.out.println(column);System.out.println(label(Job.class));}/*** 从lambda转换出字段名*/public static <T, R> String column(CusFunction<T, R> column) {SerializedLambda resolve = LambdaUtils.resolve(column);return getColumn(LambdaUtils.getClass(resolve), LambdaUtils.getMethodName(resolve) , true);}/*** 从实体class解析出标签*/public static <T> String label(Class<T> clazz) {EntityCache info = ENTITY_MAP.putIfAbsent(clazz.getTypeName(), resolve(clazz));return info.getLabels().get(0);}/*** 根据类型和方法名解析字段名* @param aClass 类型* @param methodName 方法名* @param dbField 是否数据库字段* @return 字段名*/private static String getColumn(Class<?> aClass, String methodName, boolean dbField) {String fieldName = PropertyNamer.methodToProperty(methodName);if (!dbField) {return fieldName;}EntityCache info = resolve(aClass);if (!StringUtils.hasLength(fieldName)) {throw new RuntimeException(String.format("找不到实体对应的字段-[%s.%s]", aClass.getTypeName(), methodName));}Map<String, String> map = info.getFieldNameMap();return map.get(fieldName);}/*** 解析实体* @param clazz 类型* @return 实体缓存对象*/public static <T> EntityCache resolve(Class<T> clazz) {String typeName = clazz.getTypeName();EntityCache info = ENTITY_MAP.get(typeName);if (info != null) {return info;}Field[] declaredFields = clazz.getDeclaredFields();Map<String, String> fieldNameMap = new HashMap<>();for (Field declaredField : declaredFields) {declaredField.setAccessible(true);String fieldName = declaredField.getName();String dbFieldName = fieldName;Property property = declaredField.getAnnotation(Property.class);if (property != null) {if (StringUtils.hasLength(property.name())) {dbFieldName = property.name();}if (StringUtils.hasLength(property.value())) {dbFieldName = property.value();}}fieldNameMap.put(fieldName, dbFieldName);}List<String> labelList = resolveLabel(clazz);info = new EntityCache();info.setLabels(labelList);info.setClassName(typeName);info.setFieldNameMap(fieldNameMap);ENTITY_MAP.put(typeName, info);return info;}/*** 解析标签* @param clazz 类型* @return 标签列表*/private static <T> List<String> resolveLabel(Class<T> clazz) {Node node = clazz.getAnnotation(Node.class);if (node == null) {throw new RuntimeException("非数据库实体对象实体!");}String[] value = node.value();String[] labels = node.labels();List<String> result = new ArrayList<>();result.addAll(Arrays.asList(value));result.addAll(Arrays.asList(labels));if (result.isEmpty()) {result.add(clazz.getSimpleName());}return result;}
    }
  3. 测试:

        @Testpublic void testEntity() {String column = EntityUtil.column(Job::getName);EntityUtil.label(Job.class);String column1 = EntityUtil.column(Job::getJobName);System.out.println(column +"  " + column1);}
    

使用

实际开发中,就可以将字符串进行替换,如下面:

查询标签Jobname='liry',并通过id顺序排序,取第一个的cypher构建

// match(a:Job) where a.name='liry' return a order by a.id  limit 1Node temp = Cypher.node("Job").named("a");
ResultStatement statement = Cypher.match(temp).where(temp.property("name").isEqualTo(Cypher.anonParameter(job.getName()))).returning(temp.getRequiredSymbolicName()).orderBy(temp.property("id")).limit(1).build();

进行替换

// match(a:Job) where a.name='liry' return a order by a.id  limit 1// 字符串 Job  -> EntityUtil.label(Job.class)
// 字符串 name -> EntityUtil.column(Job::getName)
// 字符串 id -> EntityUtil.column(Job::getId)
Node temp = Cypher.node(EntityUtil.label(Job.class)).named("a");
ResultStatement statement = Cypher.match(temp).where(temp.property(EntityUtil.column(Job::getName)).isEqualTo(Cypher.anonParameter(job.getName()))).returning(temp.getRequiredSymbolicName()).orderBy(temp.property(EntityUtil.column(Job::getId))).limit(1).build();

创建一个节点:

create (a:Job{name:'liry',jobName:'liry-job'}) return a;          

可以看到调试中构建的Cypher是正确的。

image-20241204181636501

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/484699.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何用AI生成胶片风格的场景图 - 实用教程

如何用AI生成胶片风格的场景图 - 实用教程 在这个教程中,我们将介绍如何使用Recraft AI生成复古胶片风格的场景图。通过简单的步骤,你就能创建出独特的复古风格图片。 成功案例展示 小红书爆火作品 11月22日,小红书博主"四月崔aprilchui"发布胶片风格的场景图…

在M3上面搭建一套lnmp环境

下载docker-desktop 官网下载docker-desktop 切换镜像源 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://docke…

思特奇亮相2024数字科技生态大会,以“智”谋新共赢AI新时代

12月3-5日,2024数字科技生态大会在广州琶洲广交会展馆D区盛大举行。大会以“AI赋能 共筑数字新生态”为主题,汇聚行业领军企业、创新型科技公司以及众多专家学者,共探数字经济时代未来发展新机遇。 作为中国电信长期重要的生态伙伴,思特奇受邀参会并亮相18.2号馆天翼AI展区,重点…

【全网最新】若依管理系统基于SpringBoot的前后端分离版本开发环境配置

目录 提前准备&#xff1a; 下载源代码 设置依赖 设置后台连接信息 运行后台 运行前端 安装npm依赖 启动前端 登录网页客户端 提前准备&#xff1a; 1、安装mysql 5以上就可以。 2、安装redis. 3、安装npm npm下载地址&#xff1a;https://nodejs.org/dist/v22.12…

远程游戏新体验!

在这个数字化的时代&#xff0c;游戏已经不仅限于家里的电视或书房的电脑了。远程游戏&#xff0c;也就是通过远程控制软件在不同地点操作游戏设备&#xff0c;给玩家带来了前所未有的自由和灵活性。RayLink远程控制软件&#xff0c;凭借其出色的性能和专为游戏设计的功能&…

【人工智能】Transformers之Pipeline(二十八):视觉问答(visual-question-answering)

​​​​​​​ 目录 一、引言 二、视觉问答&#xff08;visual-question-answering&#xff09; 2.1 概述 2.2 dandelin/ViLT 2.3 pipeline参数 2.3.1 pipeline对象实例化参数 2.3.2 pipeline对象使用参数 2.3.3 pipeline对象返回参数 2.4 pipeline实战 2.5 模型…

qt QPrinter详解

1、概述 QPrinter类是Qt框架中用于打印输出的绘图设备。它表示打印出来的一系列页面&#xff0c;并提供了一组附加功能来管理特定于设备的特性&#xff0c;比如方向和分辨率。QPrinter可以生成PDF文档&#xff0c;也可以将内容发送到打印机进行实际打印。它继承自QPagedPaintD…

AI开发: 知识图谱的初识,学会制作知识图谱- Python 机器学习

一、知识图谱的概念 知识图谱是一个通过图结构来表示和组织知识的工具&#xff0c;它将事物、概念和它们之间的关系以图的形式呈现出来&#xff0c;图中的节点代表实体&#xff08;比如人物、地点、事件等&#xff09;&#xff0c;而边代表这些实体之间的各种关系&#xff08;…

移动端登录注册界面样式,简洁切换

非常简洁的登录、注册界面模板&#xff0c;使用uni-app编写&#xff0c;直接复制粘贴即可&#xff0c;无任何引用&#xff0c;全部公开。 废话不多说&#xff0c;代码如下&#xff1a; login.vue文件 <template><view class"content"><view class&quo…

RTMP如何实现毫秒级延迟体验?

技术背景 在我们大多数音视频行业从业者的认知里&#xff0c;RTMP播放器的延迟通常可以做到2到3秒。实际上&#xff0c;在较为理想的网络环境和优化良好的系统设置下&#xff0c;RTMP播放器一样可以做到几百毫秒的延迟水平。今天就影响RTMP播放延迟的一些因素&#xff0c;做个…

Oracle数据库 用户管理模式下的冷备份与热备份

1. 用户管理模式下的冷备份 1.1. 通过数据库相关视图查询 查实例 select instance_name,version,status,archiver,database_status from v$instance; 查数据库 select dbid,name,log_mode from v$database; 查数据文件状态 select file_name,tablespace_name,status,o…

【k8s 深入学习之 event 聚合】event count累记聚合(采用 Patch),Message 聚合形成聚合 event(采用Create)

参考 15.深入k8s:Event事件处理及其源码分析 - luozhiyun - 博客园event 模块总览 EventRecorder:是事件生成者,k8s组件通过调用它的方法来生成事件;EventBroadcaster:事件广播器,负责消费EventRecorder产生的事件,然后分发给broadcasterWatcher;broadcasterWatcher:用…

浙江工业大学《2024年828自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《浙江工业大学828自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2024年真题 Part1&#xff1a;2024年完整版真题 2024年真题

AI开发:用模型来识别手写数字的完整教程含源码 - Python 机器学习

今天一起来学习scikit-learn 。 scikit-learn 是一个强大的 Python 机器学习库&#xff0c;提供多种分类、回归、聚类算法&#xff0c;适用于从数据预处理到模型评估的全流程。它支持简单一致的 API&#xff0c;适合快速构建和测试模型。 官方地址在这里&#xff0c;记得Mark…

【Docker】创建Docker并部署Web站点

要在服务器上创建Docker容器&#xff0c;并在其中部署站点&#xff0c;你可以按照以下步骤操作。我们将以Flask应用为例来说明如何完成这一过程。 1. 准备工作 确保你的服务器已经安装了Docker。如果没有&#xff0c;请根据官方文档安装&#xff1a; Docker 安装指南 2. 创…

cgo内存泄漏排查

示例程序&#xff1a; package main/* #include <stdlib.h> #include <string.h> #include <stdio.h> char* cMalloc() {char *mem (char*)malloc(1024 * 1024 * 16);return mem; } void cMemset(char* mem) {memset(mem, -, 1024 * 1024 * 16); } int arr…

在做题中学习(76):颜色分类

解法&#xff1a;三指针 思路&#xff1a;用三个指针&#xff0c;把数组划分为三个区域&#xff1a; for循环遍历数组&#xff0c;i遍历数组&#xff0c;left是0区间的末尾&#xff0c;right是2区间的开头&#xff0c;0 1 2区间成功被划分 而上面的图画是最终实现的图样&…

性能测试基础知识jmeter使用

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;测试_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 性能指标 1. 并发数 (Con…

AWS创建ec2实例并连接成功

aws创建ec2实例并连接 aws创建ec2并连接 1.ec2创建前准备 首先创建一个VPC隔离云资源并且有公有子网 2.创建EC2实例 1.启动新实例或者创建实例 2.创建实例名 3.选择AMI使用linux(HVM) 4.选择实例类型 5.创建密钥对下载到本地并填入密钥对名称 6.选择自己创建的VPC和公有子网…

Flutter提示错误:无效的源发行版17

错误描述 Flutter从3.10.1 升级到3.19.4&#xff0c;在3.10.1的时候一切运行正常&#xff0c;但是当我将Flutter版本升级到3.19.4后&#xff0c;出现了下方的错误 FAILURE: Build failed with an exception.* What went wrong: Execution failed for task :device_info_plus:…