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.xdnf.cn/news/33963.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

旋转图像

旋转图像 ​ 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 ​ 你必须在** 原地** 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,…

3D数据大屏实现过程,使用echarts、Next.js

&#x1f4dc; 本文主要内容 数据大屏自适应方案动效 echarts&#xff1a; 3D 立体柱状图动态流光折线图 3D 地球&#xff08;飞线、柱状图&#xff09;无限滚动列表 &#x1f50d; 大屏效果 数据大屏&#xff1a; 点击预览 &#x1f579; 运行条件 next 12.3.4echarts 5.4…

长文 | RAG的实战指南及探索之路

今天给大家带来一篇知乎孙鹏飞 的关于RAG实战的文章。 作者&#xff1a;孙鹏飞 知乎&#xff1a;https://zhuanlan.zhihu.com/p/6822534961. 背景介绍 RAG&#xff08;Retrieval Augmented Generation&#xff0c;检索增强生成 &#xff09;方法是指结合了基于检索的模型和生…

LeetCode—11. 盛最多水的容器(中等)

题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;…

leetcode 63.不同路径||

1.题目要求: 2.题目代码: class Solution { public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {//创建dp数组的含义vector<vector<int>> dp;dp.resize(obstacleGrid.size());for(int i 0;i < dp.size();i){dp[i].…

C++:std::deque简介

std::deque 是 C 标准模板库&#xff08;STL&#xff09;中的一个双端队列&#xff08;Double-ended Queue&#xff09;容器。它是一种动态数组&#xff0c;允许快速地在序列的两端插入和删除元素&#xff0c;同时支持随机访问。 特点 双端操作 支持在队列头部和尾部快速插入和…

【Linux】基础IO_文件系统IO_“一切皆文件”_缓冲区

目录 1. 理解"⽂件" 1-1 狭义理解 1-2 ⼴义理解 1-3 ⽂件操作的归类认知 1-4 系统⻆度 访问文件&#xff0c;需要先打开文件&#xff01;那么是由谁打开文件&#xff1f;&#xff1f;&#xff1f; 操作系统要不要把被打开的文件管理起来&#xff1f; 2. 回顾…

nginx防盗链原理与实践

nginx防盗链的原理是基于http请求头中的referer来限制对资源的访问&#xff08;referer是用来告知浏览器该网页时从哪个页面链接来的&#xff09;&#xff0c;从而防止其他网站胃经授权直接链接资源。 nginx防盗链的作用是节省带宽和资源消耗&#xff0c;保护数据安全&#xf…

UG NX二次开发(Python)-UIStyler-选取点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、设计一个UI界面3、创建长方体的代码4、需要引入的库5、测试验证1、前言 采用Python语言进行UG NX二次开发的资料比较少,我本来不是很认可采用Python进行二次开发的,但是近期有读者咨询…

linux环境中后台运行java程序

在生产环境&#xff0c;我们通常需要让java进程后台运行&#xff0c;并且即使会话关闭&#xff0c;进程也依然存在。 使用的命令&#xff1a; nohup java -jar xxx.jar -> aaa.log 2>&1 & 详细介绍下上面这条命令 &#xff08;1&#xff09;nohup&#xff1a;…

算法笔记:力扣15、三数之和

思路&#xff1a; 实现代码 class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result new ArrayList<>(); Arrays.sort(nums); // 先对数组进行排序 for (int i 0; i < nums.length - 2; i) { /…

java基础语法光速入门

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理Java的基础语法部分 适合有编程基础的人快点掌握语法使用 没学过一两门语言的话。。还是不建议看了 极致的浓缩没有一点解释 注释 单行注释 // 多行注释 /**/ 数据类型 布尔型:true false 整型:int,lon…

karmada-descheduler

descheduler规则 karmada-descheduler 定期检测所有部署&#xff0c;通常是每2分钟一次&#xff0c;并确定目标调度集群中无法调度的副本数量。它通过调用 karmada-scheduler-estimator 来完成这个过程。如果发现无法调度的副本&#xff0c;它将通过减少 spec.clusters 的配…

LeetCode 力扣 热题 100道(十四)二叉树的中序遍历(C++)

给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 如下为代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullpt…

STM32之ADC采集和DMA传输(八)

STM32F407 系列文章 -内部ADC采集和DMA传输&#xff08;八&#xff09; 目录 前言 一、ADC特性 二、DMA特性 三、ADC采集 1.单通道ADC采集 1.头文件定义 2.函数adc_init() 3.函数HAL_ADC_MspInit() 4.函数adc_channel_set() 5.函数adc_get_result() 6.函数adc_get_r…

三菱人机界面GOT SIMPLE 系列 GS2107\GS2110\GS2512

以客户需求为核心的全面升级!GOT SIMPLE系列新功能 GOT SIMPLE升级版重磅更新&#xff0c;增添了许多期待已久的新功能&#xff0c;帮助用户实现远程维护! 扩充用户存储器容量至15MB&#xff0c;并支持轮廓字体&#xff0c;以实现平滑、靓丽的字体显示。此外&#xff0c;可使用…

VLTVG代码复现并讲解

train.py 在main函数中找到这个构建模型的地方&#xff0c;ctrl&#xff0b;左键点进这个函数中去 来到了这里 又来到了这里&#xff0c;这里就是构建模型的地方&#xff1a; 又来到了这里&#xff0c;还是在VLTVG.py这个文件中&#xff1a; Method The Overall Network Visua…

转换思维是为智

转换思维是为智 2023年11月08日(节选) 我们人的思维分为人间思维&#xff0c;圣人思维&#xff0c;菩萨思维。人间思维讲得通俗一点就是世间智慧&#xff0c;他拥有的是人间的智慧&#xff0c;讲得再简单一点&#xff0c;就是人间的聪明。圣人的思维是什么&#xff0c;是一种脱…

qtcanpool 知 10:包管理雏形

文章目录 前言痛点转机雏形实践后语 前言 曾听闻&#xff1a;C/Qt 没有包管理器&#xff0c;开发起来太不方便。这是一个有过 node.js 开发经验的人对 Qt 的吐槽。 确实&#xff0c;像 python、golang、node.js 这些编程语言都有包管理器&#xff0c;给用户带来了极佳的开发体…

光敏传感器实验

用到 ADC 采集&#xff0c;通过 ADC 采集电压&#xff0c;获取光敏传感器的电阻变化&#xff0c;从而得出环境光线的变化&#xff0c;并在 TFTLCD 上面显示出来。 光敏传感器是最常见的传感器之一&#xff0c;它的种类繁多&#xff0c;主要有&#xff1a;光电管、光电倍增管…