当前位置: 首页 > news >正文

18 | 实现简洁架构的 Handler 层

提示:

  • 所有体系课见专栏:Go 项目开发极速入门实战课;
  • 欢迎加入 云原生 AI 实战 星球,12+ 高质量体系课、20+ 高质量实战项目助你在 AI 时代建立技术竞争力(聚焦于 Go、云原生、AI Infra);
  • 本节课最终源码位于 fastgo 项目的 feature/s14 分支;
  • 更详细的课程版本见:Go 项目开发中级实战课:27 | 业务实现(4):实现 Handler 层代码

fastgo 三层简洁架构开发的最后一步便是开发 Handler 层代码。Handler 层代码的实现思路和 Biz 层、Store 层保持一致。

Handler 实现

要实现 Handler,主要分为以下几步:

  1. 实现创建 Handler 层实例的方法;
  2. 实现用户相关 Handler 方法;
  3. 对请求参数进行校验;
  4. 初始化 Handler。

步骤 1:实现创建 Handler 层实例的方法

HTTP API 接口最终的逻辑是由 Handler 方法来实现的。所以,需要先实现 Handler 方法。

fastgo 项目的 Handler 层代码位于 internal/apiserver/handler/ 目录中。新建一个 Handler 结构体,该结构体包含了 fg-apiserver 的路由函数。代码位于 internal/apiserver/handler/handler.go 文件中,内容如下:

package handlerimport ("github.com/onexstack/fastgo/internal/apiserver/biz"
)// Handler 处理博客模块的请求.
type Handler struct {biz biz.IBiz
}// NewHandler 创建新的 Handler 实例.
func NewHandler(biz biz.IBiz) *Handler {return &Handler{biz: biz,}
}

Handler 结构体中包含了 Biz 层的 IBiz 接口,IBiz 接口中包含的方法用来执行具体的业务逻辑。:

步骤 2: 实现用户相关 Handler 方法

internal/apiserver/handler/user.go 文件中包含了用户相关的 Handler 方法。这些 Handler 方法的实现逻辑保持一致。实现逻辑如下:

画板

这里,我介绍下 CreateUser 路由方法的实现,其他路由实现方法类似。CreateUser 路由方法代码如下:

// CreateUser 创建新用户.
func (h *Handler) CreateUser(c *gin.Context) {slog.Info("Create user function called")var rq v1.CreateUserRequestif err := c.ShouldBindJSON(&rq); err != nil {core.WriteResponse(c, errorsx.ErrBind, nil)return}if err := validation.ValidateCreateUserRequest(c.Request.Context(), &rq); err != nil {core.WriteResponse(c, errorsx.ErrInvalidArgument.WithMessage(err.Error()), nil)return}resp, err := h.biz.UserV1().Create(c.Request.Context(), &rq)if err != nil {core.WriteResponse(c, err, nil)return}core.WriteResponse(c, nil, resp)
}

首先调用 c.ShouldBindJSON 方法将请求中的参数解析到 v1.CreateUserRequest 类型的变量 rq 中。如果解析失败,返回 errorsx.ErrBind 类型的自定义错误。

接着,调用 validation.ValidateCreateUserRequest 函数,对请求参数进行校验。为了统一管理请求参数的校验方法,提高代码可维护性。将校验方法统一放在 validation(位于 internal/apiserver/pkg/validation 目录中)。如果校验失败,返回 errorsx.ErrInvalidArgument 类型的自定义错误。这里要注意,传递的 context 是 c.Request.Context(),而不是 *gin.Context 类型的变量 c。因为 c中缺少了一些 HTTP 请求上下文信息。

接着,调用 Biz 层的方法 h.biz.UserV1().Create 执行具体的业务逻辑。

gin.Context 结构体类型提供了以下方法,分别用来绑定不同位置的请求参数到结构体:

  • ShouldBindJSON
  • ShouldBindUri:将请求中的路径参数绑定到 Go 结构体中的对应字段上,这些字段跟路径参数的映射关系,是通过 Go 结构体字段的 uri 标签来映射的;
  • XXXX:

步骤 3:对请求参数进行校验

首先创建一个校验类型的结构体 Validator,代码位于 internal/apiserver/pkg/validation/validation.go 文件中,内容如下:

