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

1.go web之gin框架

Gin框架

一、准备

1.下载依赖

 go get -u github.com/gin-gonic/gin

2.引入依赖

import "github.com/gin-gonic/gin"

3. (可选)如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包

import "net/http"

二、基本使用

1. 配置路由

package mainimport "github.com/gin-gonic/gin"func main() {// 创建一个默认的路由引擎r := gin.Default()// 配置路由r.GET("/getInfo", func(c *gin.Context) {c.JSON(200, gin.H{"msg": "成功",})})//启动 HTTP 服务,在8088端口监听r.Run(":8088")
}

在这里插入图片描述

三、Gin中的路由

1.路由概述

在 RESTful 架构中,每个网址代表一种资源,不同的请求方式表示执行不同的操作:

请求方式一般对应操作
GET(SELECT)从服务器取出资源(一项或多项)
POST(CREATE))在服务器新建一个资源
PUT(UPDATE)在服务器更新资源(客户端提供改变后的完整资源)
DELETE(DELETE))从服务器删除资源

2.简单路由

GET请求
r.GET("网址", func(c *gin.Context) {
c.String(200, "Get")
})
POST请求
r.POST("网址", func(c *gin.Context) {
c.String(200, "POST")
})
PUT请求
r.PUT("网址", func(c *gin.Context) {
c.String(200, "PUT")
})
DELETE请求
r.DELETE("网址", func(c *gin.Context) {
c.String(200, "DELETE")
})
动态路由
	r.GET("/getUser/:id", func(c *gin.Context) {id := c.Param("id")c.JSON(200, gin.H{"id":  id,"msg": "成功",})})

在这里插入图片描述

四、 响应格式

这里主要介绍使用比较多的字符串格式和json格式

c.String()

	r.GET("/getStr", func(c *gin.Context) {c.String(200, "成功")})

响应结果为字符串
在这里插入图片描述

c.JSON()

	r.GET("/getInfo", func(c *gin.Context) {c.JSON(200, gin.H{"msg": "成功",})})

响应结果为json格式
在这里插入图片描述

五、路由传参

1.GET请求传值

请求路径: /user?uid=20&page=1

后端接收

router.GET("/user", func(c *gin.Context) {
//c.Query()接收请求GET请求路径参数
uid := c.Query("uid")
//c.DefaultQuery()接收请求GET请求路径参数,接收不到时,采用默认参数
page := c.DefaultQuery("page", "0")
c.String(200, "uid=%v page=%v", uid, page)
})

2.Post 请求传值(获取 form 表单)

请求路径:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/doAddUser" method="post">
用户名:<input type="text" name="username" />
密码: <input type="password" name="password" />
<input type="submit" value="提交">
</form>
</body>
</html>

后端接收

router.POST("/doAddUser", func(c *gin.Context) {
//c.PostForm()接收form表单数据,key要与form表单name属性对应
username := c.PostForm("username")
password := c.PostForm("password")
//c.PostForm()接收form表单数据,接收不到采用默认值,key要与form表单name属性对应
age := c.DefaultPostForm("age", "20")
c.JSON(200, gin.H{ "usernmae": username, "password": password, "age": age, })
})

3.动态路由传值

请求路径:/user/20

后端接收

r.GET("/user/:uid", func(c *gin.Context) {
//c.Param()接收动态路由参数
uid := c.Param("uid")
c.String(200, "userID=%s", uid)
})

4.GET,POST 传递的结构体数据

Get 传值绑定到结构体

请求路径: /?username=zhangsan&password=123456

后端接收

