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

    @Override
    public 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());
    @Autowired
    protected 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 */
    @Deprecated
    protected 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> {
    @Autowired
    private R repository;
    @Override
    public T queryByBid(Long bid) {
        return (T) this.repository.findByBid(bid).orElse(null);
    }
    @Override
    public T create(T t) {
        t.setId(null);//id由neo4j自动生成
        return (T) this.repository.save(t);
    }
    @Override
    public 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);
    }
    @Override
    public 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 {
    @Override
    public OrganTypeEnum getOrganTypeEnum() {
        return OrganTypeEnum.AGENCY;
    }
}
@Service
public class OLTServiceImpl extends ServiceImpl<OLTRepository, OLTEntity>
        implements OLTService {
    @Override
    public OrganTypeEnum getOrganTypeEnum() {
        return OrganTypeEnum.OLT;
    }
}
@Service
public class TLTServiceImpl extends ServiceImpl<TLTRepository, TLTEntity>
        implements TLTService {
    @Override
    public 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 {
    @Test
    public void testo1(){
        IService iService = OrganServiceFactory.getBean(1);
        System.out.println(iService);
    }
}

成功返回OLT类型的服务实现类 

如果不使用工厂模式,我们就要提前注入这三种类型的服务bean,这样是不是很冗余呢,然后还需要根据需要操作的实体类的不同来判断使用哪一个服务类,十分麻烦

if(type==1) 使用oltService来操作

else if(type==2) ...

    @Resource
    OLTService oltService;
    @Resource
    TLTService tltService;
    @Resource
    AgencyService agencyService;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot (maven)分页2.0版本

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

Docker安装Minio对象存储

介绍 MinIO 是一种对象存储解决方案&#xff0c;提供与Amazon Web Services S3兼容的API并支持所有核心S3功能。MinIO可部署在任何地方&#xff1a;公共云或私有云、裸机基础设施、编排环境和边缘基础设施。 详情参见官方文档&#xff1a;MinIO Object Storage for Container…

BERT 大模型

BERT 大模型 EmbeddingTransformer预微调模块预训练任务 BERT 特点 : 优点 : 在语言理解相关任务中表现很好缺点 : 更适合 NLU 任务&#xff0c;不适合 NLG 任务 BERT 架构&#xff1a;双向编码模型 : Embedding 模块Transformer 模块预微调模块 Embedding Embedding 组成 …

cmake:定位Qt的ui文件

如题。在工程中&#xff0c;将h&#xff0c;cpp&#xff0c;ui文件放置到不同文件夹下&#xff0c;会存在cmake找不到ui文件&#xff0c;导致编译报错情况。 cmake通过指定文件路径&#xff0c;确保工程找到ui文件。 标识1&#xff1a;ui文件保存路径。 标识2&#xff1a;添加…

DFS算法篇:理解递归,熟悉递归,成为递归

1.DFS原理 那么dfs就是大家熟知的一个深度优先搜索&#xff0c;那么听起来很高大尚的一个名字&#xff0c;但是实际上dfs的本质就是一个递归&#xff0c;而且是一个带路径的递归&#xff0c;那么递归大家一定很熟悉了&#xff0c;大学c语言课程里面就介绍过递归&#xff0c;我…

H5自适应响应式代理记账与财政咨询服务类PbootCMS网站模板 – HTML5财务会计类网站源码下载

(H5自适应)响应式代理记账财政咨询服务类pbootcms网站模板 html5财务会计类网站源码下载 为了提升系统安全&#xff0c;请将后台文件admin.php的文件名修改一下。修改之后&#xff0c;后台登录地址就是&#xff1a;您的域名/您修改的文件名.php 模板特点&#xff1a; 1&#x…

嵌入式音视频开发(二)ffmpeg音视频同步

系列文章目录 嵌入式音视频开发&#xff08;零&#xff09;移植ffmpeg及推流测试 嵌入式音视频开发&#xff08;一&#xff09;ffmpeg框架及内核解析 嵌入式音视频开发&#xff08;二&#xff09;ffmpeg音视频同步 嵌入式音视频开发&#xff08;三&#xff09;直播协议及编码器…

工业自动化丨工业控制系统五层架构以及PLC、SCADA系统、DCS系统,从零基础到精通,收藏这篇就够了!

工业控制系统通常是几种类型控制系统的总称&#xff0c;包括监控和数据采集&#xff08;SCADA&#xff09;系统、分布式控制系统&#xff08;DCS&#xff09;和可编程逻辑控制器&#xff08;PLC&#xff09;以及其它控制系统。 【右下角**点赞、**转发、在看&#xff0c;为企业…

✨1.HTML、CSS 和 JavaScript 是什么?

✨✨ HTML、CSS 和 JavaScript 是构建网页的三大核心技术&#xff0c;它们相互协作&#xff0c;让网页呈现出丰富的内容、精美的样式和交互功能。以下为你详细介绍&#xff1a; &#x1f98b;1. HTML&#xff08;超文本标记语言&#xff09; 定义&#xff1a;HTML 是一种用于描…

MySQL基本操作——包含增删查改(环境为Ubuntu20.04,MySQL5.7.42)

1.库的操作 1.1 创建数据库 语法&#xff1a; 说明&#xff1a; 大写的表示关键字 [] 是可选项 CHARACTER SET: 指定数据库采用的字符集 COLLATE: 指定数据库字符集的校验规则 1.2 创建案例 创建一个使用utf8字符集的db1数据库 create database db1 charsetutf8; …

【项目】基于STM32F103C8T6的四足爬行机器人设计与实现(源码工程)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 【项目】基于STM32F103C8T6的四足爬行机器人设计与…

IIS asp.net权限不足

检查应用程序池的权限 IIS 应用程序池默认使用一个低权限账户&#xff08;如 IIS_IUSRS&#xff09;&#xff0c;这可能导致无法删除某些文件或目录。可以通过以下方式提升权限&#xff1a; 方法 1&#xff1a;修改应用程序池的标识 打开 IIS 管理器。 在左侧导航树中&#x…

【数据结构】队列(Queue)

Queue 定义 Java中的队列(Queue)是一种先进先出(FIFO)的数据结构。队列只允许在一段进行插入数据操作&#xff0c;称为入队&#xff0c;在另一端进行删除数据操作&#xff0c;称为出队。我们可以把队列形象看作为排队。在最前面的进行出队&#xff0c;从最后面进行入队。 队列…

从零搭建微服务项目Base(第5章——SpringBoot项目LogBack日志配置+Feign使用)

前言&#xff1a; 本章主要在原有项目上添加了日志配置&#xff0c;对SpringBoot默认的logback的配置进行了自定义修改&#xff0c;并详细阐述了xml文件配置要点&#xff08;只对日志配置感兴趣的小伙伴可选择直接跳到第三节&#xff09;&#xff0c;并使用Feign代替原有RestT…

Linux 网络安全技巧

网络安全是一个非常重要的课题,基本上你运行的服务后台越多,你就可能打开更多的安全漏洞.如果配置的恰当的话,Linux本身是非常安全可靠的,假使在Linux系统中有某个安全缺陷,由于Linux的源码是开放的&#xff0c;有成千上万的志愿者会立刻发现并修补它。本文旨在介绍用来增强你的…

Next.js【详解】获取数据(访问接口)

Next.js 中分为 服务端组件 和 客户端组件&#xff0c;内置的获取数据各不相同 服务端组件 方式1 – 使用 fetch export default async function Page() {const data await fetch(https://api.vercel.app/blog)const posts await data.json()return (<ul>{posts.map((…

个人shell脚本分享

在周一到周五做增量备份&#xff0c;在周六周日做完全备份 #!/bin/bash定义变量 SRC“/path/to/source” # 源目录 BKUP“/backup” # 备份主目录 FUL“KaTeX parse error: Expected EOF, got # at position 22: …ull" #̲ 完全备份目录 INC"BKUP/inc” # 增量备份…

小胡说技书博客分类(部分目录):服务治理、数据治理与安全治理对比表格

文章目录 一、对比表格二、目录2.1 服务2.2 数据2.3 安全 一、对比表格 下表从多个维度对服务治理、数据治理和安全治理进行详细对比&#xff0c;为读者提供一个直观而全面的参考框架。 维度服务治理数据治理安全治理定义对软件开发全流程、应用交付及API和接口管理进行规范化…

冒险岛079 V8 整合版源码搭建教程+IDEA启动

今天教大家来部署下一款超级怀旧游戏冒险岛&#xff0c;冒险岛源码是开源的&#xff0c;但是开源的代码会有各种&#xff0c;本人进行了加工整合&#xff0c;并且用idea进行了启动测试&#xff0c;经过修改后没有任何问题。 启动截图 后端控制台 前端游戏界面 声明 冒险岛源码…

Ubuntu 24.04.1 LTS 本地部署 DeepSeek 私有化知识库

文章目录 前言工具介绍与作用工具的关联与协同工作必要性分析 1、DeepSeek 简介1.1、DeepSeek-R1 硬件要求 2、Linux 环境说明2.1、最小部署&#xff08;Ollama DeepSeek&#xff09;2.1.1、扩展&#xff08;非必须&#xff09; - Ollama 后台运行、开机自启&#xff1a; 2.2、…