// Validator 是验证逻辑的实现结构体.
type Validator struct {// 有些复杂的验证逻辑,可能需要直接查询数据库// 这里只是一个举例,如果验证时,有其他依赖的客户端/服务/资源等,// 都可以一并注入进来store store.IStore
}// NewValidator 创建一个新的 Validator 实例.
func NewValidator(store store.IStore) *Validator {return &Validator{store: store}
}

Validator 结构体中,可以添加校验逻辑中依赖的依赖项。例如 store.IStore 类型的实例,第三方微服务客户端等。以此实现更加复杂的校验逻辑。

ValidateCreateUserRequest 方法实现如下:

func (v *Validator) ValidateCreateUserRequest(ctx context.Context, rq *v1.CreateUserRequest) error {// Validate usernameif rq.Username == "" {return errors.New("Username cannot be empty")}if len(rq.Username) < 4 || len(rq.Username) > 32 {return errors.New("Username must be between 4 and 32 characters")}// Username can only contain letters, numbers, and underscoresusernameRegex := regexp.MustCompile(`^[a-zA-Z0-9_]+$`)if !usernameRegex.MatchString(rq.Username) {return errors.New("Username can only contain letters, numbers, and underscores")}// Validate passwordif rq.Password == "" {return errors.New("Password cannot be empty")}if len(rq.Password) < 8 || len(rq.Password) > 64 {return errors.New("Password must be between 8 and 64 characters")}// Validate password complexity (must contain at least one letter and one number)passwordRegex := regexp.MustCompile(`^.*(?=.*[a-zA-Z])(?=.*\d).*$`)if !passwordRegex.MatchString(rq.Password) {return errors.New("Password must contain at least one letter and one number")}// Validate nickname (if provided)if rq.Nickname != nil && *rq.Nickname != "" {if len(*rq.Nickname) > 32 {return errors.New("Nickname cannot exceed 32 characters")}}// Validate emailif rq.Email == "" {return errors.New("Email cannot be empty")}emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)if !emailRegex.MatchString(rq.Email) {return errors.New("Invalid email format")}// Validate phone numberif rq.Phone == "" {return errors.New("Phone number cannot be empty")}// Validate Chinese mainland phone number format (11 digits starting with 1)phoneRegex := regexp.MustCompile(`^1\d{10}$`)if !phoneRegex.MatchString(rq.Phone) {return errors.New("Invalid phone number format, must be 11 digits starting with 1")}return nil
}

上述校验逻辑代码比较简单,这里不再介绍。为了提高代码的可维护性,将用户相关的校验方法统一保存在 internal/apiserver/pkg/validation/user.go 文件中。user.go 文件中只实现了 v1.CreateUserRequest 请求结构体的校验逻辑。

v1.UpdateUserRequest 等其他请求结构体的校验代码实现,留个作业,由你来实现。

步骤 4:初始化 Handler

修改 internal/apiserver/server.go 文件,添加以下代码:

package apiserverimport (..."github.com/onexstack/fastgo/internal/apiserver/biz""github.com/onexstack/fastgo/internal/apiserver/handler""github.com/onexstack/fastgo/internal/apiserver/pkg/validation""github.com/onexstack/fastgo/internal/apiserver/store"...
)
...
// NewServer 根据配置创建服务器.
func (cfg *Config) NewServer() (*Server, error) {...// 初始化数据库连接db, err := cfg.MySQLOptions.NewDB()if err != nil {return nil, err}store := store.NewStore(db)cfg.InstallRESTAPI(engine, store)...
}

在 NewServer 方法中,通过调用 cfg.MySQLOptions.NewDB() 创建了一个 *gorm.DB 的实例 db,再使用 db 创建了 store.IStore 的实例 store

将路由安装代码在 cfg.InstallRESTAPI 方法中实现,这样可以使 NewServer 更加简洁,同时也便于统一维护路由设置。

cfg.InstallRESTAPI 方法实现如下:

