golang 引入swagger(iris、gin)
golang 引入swagger(iris、gin)
在开发过程中,我们不免需要调试我们的接口,但是有些接口测试工具无法根据我们的接口变化而动态变化。文档和代码是分离的。总是出现文档和代码不同步的情况。这个时候就可以在我们项目中引入swagger,方便后期维护以及他人快速上手项目
0 下载swagger
# 1 安装swagger
# 在go.mod目录所在位置执行命令
go get -u github.com/swaggo/swag/cmd/swag# 查看是否安装成功
swag -v# 如果发现报错:zsh: command not found: swag,则需要手动编译生成swag
cd $GOPATH/pkg/mod/github.com/swaggo/swag@v1.16.2/cmd/swag/
sudo go build
sudo mv swag $GOPATH/bin
# 查看是否安装成功
swag -v
1 iris引入swagger
①导入iris-contrib/swagger依赖
//安装swagger扩展,本项目使用的是iris最新版(iris/v12),因此需要安装iris-swagger/v12扩展go get -v "github.com/iris-contrib/swagger/swaggerFiles"
go get -v "github.com/iris-contrib/swagger/v12"
②添加对应swagger注解 & swag init生成docs
在项目对应文件添加swagger注解,并通过swag init生成docs
注意
:如果代码中的swagger注释有修改,需要重新执行swag init生成文档
例如:我给controller添加注解:
package controllerimport ("encoding/json""github.com/kataras/iris/v12""github.com/kataras/iris/v12/mvc""myTest/demo_home/swagger_demo/iris/model""net/http"
)type UserController struct {Ctx iris.Context
}func (u *UserController) BeforeActivation(b mvc.BeforeActivation) {b.Handle(http.MethodGet, "/getAll", "GetAllUsers")
}// GetAllUsers @Summary 获取用户信息
// @Description 获取所有用户信息
// @Tags 用户
// @Accept json
// @Produce json
// @Router /user/getAll [get]
func (u *UserController) GetAllUsers() mvc.Result {//手动模拟从数据库查询到user信息resp := new(mvc.Response)resp.ContentType = "application/json"user1 := new(model.User)user1.Name = "zhangsan"user1.Age = 20user2 := new(model.User)user2.Name = "li4"user2.Age = 28users := []model.User{*user1, *user2}marshal, _ := json.Marshal(users)resp.Content = marshalresp.Code = http.StatusOKreturn resp
}
//在项目根目录执行swag init ( 默认会找当前目录下的 main.go 文件,如果不叫 main.go 也可以-g手动指定文件位置。)
swag init # swag init -g cmd/api/api.go -o cmd/api/docs (-o指定docs生成位置)
③main.go中引入swag生成doc包
在 main.go 中导入刚才生成的 docs 包
package mainimport ("github.com/iris-contrib/swagger/v12""github.com/iris-contrib/swagger/v12/swaggerFiles""github.com/kataras/iris/v12""myTest/demo_home/swagger_demo/iris/controller"_ "myTest/demo_home/swagger_demo/iris/docs" //引入docs包
)func main() {app := iris.New()controller.InitControllers(app)config := &swagger.Config{URL: "http://localhost:8080/swagger/doc.json", //The url pointing to API definition}app.Get("/swagger/{any}", swagger.CustomWrapHandler(config, swaggerFiles.Handler))app.Listen(":8080")
}
④运行程序访问ip:port/swagger/index.html页面
运行main.go,浏览器输入:http://localhost:8080/swagger/index.html
全部代码
Github:
https://github.com/ziyifast/ziyifast-code_instruction/tree/main/swagger_demo
项目结构:
main.go
package mainimport ("github.com/iris-contrib/swagger/v12""github.com/iris-contrib/swagger/v12/swaggerFiles""github.com/kataras/iris/v12""myTest/demo_home/swagger_demo/iris/controller"_ "myTest/demo_home/swagger_demo/iris/docs" # 引入生成的docs包
)func main() {app := iris.New()controller.InitControllers(app)config := &swagger.Config{URL: "http://localhost:8080/swagger/doc.json", //The url pointing to API definition}app.Get("/swagger/{any}", swagger.CustomWrapHandler(config, swaggerFiles.Handler))app.Listen(":8080")
}
controller/controllers.go
package controllerimport ("github.com/kataras/iris/v12""github.com/kataras/iris/v12/mvc"
)func InitControllers(app *iris.Application) {myMvc := mvc.New(app.Party("/user"))myMvc.Handle(new(UserController))
}
controller/user_controller.go
package controllerimport ("encoding/json""github.com/kataras/iris/v12""github.com/kataras/iris/v12/mvc""myTest/demo_home/swagger_demo/iris/model""net/http"
)type UserController struct {Ctx iris.Context
}func (u *UserController) BeforeActivation(b mvc.BeforeActivation) {b.Handle(http.MethodGet, "/getAll", "GetAllUsers")
}// GetAllUsers @Summary 获取用户信息
// @Description 获取所有用户信息
// @Tags 用户
// @Accept json
// @Produce json
// @Router /user/getAll [get]
func (u *UserController) GetAllUsers() mvc.Result {//手动模拟从数据库查询到user信息resp := new(mvc.Response)resp.ContentType = "application/json"user1 := new(model.User)user1.Name = "zhangsan"user1.Age = 20user2 := new(model.User)user2.Name = "li4"user2.Age = 28users := []model.User{*user1, *user2}marshal, _ := json.Marshal(users)resp.Content = marshalresp.Code = http.StatusOKreturn resp
}
2 gin引入swagger
①导入swaggo/gin-swagger依赖
// 引入gin及gin-swagger依赖
go get "github.com/gin-gonic/gin"
go get "github.com/swaggo/gin-swagger/swaggerFiles"
go get "github.com/swaggo/gin-swagger"
②添加对应swagger注解 & swag init生成docs
注意
:如果代码中的swagger注释有修改,需要重新执行swag init生成文档
user_controller.go
package controllerimport (ret "myTest/demo_home/swagger_demo/gin/response""net/http""strconv""time""github.com/gin-gonic/gin"
)// Hello 测试
// @Summary 测试SayHello
// @Description 向你说Hello
// @Tags 测试
// @Accept json
// @Produce json
// @Param who query string true "人名"
// @Success 200 {string} string "{"msg": "hello lixd"}"
// @Failure 400 {string} string "{"msg": "who are you"}"
// @Router /hello [get]
func Hello(c *gin.Context) {who := c.Query("who")if who == "" {c.JSON(http.StatusBadRequest, gin.H{"msg": "who are u?"})return}c.JSON(http.StatusOK, gin.H{"msg": "hello " + who})
}type LoginReq struct {Username string `json:"username"`Password string `json:"password"`
}
type LoginResp struct {Token string `json:"token"`
}// Login 登陆
// @Summary 登陆
// @Tags 登陆注册
// @Description 登入
// @Accept json
// @Produce json
// @Param user body LoginReq true "用户名密码"
// @Success 200 {object} ret.Result{data=LoginResp} "token"
// @Failure 400 {object} ret.Result "错误提示"
// @Router /login [post]
func Login(c *gin.Context) {var m LoginReqif err := c.ShouldBind(&m); err != nil {c.JSON(http.StatusBadRequest, ret.Fail("参数错误"))return}if m.Username == "admin" && m.Password == "123456" {resp := LoginResp{Token: strconv.Itoa(int(time.Now().Unix()))}c.JSON(http.StatusOK, ret.Success(resp))return}c.JSON(http.StatusUnauthorized, ret.Fail("user or password error"))
}
③main.go中引入swag生成doc包
package mainimport ("github.com/gin-gonic/gin"ginSwagger "github.com/swaggo/gin-swagger""github.com/swaggo/gin-swagger/swaggerFiles""myTest/demo_home/swagger_demo/gin/controller"_ "myTest/demo_home/swagger_demo/gin/docs"
)var swagHandler gin.HandlerFunc// @title Swagger Example API
// @version 1.0
// @description This is a sample server.
// @termsOfService https://lixueduan.com// @contact.name lixd
// @contact.url https://lixueduan.com
// @contact.email xueduan.li@gmail.com// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html// @host localhost:8080
// @BasePath /api/v1// SwaggerUI: http://localhost:8080/swagger/index.html
func main() {e := gin.Default()v1 := e.Group("/api/v1"){v1.GET("/hello", controller.Hello)v1.POST("/login", controller.Login)}e.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))if swagHandler != nil {e.GET("/swagger/*any", swagHandler)}if err := e.Run(":8080"); err != nil {panic(err)}
}
resp.go:
// Package ret 统一返回结构
package retimport ("net/http"
)const (MsgSuccess = "success"MsgFail = "fail"
)type Result struct {Code int `json:"code"`Data interface{} `json:"data"`Msg string `json:"msg"`
}func Success(data interface{}, msg ...string) *Result {var m = MsgSuccessif len(msg) > 0 {m = msg[0]}return &Result{Code: http.StatusOK,Data: data,Msg: m,}
}func Fail(msg ...string) *Result {var m = MsgFailif len(msg) > 0 {m = msg[0]}return &Result{Code: http.StatusBadRequest,Data: "",Msg: m,}
}
④运行程序访问ip:port/swagger/index.html
http://localhost:8080/swagger/index.html
全部代码
地址:
https://github.com/ziyifast/ziyifast-code_instruction/tree/main/swagger_demo
main.go
package mainimport ("github.com/gin-gonic/gin"ginSwagger "github.com/swaggo/gin-swagger""github.com/swaggo/gin-swagger/swaggerFiles""myTest/demo_home/swagger_demo/gin/controller"_ "myTest/demo_home/swagger_demo/gin/docs"
)var swagHandler gin.HandlerFunc// @title Swagger Example API
// @version 1.0
// @description This is a sample server.// @contact.name lixd
// @contact.name ziyi
// @contact.url https://github.com/ziyifast/ziyifast-code_instruction/tree/main/swagger_demo// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html// @host localhost:8080
// @BasePath /api/v1// SwaggerUI: http://localhost:8080/swagger/index.html
func main() {e := gin.Default()v1 := e.Group("/api/v1"){v1.GET("/hello", controller.Hello)v1.POST("/login", controller.Login)}e.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))if swagHandler != nil {e.GET("/swagger/*any", swagHandler)}if err := e.Run(":8080"); err != nil {panic(err)}
}
controller/user_controller.go
package controllerimport (ret "myTest/demo_home/swagger_demo/gin/response""net/http""strconv""time""github.com/gin-gonic/gin"
)// Hello 测试
// @Summary 测试SayHello
// @Description 向你说Hello
// @Tags 测试
// @Accept json
// @Produce json
// @Param who query string true "人名"
// @Success 200 {string} string "{"msg": "hello lixd"}"
// @Failure 400 {string} string "{"msg": "who are you"}"
// @Router /hello [get]
func Hello(c *gin.Context) {who := c.Query("who")if who == "" {c.JSON(http.StatusBadRequest, gin.H{"msg": "who are u?"})return}c.JSON(http.StatusOK, gin.H{"msg": "hello " + who})
}type LoginReq struct {Username string `json:"username"`Password string `json:"password"`
}
type LoginResp struct {Token string `json:"token"`
}// Login 登陆
// @Summary 登陆
// @Tags 登陆注册
// @Description 登入
// @Accept json
// @Produce json
// @Param user body LoginReq true "用户名密码"
// @Success 200 {object} ret.Result{data=LoginResp} "token"
// @Failure 400 {object} ret.Result "错误提示"
// @Router /login [post]
func Login(c *gin.Context) {var m LoginReqif err := c.ShouldBind(&m); err != nil {c.JSON(http.StatusBadRequest, ret.Fail("参数错误"))return}if m.Username == "admin" && m.Password == "123456" {resp := LoginResp{Token: strconv.Itoa(int(time.Now().Unix()))}c.JSON(http.StatusOK, ret.Success(resp))return}c.JSON(http.StatusUnauthorized, ret.Fail("user or password error"))
}
response/response.go
// Package ret 统一返回结构
package retimport ("net/http"
)const (MsgSuccess = "success"MsgFail = "fail"
)type Result struct {Code int `json:"code"`Data interface{} `json:"data"`Msg string `json:"msg"`
}func Success(data interface{}, msg ...string) *Result {var m = MsgSuccessif len(msg) > 0 {m = msg[0]}return &Result{Code: http.StatusOK,Data: data,Msg: m,}
}func Fail(msg ...string) *Result {var m = MsgFailif len(msg) > 0 {m = msg[0]}return &Result{Code: http.StatusBadRequest,Data: "",Msg: m,}
}
3 注解
3.1 swagger主文件注解-通用API信息
注释 | 说明 | 示例 |
---|---|---|
title | 必填 应用程序的名称 | // @title Swagger Example API |
version | 必填 提供应用程序API的版本。 | // @version 1.0 |
description | 应用程序的简短描述。 | // @description This is a sample server celler server. |
tag.name | 标签的名称。 | // @tag.name This is the name of the tag |
tag.description | 标签的描述。 | // @tag.description Cool Description |
tag.docs.url | 标签的外部文档的URL。 | // @tag.docs.url https://example.com |
tag.docs.description | 标签的外部文档说明。 | // @tag.docs.description Best example documentation |
termsOfService | API的服务条款。 | // @termsOfService http://swagger.io/terms/ |
contact.name | 公开的API的联系信息。 | // @contact.name API Support |
contact.url | 联系信息的URL。 必须采用网址格式。 | // @contact.url |
contact.email | 联系人/组织的电子邮件地址。 必须采用电子邮件地址的格式。 | // @contact.email support@swagger.io |
license.name | 必填 用于API的许可证名称。 | // @license.name Apache 2.0 |
license.url | 用于API的许可证的URL。 必须采用网址格式。 | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
host | 运行API的主机(主机名或IP地址)。 | // @host localhost:8080 |
BasePath | 运行API的基本路径。 | // @BasePath /api/v1 |
accept | API 可以使用的 MIME 类型列表。 请注意,Accept 仅影响具有请求正文的操作,例如 POST、PUT 和 PATCH。 值必须如“Mime类型”中所述。 | // @accept json |
produce | API可以生成的MIME类型的列表。值必须如“Mime类型”中所述。 | // @produce json |
query.collection.format | 请求URI query里数组参数的默认格式:csv,multi,pipes,tsv,ssv。 如果未设置,则默认为csv。 | // @query.collection.format multi |
schemes | 用空格分隔的请求的传输协议。 | // @schemes http https |
x-name | 扩展的键必须以x-开头,并且只能使用json值 | // @x-example-key {“key”: “value”} |
通用api信息,部分可以是在docs包里生成的,可以在项目启动的时候,或者在注册swagger路由的时候,修改掉部分信息,或者动态注入部分不固定的值,比如项目的基础路径:BasePath
func NewRouter() *gin.Engine {gin.SetMode("debug")engine := gin.New()docs.SwaggerInfo.BasePath = "/api/v2"engine.POST("/", v1.GetWord)engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))engine.GET("/log/:id", client.ReadLokiLog)return engine
}
3.2 单个API样例
注释 | 样例 |
---|---|
description | 操作行为的详细说明。 |
description.markdown | 应用程序的简短描述。该描述将从名为endpointname.md的文件中读取。 |
id | 用于标识操作的唯一字符串。在所有API操作中必须唯一。 |
tags | 每个API操作的标签列表,以逗号分隔。 |
summary | 该操作的简短摘要。 |
accept | API 可以使用的 MIME 类型列表。 请注意,Accept 仅影响具有请求正文的操作,例如 POST、PUT 和 PATCH。 值必须如“Mime类型”中所述。 |
produce | API可以生成的MIME类型的列表。值必须如“Mime类型”中所述。 |
param | 用空格分隔的参数。param name,param type,data type,is mandatory?,comment attribute(optional) |
security | 每个API操作的安全性。 |
success | 以空格分隔的成功响应。return code,{param type},data type,comment |
failure | 以空格分隔的故障响应。return code,{param type},data type,comment |
response | 与success、failure作用相同 |
header | 以空格分隔的头字段。 return code,{param type},data type,comment |
router | 以空格分隔的路径定义。 path,[httpMethod] |
x-name | 扩展字段必须以x-开头,并且只能使用json值。 |
// @Summary 测试swagger
// @Tags test
// @version 1.0
// @Success 200 object FinalResult{data=v1.Application} 成功后返回值
// @Failure 500 object FinalResult 添加失败
// @Router / [get]
func GetWord(ctx *gin.Context) {application := &Application{Id: 1}err := ctx.BindJSON(application)if err != nil {ctx.JSON(500, "")}ctx.JSON(200, SuccessResult(application))
}
summary 是这个api的名字,可以显示在yapi的名称
tag 是这个api所在的分组
success 支持组合嵌套
param 说明了api需要的请求参数
param的类型支持:
- query
- path
- header
- body
- formData
如果我们需要给字段添加注释,直接在字段后面添加即可
直接在参数属性后面增加注释,也可以指定参数的名称说明描述
type Application struct {Id int `json:"id" example:"2"` // 环境IDName string `json:"name" example:"环境一"` // Name 环境名称
}
忽略某个字段:
type Account struct {ID string `json:"id"`Name string `json:"name"`Ignored int `swaggerignore:"true"`
}
注意
:如果代码中的swagger注释有修改,需要重新执行swag init生成文档
参考:https://blog.csdn.net/qq_38371367/article/details/123005909
bug
1 unknown field LeftDelim in struct literal of type "github.com/swaggo/swag
注意:
如果遇到报错:
docs/docs.go:30:2: unknown field LeftDelim in struct literal of type “github.com/swaggo/swag”.Spec
可能是由于swag版本过低导致,升级版本即可:go get -u -v github.com/swaggo/swag/cmd/swag
2 添加了swag 注解,访问页面成功,但没有对应的方法
重新执行
swag init
,然后重新启动项目
- 如果代码中的swagger注解有修改,需要重新执行swag init生成文档
相关文章:

