封装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;

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

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

相关文章

2024各地低空经济政策汇编资料

互联网各领域资料分享专区(不定期更新)&#xff1a; Sheet 前言 由于内容较多&#xff0c;且不便于排版&#xff0c;为避免资源失效&#xff0c;请用手机点击链接进行保存&#xff0c;若链接生效请及时反馈&#xff0c;谢谢~ 正文 链接如下&#xff08;为避免资源失效&#x…

基于JAVA的幼儿园管理系统的设计与实现源码(springboot+vue+mysql)

项目简介 幼儿园管理系统实现了以下功能&#xff1a; 基于JAVA的幼儿园管理系统的设计与实现的主要使用者管理员可以管理系统基本信息&#xff1b;管理轮播图、系统简介、教师管理、课程管理、幼儿活动管理、餐饮管理、留言管理等功能&#xff1b;前台用户注册登录&#xff0…

智能车摄像头开源—8 元素处理

目录 一、前言 二、无元素状态 三、直线与弯道 四、十字与环岛 1、十字识别处理 2、环岛识别处理 五、坡道 六、障碍物 七、斑马线 八、入库 九、出界停车 一、前言 在写这篇文章之前&#xff0c;考虑了很久到底该写到什么程度&#xff0c;但思来想去&#xff0c;不同…

LC-随机链表的复制、排序链表、合并K个升序链表、LRU缓存

随机链表的复制 为了在 O(n) 时间复杂度内解决这个问题&#xff0c;并且使用 O(1) 的额外空间&#xff0c;可以利用以下技巧&#xff1a; 将新节点插入到原节点后面&#xff1a;我们可以将复制节点插入到原节点后面。例如&#xff0c;如果链表是 A -> B -> C&#xff0c…

编码格式大全:类型 特点及其在网络安全中的作用

目录 说明: 1. Base64 Base64编码的字符集通常包括&#xff1a; Base64的工作原理&#xff1a; Base64编码在安全渗透中的应用场景 常见的Base64编码绕过场景 如何防范Base64绕过攻击 2. URL编码&#xff08;Percent Encoding&#xff09; URL编码与安全渗透的关系 示…

BGP分解实验·18——BGP选路原则之权重

在本地对进入的NLRI做权重设置&#xff0c;从而对过滤特定的路由进行优选。严格来说&#xff0c;权重值并不能算是路径属性&#xff0c;因为它并处传递&#xff0c;所能影响的仅仅限于本地路由器。 实验拓扑如下&#xff1a; 完成实验拓扑的基础实验&#xff0c;R1的配置如下…

pandas(13 Caveats Gotchas和SQL比较)

前面内容&#xff1a;pandas(12 IO工具和稀松数据) 目录 一、Caveats警告 & Gotchas预见 1.1 在Pandas中使用if/Truth语句 1.2 位运算布尔 1.3 isin操作 1.4 重新索引reindex和 loc&iloc 使用注意事项 1.5 loc和iloc 二、Python Pandas 与SQL的比较 2.1 数…

FPGA的星辰大海

编者按 时下风头正盛的DeepSeek,正值喜好宏大叙事的米国大统领二次上岗就业,OpenAI、软银、甲骨文等宣布投资高达5000亿美元“星际之门”之际,对比尤为强烈。 某种程度上,,是低成本创新理念的直接落地。 包括来自开源社区的诸多赞誉是,并非体现技术有多“超越”,而是…

AI大模型的文本流如何持续吐到前端,实时通信的技术 SSE(Server-Sent Events) 认知

写在前面 没接触过 SSE&#xff08;Server-Sent Events&#xff09;&#xff0c;AI大模型出来之后&#xff0c;一直以为文本流是用 WebSocket 做的偶然看到返回到报文格式是 text/event-stream,所以简单认知&#xff0c;整理笔记博文内容涉及 SSE 认知&#xff0c;以及对应的 D…

大学信息安全技术 期末考试复习题

一、单选题&#xff08;一&#xff09; 1、在以下人为的恶意攻击行为中&#xff0c;属于主动攻击的是&#xff08; &#xff09;A A&#xff0e;数据篡改及破坏 B&#xff0e;数据窃听 C&#xff0e;数据流分析 D&#xff0e;非法访问 2、数据完整性指的是&#xff08; &#x…