// 注册 API 路由。路由的路径和 HTTP 方法,严格遵循 REST 规范.
func (cfg *Config) InstallRESTAPI(engine *gin.Engine, store store.IStore) {...// 创建核心业务处理器handler := handler.NewHandler(biz.NewBiz(store), validation.NewValidator(store))authMiddlewares := []gin.HandlerFunc{}// 注册 v1 版本 API 路由分组v1 := engine.Group("/v1"){// 用户相关路由userv1 := v1.Group("/users"){// 创建用户。这里要注意:创建用户是不用进行认证和授权的userv1.POST("", handler.CreateUser)userv1.PUT(":userID", handler.UpdateUser)    // 更新用户信息userv1.DELETE(":userID", handler.DeleteUser) // 删除用户userv1.GET(":userID", handler.GetUser)       // 查询用户详情userv1.GET("", handler.ListUser)             // 查询用户列表.}// 博客相关路由postv1 := v1.Group("/posts", authMiddlewares...){postv1.POST("", handler.CreatePost)       // 创建博客postv1.PUT(":postID", handler.UpdatePost) // 更新博客postv1.DELETE("", handler.DeletePost)     // 删除博客postv1.GET(":postID", handler.GetPost)    // 查询博客详情postv1.GET("", handler.ListPost)          // 查询博客列表}}
}

InstallRESTAPI 方法中,通过 handler.NewHandler 函数创建了 Handler 层的实例。并使用 Handler 的实例 handler 提供的路由方法来设置 HTTP 路由。

创建 handler 实例依赖 biz.IBiz*validation.Validator 类型的实例。上述实例分别通过 biz.NewBiz(store)validation.NewValidator(store) 函数来创建。

上述代码,使用 Gin 框架提供的各类路由注册方法注册了符合 REST 规范的 HTTP 路由。Gin 框架如何注册路由,请阅读 Gin GitHub 项目仓库的 README 文件。上述代码注册的 HTTP 路由见 下表所示。

HTTP 路由(HTTP 方法 HTTP 路径)路由描述
GET /healthz健康检查接口
POST /v1/users创建用户
PUT /v1/users/:userID更新用户信息
DELETE /v1/users/:userID删除用户
GET /v1/users/:userID获取用户信息
GET /v1/users列出所有用户
POST /v1/posts创建文章
PUT /v1/posts/:postID更新文章
DELETE /v1/posts删除文章
GET /v1/posts/:postID获取文章信息
GET /v1/posts列出所有文章

编译并测试

执行以下命令重新编译并运行 fg-apiserver:

$ ./build.sh
$ _output/fg-apiserver -c configs/fg-apiserver.yaml

打开另一个 Linux 终端,执行以下命令测试 HTTP 接口是否正常工作:

$ curl -XPOST -H'Content-Type: application/json' http://127.0.0.1:6666/v1/users  -d '{"username":"colin","password":"fastgo1234","nickname":"belm","email":"nosbelm@qq.com","phone":"1818888xxxx"}'
{"userID":"user-gxqfqn"}

上述命令创建了一个新的用户,并返回了 用户 ID user-gxqfqn

相关文章:

18 | 实现简洁架构的 Handler 层

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入 云原生 AI 实战 星球&#xff0c;12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力&#xff08;聚焦于 Go、云原生、AI Infra&#xff09;&#xff1b;本节课最终…...

谷歌Gemma 3:开启AI新纪元的强大引擎

摘要 谷歌公司今日宣布推出最新版本的人工智能模型——Gemma 3。该模型基于Gemini AI技术&#xff0c;是继一年前两款“开放”Gemma AI模型后的进一步发展。Gemma 3以其卓越性能著称&#xff0c;能够在单个GPU上运行&#xff0c;成为迄今为止最强大的AI模型之一。这一技术升级标…...

【Java项目】基于JSP的电子商城系统

【Java项目】基于JSP的电子商城系统 技术简介&#xff1a;采用JSP技术、B/S结构、MYSQL数据库等实现。 系统简介&#xff1a;该电子商城系统包括用户、医生和管理员。其主要功能包括管理员&#xff1a;个人中心、用户管理、医生管理、药品信息管理、线上诊疗管理、医生信息管理…...

双 Token 无感刷新机制在前后端分离架构中实现

在前后端分离的架构中&#xff0c;双 Token 无感刷新是一种常见的身份验证机制&#xff0c;用于在 Access Token 过期时&#xff0c;通过 Refresh Token 自动获取新的 Access Token&#xff0c;从而避免用户频繁登录。 1. 双 Token 无感刷新的核心流程 1.1 核心流程 用户登录&…...

Linux中的基本指令(下)

目录 mv指令 more指令 less指令 head指令 tail 指令 继续理解文件 重定向和追加重定向操作 理解管道 find指令 whereis 指令 bc指令 uname ‒r指令 grep 指令 关机 扩展命令 zip/unzip 指令 tar指令 关于rzsz 系统间的文件互传 接上&#xff01; mv指令 m…...

