侧边栏壁纸
博主头像
樯哥的技术分享网博主等级

学无止境,学以致用,志存高远。

  • 累计撰写 17 篇文章
  • 累计创建 10 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

halo插件开发——简单增删改查接口开发

随心
2023-11-11 / 0 评论 / 2 点赞 / 83 阅读 / 5989 字

这是halo插件开发系列的第二篇文章,是时候讲一点干货了。其实官方文档也提供了一些简单的示例源码。只不过很多代码注释都是全英文,而且也说得不明不白。本文只是提供一个辅助,建议结合官方文档一起看。

其实开发插件和开发一般的Java系统没啥太多区别,平时开发Java系统一般就这么几个步骤:1. 建立表结构,2. 建立与表结构对应的实体类映射,3. 编写增删改查的接口。

halo系统在这方面做了深度的封装,整个数据库就一张表,而且是作为类似Redis的一种key-value结构使用的。因此,我们不需要建立表结构,但是我们需要建立一个实体类,来描述我们存入数据库中的是什么样的数据结构。此外,halo系统提供了通用的增删改查接口模板,因此,只需要我们按照一定规范,定义一个实体类,整个系统就会自动生成对应的增删改查接口,接下来我们看看具体如何编码。

编写CRUD接口

  1. 这里我们可以直接使用上一篇文章中的插件模板项目,我们在StarterPlugin类下创建一个子包,并创建我们的实体类,我这里举个简单的例子,如图:

至于为什么这个类放在这个目录下,这种问题我想任何一个使用过springboot的都不应该问。我这里重点解释下代码:

我们必须继承`AbstractExtension`类,该类提供了一些公共的属性,就好比数据库中所有表都有创建时间、更新时间以及id字段一样。

@Data@EqualsAndHashCode(callSuper = true)注解是lombok的注解,不清楚的建议自己去了解下。

@Schema注解是生成接口文档使用到的字段描述,就是写给前段看的。可以自行了解,这里可以不写,不重要。

重点是@GVK注解,这个注解中的配置内容会直接关系到最终接口的生成。group中类似于Java的包名,这个东西建议按照规范写个性化一点的,防止和别人的重复。version就是写明版本号。kind就是自己随便命名,用于给这一系列增删改查接口分组。而后面两个就是该实体的名字,一个是单数一个是复数。

需要注意的是,@GVK 注解中配置的前面三个参数都和最终生成的接口路径有着直接关系,甚至和接口传参也有关系。

  1. 修改StarterPlugin类中的代码,修改后的代码如下:

根据第一篇文章的知识打包插件,然后使用halo项目源码运行起来。此时访问:Swagger UI

我们就可以看见对应的CRUD接口了,至于前端如何请求对应的接口,这个纯粹就是vue的知识了。这里需要注意的是,所有以/api/apis开头的接口都有身份认证,halo采用了basic auth的认证方式,至于如何在js中使用,网上的例子太多了,自行百度。关于前端的知识不会作为本系列文章的重点。

测试接口

这里简单介绍下,如果没有页面时,如何调试接口。我们可以使用apifox这个软件来进行请求。首先下载安装apifox,打开软件后创建一个项目。然后按照下图进行设置:

上面设置后,点击立即导入,就可以把halo的所有接口导入到这个请求工具里。然后我们对所有接口进行统一的身份认证设置:

如果要测试接口,我们还需要设置接口的地址,我们点击右上角的开发环境按钮,点击管理环境,将默认服务修改为本地的halo服务地址:

很多人可能不清楚参数如何传递,我这里简单讲解一下接口参数。

首先,找到我们自己定义的接口,其中POST是新增数据的接口,这有几个必传参数:

apiVersion就是我们之前配置的group和version拼接而来,kind也就是我们之前配置的kind。而下面的key和secret就是我们之前自己定义的字段,这个字段可以定义成别的,这里也要对应改。至于metadata中的name字段,实际上是当前实体对象的唯一key。其他的接口可以通过这个值获查找到我们刚才新增的数据。可以理解为整个数据以key-value形式存储在数据库中,而key就是metadata中的name属性的值。其实metadata中还有一些其他属性,比如创建时间,删除时间等等,这些其实我们用不着。

@GVK(
    group = "wx.qy.plugin.halo.run",//命名规则类似包名,最好全局唯一
    version = "v1",//版本号,建议字母开头
    kind = "WxConfig",//给这一系列增删改查接口分组,建议使用当前实体类的类名
    singular = "wxConfig",//当前实体的单数形式
    plural = "wxConfig")//当前实体的复数表现形式

接下来我们使用查询详情的接口,也就是上面截图中第四个接口。

可以很明显的看见效果,这里的name就是我们之前创建的数据对应的name。至于删除接口,和查询详情的接口使用方式一模一样。接下来我们再看更新接口:

更新接口的params处传参方式和修改删除接口一致,但是body处却和前面的不同。这里的body必须传一个version字段,而version的值就是通过get请求查询到的结果中的值,我们每次修改之后该version字段都会自增1。也就是说,我每次调用修改接口之后,都必须修改version的值才能继续修改。这里version的功能类似于数据库的乐观锁。

接下来我们看下列表查询接口:

该接口支持分页查询,page是页数,从1开始,size是每一页的条数,如果size为负数,则不分页,sort则可以按指定的字段进行升序排序。

上面的条件就是查询第一页,按每一页十条进行查询,并且按照key的值进行升序排序。需要注意的是,我取消了前面两个查询条件,因为fieldSelector和labelSelector字段如果传空字符串会报错,所以要么不传,要么传入指定格式。如果要按照key降序排序,可以传入key,desc。

接下来重点讲解下这两个查询条件的作用。

fieldSelector参数可以针对name的值进行搜索,如果不记得name是啥,请往上翻截图。具体参数值例如:name=test04,name!=test04

在讲labelSelector参数之前,我们回到最初创建数据的接口,在最开始时,我只是说了创建数据至少需要传哪些参数。其实我们还有很多可选参数:

这里我只讲metadata下的labels属性,该值是一个Map类型,key和value都只能是字符串。至于如何传参想必不需要我多讲了吧?在前端js中也有Map结构,只要保证key和value都是字符串就可以直接传。那么这个字段有啥用?说白了就是可以额外存储一些数据信息使用的。当你定义实体类时,不知道定义什么属性,或者属性个数不确定时,你可以选择直接把数据存这里面。存储在这个字段里面有个好处就是,我们可以使用前面提到的labelSelector参数对它进行条件搜索。具体的条件包括是否存在该label以及对指定label的值进行匹配等等。

2

评论区