golang 引入swagger(iris、gin)
golang 引入swagger(iris、gin) 在开发过程中,我们不免需要调试我们的接口,但是有些接口测试工具无法根据我们的接口变化而动态变化。文档和代码是分离的。总是出现文档和代码不同步的情况。这个时候就可以在我们项目中引入swagge…...

Java开发IntelliJ IDEA2023
IntelliJ IDEA 2023是一款强大的集成开发环境(IDE),专为Java开发人员设计。它提供了许多特色功能,帮助开发人员更高效地编写、测试和调试Java应用程序。以下是一些IntelliJ IDEA 2023的特色功能: 智能代码编辑器&…...
LeetCode LCP 30.魔塔游戏:贪心(优先队列)
【LetMeFly】LCP 30.魔塔游戏:贪心(优先队列) 力扣题目链接:https://leetcode.cn/problems/p0NxJO/ 小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于…...
Oracle的权限
通过用户登录plsql工具后,如果在创建视图(或其他对象)时,没有指明视图或对象的用户,该视图或对象将直接创建在当前登录用户下。 GRANT SELECT ON user2.table1 TO user1;//将用户2的表1的select权限给用户1 GRANT ALL ON user2.table1 TO u…...

20240206三次握手四次挥手
TCP和UDP异同点 相同点:同属于传输层的协议 不同点: TCP ----> 稳定 1> 提供面向连接的,可靠的数据传输服务 2> 传输过程中,数据无误、数据无丢失、数据无失序、数据无重复 1、TCP会给每个数据包编上编号ÿ…...