电子电气架构 --- 智能电动汽车概述

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 人生是一场骗局&#xff0c;最大的任务根本不是什么买车买房&#xff0c;也不是及时行乐&#xff0c;这就…...

Unity | 工具类:消息管理器-延迟分发

目录 一、消息管理器 二、获得新装备 三、UI面板创建 消息管理器除了简单的订阅(Subscribe)、取消订阅(Unsubscribe)操作以外&#xff0c;还需处理延迟分发(Dispatch)的情况。 &#xff08;即时处理可参考&#xff1a;Unity | 工具类-利用事件系统进行业务串通-CSDN博客&…...

医院本地化DeepSeek R1对接混合数据库技术实战方案研讨

1. 引言 Deep SEEK R1是一个医疗智能化平台,通过本地化部署实现数据的安全性和可控性,同时提供高效的计算能力。随着医疗信息化的迅速发展,各种数据源的增加使得医院面临更多复杂的挑战,包括如何处理实时监测数据、如何进行大数据环境下的复杂查询以及如何整合多模态数据等…...

GPU加速的国密SM2算法实现

目录 GPU加速的国密SM2算法实现一、前言二、国密SM2算法概述2.1 国密SM2算法背景2.2 SM2的数学基础2.3 SM2数字签名流程三、GPU加速在SM2算法中的应用3.1 高性能运算需求3.2 GPU加速优势3.3 加速实现思路四、基于Python的SM2算法实现与GPU加速4.1 算法模块设计4.2 主要数学公式…...

《UE5_C++多人TPS完整教程》学习笔记35 ——《P36 武器类(Weapon Class)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P36 武器类&#xff08;Weapon Class&#xff09;》 的学习笔记&#xff0c;该系列教学视频为计算机工程师、程序员、游戏开发者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; Stephen …...

Linux——Shell运行原理以及Linux权限

目录 1. Shell的运行原理 2. Linux中的权限问题 2.1 Linux权限的概念 2.1.1 如何实现用户账号之间的切换 2.1.2 如何将普通用户添加到信任列表中 2.1.3 如何仅提升当前指令的权限 2.2 Linux权限管理 2.2.1 文件访问者的分类&#xff08;人&#xff09; 2.2.2 文件类型…...

SpringBoot注解驱动CRUD工具:spring-avue-plus

项目背景 作为一个后端小伙伴&#xff0c;最大的痛点就是写完的接口需要拥有一些可视化的页面去承载这些功能使用【如果是只给后端那么swagger也足够了&#xff0c;非后端有点呛】如果有专业前端去弄确实也快&#xff0c;但是小公司呀~~~ 学呗~妈呀&#xff0c;现在的前端也挺…...

Redis 数据持久化之AOF

AOF&#xff08;Append Only File&#xff09; 以日志的形式来记录每个写操作&#xff0c;将Redis执行过的所有写指令记录下来&#xff08;读操作不记录&#xff09;&#xff0c;只许追加文件但不可以改写文件&#xff0c;redis启动之初会读取该文件重新构建数据&#xff0c;换…...

API调试工具的无解困境:白名单、动态IP与平台设计问题

引言 你是否曾经在开发中遇到过这样的尴尬情形&#xff1a;你打开了平台的API调试工具&#xff0c;准备一番操作&#xff0c;结果却发现根本无法连接到平台&#xff1f;别急&#xff0c;问题出在调试工具本身。今天我们要吐槽的就是那些神奇的开放平台API调试工具&#xff0c;…...

git commit messege 模板设置 (规范化管理git)

配置方法 git config --global core.editor vim &#xff08;设置 Git 的默认编辑器为 Vim&#xff09;在用户根目录下&#xff08;~&#xff09;&#xff0c;创建一个.git_commit_msg文件&#xff0c;然后把下面的内容拷贝到文件中并保存。 [version][模块][类型]{解决xxx问题…...

串口通信ASCII码转16进制及C#串口编程完整源码下载

在工业自动化、嵌入式系统及物联网以行业中&#xff0c;串口编程非常重要。 串口编程&#xff0c;重点在于串口数据通信和数据处理。 在C#中&#xff0c;System.IO.Ports命名空间提供了SerialPort类&#xff0c;用于实现串口通信。 串口程序的开发主要包括以下几点 1.引用命…...

第十一届蓝桥杯单片机国赛