//注意首字母大写
type Userinfo struct {
Username string `form:"username" json:"user"`
Password string `form:"password" json:"password"` }router.GET("/", func(c *gin.Context) {
var userinfo Userinfo
if err := c.ShouldBind(&userinfo); err == nil {
c.JSON(http.StatusOK, userinfo)
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
Post 传值绑定到结构体

请求路径:
在这里插入图片描述

后端接收

router.POST("/doLogin", func(c *gin.Context) {
var userinfo Userinfo
if err := c.ShouldBind(&userinfo); err == nil {
c.JSON(http.StatusOK, userinfo)
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})

.ShouldBind()能够基于请求自动提
取 JSON、form 表单和 QueryString 类型的数据,并把值绑定到指定的结构体对象

六、路由组

func main() {router := gin.Default()// 简单的路由组: v1v1 := router.Group("/v1"){v1.POST("/login", loginEndpoint)v1.POST("/submit", submitEndpoint)v1.POST("/read", readEndpoint)}// 简单的路由组: v2v2 := router.Group("/v2"){v2.POST("/login", loginEndpoint)v2.POST("/submit", submitEndpoint)v2.POST("/read", readEndpoint)}router.Run(":8080")
}

七、Gin路由文件分组

新建 routes 文件夹,routes 文件下面新建 adminRoutes.goapiRoutes.go、defaultRoutes.go

新建adminRoutes

package routesimport ("net/http""github.com/gin-gonic/gin"
)func AdminRoutesInit(router *gin.Engine) {adminRouter := router.Group("/admin"){adminRouter.GET("/user", func(c *gin.Context) {c.String(http.StatusOK, "用户")})adminRouter.GET("/news", func(c *gin.Context) {c.String(http.StatusOK, "news")})}
}

新建apiRoutes.go

package routesimport ("net/http""github.com/gin-gonic/gin"
)func ApiRoutesInit(router *gin.Engine) {apiRoute := router.Group("/api"){apiRoute.GET("/user", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"username": "张三","age": 20})})apiRoute.GET("/news", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"title": "这是新闻"})})}
}

新建defaultRoutes.go

package routesimport ("github.com/gin-gonic/gin"
)func DefaultRoutesInit(router *gin.Engine) {defaultRoute := router.Group("/"){defaultRoute.GET("/", func(c *gin.Context) {c.String(200, "首页")})}
}

配置main.go

