封装neo4j的持久层和服务层
目录
持久层
mp
模仿:
1.抽取出通用的接口类
2.创建自定义的repository接口
服务层
mp
模仿:
1.抽取出一个IService通用服务类
2.创建ServiceImpl类实现IService接口
3.自定义的服务接口
4.创建自定义的服务类
工厂模式
为什么可以使用工厂模式
如何使用工厂模式
枚举类
工厂类
第一种方式:使用switch方式来判断要返回哪一种服务类型
第二种:通过反射来判断
使用工厂模式
这里我来分享以下参考mybatis-plus的格式来封装neo4j的持久层,和设计出一个服务层
持久层
mp
这里我们先看以下mp持久层的是如何操作的
可以发现mp抽取出了一个通用的BaseMapper接口,并使用泛型T代指对实体类对象的统一操作
public interface BaseMapper<T> extends Mapper<T> {int insert(T entity);int deleteById(Serializable id);int deleteById(T entity);
...
}
然后我们就可以创建一个mapper类,并继承自BaseMapper接口,然后泛型指定为PayChannelEntity实体类,这个实体类就是使用@TableName注解与数据表一一对应的实体类
@Mapper
public interface PayChannelMapper extends BaseMapper<PayChannelEntity> {}
总结,mp通过抽取出一个BaseMapper通用的接口,然后让我们自己创建的mapper类去继承BaseMapper,并指定要操作的实体类,这样一来,大多数的CURD操作我们就不用自己实现,并且我们自己创建的mapper类使用@Mapper注解,这个注解可以让Spring扫描并为其创建一个代理对象。
模仿:
1.抽取出通用的接口类
这个类继承Neo4jRepository接口,这个接口有neo4j提供的大多数CURD方法
并且也使用泛型,并且规定这个T泛型必须继承自BaseEntity类,还有另一个泛型ID,表示id属性的类型
这里使用@NoRepositoryBean注解的作用是不用给这个通用接口类生成bean,因为继承Neo4jRepository接口的接口都会被扫描生成代理对象,这里没必要生成,mp是使用了@Mapper注解才会生成代理对象
/*** Repository基本方法的实现**/
@NoRepositoryBean//让这个类不生成bean
public interface BaseRepository<T extends BaseEntity, ID> extends Neo4jRepository<T, ID> {/*** 根据业务id查询节点数据** @param bid 业务id* @return 节点数据*/Optional<T> findByBid(Long bid);/*** 根据业务id删除节点数据** @param bid 业务id* @return 删除的数据数量*/Long deleteByBid(Long bid);
}
2.创建自定义的repository接口
这里指定泛型为AgencyEntity类,和id属性为Long类
AgencyEntity类是与neo4j中AGENCY标签一一对应的实体类
通过实现getAgencyType()抽象方法来区别不同的机构实体类
/*** 网点数据操作*/
public interface AgencyRepository extends BaseRepository<AgencyEntity, Long> {}@Node("AGENCY")
@Data
@ToString(callSuper = true)
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
public class AgencyEntity extends BaseEntity {@Overridepublic OrganTypeEnum getAgencyType() {return OrganTypeEnum.AGENCY;}
}@Data
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public abstract class BaseEntity {@Id@GeneratedValue@ApiModelProperty(value = "Neo4j ID", hidden = true)private Long id;@ApiModelProperty(value = "父节点id", required = true)private Long parentId;@ApiModelProperty(value = "业务id", required = true)private Long bid;@ApiModelProperty(value = "名称", required = true)private String name;@ApiModelProperty(value = "负责人", required = true)private String managerName;@ApiModelProperty(value = "电话", required = true)private String phone;@ApiModelProperty(value = "地址", required = true)private String address;@ApiModelProperty(value = "位置坐标, x: 纬度,y: 经度", required = true)private Point location;@ApiModelProperty(value = "是否可用", required = true)private Boolean status;@ApiModelProperty(value = "扩展字段,以json格式存储")private String extra;//机构类型public abstract OrganTypeEnum getAgencyType();}
还有另外两个持久层接口类

服务层
mp
这里看一下mp的服务层实现
可以发现mp的服务层也抽取出了一个通用的服务接口类,也使用了泛型T来代指操作的实体类
public interface IService<T> {int DEFAULT_BATCH_SIZE = 1000;default boolean save(T entity) {return SqlHelper.retBool(this.getBaseMapper().insert(entity));}@Transactional(rollbackFor = {Exception.class})default boolean saveBatch(Collection<T> entityList) {return this.saveBatch(entityList, 1000);}boolean saveBatch(Collection<T> entityList, int batchSize);
BaseMapper<T> getBaseMapper();Class<T> getEntityClass();
...
}
这个接口类是没有实现的,如果我们要自己创建一个服务类去实现这个接口,是十分麻烦的,所以mp提供了一个ServiceImpl类对这个接口进行了实现
这个实现类使用了一个泛型M代指继承了BaseMapper接口的类,还有泛型T代指实体类
这样一来就可以使用M来实现IService接口的所有方法操作了。
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {protected Log log = LogFactory.getLog(this.getClass());@Autowiredprotected M baseMapper;protected Class<T> entityClass = this.currentModelClass();protected Class<M> mapperClass = this.currentMapperClass();public ServiceImpl() {}public M getBaseMapper() {return this.baseMapper;}public Class<T> getEntityClass() {return this.entityClass;}/** @deprecated */@Deprecatedprotected boolean retBool(Integer result) {return SqlHelper.retBool(result);}protected Class<M> currentMapperClass() {return ReflectionKit.getSuperClassGenericType(this.getClass(), ServiceImpl.class, 0);}
...
}
自定义的服务接口类,用来拓展自己特有的方法
public interface PayChannelService extends IService<PayChannelEntity> {}
自定义的服务类,把对应的mapper接口类型,和需要操作的实体类作为泛型传入
@Service
public class PayChannelServiceImpl extends ServiceImpl<PayChannelMapper, PayChannelEntity> implements PayChannelService {
}
模仿:
1.抽取出一个IService通用服务类
使用泛型T代指需要操作的实体类
public interface IService<T extends BaseEntity> {/*** 根据业务id查询数据** @param bid 业务id* @return 节点数据*/T queryByBid(Long bid);/*** 新增节点** @param t 节点数据* @return 新增的节点数据*/T create(T t);/*** 更新节点** @param t 节点数据* @return 更新的节点数据*/T update(T t);/*** 根据业务id删除数据** @param bid 业务id* @return 是否删除成功*/Boolean deleteByBid(Long bid);}
2.创建ServiceImpl类实现IService接口
这里使用R泛型代指repostory接口类,这样一来就可以使用R类型的repostory接口来对方法进行实现。
/*** 基础服务的实现*/
public class ServiceImpl<R extends BaseRepository, T extends BaseEntity> implements IService<T> {@Autowiredprivate R repository;@Overridepublic T queryByBid(Long bid) {return (T) this.repository.findByBid(bid).orElse(null);}@Overridepublic T create(T t) {t.setId(null);//id由neo4j自动生成return (T) this.repository.save(t);}@Overridepublic T update(T t) {//先查询,再更新T tData = this.queryByBid(t.getBid());if (ObjectUtil.isEmpty(tData)) {return null;}BeanUtil.copyProperties(t, tData, CopyOptions.create().ignoreNullValue().setIgnoreProperties("id", "bid"));return (T) this.repository.save(tData);}@Overridepublic Boolean deleteByBid(Long bid) {return this.repository.deleteByBid(bid) > 0;}
}
3.自定义的服务接口
public interface AgencyService extends IService<AgencyEntity> {}public interface OLTService extends IService<OLTEntity> {}
public interface TLTService extends IService<TLTEntity> {}
4.创建自定义的服务类
创建实现类,并把这个类都交给spring管理
@Service
public class AgencyServiceImpl extends ServiceImpl<AgencyRepository, AgencyEntity> implements AgencyService {
}@Service
public class TLTServiceImpl extends ServiceImpl<TLTRepository, TLTEntity>implements TLTService {
}@Service
public class OLTServiceImpl extends ServiceImpl<OLTRepository, OLTEntity>implements OLTService {
}
工厂模式
我们可以使用工厂模式来动态的生成不同的服务实现类供我们使用
为什么可以使用工厂模式
因为所有的服务类都实现了IService这个通用的服务接口,这样一来就可以使用父类引用指向子类对象的多态思想
如何使用工厂模式
我们可以创建一个工厂类,还有一个枚举类,代替不同的机构类型,然后再工厂类的静态方法中根据不同的枚举类的code值来创建对应的服务类并返回。
枚举类
public enum OrganTypeEnum implements BaseEnum {OLT(1, "一级转运中心"),TLT(2, "二级转运中心"),AGENCY(3, "网点");/*** 类型编码*/private final Integer code;/*** 类型值*/private final String value;OrganTypeEnum(Integer code, String value) {this.code = code;this.value = value;}public Integer getCode() {return code;}public String getValue() {return value;}public static OrganTypeEnum codeOf(Integer code) {return EnumUtil.getBy(OrganTypeEnum::getCode, code);}
}
工厂类
第一种方式:使用switch方式来判断要返回哪一种服务类型
根据传入的Integer类型数据,使用枚举类的codeOf方法,创建对应的枚举类对象
然后使用hutool的SpringUtil获取对应服务类的实例bean对象并返回
/*** 根据type选择对应的service返回** @author zzj* @version 1.0*/
public class OrganServiceFactory {public static IService getBean(Integer type) {OrganTypeEnum organTypeEnum = OrganTypeEnum.codeOf(type);if (null == organTypeEnum) {throw new SLException(ExceptionEnum.ORGAN_TYPE_ERROR);}switch (organTypeEnum) {case AGENCY: {return SpringUtil.getBean(AgencyService.class);}case OLT: {return SpringUtil.getBean(OLTService.class);}case TLT: {return SpringUtil.getBean(TLTService.class);}}return null;}}
第二种:通过反射来判断
以上方法我们要通过switch语句来判断是要返回哪一种类型的服务类,那如果枚举类型很多的话,这样是不是冗杂
定义一个接口,在接口里定义能返回对应机构枚举类型的方法
public interface OrganTypeService {/*** 获取对应的机构枚举类型*/OrganTypeEnum getOrganTypeEnum();
}
然后自定义的服务接口都继承这个接口
public interface AgencyService extends IService<AgencyEntity> ,OrganTypeService{}
public interface OLTService extends IService<OLTEntity> ,OrganTypeService{}
public interface TLTService extends IService<TLTEntity>,OrganTypeService{}
服务类实现这个方法,分别返回对应的枚举类型
@Service
public class AgencyServiceImpl extends ServiceImpl<AgencyRepository, AgencyEntity> implements AgencyService {@Overridepublic OrganTypeEnum getOrganTypeEnum() {return OrganTypeEnum.AGENCY;}
}
@Service
public class OLTServiceImpl extends ServiceImpl<OLTRepository, OLTEntity>implements OLTService {@Overridepublic OrganTypeEnum getOrganTypeEnum() {return OrganTypeEnum.OLT;}
}
@Service
public class TLTServiceImpl extends ServiceImpl<TLTRepository, TLTEntity>implements TLTService {@Overridepublic OrganTypeEnum getOrganTypeEnum() {return OrganTypeEnum.TLT;}
}
方法实现
public class OrganServiceFactory {public static IService getBean(Integer type) {OrganTypeEnum organTypeEnum = OrganTypeEnum.codeOf(type);if (null == organTypeEnum) {throw new SLException(ExceptionEnum.ORGAN_TYPE_ERROR);}//先从容器中获取所有的IService类型的bean实例对象Map<String, IService> beans = SpringUtil.getBeansOfType(IService.class);for (Map.Entry<String, IService> entry : beans.entrySet()) {//通过反射执行getOrganTypeEnum()方法Object invoke = ReflectUtil.invoke(entry.getValue(), "getOrganTypeEnum");//如果类型一致就返回对应的服务类实例if(ObjectUtil.equal(invoke,organTypeEnum)){return entry.getValue();}}return null;}}
对比:
第一种方式不用写额外的方法来返回对应的枚举类型,但是需要在工厂的静态方法里来判断枚举类型,如果枚举类型少而且不用经常改变代码,就可以使用这种方式
第二种方式需要写额外的方法来返回对应的枚举类型,但是在工厂方法里就可以使用反射直接执行获取枚举类型的方法来动态获取对应的服务类型。
使用工厂模式
@SpringBootTest
public class Test1 {@Testpublic void testo1(){IService iService = OrganServiceFactory.getBean(1);System.out.println(iService);}
}
成功返回OLT类型的服务实现类

如果不使用工厂模式,我们就要提前注入这三种类型的服务bean,这样是不是很冗余呢,然后还需要根据需要操作的实体类的不同来判断使用哪一个服务类,十分麻烦
如
if(type==1) 使用oltService来操作
else if(type==2) ...
@ResourceOLTService oltService;@ResourceTLTService tltService;@ResourceAgencyService agencyService;
相关文章:
封装neo4j的持久层和服务层
目录 持久层 mp 模仿: 1.抽取出通用的接口类 2.创建自定义的repository接口 服务层 mp 模仿: 1.抽取出一个IService通用服务类 2.创建ServiceImpl类实现IService接口 3.自定义的服务接口 4.创建自定义的服务类 工厂模式 为什么可以使用工厂…...
基于Spring Boot的宠物爱心组织管理系统的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
error: conflicting types for ‘SSL_SESSION_get_master_key’
$ make make all-am make[1]: Entering directory ‘/home/linuxuser/tor’ CC src/lib/tls/libtor_tls_a-tortls_openssl.o In file included from src/lib/tls/tortls_openssl.c:61: ./src/lib/tls/tortls_internal.h:55:8: error: conflicting types for ‘SSL_SESSION_get_…...
测试狗参加国家超级计算成都中心2024年度用户大会
近日,国家超级计算成都中心举办了“数启新篇算领未来”2024年度用户大会。这场盛会汇聚了来自政府部门、科研院所及企业界的百余位领导专家及用户代表,共同探讨高性能计算在科技创新中的赋能作用,探索超算融合领域的创新发展之路。其中&#…...
从2025年起:数字化建站PHP 8.1应成为建站开发的基准线
在数字化浪潮席卷全球的今天,PHP语言仍然保持着Web开发领域的核心地位。根据W3Techs最新统计,PHP驱动着全球78.9%的已知服务端网站。当时间指向2025年,这个拥有28年历史的编程语言将迎来新的发展里程碑——PHP 8.1版本应成为网站开发的最低基准要求,这不仅是技术迭代的必然…...
飞牛OS与昔映OS深度对比
无论是备份珍贵的照片、视频,搭建个人专属的影视库,还是实现高效的文件共享与协作,NAS 都能成为我们的得力助手。而在众多的 NAS 系统中,飞牛 OS 与昔映 OS 凭借各自的特点,吸引了不少用户的关注。今天,咱们…...
vscode本地和远程对应分支没有同步提交数量
1、问题: 下载了最新的vscode后发现本地分支不显示跟远端分支的提交数量,每次都要手动拉取,如下图 2、解决 在vscode点击左下角设置图标,选择settings,直接搜索git的配置 果然自动拉取的配置设置为false,调整为true即…...
通过docker启用rabbitmq插件
创建文件,docker-compose.yml services:rabbitmq:image: rabbitmq:4.0-managementports:- "5672:5672"- "15672:15672"volumes:- ./data/rabbitmq/data:/var/lib/rabbitmq # 持久化数据- ./data/rabbitmq/plugins/rabbitmq_delayed_message_ex…...
DeepSeek计算机视觉(Computer Vision)基础与实践
计算机视觉(Computer Vision)是人工智能领域的一个重要分支,专注于让计算机理解和处理图像和视频数据。计算机视觉技术广泛应用于图像分类、目标检测、图像分割、人脸识别等场景。DeepSeek提供了强大的工具和API,帮助我们高效地构建和训练计算机视觉模型。本文将详细介绍如…...
哪些专业跟FPGA有关?
FPGA产业作为近几年新兴的技术领域,薪资高、待遇好,吸引了大量的求职者。特别是对于毕业生,FPGA领域的岗位需求供不应求。那么,哪些专业和FPGA相关呢? 哪些专业跟FPGA有关? 微电子学与固体电子学、微电子科…...
【STM32系列】利用MATLAB配合ARM-DSP库设计IIR数字滤波器(保姆级教程)
ps.源码放在最后面 设计FIR数字滤波器可以看这里:利用MATLAB配合ARM-DSP库设计FIR数字滤波器(保姆级教程) 设计IIR滤波器 MATLAB配置 设计步骤 首先在命令行窗口输入"filterDesigner",接着就会跳出以下界面…...
Java每日精进·45天挑战·Day18
一、解码嵌套编码字符串 在编程中,我们经常遇到需要对特定格式的字符串进行解析和解码的任务。今天,我们来探讨一个具体的例子:如何解码一个按照特定规则编码的字符串。这个规则允许字符串中的一部分被重复多次,且这种重复可以嵌…...
C# 中用于比较两个字符串的方法string.Compare
string.Compare 是 C# 中用于比较两个字符串的方法。它返回一个整数,表示两个字符串在字典顺序(lexicographical order)中的相对关系。这个方法非常有用,尤其是在排序、查找或比较字符串时。 string.Compare 的详细说明 方法签名…...
进阶数据结构——树状数组
前言 看这篇文章前我建议你们先看这个视频还有这个视频,不然你们可能看不懂。 一、树状数组的核心思想与本质 核心思想:树状数组(Fenwick Tree)是一种用于高效处理前缀和查询和单点更新的数据结构。 本质:通过二进…...
键盘启用触摸板-tips
在日常使用笔记本电脑时,我们会遇到没带鼠标,触摸板关闭的情况,通常情况下,我们习惯通过鼠标点击或触摸屏操作来启用触摸板,但其实通过键盘也能轻松实现这一功能。以下就是一种通过键盘操作启用触摸板的方法࿰…...
信息安全之网络安全
网络安全技术是一类包含内容极其广泛的技术,广义上说任何检测、防御和抵制网络攻击的技术都属于网络安全技术,而且很多网络安全技术都是攻击驱动型的。 网络安全大致包含的内容主要有防火墙,入侵检测,漏洞扫描与网络隔离…...
成都国际数字影像产业园布局者树莓集团,亮相宜宾翠屏招商签约
在商业版图的不断拓展中,树莓集团始终以敏锐的市场洞察力和果敢的决策力占据先机。近期,作为成都国际数字影像产业园的布局者,树莓集团高调亮相宜宾翠屏招商签约盛会,引发行业内外的广泛关注。 宜宾翠屏招商签约盛会,…...
opencascade 获取edge起始点 会出现终点与实际不同的情况
在使用 OpenCASCADE 获取 TopoDS_Edge 的起始点和终点时,可能会出现终点与实际不一致的情况。这通常是由于以下原因导致的: 几何曲线的方向问题:在某些情况下,几何曲线的方向可能与拓扑边的方向不一致,导致通过几何曲线…...
掌握正则表达式_模式匹配的艺术
当然,以下是《掌握正则表达式:模式匹配的艺术》文章内容,使用 Java 正则表达式,并包含丰富的代码示例: 1. 引言 1.1 正则表达式的定义与历史 正则表达式(Regular Expression,简称 regex 或 regexp)是一种用于描述文本模式的强大工具。它最初由数学家 Stephen Kleene…...
【蓝桥】二维DP--摆花
📌题目描述 📌解题思路 📌完整代码 📌举例 📌题目描述 📌解题思路 动态规划(DP) 问题,核心是 “前 i 种物品,每种物品最多可以使用x 次,组成总和…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
python基础语法Ⅰ
python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器,来进行一些算术…...
