go-zero(七) RPC服务和ETCD
go-zero 实现 RPC 服务
在实际的开发中,我们是通过RPC来传递数据的,下面我将通过一个简单的示例,说明如何使用go-zero框架和 Protocol Buffers 定义 RPC 服务。
一、生成 RPC项目
在这个教程中,我们根据user.api文件,来编写一个user.proto 文件,创建一个用户管理的 RPC 服务.
1.回顾user.api
go-zero的 API 文件通常定义 HTTP 接口,包括请求和响应的格式。它主要用于 RESTful API 的定义。
我们先来回顾下之前的user.api文件
type (RegisterRequest {Username string `json:"username" validate:"required"` // 注册请求,用户名Password string `json:"password" validate:"required"` // 注册请求,密码}RegisterResponse {Message string `json:"message"` // 响应消息}
)type (LoginRequest {Username string `json:"username" validate:"required"` // 登录请求,用户名Password string `json:"password" validate:"required"` // 登录请求,密码}LoginResponse {Token string `json:"token"` // 登录响应,JWT token}
)@server (group: user // 代表当前 service 代码块下的路由生成代码时都会被放到 user 目录下prefix: /v1 //定义路由前缀为 "/v1"
)
// 微服务名称为 user-ap,生成的代码目录和配置文件将和 user 值相关
service user-api {//用户注册@handler RegisterHandler//提交post请求 RegisterRequest为请求体 RegisterResponse为响应体post /register (RegisterRequest) returns (RegisterResponse)//用户登录@handler LoginHandlerpost /login (LoginRequest) returns (LoginResponse)
}//因为我们想要通过jwt来传递数据,所以我们不需求请求信息
type (GetInfoResponse {Username string `json:"username" `Password string `json:"password" `}
)//更新数据我们就简单修改下密码
type (UpdataRequest {Password string `json:"password" ` // 更新请求,新的密码}UpdataResponse {Message string `json:"message"` // 更新响应消息}
)@server (group: userprefix: /v1jwt: Auth //开启jwt
)
service user-api {@handler GetInfoHandler// 不需要请求信息post /getinfo returns (GetInfoResponse)@handler UpdataHandlerpost /updata (UpdataRequest) returns (UpdataResponse)
}
2. 创建proto 文件
Proto 文件,用于定义 gRPC 服务和消息格式。它主要用于远程过程调用(RPC),使用 Protocol Buffers 进行数据序列化。
根据user.api文件创建user.proto文件:
syntax = "proto3"; //声明使用 Protocol Buffers 的版本为 3//proto 包名
package pb;
//生成 golang 代码后的包名
option go_package ="./pb"; //必须要有“./” 这样的路径
//指定生成的 Go 代码的包名为 pb,在同一目录下创建一个名为 pb 的包//定义用户消息结构
message Users {int64 id = 1; // 用户 IDstring username = 2; // 用户名string password = 3; // 密码int64 createdAt = 4; // 创建时间
}//注册请求消息
message RegisterReq {string username = 1; // 用户名string password = 2; // 密码int64 createdAt = 3; // 创建时间
}//注册响应消息
message RegisterResp {string message =1; // 响应消息
}
//登录请求消息
message LoginReq {string username = 1; // 用户名string password = 2; // 密码
}
//登录响应消息
message LoginResp {string token = 1; // JWT token
}//更新数据请求消息
message UpdateReq {string password = 1; //password
}//更新数据响应消息
message UpdateResp {string message =1;
}// 通过username查询 请求消息
message GetInfoReq {string username = 1; //id
}// 通过username查询 响应消息
message GetInfoResp {Users users = 1; //users
}//定义了一个名为 user 的服务,提供了四个 RPC(Remote Procedure Call)方法,
// 分别对应用户的注册、登录、更新信息和查询信息操作:
service user{rpc Register(RegisterReq) returns (RegisterResp);rpc Login(LoginReq) returns (LoginResp);rpc Update(UpdateReq) returns (UpdateResp);rpc Getinfo(GetInfoReq) returns (GetInfoResp);
}
可以看到user.proto文件 和 user.api结构都差不多
3.API 文件与 Proto 文件的关系
字段一致性
虽然它们不需要完全一致,但在以下方面保持一致是好的实践:
-
字段名称:请求和响应消息的字段名称在 API 和 Proto 中应当保持一致,以避免混淆和确保一致的接口。
-
数据类型:字段的数据类型应在 API 和 Proto 中一致,确保数据传输时类型安全。
-
业务逻辑:API 和 Proto 文件应反映相同的业务逻辑。例如,如果 API 文件中的某个字段代表用户的 username,那么在 Proto 文件中也应有相应的 username 字段,以确保在处理登录或注册时一致。
实现一致性
在上面的文件中,RegisterRequest 和 RegisterResp 的字段在类型和名称上是一致的。这有助于维护这些接口之间的一致性。而在后端实现中,你可以从 API 层接收请求数据,并在处理时将这些数据转换为 Proto 消息,随后调用 gRPC 服务。
4.使用goctl生成代码
goctl rpc 是 goctl 中的核心模块之一,其可以通过 .proto 文件一键快速生成一个 rpc 服务,在项目根目录下新建一个RPC 目录,并执行以下命令生成 RPC 服务:
goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=. --client=true
goctl rpc protoc是根据 protobufer 文件生成 rpc 服务go_out是proto生成的go代码所在的目录,proto本身的命令参数go-grpc_out是proto生成的grpc代码所在的目录,proto本身的命令参数,和go_out必须同一个目录zrpc_out是 goctl rpc自带的命令,go-zero生成的代码所在的目录client=true是否生成客户端代码
二、实现RPC服务端
1. 配置说明
在使用gRPC服务时,我们会用到go-zero内置的RpcClientConf配置和RpcServerConf配置
RpcSeverConf:
- ServiceConf: 基础服务配置
- ListenOn: 监听地址
- Etcd: etcd 配置项
- Auth: 是否开启 Auth
- Redis: rpc 认证,仅当 Auth 为 true 生效
- Timeout: 超时时间
- Middlewares: 启用中间件
- Health: 是否开启健康检查
RpcClientConf:
- Etcd: 服务发现配置,当需要使用 etcd 做服务发现时配置
- Endpoints: RPC Server 地址列表,用于直连,当需要直连 rpc server 集群时配置
- Target: 域名解析地址,名称规则请参考
- App: rpc 认证的 app 名称,仅当 rpc server 开启认证时配置
- Token: rpc 认证的 token,仅当 rpc server 开启认证时配置
- NonBlock: 是否阻塞模式,当值为 true 时,不会阻塞 rpc 链接
- Timeout: 超时时间
- KeepaliveTime: 保活时间
- Middlewares: 是否启用中间件
我们现在只关注Etcd和Endpoints 这两个参数说明,rpc服务端和客户端直接是支持etcd和直连的。
2. 初始化配置
在实际开发者,我们希望尽量使用rpc来实现数据库的CURD,为了方便RPC调用,我们将之前生成的 model 移动到项目根目录。

如果不知道model怎么生成的,可以看前面的文章
在user.yaml配置中添加数据库连接和 JWT 配置,并去掉etcd配置,采用直连模式:
Name: user.rpc
ListenOn: 0.0.0.0:8080
#因为是演示项目,所以我们不需要使用ETCD,直接直连就可以了
#Etcd:
# Hosts:
# - 127.0.0.1:2379
# Key: user.rpc#为RPC添加 auth和数据连接
JwtAuth:AccessSecret: "sss12345678" # AccessSecret的值要是8位以上的字符串AccessExpire: 10000 #AccessExpire是过期时间,单位是秒MysqlDB:# 数据库需要替换成你实际的地址、账号、密码和数据库DbSource: "root:root@tcp(127.0.0.1:33069)/test_zero?charset=utf8mb4&parseTime=True&loc=Local"
接着在config.go文件中添加字段:
type Config struct {zrpc.RpcServerConfJwtAuth struct {AccessSecret stringAccessExpire int64}MysqlDB struct {DbSource string `json:"dbSource"`}
}
在servicecontext.go文件中注册数据模型,
type ServiceContext struct {Config config.ConfigUserModel model.UsersModel //配置model
}func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config: c,// 用数据库连接初始化modelUserModel: model.NewUsersModel(sqlx.NewMysql(c.MysqlDB.DbSource)),}
}
到这你会发现,rpc用法基本上和原来的api服务一样。
3. 实现业务逻辑
现在我们来实现业务逻辑,这里我只演示登录业务,因为代码基本上和之前的API项目没啥区别,打开loginlogic.go:
func (l *LoginLogic) Login(in *pb.LoginReq) (*pb.LoginResp, error) {// todo: add your logic here and delete this lineuserModel := l.svcCtx.UserModel//在api中 是req.Username 现在修改成 in.Usernameuser, err := userModel.FindOneByUsername(l.ctx, in.Username)if err != nil && err != model.ErrNotFound {return nil, errors.New(0, "数据库连接失败")}//从配置文件中获取secret 、secretsecret := l.svcCtx.Config.JwtAuth.AccessSecretexpire := l.svcCtx.Config.JwtAuth.AccessExpire//生成jwt tokentoken, err := getJwtToken(secret, time.Now().Unix(), expire, in.Username)if err != nil {return nil, errors.New(4, "token生成失败")}//查询username判断是否有数据if user != nil {//如果有数据,密码是否和数据库匹配//在api中 是req.Password 现在修改成 in.Password if in.Password == user.Password {return &pb.LoginResp{Token: "Bearer " + token, //开头添加Bearer}, nil} else {return nil, errors.New(5, "密码错误")}} else {return nil, errors.New(6, "用户未注册")}
}
4. 测试RPC服务
由于 RPC 不能像 REST API 那样直接使用 Postman的http 或 cURL 进行测试,我们需要使用 grpcurl 工具,先去网站中下载好工具,下载完成后,需要配置环境变量或者直接放在GOPATH的bin目录下即可。
下载地址:https://github.com/fullstorydev/grpcurl
grpcurl的使用方法你们可以去看下官方文档,我就不过多介绍了。
为了演示直观一点,我使用Postman进行测试,首先新建一个请求,然后把http 切换成gRPC

我们先选择对应的proto文件 ,然后输入服务地址

选好proto文件后,会自动弹出服务的方法,我们选择Login

最后输入服务地址和请求参数,invoke 以测试服务。:

三、实现RPC客户端(在API中使用)
现在我们切换到API的项目中,刚刚我们实现了RPC的服务端,现在我们需要实现RPC的客户端,也就是在API中实现RPC的调用。
1.初始化配置
首先我们需要在API中配置RPC的链接 ,打开user-api.yaml ,添加字段:
Name: user-api
Host: 0.0.0.0
Port: 8889UserRpcConf:Endpoints:- 127.0.0.1:8080
服务端使用的直连,所以客户端我们也使用Endpoints进行直连,因为我们现在使用rpc对model进行操作,所以需要删除关于数据库和Auth 认证相关的字段.
接着修改,config,go文件:
type Config struct {rest.RestConf// 添加prc链接UserRpcConf zrpc.RpcClientConf
}
最后修改servicecontext.go文件,把rpc服务注册到上下文:
type ServiceContext struct {Config config.ConfigUserRpc user.User //添加user服务
}func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config: c,// 初始化user服务UserRpc: user.NewUser(zrpc.MustNewClient(c.UserRpcConf)),}
}
2. 调用RPC服务
我们在loginlogic.go中调用 RPC 登录服务:
import (/*....省略其他包*/userRpc "newTest/newrpc/user" //导入userRPC服务,设置别名避免冲突// 为了避免服务名冲突,应该在proto文件就考虑好服务名的设置
)func (l *LoginLogic) Login(req *types.LoginRequest) (resp *types.LoginResponse, err error) {// todo: add your logic here and delete this line//从服务上下文获取UserRpc的login服务loginResp, err := l.svcCtx.UserRpc.Login(l.ctx, &userRpc.LoginReq{Username: req.Username, //从请求中获取usernamePassword: req.Password, //从请求中获取Password})if err != nil {return nil, errors.New(13, "登录rpc链接错误")}return &types.LoginResponse{Token: loginResp.Token,}, nil
}
通过代码你可以发现,go-zero调用RPC服务就是这么简单,像调用本地服务一样。
3.测试RPC调用
启动 user RPC 和 user API 的服务,进行测试:

四、使用etcd
如何让服务快速并透明地加入计算集群,并确保集群中的所有机器都能迅速找到共享的配置信息,同时构建一个高可用、安全、易于部署且响应迅速的服务集群,都是待解决的挑战。etcd 作为一种工具,为解决这些问题提供了有效的解决方案。
1.什么是 etcd?
etcd 是一个开源的分布式键值存储系统,主要用于配置共享、服务发现和数据管理,以确保各个服务之间能够高效、可靠地协调和通信。
etcd 通常使用 Raft 算法来确保强一致性和高可用性,这使它非常适合存储和管理配置信息、服务注册信息以及其他关键数据。
etcd 的主要特点:
-
强一致性:
- etcd 使用 Raft 共识算法,确保数据的一致性和高可靠性,特别是在节点故障或网络分区的情况下。
-
高可用性:
- etcd 能够根据选定的副本数进行扩展,并能够承受部分节点的故障,而不会影响整体服务的可用性。
-
简洁的 API:
- etcd 提供简单的 HTTP/gRPC 接口,允许用户轻松存取和管理数据。
-
支持 Watch 功能:
- 用户可以订阅/观察特定键的更改,这使得应用程序能够根据配置变化做出实时反应。
-
版本控制:
- etcd 自动为每个键生成版本号,用户可以方便地访问和回滚到特定版本的配置。
-
轻松集成:
- etcd 在云原生应用程序和微服务架构中广泛使用,特别是 Kubernetes 作为其核心组件。
2.为什么使用 etcd?
使用 etcd 的原因主要包括以下几点:
-
配置管理:
- 在分布式系统中,服务的配置通常需要在多个节点之间共享和一致。etcd 允许你集中存储所有配置,并在节点之间保持一致性。
-
服务发现:
- 微服务架构中,应该能够快速发现和连接到可用的服务实例。etcd 提供服务注册和发现功能,使得服务可以动态注册和注销。
-
高可用性和容错性:
- etcd 设计上考虑了高可用性和节点故障容错。当某些节点发生故障时,系统可以通过其他节点继续提供服务,从而避免单点故障。
-
强一致性保障:
- 尽管分布式系统的拓扑结构可能变化,但是 etcd 确保了一致性,使得在任何时间点读取的数据都是最新的,适合管理关键配置数据。
-
实时监控与通知:
- 使用 etcd 的 Watch 功能,可以在配置更改时获得实时通知,这对于动态更新配置非常有用。
3. 在docker中部署etcd
我们使用docke部署etcd ,创建etcd.yaml,把下面的内容保存到改文件上:
ersion: "3.5"
services:Etcd:container_name: etcd3-go-zeroimage: bitnami/etcd:3.5.6deploy:replicas: 1restart_policy:condition: on-failureenvironment:- ALLOW_NONE_AUTHENTICATION=yes- ETCD_SNAPSHOT_COUNT=10000- ETCD_QUOTA_BACKEND_BYTES=6442450944privileged: truevolumes:- ./volumes/etcd/data:/bitnami/etcd/dataports:- 2379:2379- 2380:2380
然后使用docker-compose 拉取仓库:
docker-compose -f docker-compose-etcd.yml up -d
4.使用etcd
server端
在 user.yaml 中取消 etсd 的注释并配置:
Name: user.rpc
ListenOn: 0.0.0.0:8080
# 取消etcd的注释,重新启用
Etcd:Hosts:- 127.0.0.1:2379Key: user.rpc
client端
在 user-api.yaml 中修改 RPC 配置,使用 etcd 进行服务发现:
Name: user-api
Host: 0.0.0.0
Port: 8889#取消Endpoints直连,使用etcd
UserRpcConf:#Endpoints:# - 127.0.0.1:8080Etcd:Hosts:- 127.0.0.1:2379Key: user.rpc #和server的key要一致
注意 server和client的 key要一致
相关文章:
go-zero(七) RPC服务和ETCD
go-zero 实现 RPC 服务 在实际的开发中,我们是通过RPC来传递数据的,下面我将通过一个简单的示例,说明如何使用go-zero框架和 Protocol Buffers 定义 RPC 服务。 一、生成 RPC项目 在这个教程中,我们根据user.api文件࿰…...
Jenkins + gitee 自动触发项目拉取部署(Webhook配置)
目录 前言 Generic Webhook Trigger 插件 下载插件 编辑 配置WebHook 生成tocken 总结 前言 前文简单介绍了Jenkins环境搭建,本文主要来介绍一下如何使用 WebHook 触发自动拉取构建项目; Generic Webhook Trigger 插件 实现代码推送后,触…...
043 商品详情
文章目录 详情页数据表结构voSkuItemVo.javaSkuItemSaleAttrVo.javaAttrValueAndSkuIdVo.javaSpuAttrGroupVo.javaGroupAttrParamVo.java pom.xmlSkuSaleAttrValueDao.xmlSkuSaleAttrValueDao.javaAttrGroupDao.xmlAttrGroupServiceImpl.javaSkuInfoServiceImpl.javaSkuSaleAtt…...
【人工智能】Python与Scikit-learn的模型选择与调参:用GridSearchCV和RandomizedSearchCV提升模型性能
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在机器学习建模过程中,模型的表现往往取决于参数的选择与优化。Scikit-learn提供了便捷的工具GridSearchCV和RandomizedSearchCV,帮助我们在参数空间中搜索最佳组合以提升模型表现。本文将从理论和实践两个角度…...
深入探讨 Puppeteer 如何使用 X 和 Y 坐标实现鼠标移动
背景介绍 现代爬虫技术中,模拟人类行为已成为绕过反爬虫系统的关键策略之一。无论是模拟用户点击、滚动,还是鼠标的轨迹移动,都可以为爬虫脚本带来更高的“伪装性”。在众多的自动化工具中,Puppeteer作为一个无头浏览器控制库&am…...
<OS 有关> ubuntu 24 不同版本介绍 安装 Vmware tools
原因 想用 apt-get download 存到本地 / NAS上,减少网络流浪。 看到 VMware 上的确实有 ubuntu,只是版本是16。 ubuntu 版本比较:LTS vs RR LTS: Long-Term Support 长周期支持, 一般每 2 年更新,会更可靠与更稳定…...
C#调用JAVA
参考教程:使用IKVMC转换Jar为dll动态库(含idea打包jar方法)-CSDN博客 已经实践过,好使。...
JavaEE-多线程基础知识
文章目录 前言与回顾创建一个多线程线程的创建以及运行机制简述step1: 继承Thread类step2: 实现Runable接口step3: 基于step1使用匿名内部类step4: 基于step2使用匿名内部类step5: 基于step4使用lambda表达式(推荐) Thread的常见方法关于jconsole监视线程的工具构造方法解析获取…...
Pulid:pure and lightning id customization via contrastive alignment
1.introduction 基于微调的方案,对每个id进行定制需要花费数十分钟。另一项研究则放弃了对每个id进行微调,而是选择在一个庞大的肖像数据集上预训练一个id适配器。这些方法通常利用编码器例如clip来提取id特征,提取的特征随后以特定方式例如嵌入到cross attention集成到基础…...
什么是GraphQL,有什么特点
什么是GraphQL? GraphQL 是一种用于 API(应用程序编程接口)的查询语言,由 Facebook 在 2012 年开发,并于 2015 年开源。它提供了一种更高效、强大的方式来获取和操作数据,与传统的 RESTful API 相比&#…...
Java项目-基于SpringBoot+vue的租房网站设计与实现
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
1.实验目的 熟悉了解掌握SQL Server软件的基本操作与使用方法,以及通过理论课学习与实验参考书的帮助,熟练掌握使用T-SQL语句和交互式方法对数据表进行插入数据、修改数据、删除数据等等的操作;作为后续实验的基础,根据实验要求重…...
【大数据学习 | Spark】RDD的概念与Spark任务的执行流程
1. RDD的设计背景 在实际应用中,存在许多迭代式计算,这些应用场景的共同之处是,不同计算阶段之间会重用中间结果,即一个阶段的输出结果会作为下一个阶段的输入。但是,目前的MapReduce框架都是把中间结果写入到HDFS中&…...
ruoyi框架完成分库分表,按月自动建表功能
前提 这个分库分表功能,按月自动建表,做的比较久了,还没上线,是在ruoyi框架内做的,踩了不少坑,但是已经实现了,就分享一下代码吧 参考 先分享一些参考文章 【若依系列】集成ShardingSphere S…...
Antd中的布局组件
文章目录 一、Layout二、Menu三、Grid栅格 布局组件涉及项目框架的搭建,往往被忽略和低关注,毕竟不是经常用到,但是在调整项目结构的时候往往又需要重新设计布局,所以有必要提前归纳分析; 一、Layout Layout导出Sider,…...
一文详解kafka知识点
目录 1、kafka定义 2、消息队列 2.1、产品选择 2.2、应用场景 2.3、消息队列的两种模式 3、kafka架构 4、kafka生产者 4.1、kafka生产者原理 4.2、kafka生产者异步发送 4.3、同步发送 4.4、分区 4.4.1、kafka分区好处 4.4.2、分区策略 4.4.3、自定义分区 4.5、生成吞…...
C语言基础学习:抽象数据类型(ADT)
基础概念 抽象数据类型(ADT)是一种数据类型,它定义了一组数据以及可以在这组数据上执行的操作,但隐藏了数据的具体存储方式和实现细节。在C语言中,抽象数据类型(ADT)是一种非常重要的概念&…...
提升性能测试效率与准确性:深入解析JMeter中的各类定时器
在软件性能测试领域,Apache JMeter是一款广泛使用的开源工具,它允许开发者模拟大量用户对应用程序进行并发访问,从而评估系统的性能和稳定性。在进行性能测试时,合理地设置请求之间的延迟时间对于模拟真实用户行为、避免服务器过载…...
施密特正交化与单位化的情形
在考研数学的线性代数部分,施密特正交化和单位化是两种不同的处理向量的方法,它们在特定的情况下被使用。以下是详细说明: 施密特正交化的应用场景 施密特正交化(Gram-Schmidt Orthogonalization)是一种从线性无关向…...
ROS机器视觉入门:从基础到人脸识别与目标检测
前言 从本文开始,我们将开始学习ROS机器视觉处理,刚开始先学习一部分外围的知识,为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。我采用的笔记本是联想拯救者游戏本,系统采用Ubuntu20.04,ROS采用noetic。 颜…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