什么&#xff1f;4T模拟赛和省赛做起来轻轻松松&#xff1f;不妨来挑战一下第十一届国赛&#xff0c;这一届的国赛居然没考超声波、串口通信&#xff01;只要你正确地理解了题目的意思&#xff0c;规避出题人挖的坑&#xff0c;拿个国一轻轻松松。 附件&#xff1a;第十一届蓝桥…...

Ateme在云端构建可扩展视频流播平台

Akamai Connected Cloud帮助Ateme客户向全球观众分发最高质量视频内容。 “付费电视运营商和内容提供商现在可以在Akamai Connected Cloud上通过高质量视频吸引观众&#xff0c;并轻松扩展。”── Ateme首席战略官Rmi Beaudouin ​ Ateme是全球领先的视频压缩和传输解决方案提…...

QT系列教程(20) Qt 项目视图便捷类

视频连接 https://www.bilibili.com/video/BV1XY41127t3/?vd_source8be9e83424c2ed2c9b2a3ed1d01385e9 Qt项目视图便捷类 Qt项目视图提供了一些便捷类&#xff0c;包括QListWidget, QTableWidget&#xff0c; QTreeWidget等。我们分别介绍这几个便捷类。 我们先创建一个Qt …...

【最后203篇系列】014 AI机器人-1

说明 终于开张了&#xff0c;我觉得AI机器人是一件真正正确&#xff0c;具有商业价值的事。 把AI机器人当成一笔生意&#xff0c;我如何做好这笔生意&#xff1f;一端是业务价值&#xff0c;另一端是技术支撑。如何构造高质量的内容和服务&#xff0c;如何确保技术的广度和深度…...

cfi网络安全 网络安全hcip

目录 RIP (路由信息协议) 算法 开销 版本 开销值的计算方式 RIPV1和RIPV2的区别 RIP的数据包 Request(请求)包 Reponse(应答)包 RIP的特征 周期更新 RIP的计时器 1&#xff0c;周期更新计时器 2&#xff0c;失效计时器 3&#xff0c;垃圾回收计时器 RIP的核心思…...

HTML 基础

一、HTML 基本结构 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>页面标题</title> </head> <body><!-- 可见内容区域 --> </body> </html><!DOCTYPE html>&#xff1a;声明…...

数据结构与算法:归并排序

目录 归并排序的基本思想 归并排序的特性总结 代码 归并排序的非递归版 归并排序的基本思想 归并排序是建立在归并操作上的一种有效的排序算法。改算法是采用分治法的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列…...

Tweak Power:全方位电脑系统优化的高效工具

在日常使用电脑时&#xff0c;系统性能的下降、垃圾文件的堆积以及硬盘的老化等问题常常困扰着用户。为了提升电脑性能、优化系统运行&#xff0c;许多人会选择系统优化工具。然而&#xff0c;国内一些系统优化软件常常因为广告过多或功能冗杂而让人望而却步。此时&#xff0c;…...

stm32中分析UART中IDLE,RXNE,TC,TXE这些标志位的作用

下面将基于 STM32 标准库&#xff0c;结合之前提到的不同应用场景&#xff0c;给出使用 TXE、TC、IDLE 和 RXNE 标志位的代码示例及分析。 1. 连续数据发送&#xff08;使用 TXE&#xff09; 应用场景 向外部设备连续发送大量数据&#xff0c;如向显示屏发送显示数据、向传感…...

代码随想录算法训练营第十天,150.逆波兰表达式求值,239.滑动窗口最大值,347.前K个高频元素

今日内容&#xff1a;150.逆波兰表达式求值&#xff0c;239.滑动窗口最大值&#xff0c;347.前K个高频元素&#xff0c;栈与队列总结 心得&#xff1a;昨天休息了一天&#xff0c;栈与队列的题都比较典型&#xff0c;之前也是恶补过堆栈的知识&#xff0c;所以做起来相对kmp好一…...

【python】Flask web框架

文章目录 一、Flask 简介二、核心组件解析2.1 路由系统2. 模板引擎 (Jinja2)2.3 表单处理与请求上下文 三、现代开发实践3.1 应用工厂模式3.2 异步处理支持 四、安全最佳实践五、性能优化策略六、扩展生态精选七、部署方案对比 一、Flask 简介 Flask 是基于 Python 的微型 Web…...

Node.js:快速启动你的第一个Web服务器