package mainimport ("gin_demo/routes""github.com/gin-gonic/gin"//注意首字母大写
type Userinfo struct {Username string `form:"username" json:"user"`Password string `form:"password" json:"password"`
}func main() {r := gin.Default()routes.AdminRoutesInit(r)routes.ApiRoutesInit(r)routes.DefaultRoutesInit(r)r.Run(":8080")
}

八、Gin中自定义控制器

控制器分组

1.新建controller/admin/NewsController.go
package adminimport ("net/http""github.com/gin-gonic/gin"
)type NewsController struct {
}func (c NewsController) Index(ctx *gin.Context) {ctx.String(http.StatusOK, "新闻首页")
}
2.新建 controller/admin/UserController.go
package adminimport ("net/http""github.com/gin-gonic/gin"
)type UserController struct {
}func (c UserController) Index(ctx *gin.Context) {ctx.String(http.StatusOK, "这是用户首页")
}
func (c UserController) Add(ctx *gin.Context) {ctx.String(http.StatusOK, "增加用户")
}
3.在路由文件分组中配置控制器(将处理中间件改为控制器的方法)
package routesimport ("gin_demo/controller/admin""github.com/gin-gonic/gin"
)func AdminRoutesInit(router *gin.Engine) {adminRouter := router.Group("/admin"){adminRouter.GET("/user", admin.UserController{}.Index)adminRouter.GET("/user/add", admin.UserController{}.Add)adminRouter.GET("/news", admin.NewsController{}.Add)}
}

九、路由中间件

通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作

Gin 中的中间件必须是一个 gin.HandlerFunc 类型,配置路由的时候可以传递多个 func 回调函
数,最后一个 func 回调函数前面触发的方法都可以称为中间件。

1.路由中间件基本使用

package mainimport ("fmt""github.com/gin-gonic/gin"
)func initMiddleware(ctx *gin.Context) {fmt.Println("我是一个中间件")
}
func main() {r := gin.Default()r.GET("/", initMiddleware, func(ctx *gin.Context) {ctx.String(200, "首页--中间件演示")})r.GET("/news", initMiddleware, func(ctx *gin.Context) {ctx.String(200, "新闻页面--中间件演示")})r.Run(":8080")
}

2.ctx.Next()调用该请求的剩余处理程序

中间件里面加上 ctx.Next()可以让我们在路由匹配完成后执行一些操作
比如我们统计一个请求的执行时间。

package mainimport ("fmt""time""github.com/gin-gonic/gin"
)func initMiddleware(ctx *gin.Context) {fmt.Println("1-执行中中间件")start := time.Now().UnixNano()// 调用该请求的剩余处理程序ctx.Next()fmt.Println("3-程序执行完成 计算时间")// 计算耗时 Go 语言中的 Since()函数保留时间值,并用于评估与实际时间的差异end := time.Now().UnixNano()fmt.Println(end - start)
}
func main() {r := gin.Default()r.GET("/", initMiddleware, func(ctx *gin.Context) {fmt.Println("2-执行首页返回数据")ctx.String(200, "首页--中间件演示")})r.GET("/news", initMiddleware, func(ctx *gin.Context) {ctx.String(200, "新闻页面--中间件演示")})r.Run(":8080")
}

3.全局中间件

package mainimport ("fmt""github.com/gin-gonic/gin"
)func initMiddleware(ctx *gin.Context) {fmt.Println("全局中间件 通过 r.Use 配置")// 调用该请求的剩余处理程序ctx.Next()
}
func main() {r := gin.Default()//注册全局中间件r.Use(initMiddleware)r.GET("/", func(ctx *gin.Context) {ctx.String(200, "首页--中间件演示")})r.GET("/news", func(ctx *gin.Context) {ctx.String(200, "新闻页面--中间件演示")})r.Run(":8080")
}

4.在路由分组中配置中间件

写法一:

shopGroup := r.Group("/shop", StatCost())
{
shopGroup.GET("/index", func(c *gin.Context) {...})
... }

写法二:

shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{
shopGroup.GET("/index", func(c *gin.Context) {...})
... }

十、中间件和对应控制器之间共享数据

1.设置值

func InitAdminMiddleware(ctx *gin.Context) {// 可以通过 ctx.Set 在请求上下文中设置值,后续的处理函数能够取到该值ctx.Set("username", "张三")
}

2.获取值

func (c UserController) Index(ctx *gin.Context) {username, _ := ctx.Get("username")
}

十一、中间件注意事项

gin 默认中间件
gin.Default()默认使用了 Logger 和 Recovery 中间件,其中:
• Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release。
• Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500 响应码。
如果不想使用上面两个默认的中间件,可以使用 **gin.New()**新建一个没有任何默认中间件的路由

gin 中间件中使用 goroutine
当在中间件或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),
必须使用其只读副本(c.Copy())

r.GET("/", func(c *gin.Context) {//拷贝副本cCp := c.Copy()go func() {// simulate a long task with time.Sleep(). 5 secondstime.Sleep(5 * time.Second)// 这里使用你创建的副本fmt.Println("Done! in path " + cCp.Request.URL.Path)}()c.String(200, "首页")
})

十二、Gin中的Cookie

设置cookie

c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)

获取cookie

cookie, err := c.Cookie("name")

完整demo