Navicat的使用教程,操作详解
这篇文章主要针对mysql数据库。 在使用Navicat之前,首先要确保你在本地已经安装好了,mysql数据库,安装教程可以参考我的另一篇博文 在windows平台上mysql的安装教程-CSDN博客 1.Navicat连接你的数据库 连接名,随便写,…...

Git―基本操作
Git ⛅认识 Git⛅安装 GitCentos(7.6)Ubuntu ⛅Git―基本操作创建本地仓库🍂配置本地仓库🍂工作区, 暂存区, 版本库🍂版本库工作区 添加文件🍂查看文件🍂修改文件🍂版本回退🍂☃️案例 撤销修改…...

【PostgreSQL内核学习(二十六) —— (共享数据缓冲区)】
共享数据缓冲区 概述共享数据缓冲区管理共享缓冲区管理的核心功能包括: 共享数据缓冲区的组织结构初始化共享缓冲池BufferDesc 结构体InitBufferPool 函数 如何确定请求的数据页面是否在缓冲区中?BufferTag 结构体RelFileNode 结构体ForkNumber 结构体Re…...

word调整论文格式的记录
页眉的分章显示内容 效果: 步骤: 确保“显示/隐藏的标记”符号打开点亮 前提是章节前面有“分节符(下一页)”,没有则添加,在菜单栏“布局”——》“下一页” 添加页眉,双击页眉,选…...
android.MediaMuxer时间裁剪
使用MediaMuxer裁剪视频_安卓muxer 裁剪视频画布-CSDN博客 关键步骤 mediaExtractor.seekTo(beginTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);long presentTimeUs mediaExtractor.getSampleTime(); if (presentTimeUs > endTime)break; 功能代码 VideoView videoVie…...