Node.js 全面入门指南 文章目录 Node.js 全面入门指南一 安装Node.js1. Windows2. MacOS/Linux 二 配置开发环境1. VSCode集成 三 第一个Node.js程序1. 创建你的第一个Node.js程序 四 使用Express框架1. 快速搭建服务器 一 安装Node.js 1. Windows 以下是Windows环境下Node.j…...

3-003:在 MySQL 中建索引时需要注意哪些事项?

在 MySQL 中创建索引时&#xff0c;需要注意以下事项&#xff0c;以确保索引高效且合理&#xff1a; 1. 选择合适的索引类型 主键索引&#xff08;PRIMARY KEY&#xff09;&#xff1a;每个表只能有一个&#xff0c;默认是聚簇索引。唯一索引&#xff08;UNIQUE&#xff09;&…...

基于WPF的雷达上位机系统开发实践

一、雷达上位机系统概述 1.1 系统功能需求 现代雷达上位机系统通常需要实现以下核心功能模块&#xff1a; 数据采集与解析 支持多种通信协议&#xff08;TCP/IP、UDP、RS422等&#xff09; 实时解析雷达原始数据&#xff08;目标距离、方位、速度、RCS等&#xff09; 典型数…...

版本号标识

Visual Studio 16 2019 是 Microsoft Visual Studio 2019 的版本号标识。具体来说&#xff1a; Visual Studio 是微软提供的一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;用于开发各种应用程序&#xff0c;如桌面软件、Web 应用、移动应用等&#xff0c;支持多种编…...

计算机考研C语言

C语言程序设计从入门到精通【2025完整版】考研复试 嵌入式 计算机二级 软考 专升本也适用_哔哩哔哩_bilibili 1、第一个C程序 helloC #include <stdio.h>int main(){printf("hehe");return 0;}每个C语言程序不管有多少行代码&#xff0c;都是从main函数开始执…...

STM32 内置的通讯协议

数据是以帧为单位发的 USART和UART的区别就是有没有同步功能 同步是两端设备有时钟连接&#xff0c;异步是没时钟连接&#xff0c;靠约定号的频率&#xff08;波特率&#xff09;接收发送数据 RTS和CTS是用来给外界发送已“可接收”或“可发送”信号的&#xff0c;一般用不到…...

QT:串口上位机

创建工程 布局UI界面 设置名称 设置数据 设置波特率 波特率默认9600 设置数据位 数据位默认8 设置停止位 设置校验位 调整串口设置、接收设置、发送设置为Group Box 修改配置 QT core gui serialport 代码详解 mianwindow.h 首先在mianwindow.h当中定义一个串口指…...

f QT测试

# 添加 Qt Test 模块&#xff0c;用于支持单元测试功能 QT testlib# 添加 Qt 的核心模块和 GUI 模块&#xff0c;这是构建 Qt 应用程序的基础模块 QT core gui# 如果 Qt 的主版本号大于 4&#xff0c;则添加 widgets 模块。 # 这是因为 Qt Widgets 模块是从 Qt 5 开始引…...

vue3在ts中动态添加DOM(1、使用render函数,2、使用tsx)

1、使用render函数和h函数 h函数创建虚拟节点&#xff08;VNode&#xff09;&#xff0c;render函数实现虚拟节点生成真实DOM元素 实现添加一个el-button按钮 <script setup lang"ts"> import { ElButton } from "element-plus"; //需要在页面中引…...

C++基础(VScode环境安装)

MinGW Distro - nuwen.net 安装完成之后我们打开刚刚的安装路径&#xff0c;找到并打开MinGW -> bin,进入bin文件夹之后点一下这里&#xff0c;右键复制路径 之后我们进入设置&#xff0c;搜索“环境变量”&#xff0c;选择“编辑系统环境变量” 按WinR,输入cmd&#xff0…...

MySQL:SQL优化实际案例解析(持续更新)

文章目录 一、MySQL&#xff1a;SQL优化1、时间格式化问题&#xff08;字符串&#xff09;2、in/inner join的问题 一、MySQL&#xff1a;SQL优化 1、时间格式化问题&#xff08;字符串&#xff09; -- 优化前 SELECT * FROM test_table WHERE date_format( begin_time, %Y-%…...

代理(Delegate)、闭包(Closure)、Notification(通知中心) 和 swift_event_bus适用场景和工作方式

在 Swift 开发中&#xff0c;在 Swift 开发中&#xff0c;代理&#xff08;Delegate&#xff09;、闭包&#xff08;Closure&#xff09;、Notification&#xff08;通知中心&#xff09; 和 swift_event_bus 主要用于 组件之间的通信&#xff0c;但它们的适用场景和工作方式有…...

