[golang gin框架] 40.Gin商城项目-微服务实战之Captcha验证码微服务
本次内容需要 gin框架基础知识, golang微服务基础知识才能更好理解
一.Captcha验证码功能引入
在前面,讲解了微服务的架构等,这里,来讲解前面商城项目的 Captcha验证码 微服务 ,captcha验证码功能在前台,后端 都要用到 ,可以把它 抽离出来 ,做成微服务功能
编辑
这个验证码功能封装代码captcha.go如下:
package models//验证码属性: https://captcha.mojotv.cn/
import ("github.com/mojocn/base64Captcha""image/color"
)//创建store,保存验证码的位置,默认为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中
//var store = base64Captcha.DefaultMemStore//配置RedisStore, 保存验证码的位置为redis, RedisStore实现base64Captcha.Store接口
var store base64Captcha.Store = RedisStore{}//获取验证码
func MakeCaptcha(height int, width int, length int) (string, string, error) {//定义一个drivervar driver base64Captcha.Driver//创建一个字符串类型的验证码驱动DriverString, DriverChinese :中文驱动driverString := base64Captcha.DriverString{Height: height, //高度Width: width, //宽度NoiseCount: 0, //干扰数ShowLineOptions: 2 | 4, //展示个数Length: length, //长度Source: "1234567890qwertyuioplkjhgfdsazxcvbnm", //验证码随机字符串来源BgColor: &color.RGBA{ // 背景颜色R: 3,G: 102,B: 214,A: 125,},Fonts: []string{"wqy-microhei.ttc"}, // 字体}driver = driverString.ConvertFonts()//生成验证码c := base64Captcha.NewCaptcha(driver, store)id, b64s, err := c.Generate()return id, b64s, err
}//校验验证码
func VerifyCaptcha(id string, VerifyValue string) bool {// 参数说明: id 验证码id, verifyValue 验证码的值, true: 验证成功后是否删除原来的验证码if store.Verify(id, VerifyValue, true) {return true} else {return false}
}
把这个验证码做成微服务的话,就需要实现上面的两个方法: 获取验证码(MakeCaptcha), 校验验证码(VerifyCaptcha)
二.创建captcha验证码微服务服务端
-
创建两个文件夹,client(客户端),server(服务端)
-
生成服务端captcha微服务代码
在server目录下运行: go-micro new service captcha,生成captcha服务端代码
运行命令后,生成的服务端目录如下:
-
编写proto/captcha.proto文件
在这个文件中编写 获取验证码,验验证码相关代码
syntax = "proto3";package captcha;option go_package = "./proto/captcha";service Captcha {//获取验证码: MakeCaptchaRequest请求, MakeCaptchaRequest返回rpc MakeCaptcha(MakeCaptchaRequest) returns (MakeCaptchaResponse) {}//校验验证码: VerifyCaptchaRequest请求, VerifyCaptchaResponse返回rpc VerifyCaptcha(VerifyCaptchaRequest) returns (VerifyCaptchaResponse) {}
}//以下具体参数类型参考captcha.go中对应的方法//获取验证码请求参数
message MakeCaptchaRequest {//验证码高度int32 height =1;//验证码宽度int32 width = 2;//验证码长度int32 length = 3;
}//获取验证码返回数据
message MakeCaptchaResponse {//验证码idstring id = 1;//验证码base64编码string b64s = 2;
}//校验验证码请求参数
message VerifyCaptchaRequest {//验证码idstring id = 1;//输入的验证码string verifyValue = 2;
}//校验验证码返回数据
message VerifyCaptchaResponse {//校验的结果bool verifyResult = 1;
}
-
生成proto相关文件
参考 [golang 微服务] 7. go-micro框架介绍,go-micro脚手架,go-micro结合consul搭建微服务案例,windows下运行 Makefile里面的proto下的代码 :protoc --proto_path=. --micro_out=. --go_out=:. proto/captcha.proto, 当然,如果是初次使用go-micro,则还需运行init下面的代码(@go xxx),引入相关包
-
初始化项目
在captcha目录下运行命令: go mod init captcha,初始化项目
删除go.mod后再次执行 go mod init captcha命令:
运行命令 :go mod tidy,加载项目需要的包:
上面表示:下载 "go-micro.dev/v4"这个包失败了,这时则需运行命令 go get go-micro.dev/v4, 具体参考 : [golang 微服务] 7. go-micro框架介绍,go-micro脚手架,go-micro结合consul搭建微服务案例
在这里可能会出现 import中始终报红 的情况,解决见 : golang开启mod后import报红解决方案
-
启动consul服务发现
在cmd中运行命令: consul agent -dev,具体参考: [golang 微服务] 5. 微服务服务发现介绍,安装以及consul的使用,Consul集群
-
main.go中实例化consul
具体参考: [golang 微服务] 7. go-micro框架介绍,go-micro脚手架,go-micro结合consul搭建微服务案例,代码如下:
package mainimport ("captcha/handler"pb "captcha/proto/captcha""go-micro.dev/v4""go-micro.dev/v4/logger""github.com/go-micro/plugins/v4/registry/consul"
)var (service = "captcha"version = "latest"
)func main() {//集成consulconsulReg := consul.NewRegistry()// Create servicesrv := micro.NewService(micro.Address("127.0.0.1:8081"), //指定微服务的ip: 选择注册服务器地址,也可以不配置,默认为本机,也可以选择consul集群中的clientmicro.Name(service),micro.Version(version),//注册consulmicro.Registry(consulReg),)srv.Init(micro.Name(service),micro.Version(version),)// Register handlerif err := pb.RegisterCaptchaHandler(srv.Server(), new(handler.Captcha)); err != nil {logger.Fatal(err)}// Run serviceif err := srv.Run(); err != nil {logger.Fatal(err)}
}
-
handler/captcha.go封装实现proto/captcha.proto里面的rpc方法
参考 proto/captcha.proto里面的 service Captcha 方法实现,也可以参考生成的 .pb.micro.go里面生成的方法进行实现
(1).pb.micro.go参考代码:
// Client API for Captcha service
type CaptchaService interface {// 获取验证码: MakeCaptchaRequest请求, MakeCaptchaRequest返回MakeCaptcha(ctx context.Context, in *MakeCaptchaRequest, opts ...client.CallOption) (*MakeCaptchaResponse, error)// 校验验证码: VerifyCaptchaRequest请求, VerifyCaptchaResponse返回VerifyCaptcha(ctx context.Context, in *VerifyCaptchaRequest, opts ...client.CallOption) (*VerifyCaptchaResponse, error)
}
(2).handler/captcha.go代码:
把 一.Captcha验证码功能引入中captcha.go的代码复制到 handler/captcha.go中, 然后修修改改就可以了
1)首先,import "github.com/mojocn/base64Captcha"
把" github.com/mojocn/base64Captcha"放入import中,然后通过 go mod tidy或者 go get
github.com/mojocn/base64Captcha 引入
2).配置RedisStore
把 var store base64Captcha.Store = RedisStore{}复制进去
//创建store,保存验证码的位置,默认为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中
//var store = base64Captcha.DefaultMemStore//配置RedisStore, 保存验证码的位置为redis, RedisStore实现base64Captcha.Store接口
var store base64Captcha.Store = RedisStore{}
这里使用的是 redis的存储方式,故需要 初始化redis,以及实现 设置 captcha 的方法的代码,故需要在captcha下创建 models/redisCore.go, models/redisStore.go文件,具体参考: [golang gin框架] 12.Gin 商城项目-base64Captcha生成图形验证码以及分布式架构中配置Captcha
初始化redis的代码
redisCore.go代码如下:
package models//redis官网: github.com/go-redis
//下载go-redis: go get github.com/redis/go-redis/v9
//连接redis数据库核心代码import ("context""fmt""github.com/redis/go-redis/v9""gopkg.in/ini.v1""os"
)//全局使用,就需要把定义成公有的
var ctxRedis = context.Background()var (RedisDb *redis.Client
)//是否开启redis
var redisEnable bool//自动初始化数据库
func init() {//加载配置文件config, iniErr := ini.Load("./conf/app.ini")if iniErr != nil {fmt.Printf("Fail to read file: %v", iniErr)os.Exit(1)}//获取redis配置ip := config.Section("redis").Key("ip").String()port := config.Section("redis").Key("port").String()redisEnable, _ = config.Section("redis").Key("redisEnable").Bool()//判断是否开启redisif redisEnable {RedisDb = redis.NewClient(&redis.Options{Addr: ip + ":" + port,Password: "", // no password setDB: 0, // use default DB})//连接redis_, err := RedisDb.Ping(ctxRedis).Result()//判断连接是否成功if err != nil {println(err)}}
}
设置 captcha 的方法的代码
redisStore.go代码如下:
package models/**
使用redis需实现Store中的三个方法
type Store interface {// Set sets the digits for the captcha id.Set(id string, value string)// Get returns stored digits for the captcha id. Clear indicates// whether the captcha must be deleted from the store.Get(id string, clear bool) string//Verify captcha's answer directlyVerify(id, answer string, clear bool) bool
}*/import ("context""fmt""time"
)var ctx = context.Background()const CAPTCHA = "captcha:"type RedisStore struct {
}//实现设置 captcha 的方法
func (r RedisStore) Set(id string, value string) error {key := CAPTCHA + iderr := RedisDb.Set(ctx, key, value, time.Minute*2).Err()return err
}//实现获取 captcha 的方法
func (r RedisStore) Get(id string, clear bool) string {key := CAPTCHA + id//获取 captchaval, err := RedisDb.Get(ctx, key).Result()if err != nil {fmt.Println(err)return ""}//如果clear == true, 则删除if clear {err := RedisDb.Del(ctx, key).Err()if err != nil {fmt.Println(err)return ""}}return val
}//实现验证 captcha 的方法
func (r RedisStore) Verify(id, answer string, clear bool) bool {v := RedisStore{}.Get(id, clear)return v == answer
}
这里使用了ini.Load加载
参考: [golang gin框架] 9.Gin GORM 中使用事务以及go-ini加载.ini配置文件
3).实现获取验证码方法的业务逻辑代码
把 一.Captcha验证码功能引入中captcha.go 获取验证码方法代码复制到handler/captcha.go的
MakeCaptcha,然后修修改改就可以了,代码如下
//获取验证码的方法
func (e *Captcha) MakeCaptcha(ctx context.Context, req *pb.MakeCaptchaRequest, rsp *pb.MakeCaptchaResponse) error {//实现业务逻辑代码//定义一个drivervar driver base64Captcha.Driver//创建一个字符串类型的验证码驱动DriverString, DriverChinese :中文驱动driverString := base64Captcha.DriverString{Height: int(req.Height), //高度Width: int(req.Width), //宽度NoiseCount: 0, //干扰数ShowLineOptions: 2 | 4, //展示个数Length: int(req.Length), //长度Source: "1234567890qwertyuioplkjhgfdsazxcvbnm", //验证码随机字符串来源BgColor: &color.RGBA{ // 背景颜色R: 3,G: 102,B: 214,A: 125,},Fonts: []string{"wqy-microhei.ttc"}, // 字体}driver = driverString.ConvertFonts()//生成验证码c := base64Captcha.NewCaptcha(driver, store)id, b64s, err := c.Generate()//把生成的验证码id,base64编码赋值给返回的rsp参数rsp.Id = idrsp.B64S = b64sreturn err
}
4).实现校验验证码方法的业务逻辑代码
把 一.Captcha验证码功能引入中captcha.go 校验验证码的方法代码复制到handler/captcha.go的
MakeCaptcha,然后修修改改就可以了,代码如下:
//校验验证码的方法
func (e *Captcha) VerifyCaptcha(ctx context.Context, req *pb.VerifyCaptchaRequest, rsp *pb.VerifyCaptchaResponse) error {// 参数说明: id 验证码id, verifyValue 验证码的值, true: 验证成功后是否删除原来的验证码if store.Verify(req.Id, req.VerifyValue, true) {rsp.VerifyResult = true //校验成功} else {rsp.VerifyResult = false //校验失败}return nil
}
4).完整代码如下
package handlerimport ("captcha/models"pb "captcha/proto/captcha""context""github.com/mojocn/base64Captcha""image/color"
)//创建store,保存验证码的位置,默认为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中
//var store = base64Captcha.DefaultMemStore//配置RedisStore, 保存验证码的位置为redis, RedisStore实现base64Captcha.Store接口
var store base64Captcha.Store = models.RedisStore{}type Captcha struct{}//获取验证码的方法
func (e *Captcha) MakeCaptcha(ctx context.Context, req *pb.MakeCaptchaRequest, rsp *pb.MakeCaptchaResponse) error {//实现业务逻辑代码//定义一个drivervar driver base64Captcha.Driver//创建一个字符串类型的验证码驱动DriverString, DriverChinese :中文驱动driverString := base64Captcha.DriverString{Height: int(req.Height), //高度Width: int(req.Width), //宽度NoiseCount: 0, //干扰数ShowLineOptions: 2 | 4, //展示个数Length: int(req.Length), //长度Source: "1234567890qwertyuioplkjhgfdsazxcvbnm", //验证码随机字符串来源BgColor: &color.RGBA{ // 背景颜色R: 3,G: 102,B: 214,A: 125,},Fonts: []string{"wqy-microhei.ttc"}, // 字体}driver = driverString.ConvertFonts()//生成验证码c := base64Captcha.NewCaptcha(driver, store)id, b64s, err := c.Generate()//把生成的验证码id,base64编码赋值给返回的rsp参数rsp.Id = idrsp.B64S = b64sreturn err
}//校验验证码的方法
func (e *Captcha) VerifyCaptcha(ctx context.Context, req *pb.VerifyCaptchaRequest, rsp *pb.VerifyCaptchaResponse) error {// 参数说明: id 验证码id, verifyValue 验证码的值, true: 验证成功后是否删除原来的验证码if store.Verify(req.Id, req.VerifyValue, true) {rsp.VerifyResult = true //校验成功} else {rsp.VerifyResult = false //校验失败}return nil
}
-
注册验证码微服务服务端到服务发现(consul)
captcha目录下运行go run main.go,然后在consul UI 查看,是否注册成功
注册成功了
三.创建captcha验证码微服务客户端
-
在前面商城项目单体架构中生成客户端代码
前面单体架构商城中调用captcha验证码接口代码是通过接口 http://127.0.0.1:8080/admin/captcha这个访问的,具体代码如下:
adminRouters.go
//验证码
adminRouters.GET("/captcha", admin.LoginController{}.Captcha)
LoginController.go
//获取验证码,验证验证码func(con LoginController) Captcha(c *gin.Context) {id, b64s, err := models.MakeCaptcha(50, 100 ,1)if err != nil {fmt.Println(err)}c.JSON(http.StatusOK, gin.H{"captchaId": id,"captchaImage": b64s,})
}
上面调用models下 captcha.go中的方法 MakeCaptcha()获取验证码,该captcha.go也就是 一.Captcha验证码功能引入 中captcha.go代码,这是 原来单体架构的做法,访问如下:
现在就要交给 captcha验证码微服务来处理
-
首先把server/captcha/proto文件夹复制到项目中
-
封装captcha.go验证码微服务客户端方法
前面章节对于验证码这块儿, 前端和 后台都需要进行 验证码逻辑处理,调用的方法都是models/captcha.go下面的方法,故在进行微服务客户端处理时,也在这里面进行修改
(1).配置consul服务发现
首先,在models下创建initCaptchaConsul.go,配置consul服务发现,以便调用,代码如下:
package models//微服务客户端配置: 初始化consul配置,当一个项目中多个微服务时,就很方便了
//建议:一个微服务对应一个客户端,这样好管理import ("github.com/go-micro/plugins/v4/registry/consul""go-micro.dev/v4/client""go-micro.dev/v4/registry"
)//CaptchaClient: 全局变量 在外部的包中可以调用
var CaptchaClient client.Client//init 方法: 当程序运行时就会自动执行
func init() {consulRegistry := consul.NewRegistry(//指定微服务的ip: 选择注册服务器地址,默认为本机,也可以选择consul集群中的client,建议一个微服务对应一个consul集群的clientregistry.Addrs("127.0.0.1:8500"),)// Create servicesrv := micro.NewService(micro.Registry(consulRegistry),)srv.Init()CaptchaClient = srv.Client()
}
在这里,也许没有引入,执行命令:go mod tidy引入对应的包
(2).完善models/captcha.go中的MakeCaptcha获取验证码方法
在该方法中实现调用获取验证码微服务逻辑功能
//调用获取验证码微服务
func MakeCaptcha(height int, width int, length int) (string, string, error) {// Create client: 这里的服务名称需要和服务端注册的名称一致captchaClient := pbCaptcha.NewCaptchaService("captcha", CaptchaClient)// Call service: 创建连接captcha微服务的连接,并传递参数,//该方法最终是请求server端handler中的captcha.go中的MakeCaptcha方法rsp, err := captchaClient.MakeCaptcha(context.Background(), &pbCaptcha.MakeCaptchaRequest{Height: int32(height), //验证码高度Width: int32(width), //验证码宽度Length: int32(length), //验证码长度})//判断是否获取成功if err != nil {log.Fatal(err)}//记录loglog.Info(rsp)//返回return rsp.Id, rsp.B64S, err
}
(3).完善models/captcha.go中的VerifyCaptcha校验验证码方法
在该方法中实现调用校验验证码微服务逻辑功能
//调用校验验证码微服务
func VerifyCaptcha(id string, VerifyValue string) bool {// Create client: 这里的服务名称需要和服务端注册的名称一致captchaClient := pbCaptcha.NewCaptchaService("captcha", CaptchaClient)// Call service: 创建连接captcha微服务的连接,并传递参数,//该方法最终是请求server端handler中的captcha.go中的VerifyCaptcha方法rsp, err := captchaClient.VerifyCaptcha(context.Background(), &pbCaptcha.VerifyCaptchaRequest{Id: id, //验证码IdVerifyValue: VerifyValue, //验证码})//判断是否获取成功if err != nil {log.Fatal(err)}//记录loglog.Info(rsp)//返回return rsp.VerifyResult
}
(4).完整代码如下
package models//验证码属性: https://captcha.mojotv.cn/
import ("context""github.com/prometheus/common/log"pbCaptcha "goshop/proto/captcha"
)//调用获取验证码微服务
func MakeCaptcha(height int, width int, length int) (string, string, error) {// Create client: 这里的服务名称需要和服务端注册的名称一致captchaClient := pbCaptcha.NewCaptchaService("captcha", CaptchaClient)// Call service: 创建连接captcha微服务的连接,并传递参数,//该方法最终是请求server端handler中的captcha.go中的MakeCaptcha方法rsp, err := captchaClient.MakeCaptcha(context.Background(), &pbCaptcha.MakeCaptchaRequest{Height: int32(height), //验证码高度Width: int32(width), //验证码宽度Length: int32(length), //验证码长度})//判断是否获取成功if err != nil {log.Fatal(err)}//记录loglog.Info(rsp)//返回return rsp.Id, rsp.B64S, err
}//调用校验验证码微服务
func VerifyCaptcha(id string, VerifyValue string) bool {// Create client: 这里的服务名称需要和服务端注册的名称一致captchaClient := pbCaptcha.NewCaptchaService("captcha", CaptchaClient)// Call service: 创建连接captcha微服务的连接,并传递参数,//该方法最终是请求server端handler中的captcha.go中的VerifyCaptcha方法rsp, err := captchaClient.VerifyCaptcha(context.Background(), &pbCaptcha.VerifyCaptchaRequest{Id: id, //验证码IdVerifyValue: VerifyValue, //验证码})//判断是否获取成功if err != nil {log.Fatal(err)}//记录loglog.Info(rsp)//返回return rsp.VerifyResult
}
-
校验captcha验证码微服务功能
(1).先启动服务端
见前面代码
(2).启动客户端
在项目根目录下运行 :go run main.go,启动项目
(3).访问http://127.0.0.1:8080/admin/captcha
访问 http://127.0.0.1:8080/admin/captcha看看是否显示验证码相关数据
显示了,说明调用了验证码微服务操作
(4).校验验证码微服务操作是否成功
访问后台登录页面,输入用户名,密码,验证码,看看是否成功
好了,captcha验证码微服务客户端操作完成,在这里,上面讲解的是web页面调用captcha验证码微服务功能,下面则讲解Go Web Restfull APi 调用Captcha验证码微服务
四.Go Web Restfull APi 调用Captcha验证码微服务
Go Web Restfull APi 调用Captcha验证码微服务主要是给手机app,微信小程序等提供接口,架构如下
-
创建一个api的Gin项目,并配置routers
这里直接以上面项目为案例,在routers下创建 apiRouters.go路由文件
-
构建验证码相关接口,代码如下
在controllers/api/ CaptchaController.go下编写获取验证码,校验验证码相关逻辑,代码如下:
package apiimport ("context""github.com/gin-gonic/gin""github.com/prometheus/common/log""goshop/models"pbCaptcha "goshop/proto/captcha""net/http"
)type CatpchaController struct {
}//获取验证码的接口(调用验证码微服务操作)
func (con CatpchaController) MakeCaptcha(c *gin.Context) {// Create client: 这里的服务名称需要和服务端注册的名称一致captchaClient := pbCaptcha.NewCaptchaService("captcha", models.CaptchaClient)// Call service: 创建连接captcha微服务的连接,并传递参数,//该方法最终是请求server端handler中的captcha.go中的MakeCaptcha方法rsp, err := captchaClient.MakeCaptcha(context.Background(), &pbCaptcha.MakeCaptchaRequest{Height: 100, //验证码高度Width: 200, //验证码宽度Length: 4, //验证码长度})//判断是否获取成功if err != nil {log.Fatal(err)}//记录loglog.Info(rsp)//返回c.JSON(http.StatusOK, gin.H{"captchaId": rsp.Id,"B64s": rsp.B64S,})
}//校验验证码接口
func (con CatpchaController) VerifyCaptcha(c *gin.Context) {//获取请求参数verifyId := c.PostForm("verifyId")verifyValue := c.PostForm("verifyValue")// Create client: 这里的服务名称需要和服务端注册的名称一致captchaClient := pbCaptcha.NewCaptchaService("captcha", models.CaptchaClient)// Call service: 创建连接captcha微服务的连接,并传递参数,//该方法最终是请求server端handler中的captcha.go中的VerifyCaptcha方法rsp, err := captchaClient.VerifyCaptcha(context.Background(), &pbCaptcha.VerifyCaptchaRequest{Id: verifyId, //验证码IdVerifyValue: verifyValue, //验证码})//判断是否获取成功if err != nil {log.Fatal(err)}//记录loglog.Info(rsp)//返回if rsp.VerifyResult == true { // 说明验证通过c.JSON(http.StatusOK, gin.H{"message": "验证验证码成功","success": true,})} else {c.JSON(http.StatusOK, gin.H{"message": "验证验证码失败","success": false,})}
}
-
校验api请求是否成功
请求http://127.0.0.1:8080/api/MakeCaptcha,看看是否返回对应的验证码json请求
从上图看得出来,返回了对应验证码的数据的,把 B64s中的数据放入<img src="B64s" />中,就可以了,展示的图片如下:
然后校验验证码,一般通过postman校验
好了,Go Web Restfull APi 调用Captcha验证码微服务 获取验证码,以及校验验证码api接口操作就完成了
[上一节][golang gin框架] 39.Gin商城项目-微服务实战之微服务架构
[下一节][golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)
相关文章:
[golang gin框架] 40.Gin商城项目-微服务实战之Captcha验证码微服务
本次内容需要 gin框架基础知识, golang微服务基础知识才能更好理解 一.Captcha验证码功能引入 在前面,讲解了微服务的架构等,这里,来讲解前面商城项目的 Captcha验证码 微服务 ,captcha验证码功能在前台,后端 都要用到 ,可以把它 抽离出来 ,做成微服务功能 编辑 这个验证码功能…...
【LeetCode热题100】打卡第44天:倒数第30~25题
文章目录 【LeetCode热题100】打卡第44天:倒数第30~25题⛅前言 移动零🔒题目🔑题解 寻找重复数🔒题目🔑题解 二叉树的序列化与反序列化🔒题目🔑题解 最长递增子序列🔒题目ǵ…...
C# 匿名方法和Lambda表达式
一.匿名方法 1.匿名方法的演变 匿名方法是为了简化委托的实现,方便调用委托方法而出现的,同时,匿名方法也是学好lambda表达式的基础。在委托调用的方法中,如果方法只被调用一次,这个时候我们就没有必要创建具名方法&…...
uniapp微信小程序scroll-view滚动scrollLeft不准确
今天在实现微信小程序的一个横向导航的时候出现了一个问题,就是每次滑到滚动条最右边的时候 scrollLeft的值都不准确 原因:因为每次滚动监听事件都会被调用比较耗费资源系统会默认节流,可以在scroll-view 加一个 throttle“{{false}}” 关闭…...
symfony/console
github地址:GitHub - symfony/console: Eases the creation of beautiful and testable command line interfaces 文档地址:The Console Component (Symfony 5.4 Docs) 默认命令list,可以用register注册一个command命令,之后可以…...
OSI模型简介及socket,tcp,http三者之间的区别和原理
1.OSI模型简介(七层网络模型) OSI 模型(Open System Interconnection model):一个由国际标准化组织提出的概念模型,试图提供一个使各种不同的计算机和网络在世界范围内实现互联的标准框架。 它将计算机网络体系结构划分为七层,每…...
【leetcode】leetcode69 x的平方根
文章目录 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。原理牛顿法(数值分析中使用到的):二分法 解决方案java 实现实例执行结果 python 实现实例 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数&…...
springboot与rabbitmq的整合【演示5种基本交换机】
前言: 👏作者简介:我是笑霸final,一名热爱技术的在校学生。 📝个人主页:个人主页1 || 笑霸final的主页2 📕系列专栏:后端专栏 📧如果文章知识点有错误的地方,…...
【设计模式】设计原则-单一职责原则
单一职责原则 类的设计原则之单一职责原则,是最常用的类的设计的原则之一。 百度百科:就一个类而言,应该仅有一个引起它变化的原因。应该只有一个职责。 通俗的讲就是:一个类只做一件事 这个解释更通俗易懂,也更符…...
【C++】-多态的底层原理
💖作者:小树苗渴望变成参天大树🎈 🎉作者宣言:认真写好每一篇博客💤 🎊作者gitee:gitee✨ 💞作者专栏:C语言,数据结构初阶,Linux,C 动态规划算法🎄 如 果 你 …...
【部署】让你的电脑多出一个磁盘来用!使用SSHFS将远程服务器目录挂载到Windows本地,挂载并共享服务器资源
让你的电脑多出一个磁盘来用!---使用SSHFS将远程服务器目录挂载到Windows本地 1. 方法原理介绍2.SSHFS-Win使用教程—实现远程服务器磁盘挂载本地 由于日常主要用 Windows 系统,每次都得 ssh 到服务器上进行取资源(本地磁盘不富裕)…...
/var/lock/subsys目录的作用
总的来说,系统关闭的过程(发出关闭信号,调用服务自身的进程)中会检查/var/lock/subsys下的文件,逐一关闭每个服务,如果某一运行的服务在/var/lock/subsys下没有相应的选项。在系统关闭的时候,会…...
DETR (DEtection TRansformer)基于自建数据集开发构建目标检测模型超详细教程
目标检测系列的算法模型可以说是五花八门,不同的系列有不同的理论依据,DETR的亮点在于它是完全端到端的第一个目标检测模型,DETR(Detection Transformer)是一种基于Transformer的目标检测模型,由Facebook A…...
C++初阶 - 5.C/C++内存管理
目录 1.C/C的内存分布 2.C语言中动态内存管理方式:malloc、calloc、realloc、free 3.C内存管理方式 3.1 new/delete操作内置类型 3.2 new 和 delete操作自定义类型 4.operator new 与 operator delete 函数(重要点) 4.1 operator new 与…...
数学建模学习(3):综合评价类问题整体解析及分析步骤
一、评价类算法的简介 对物体进行评价,用具体的分值评价它们的优劣 选这两人其中之一当男朋友,你会选谁? 不同维度的权重会产生不同的结果 所以找到每个维度的权重是最核心的问题 0.25 二、评价前的数据处理 供应商ID 可靠性 指标2 指…...
【后端面经】微服务构架 (1-5) | 限流:濒临奔溃?限流守护者拯救系统于水火之中!
文章目录 一、前置知识1、什么是限流?2、限流算法A) 静态算法a) 漏桶b) 令牌桶c) 固定窗口d) 滑动窗口B) 动态算法3、限流的模式4、 限流对象4、限流后应该怎么做?二、面试环节1、面试准备2、基本思路3、亮点展现A) 突发流量(针对请求个数而言)B) 请求大小(针对请求大小而言)…...
HDFS异构存储详解
异构存储 HDFS异构存储类型什么是异构存储异构存储类型如何让HDFS知道集群中的数据存储目录是那种类型存储介质 块存储选择策略选择策略说明选择策略的命令 案例:冷热温数据异构存储对应步骤 HDFS内存存储策略支持-- LAZY PERSIST介绍执行使用 HDFS异构存储类型 冷…...
《面试1v1》Kafka消息是采用Pull还是Push模式
🍅 作者简介:王哥,CSDN2022博客总榜Top100🏆、博客专家💪 🍅 技术交流:定期更新Java硬核干货,不定期送书活动 🍅 王哥多年工作总结:Java学习路线总结…...
Windows环境Docker安装
目录 安装Docker Desktop的步骤 Docker Desktop 更新WSL WSL 的手动安装步骤 Windows PowerShell 拉取(Pull)镜像 查看已下载的镜像 输出"Hello Docker!" Docker Desktop是Docker官方提供的用于Windows的图形化桌面应用程序,…...
Spring 6.0官方文档示例(23): singleton类型的bean和prototype类型的bean协同工作的方法(二)
使用lookup-method: 一、实体类: package cn.edu.tju.domain2;import java.time.LocalDateTime; import java.util.Map;public class Command {private Map<String, Object> state;public Map<String, Object> getState() {return state;}public void …...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