【蓝桥杯选拔赛真题91】Scratch筛选数据 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析
目录 scratch筛选数据 一、题目要求 编程实现 二、案例分析 1、角色分析...
英语学习——16组英语常用短语
第1组:look look at 看 look for 寻找 look up 查阅,向上看 look out 向外看,小心 look after 照顾 look like 看起来像 look through 浏览 look into 向里看 look around 环顾四周 look forward to 期盼 look ahead 向前看 Look…...

unity 增加系统时间显示、FPS帧率、ms延迟
代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;using UnityEngine;public class Frame : MonoBehaviour {// 记录帧数private int _frame;// 上一次计算帧率的时间private float _lastTime;// 平…...

【Python基础】文件详解(文件基础、csv文件、时间处理、目录处理、excel文件、jsonpicke、ini配置文件)
文章目录 (一)文件详解1 快速入门文件操作1.1 快速实现文件读取1.2 快速实现文件写入 2 文件打开方式详解2.1 open方法2.2 打开方式2.3 文件读写操作2.3.1 基本读写2.3.2 读写方式打开2.3.3 实现重复读取 3 文件编码问题4 文件读写方法4.1 文件读取方式4…...

[UI5 常用控件] 05.FlexBox, VBox,HBox,HorizontalLayout,VerticalLayout
文章目录 前言1. FlexBox布局控件1.1 alignItems 对齐模式1.2 justifyContent 对齐模式1.3 Direction1.4 Sort1.5 Render Type1.6 嵌套使用1.7 组件等高显示 2. HBox,VBox3. HorizontalLayout,VerticalLayout 前言 本章节记录常用控件FlexBox,VBox,HBox,Horizontal…...

Unity类银河恶魔城学习记录1-14 AttackDirection源代码 P41
Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili PlayerPrimaryAttackState.cs using System.Collections; using System.Co…...

DataX详解和架构介绍
系列文章目录 一、 DataX详解和架构介绍 二、 DataX源码分析 JobContainer 三、DataX源码分析 TaskGroupContainer 四、DataX源码分析 TaskExecutor 五、DataX源码分析 reader 六、DataX源码分析 writer 七、DataX源码分析 Channel 文章目录 系列文章目录DataX是什么ÿ…...

02.05
1.单链表 main #include "1list_head.h" int main(int argc, const char *argv[]) { //创建链表之前链表为空Linklist headNULL;int n;datatype element;printf("please enter n:");scanf("%d",&n);for(int i0;i<n;i){printf("ple…...

【C语言】贪吃蛇 详解
该项目需要的技术要点 C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32API等。 由于篇幅限制 和 使知识模块化, 若想了解 使用到的 Win32API 的知识:请点击跳转:【Win32API】贪吃蛇会使用到的 Win32API 目录 1. 贪吃蛇游…...

Mysql MGR搭建
一、架构说明 1.1 架构概述 MGR(单主)VIP架构是一种分布式数据库架构,其中数据库系统采用单主复制模式, 同时引入虚拟IP(VIP)来提高可用性和可扩展性。 这种架构结合了传统主从复制和虚拟IP技术的优势,为数据库系统提供了高可用、 高性能和…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...