力扣第585题

with t as (select *, count(tiv_2015) over(partition by tiv_2015) cnt1 , count(*) over(partition by lat,lon) cnt2 from insurance) select round(sum(tiv_2016),2) tiv_2016 from t where cnt1>1 and cnt21; 以上代码的思路&#xff1a; ①明确查询需求&#xff1a…...

C++学习——顺序表(四)

文章目录 前言一、最大连续1的个数二、差的绝对值为K的数对数目三、数组中两元素的最大乘积四、数组元素和与数字和的绝对值的差五、K个元素的最大和六、等差三元组的数目七、移除元素 前言 本文为《C学习》的第14篇文章&#xff0c;今天通过Leetcode的几道题来熟悉顺序表的大…...

java虚拟机(JVM)以及各种参数详解

Java 虚拟机&#xff08;JVM&#xff09;提供了许多参数来调整其行为和性能&#xff0c;以便更好地适应不同的应用场景。理解和使用这些参数对于优化 Java 应用程序的性能非常重要。以下是一些常用的 JVM 参数及其详细说明&#xff1a; 1. 内存管理参数 -Xms<size>&…...

Android电量与流量优化

Android电量与流量优化 一、电量优化基础 1.1 电量消耗原理 Android设备的电量消耗主要来源于以下几个方面: 屏幕显示:屏幕是耗电量最大的硬件之一,尤其是高亮度和高刷新率的屏幕。CPU处理:CPU执行计算任务时会消耗大量电量,尤其是高负载运算。网络通信:移动数据、Wi-…...

机器人运动学与动力学

在当今科技飞速发展的时代&#xff0c;机器人已逐渐渗透到我们生活的方方面面&#xff0c;从工业生产线上的高效作业&#xff0c;到医疗领域的精准辅助&#xff0c;再到家庭服务的贴心陪伴&#xff0c;机器人技术的广泛应用正深刻改变着我们的生活和工作方式。而在机器人技术的…...

【web前端开发】HTML排版标签、HTML语义化标签、常用的文本标签

1、HTML排版标签 标签名 标签含义 单/双标签 h1~h6 …...

Linux的TTY子系统(TTY框架)的重要结构体termios的`c_iflag`字段的BRKINT选项和IGNBRK选项的含义【详解串口的BREAK信号】

引言 要搞清楚结构体termios的c_iflag字段的BRKINT选项和IGNBRK选项的含义&#xff0c;首先要搞清楚BREAK信号的含义。其实当你搞清楚BREAK信号后&#xff0c;结构体termios的c_iflag字段的BRKINT选项和IGNBRK选项的含义你也就自然知道了。 1. 什么是 BREAK 信号&#xff1f;…...

YashanDB认证,YCA证书认证教程,免费证书,内含真题考试题库及答案——五分钟速成

目录 一.账号及平台注册登录流程 二.登录进行设备调试核验 三.考试&#xff08;考完获取分数&#xff09; 四.获取证书 五.题库及答案 一.账号及平台注册登录流程 1-点击这里进行账号注册&#xff08;首次学习必须先注册&#xff0c;有账号之后可以直接在2号链接登录&#…...

网络爬虫-1:发送请求+维持会话+代理设置/超时设置

1.基于get发送请求 2.基于post发送请求 3.维持会话 4.代理设置/超时设置 一.基于get发送请求 1.获取网页源码1 使用json库中的json.loads(),将json格式的字符串变为Python的字典形式 以下通过http://httpbin.org/get网址进行基本练习操作 import requests import json urlh…...

VSCode 配置优化指南:打造极致高效的前端开发环境

VSCode 配置优化指南&#xff1a;打造极致高效的前端开发环境 一、基础环境配置&#xff1a;让开发更流畅 1. 性能优化设置 // settings.json {"files.autoSave": "afterDelay", // 自动保存&#xff08;延迟1秒&#xff09;"files.exclud…...

【实战-解决方案】Webpack 打包后很多js方法报错:not defined

问题分析 在不打包的情况下&#xff0c;方法&#xff08;如 checkLoginStatus、filterSites、initProgressBar 等&#xff09;可以正常运行&#xff0c;而经过 Webpack 打包后报 is not defined 错误&#xff0c;通常有以下几个可能的原因&#xff1a; 全局变量丢失 在 Webpac…...