package mainimport ("gin_demo/models""github.com/gin-gonic/gin""html/template"
)func main() {r := gin.Default()r.SetFuncMap(template.FuncMap{"unixToDate": models.UnixToDate})r.GET("/", func(c *gin.Context) {//设置cookiec.SetCookie("usrename", "张三", 3600, "/", "localhost", false, true)c.String(200, "首页")})r.GET("/user", func(c *gin.Context) {//获取cookieusername, _ := c.Cookie("usrename")c.String(200, "用户-"+username)})r.Run(":8080")
}

十三、Gin中的Session

Gin 官方没有给我们提供 Session 相关的文档,这个时候我们可以使用第三方的 Session 中间件来实现
session

gin-contrib/sessions 中间件支持的存储引擎:
• cookie
• memstore
• redis
• memcached
• mongodb

1.安装session包

go get github.com/gin-contrib/sessions

2.基本session用法

package mainimport ("github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 1.创建基于 cookie 的存储引擎,secret11111 参数是用于加密的秘钥store := cookie.NewStore([]byte("secret11111"))// 设置 session 中间件,参数 mysession,指的是 session 的名字,也是 cookie 的名字// 2.store 是前面创建的存储引擎,我们可以替换成其他存储引擎r.Use(sessions.Sessions("mysession", store))r.GET("/", func(c *gin.Context) {//初始化 session 对象session := sessions.Default(c)//设置过期时间session.Options(sessions.Options{MaxAge: 3600 * 6, // 6hrs})//设置 Sessionsession.Set("username", "张三")session.Save()c.JSON(200, gin.H{"msg": session.Get("username")})})r.GET("/user", func(c *gin.Context) {// 初始化 session 对象session := sessions.Default(c)// 通过 session.Get 读取 session 值username := session.Get("username")c.JSON(200, gin.H{"username": username})})r.Run(":8000")
}

相关文章:

1.go web之gin框架

Gin框架 一、准备 1.下载依赖 go get -u github.com/gin-gonic/gin2.引入依赖 import "github.com/gin-gonic/gin"3. &#xff08;可选&#xff09;如果使用诸如 http.StatusOK 之类的常量&#xff0c;则需要引入 net/http 包 import "net/http"二、基…...

工程物料管理信息化建设(十二)——关于工程物料管理系统最后的思考

目录 1 功能回顾1.1 MTO模块1.2 请购模块1.3 采购模块1.4 催交模块1.5 现场管理模块1.6 数据分析和看板模块1.7 其它模块 2 最后几个问题2.1 按管线发料和直接发料重叠2.2 YHA 材料编码的唯一性问题2.3 “合同量单-箱单-入库单” 数据映射 3 关于未来的思考3.1 三个专业之间的关…...

什么是API网关?——驱动数字化转型的“隐形冠军”

什么是API网关 API网关&#xff08;API Gateway&#xff09;是一个服务器&#xff0c;位于应用程序和后端服务之间&#xff0c;提供了一种集中式的方式来管理API的访问。它是系统的入口点&#xff0c;负责接收并处理来自客户端的请求&#xff0c;然后将请求路由到相应的后端服…...

Java 序列化和反序列化为什么要实现 Serializable 接口?

序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化. 反序列化&#xff1a;把字节序列恢复为对象的过程称为对象的反序列化. 什么时候需要用到序列化和反序列化呢或者对象序列化的两种用途… &#xff1a; (1) 对象持久化&#xff1a;把对象的…...

【【萌新的SOC学习之GPIO学习 水】】

萌新的SOC学习之GPIO学习 General Purpose I/O 通用I/O zynq-7000 SOC PS 分为四大部分 APU application Processor UintMemoryIO外设Interconnect 内部互联 PL &#xff1a; IO外设 GPIO可以连接通用的设备&#xff08;比如按键&#xff09; 也可以用GPIO模拟其他的协议 GP…...

10-Node.js入门

01.什么是 Node.js 目标 什么是 Node.js&#xff0c;有什么用&#xff0c;为何能独立执行 JS 代码&#xff0c;演示安装和执行 JS 文件内代码 讲解 Node.js 是一个独立的 JavaScript 运行环境&#xff0c;能独立执行 JS 代码&#xff0c;因为这个特点&#xff0c;它可以用来…...

Redis 的过期键 | Navicat 技术干货

Redis 是一种高性能的内存数据存储&#xff0c;以其速度和多功能性而闻名。其中一个有用的特性是为键设置过期时间的功能。在 Redis 中&#xff0c;为键设置过期时间对于管理数据和确保过时或临时数据自动从数据库中删除是至关重要的。在本文中&#xff0c;我们将探讨在 redis-…...

IDC服务器商是如何保护服务器的数据安全

服务器是作为一个公司存储数据和管理服务的设备&#xff0c;随着网络的不断发展大数据的普遍性&#xff0c;所以数据安全问题也越来越受到企业和个体的重视&#xff0c;那么IDC服务器商家是如何对服务器的数据进行安全保护的呢&#xff1f; 配置防火墙。防火墙是服务器的必备工…...

c++中什么时候用double?

c中什么时候用double? 在C中&#xff0c;通常使用double数据类型来表示浮点数&#xff0c;特别是当需要更高的精度时。以下是一些情况下可以考虑使用double的示例&#xff1a; 1. **需要高精度的计算**&#xff1a;当您需要进行精确的浮点数计算时&#xff0c;double通常比flo…...

TCP/IP(四)TCP的连接管理(一)三次握手

一 tcp连接回顾 部分内容来自小林coding TCP篇 记录的目的&#xff1a; 亲身参与进来,加深记忆 ① 引入 前面我们知道&#xff1a; TCP 是面向连接 [点对点的单播]的、可靠的、基于字节流的传输层通信协议面向连接意味着&#xff1a;在使用TCP之前,通信双方必须先建立一…...

bash上下键选择选项demo脚本

效果如下&#xff1a; 废话不多说&#xff0c;上代码&#xff1a; #!/bin/bashoptions("111" "222" "333" "444") # 选项列表 options_index0 # 默认选中第一个选项 options_len${#options[]}echo "请用上下方向键进行选择&am…...

cf 1886A

题目是输入一个数字&#xff0c;分解成三个数字的和&#xff0c;这三个数字都不相同&#xff0c;并且都不可以被三整除&#xff0c;如果存在输出YES并且输出任意一组可能的三个数字&#xff0c;否则输出NO 代码 #include<bits/stdc.h> using namespace std;int main() …...

Spring5应用之事务属性

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Spring5应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言事务…...

C# 搭建一个简单的WebApi项目23.10.10

一、创建Web API 1、创建一个新的web API项目 启动VS 2019&#xff0c;并在“开始页”选择“创建新项目”。或从“文件”菜单选择“新建”&#xff0c;然后选择“项目”。 选择ASP.NET Web应用程序(.NET Framework) 2.点击下一步&#xff0c;到这个页面时选择Web API。 3.选中…...

VGG卷积神经网络实现Cifar10图片分类-Pytorch实战

前言 当涉足深度学习&#xff0c;选择合适的框架是至关重要的一步。PyTorch作为三大主流框架之一&#xff0c;以其简单易用的特点&#xff0c;成为初学者们的首选。相比其他框架&#xff0c;PyTorch更像是一门易学的编程语言&#xff0c;让我们专注于实现项目的功能&#xff0…...

CentOS 7文件系统中的软链接和硬链接

软链接&#xff08;Symbolic Link&#xff09; 软链接&#xff0c;也称为符号链接&#xff0c;是一个指向另一个文件或目录的特殊类型的文件。它是一个指向目标文件的符号&#xff0c;就像快捷方式一样。软链接的创建和使用非常灵活&#xff0c;适用于各种情况。 创建软链接 …...

【AI】深度学习——前馈神经网络——全连接前馈神经网络

文章目录 1.1 全连接前馈神经网络1.1.1 符号说明超参数参数活性值 1.1.2 信息传播公式通用近似定理 1.1.3 神经网络与机器学习结合二分类问题多分类问题 1.1.4 参数学习矩阵求导链式法则更为高效的参数学习反向传播算法目标计算 ∂ z ( l ) ∂ w i j ( l ) \frac{\partial z^{…...

超简单的视频截取方法,迅速提取所需片段!

“视频可以截取吗&#xff1f;用相机拍摄了一段视频&#xff0c;但是中途相机发生了故障&#xff0c;录进去了很多不需要的片段&#xff0c;现在想截取一部分视频出来&#xff0c;但是不知道方法&#xff0c;想问问广大的网友&#xff0c;知不知道视频截取的方法。” 无论是工…...

ArcGIS/GeoScene脚本:基于粒子群优化的支持向量机回归模型

参数输入 1.样本数据必须包含需要回归的字段 2.回归字段是数值类型 3.影响因子是栅格数据&#xff0c;可添加多个 4.随机种子可以确保每次运行的训练集和测试集一致 5.训练集占比为0-1之间的小数 6.迭代次数&#xff1a;迭代次数越高精度越高&#xff0c;但是运行时间越长…...

vue3组件的通信方式

一、vue3组件通信方式 通信仓库地址:vue3_communication: 当前仓库为贾成豪老师使用组件通信案例 不管是vue2还是vue3,组件通信方式很重要,不管是项目还是面试都是经常用到的知识点。 比如:vue2组件通信方式 props:可以实现父子组件、子父组件、甚至兄弟组件通信 自定义事件:可…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...