CES 2025 上的创新方案——无电池智能纸尿裤-AP4470

这款纸尿裤采用了可重复使用的组件&#xff0c;通过检测液体的存在来增强老年人和婴儿的护理&#xff0c;即使电极上滴了几滴液体也是如此。 其原理为尿液中的水分作为电解液&#xff0c;将尿布里安装的两种导电性材料作为正负极&#xff0c;充当电池&#xff0c;从而产生300m…

C++17中的LegacyContiguousIterator(连续迭代器)

文章目录 特点内存连续性与指针的兼容性更高的性能 适用场景与C接口交互高性能计算 支持连续迭代器的容器示例代码性能优势缓存局部性指针算术优化 注意事项总结 在C17标准里&#xff0c;LegacyContiguousIterator&#xff08;连续迭代器&#xff09;是一类特殊的迭代器。它不仅…

小白win10安装并配置yt-dlp

需要yt-dlp和ffmpeg 注意存放路径最好都是全英文 win10安装并配置yt-dlp 一、下载1.下载yt-dlp2. fffmpeg下载 二、配置环境三、cmd操作四、yt-dlp下视频操作 一、下载 1.下载yt-dlp yt-dlp地址 找到win的压缩包点下载&#xff0c;并解压 2. fffmpeg下载 ffmpeg官方下载 …

【线性代数】2矩阵

1.矩阵的运算 1.1.定义 矩阵行列式数表数行数和列数可以不相等行数和列数必须相等1.2.加法与数乘 矩阵的数乘:所有元素都乘这个数 矩阵的加法:对应位置处元素相加 🦊已知,求 1.3.乘法 矩阵乘法三步法 ①能不能乘:内定乘 ②乘完是何类型:外定型 ③中的元素是什么:左…

【Leetcode 952】按公因数计算最大组件大小

题干 给定一个由不同正整数的组成的非空数组 nums &#xff0c;考虑下面的图&#xff1a; 有 nums.length 个节点&#xff0c;按从 nums[0] 到 nums[nums.length - 1] 标记&#xff1b;只有当 nums[i] 和 nums[j] 共用一个大于 1 的公因数时&#xff0c;nums[i] 和 nums[j]之…

DeepSeek-R1 大模型本地部署指南

文章目录 一、系统要求硬件要求软件环境 二、部署流程1. 环境准备2. 模型获取3. 推理代码配置4. 启动推理服务 三、优化方案1. 显存优化技术2. 性能加速方案 四、部署验证健康检查脚本预期输出特征 五、常见问题解决1. CUDA内存不足2. 分词器警告处理3. 多GPU部署 六、安全合规…

家里WiFi信号穿墙后信号太差怎么处理?

一、首先在调制解调器&#xff08;俗称&#xff1a;猫&#xff09;测试网速&#xff0c;网速达不到联系运营商&#xff1b; 二、网线影响不大&#xff0c;5类网线跑500M完全没问题&#xff1b; 三、可以在卧室增加辅助路由器&#xff08;例如小米AX系列&#xff09;90~200元区…

win11系统 Docker Desktop提示Docker Engine stopped解决全过程记录

DockerDesktop安装指南以及Windows下WSL2和 Hyper-V相关问题追查 【已解决】win10系统 Docker 提示Docker Engine stopped解决全过程记录 本篇文章主要记录Docker Desktop安装和使用时出现的问题及解决方法&#xff0c;以及后续使用夜神模拟器&#xff0c;关闭了Hyper-V时&am…

手动埋点的demo

上代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>埋点示例</title> </head><b…

数据结构——链表

目录 一、链表 1.1 链表的概念 二、单链表 2.1 单链表的概念 2.2单链表的操作 2.2.1 单链表的结点创建 2.2.2 单链表的头插 2.2.3 单链表遍历 2.2.4 单链表的头删 2.2.5 单链表的尾插 2.2.6 单链表的尾删 2.2.7 单链表按位置插入 2.2.8 单链表按位置删除 2.2.9 单链表按位置修…