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

8-Gin 中间件 --[Gin 框架入门精讲与实战案例] 【文末有测试代码】

路由中间件

Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。它以性能好、中间件支持灵活著称,非常适合用来构建微服务或 RESTful API 服务。下面我将提供三个使用 Gin 的路由中间件的完整示例。

示例 1: 简单的日志记录中间件

这个中间件会在每个请求处理前后打印日志信息,包括请求的方法、路径和响应状态码。

package mainimport ("log""net/http""time""github.com/gin-gonic/gin"
)// Logger 返回一个日志中间件,用于记录HTTP请求的详细信息。
// 该中间件主要记录了请求的路径、查询字符串、响应状态码、客户端IP和请求处理时间。
// 它通过gin.HandlerFunc类型返回一个闭包函数,以便在Gin路由中使用。
func Logger() gin.HandlerFunc {return func(c *gin.Context) {// 记录请求开始时间start := time.Now()// 获取请求路径path := c.Request.URL.Path// 获取查询字符串raw := c.Request.URL.RawQuery// 处理请求前c.Next() // 处理请求// 处理请求后// 记录请求结束时间end := time.Now()// 计算请求处理耗时latency := end.Sub(start)// 获取HTTP响应状态码statusCode := c.Writer.Status()// 获取客户端IPclientIP := c.ClientIP()// 打印日志信息log.Printf("| %3d | %13v | %15s | %40s |",statusCode, latency, clientIP, path+"?"+raw)}
}func main() {// 初始化Gin默认引擎r := gin.Default()// 使用Logger中间件r.Use(Logger())// 定义一个模拟耗时操作的测试路由r.GET("/test", func(c *gin.Context) {// 模拟耗时操作time.Sleep(5 * time.Second)// 返回JSON响应c.JSON(http.StatusOK, gin.H{"message": "pong",})})// 启动HTTP服务器,监听端口8080r.Run(":8080")
}

在这里插入图片描述

示例 2: 认证中间件

这个中间件会检查每个请求中是否包含特定的 Authorization header,并验证其值是否为预期的 token。

package mainimport ("fmt""net/http""github.com/gin-gonic/gin"
)// AuthRequired 是一个中间件函数,用于验证请求是否具有有效的授权令牌。
// 它通过检查HTTP请求的头部中的 "Authorization" 字段是否匹配预设的令牌来实现。
// 如果令牌无效,它会中止请求并返回 "Unauthorized" 错误。
// 如果令牌有效,它会允许请求继续进行到下一个处理函数。
func AuthRequired() gin.HandlerFunc {return func(c *gin.Context) {c.Request.Header.Set("Authorization", "my-secret-token")token := c.GetHeader("Authorization")fmt.Println("Token:", token)if token != "my-secret-token" {c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})c.Abort()return}c.Next()}
}func main() {r := gin.Default()// 应用认证中间件到所有 /admin 路由// 这里通过将 AuthRequired 作为参数传递给 r.Group 来实现,// 确保所有以 "/admin" 开头的路由都受到保护,防止未经授权的访问。admin := r.Group("/admin", AuthRequired()){// 定义 /admin/dashboard 路由的处理函数。// 该函数仅在通过 AuthRequired 中间件的验证后执行,// 确保只有拥有有效令牌的请求才能访问dashboard。admin.GET("/dashboard", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "Welcome to the dashboard"})})}// 启动HTTP服务器,监听端口8080。r.Run(":8080")
}

在这里插入图片描述

示例 3: 自定义恢复中间件

当应用程序遇到未捕获的异常(panic)时,这个中间件会捕获并恢复程序,返回一个标准的错误消息给客户端。

package mainimport ("net/http""github.com/gin-gonic/gin"
)// CustomRecovery 自定义恢复中间件,用于捕获并处理panic
// 这个中间件的目的是当发生panic时,能够优雅地恢复并返回500错误响应
func CustomRecovery() gin.HandlerFunc {return func(c *gin.Context) {defer func() {if err := recover(); err != nil {// 如果有 panic 发生,设置状态码为 500 并返回错误信息c.Error(err.(error)).SetMeta("recovered")c.AbortWithStatusJSON(http.StatusInternalServerError,gin.H{"error": "Internal Server Error"})}}()c.Next()}
}func main() {r := gin.Default()// 使用自定义的恢复中间件r.Use(CustomRecovery())// 设置一个路由,访问该路由会触发panicr.GET("/panic", func(c *gin.Context) {panic("an error occurred!")// fmt.Print("This line will not be executed.")})r.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Hello, World!"})})// 启动服务器,监听8080端口r.Run(":8080")
}

在这里插入图片描述

在上述示例中,我们创建了三种不同类型的中间件:用于日志记录、用户认证和异常恢复。你可以根据需要组合这些中间件,或者创建更多自定义中间件来满足你的应用需求。

全局中间件

在 Gin 框架中,全局中间件是应用于所有路由请求的中间件。你可以通过 gin.Engine.Use() 方法来注册这些中间件。下面我将给出三个使用全局中间件的完整示例,涵盖日志记录、异常恢复和性能监控。

示例 1: 全局日志记录中间件

这个中间件会在每个请求处理前后打印日志信息,包括请求的方法、路径、客户端 IP 和响应状态码。

package mainimport ("log""net/http""time""github.com/gin-gonic/gin"
)// GlobalLogger 返回一个gin.HandlerFunc类型的中间件,用于全局日志记录
// 它记录了请求的来源IP、路径、查询参数以及请求处理时间
func GlobalLogger() gin.HandlerFunc {return func(c *gin.Context) {// 记录请求开始时间start := time.Now()// 获取请求路径path := c.Request.URL.Path// 获取查询参数raw := c.Request.URL.RawQuery// 获取客户端IPclientIP := c.ClientIP()// 日志记录:开始处理请求log.Printf("Start handling request from %s: %s?%s", clientIP, path, raw)// 继续处理请求链中的其他处理器和中间件c.Next()// 记录请求结束时间end := time.Now()// 计算请求处理耗时latency := end.Sub(start)// 获取HTTP响应状态码statusCode := c.Writer.Status()// 日志记录:请求处理结果,包括状态码、耗时、客户端IP和请求路径log.Printf("| %3d | %13v | %15s | %40s |\n",statusCode, latency, clientIP, path+"?"+raw)}
}func main() {// 创建默认的gin路由器r := gin.Default()// 添加全局中间件:使用GlobalLogger记录所有请求的信息r.Use(GlobalLogger())// 定义路由:GET请求到/ping路径r.GET("/ping", func(c *gin.Context) {// 模拟耗时操作:休眠2秒time.Sleep(2 * time.Second)// 响应JSON数据:{"message": "pong"}c.JSON(http.StatusOK, gin.H{"message": "pong",})})// 启动服务器,监听8080端口r.Run(":8080")
}

在这里插入图片描述

示例 2: 全局异常恢复中间件

当应用程序遇到未捕获的异常(panic)时,这个中间件会捕获并恢复程序,返回一个标准的错误消息给客户端。

package mainimport ("net/http""github.com/gin-gonic/gin"
)// CustomRecovery 自定义异常恢复中间件
// 该中间件用于捕获并处理控制器中的 panic
// 返回: gin.HandlerFunc 类型的中间件函数
func CustomRecovery() gin.HandlerFunc {return func(c *gin.Context) {defer func() {if err := recover(); err != nil {// 如果有 panic 发生,设置状态码为 500 并返回错误信息c.Error(err.(error)).SetMeta("recovered")c.AbortWithStatusJSON(http.StatusInternalServerError,gin.H{"error": "Internal Server Error"})}}()c.Next()}
}func main() {r := gin.Default()// 添加全局异常恢复中间件r.Use(CustomRecovery())// 定义可能引发 panic 的路由r.GET("/panic", func(c *gin.Context) {panic("an error occurred!")})r.Run(":8080")
}

在这里插入图片描述

示例 3: 全局性能监控中间件

这个中间件用于记录每个请求的处理时间,并且可以根据需要收集更多的性能指标。

package mainimport ("log""net/http""time""github.com/gin-gonic/gin"
)// PerformanceMonitor 是一个中间件函数,用于监控请求的性能。
// 它会记录每个请求的处理时间。
func PerformanceMonitor() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()// 继续处理请求链中的其他处理器和中间件c.Next()// 请求处理后的操作end := time.Now()latency := end.Sub(start)log.Printf("Request completed in %v\n", latency)}
}func main() {r := gin.Default()// 添加全局性能监控中间件r.Use(PerformanceMonitor())// 定义一些路由r.GET("/slow", func(c *gin.Context) {time.Sleep(5 * time.Second) // 模拟耗时操作c.JSON(http.StatusOK, gin.H{"message": "This is a slow endpoint",})})r.Run(":8080")
}

在这里插入图片描述

在这三个示例中,我们展示了如何创建和应用全局中间件来增强 Gin 应用的功能。GlobalLogger 中间件记录了每个请求的信息,CustomRecovery 中间件提供了异常恢复机制,而 PerformanceMonitor 中间件则可以用来监控应用程序的性能。你可以根据自己的需求调整这些中间件或添加新的全局中间件。

在路由分组中配置中间件

在 Gin 框架中,路由分组(Group)允许你将一组相关的路由归类在一起,并且可以为这个组配置特定的中间件。这有助于保持代码的整洁和模块化,同时提供更细粒度的控制。下面是三个使用路由分组并配置中间件的完整示例。

示例 1: API 版本控制

这个例子展示了如何创建不同版本的 API 分组,并为每个版本添加不同的中间件。

package mainimport ("github.com/gin-gonic/gin"
)// VersionMiddleware 返回一个中间件处理器,用于在上下文中设置API版本信息。
// 参数 version 指定要设置的API版本。
// 该中间件使得后续的处理器可以访问通过c.Get("api-version")获取版本信息。
func VersionMiddleware(version string) gin.HandlerFunc {return func(c *gin.Context) {c.Set("api-version", version)c.Next()}
}func main() {r := gin.Default()// 创建并配置/v1版本的API路由组。// 使用VersionMiddleware设置API版本为"1.0"。v1 := r.Group("/v1", VersionMiddleware("1.0")){// 处理/v1版本的GET请求,返回用户列表信息和API版本。v1.GET("/users", func(c *gin.Context) {version := c.MustGet("api-version").(string)c.JSON(200, gin.H{"version": version, "message": "Users list"})})}// 创建并配置/v2版本的API路由组。// 使用VersionMiddleware设置API版本为"2.0"。v2 := r.Group("/v2", VersionMiddleware("2.0")){// 处理/v2版本的GET请求,返回用户列表信息和API版本,可能包含新特性。v2.GET("/users", func(c *gin.Context) {version := c.MustGet("api-version").(string)c.JSON(200, gin.H{"version": version, "message": "Users list with new features"})})}// 启动HTTP服务器,监听端口8080。r.Run(":8080")
}

在这里插入图片描述

示例 2: 用户认证中间件应用于部分路由

这个例子展示了如何为需要用户认证的路由分组添加认证中间件。

package mainimport ("net/http""github.com/gin-gonic/gin"
)// AuthMiddleware 返回一个中间件函数,用于验证请求的授权令牌
// 如果令牌有效,请求将继续处理;如果令牌无效,将返回401 Unauthorized错误
func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {token := c.GetHeader("Authorization")if token != "my-secret-token" {c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})c.Abort()return}c.Next()}
}func main() {r := gin.Default()// 不需要认证的公开路由public := r.Group("/public"){public.GET("/ping", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "pong"})})}// 需要认证的受保护路由// 使用AuthMiddleware中间件来验证请求的授权令牌protected := r.Group("/protected", AuthMiddleware()){protected.GET("/dashboard", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "Welcome to the dashboard"})})}r.Run(":8080")
}

在这里插入图片描述

示例 3: 结合全局中间件与分组中间件

此示例展示了如何结合全局中间件和分组中间件,以确保所有请求都经过日志记录中间件,而只有特定的分组才需要通过额外的中间件。

package mainimport ("log""net/http""time""github.com/gin-gonic/gin"
)func LoggerMiddleware() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()path := c.Request.URL.Pathraw := c.Request.URL.RawQuery// 请求处理前的操作log.Printf("Start handling request: %s?%s", path, raw)// 继续处理请求链中的其他处理器和中间件c.Next()// 请求处理后的操作end := time.Now()latency := end.Sub(start)statusCode := c.Writer.Status()clientIP := c.ClientIP()log.Printf("| %3d | %13v | %15s | %40s |\n",statusCode, latency, clientIP, path+"?"+raw)}
}func RateLimitMiddleware(limit int) gin.HandlerFunc {return func(c *gin.Context) {// 这里只是一个简单的示例,实际应用中应该实现更复杂的限流逻辑time.Sleep(time.Duration(limit) * time.Millisecond)c.Next()}
}func main() {r := gin.Default()// 添加全局中间件r.Use(LoggerMiddleware())// 创建一个没有额外中间件的公共路由分组public := r.Group("/public"){public.GET("/ping", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "pong"})})}// 创建一个有速率限制的分组limit := r.Group("/limited", RateLimitMiddleware(100)){limit.GET("/slow", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "This is a rate-limited endpoint"})})}r.Run(":8080")
}

在这里插入图片描述

在这三个示例中,我们展示了如何使用中间件来增强 Gin 路由的功能。你可以根据自己的需求组合全局中间件和分组中间件,以实现更复杂的应用逻辑。

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

在 Gin 框架中,中间件和控制器之间共享数据的一个常用方法是使用 gin.ContextSet()Get() 方法。gin.Context 是一个上下文对象,它贯穿整个请求的生命周期,因此可以在中间件中设置一些值,并在之后的控制器处理函数中获取这些值。

下面是三个展示如何在中间件和控制器之间共享数据的完整示例:

示例 1: 用户认证信息共享

在这个例子中,我们将在认证中间件中解析用户的认证信息,并将其存储到 gin.Context 中,以便后续的控制器可以访问这些信息。

package mainimport ("net/http""github.com/gin-gonic/gin"
)// AuthMiddleware 是一个中间件,用于验证请求的授权信息。
// 它通过检查请求头中的 Authorization 字段来确定请求是否经过授权。
// 如果验证通过,它会设置用户信息并允许请求继续进行;
// 如果验证失败,它会返回 401 状态码和错误信息。
func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {token := c.GetHeader("Authorization")if token == "my-secret-token" {c.Set("user", "authenticated-user") // 设置用户信息c.Next()} else {c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})c.Abort()}}
}func main() {r := gin.Default()// 创建一个受保护的路由组,所有该组内的请求都需要经过授权验证。protected := r.Group("/protected", AuthMiddleware()){// 处理 /protected/profile 路径的 GET 请求。// 如果请求已授权,返回欢迎信息;否则,返回错误信息。protected.GET("/profile", func(c *gin.Context) {if user, exists := c.Get("user"); exists {c.JSON(http.StatusOK, gin.H{"message": "Welcome " + user.(string)})} else {c.JSON(http.StatusInternalServerError, gin.H{"error": "User info not found"})}})}// 启动 HTTP 服务器,监听 8080 端口。r.Run(":8080")
}

在这里插入图片描述

示例 2: 请求计数器

这个例子展示了如何在中间件中维护一个简单的请求计数器,并在控制器中访问这个计数器。

package mainimport ("net/http""sync""github.com/gin-gonic/gin"
)// requestCount 记录HTTP请求的次数
var (requestCount intmu           sync.Mutex
)// RequestCounter 是一个中间件函数,用于在每次HTTP请求时增加请求计数
// 该函数首先锁定互斥锁以确保并发安全,然后增加请求计数,并将计数存储在gin.Context中
// RequestCounter 返回一个中间件函数,用于统计HTTP请求的数量。
// 该中间件使用了互斥锁确保并发安全,特别是在处理高并发请求时。
// 它在每个请求的上下文中设置了当前的请求计数,供后续处理使用。
func RequestCounter() gin.HandlerFunc {return func(c *gin.Context) {// 上锁以确保并发安全mu.Lock()// 增加请求计数requestCount++// 在上下文中设置当前的请求计数c.Set("requestCount", requestCount)// 解锁以释放资源mu.Unlock()// 调用链中的下一个处理函数c.Next()}
}func main() {r := gin.Default()// 使用RequestCounter中间件来跟踪和增加请求计数r.Use(RequestCounter())// 处理/count路由的GET请求,返回当前请求计数r.GET("/count", func(c *gin.Context) {if count, exists := c.Get("requestCount"); exists {c.JSON(http.StatusOK, gin.H{"count": count})} else {c.JSON(http.StatusInternalServerError, gin.H{"error": "Request count not found"})}})// 启动HTTP服务器,监听8080端口r.Run(":8080")
}

在这里插入图片描述

示例 3: 查询参数预处理

此示例展示了如何在中间件中解析并预处理查询参数,然后将处理后的结果传递给控制器。

package mainimport ("fmt""net/http""strings""github.com/gin-gonic/gin"
)// QueryParamProcessor 是一个中间件函数,用于处理查询参数。
// 它从请求中获取 'search' 查询参数,
// 对其进行一些处理(例如去除首尾空白字符),
// 并将处理后的结果存储在上下文中,键为 'processedQuery'。
// 这样后续的处理器可以访问到处理后的查询参数。
func QueryParamProcessor() gin.HandlerFunc {return func(c *gin.Context) {query := c.Query("search")processedQuery := strings.TrimSpace(query) // 假设这里有一些复杂的处理逻辑fmt.Println("Processed query:", processedQuery)c.Set("processedQuery", processedQuery)c.Next()}
}func main() {r := gin.Default()// 使用全局中间件 QueryParamProcessor。// 该中间件会预处理所有传入请求的查询参数,// 使任何后续路由处理器都可以访问处理后的查询参数。r.Use(QueryParamProcessor())// 定义 '/search' 的 GET 路由。// 该路由检查上下文中是否存在 'processedQuery'。// 如果存在,则返回包含处理后查询参数的搜索结果;// 否则,返回一条消息表示未提供查询参数。r.GET("/search", func(c *gin.Context) {if query, exists := c.Get("processedQuery"); exists {c.JSON(http.StatusOK, gin.H{"search_results": "Results for: " + query.(string)})} else {c.JSON(http.StatusOK, gin.H{"search_results": "No query provided"})}})// 启动 Gin 服务器,并监听 8080 端口。r.Run(":8080")
}

在这里插入图片描述

在这三个示例中,我们展示了不同的场景下如何利用 gin.ContextSet()Get() 方法来在中间件和控制器之间共享数据。这种方式不仅可以简化代码逻辑,还能确保数据在整个请求处理过程中的一致性和可访问性。请注意,在并发环境中操作共享变量时(如示例2中的 requestCount),应采取适当的同步措施以保证线程安全。

中间件注意事项

在使用 Gin 框架的中间件时,有一些重要的注意事项可以帮助你更安全、有效地编写和使用中间件。以下是一些关键点:

1. 中间件链的顺序

  • 中间件的执行顺序是按照它们被添加到路由或路由组中的顺序来决定的。因此,先添加的中间件会最先处理请求,并且最后处理响应。
  • 如果有多个中间件,确保它们的顺序符合你的逻辑需求。例如,日志记录中间件通常应该放在其他中间件之前,以便它可以记录整个请求过程。

2. c.Next() 的调用

  • 在中间件中一定要调用 c.Next() 方法,它表示继续处理请求链中的下一个处理器或中间件。如果不调用 c.Next(),那么后续的处理器将不会被执行。
  • 如果某个中间件需要阻止请求继续前进(如认证失败),可以调用 c.Abort()c.AbortWithStatus() 来停止链的执行。

3. 线程安全

  • 如果你在中间件中共享了某些变量或资源,确保这些资源是线程安全的。Gin 是并发处理请求的,所以多个 goroutine 可能同时访问这些资源。
  • 使用互斥锁(sync.Mutex)或者其他同步机制来保护共享状态。

4. 避免不必要的延迟

  • 中间件不应该引入不必要的延迟。如果一个中间件需要执行耗时操作,考虑将其移到后台 goroutine 中,或者异步处理。
  • 对于性能敏感的应用程序,尽量减少中间件的数量和复杂度。

5. 错误处理

  • 中间件中应包含适当的错误处理逻辑。比如,在遇到未捕获的 panic 时,应该使用恢复中间件(recovery middleware)来捕获异常并返回合适的 HTTP 状态码。
  • 当发生错误时,不要忘记调用 c.Error() 方法记录错误信息,这有助于后续的日志分析和调试。

6. 数据共享

  • 使用 gin.Context.Set()gin.Context.Get() 方法在中间件与控制器之间传递数据。但是要注意,不要过度依赖这种方式,因为过多的状态管理会使代码难以维护。
  • 如果你需要在整个应用中频繁访问某些数据,考虑使用配置文件或者依赖注入的方式来提供这些数据。

7. 清理工作

  • 如果中间件分配了资源(如打开文件、网络连接等),确保在请求完成后正确释放这些资源。你可以使用 defer 关键字来确保即使发生错误也能执行清理代码。

8. 测试

  • 编写单元测试来验证中间件的行为非常重要。Gin 提供了良好的测试支持,可以模拟 HTTP 请求来测试中间件和控制器的行为。

9. 文档和注释

  • 给中间件添加清晰的注释和文档,解释它的功能和预期行为,这对于团队协作和后期维护都非常有用。

遵循上述注意事项,可以帮助你构建更加稳健和高效的 Gin 应用程序。记住,中间件是强大的工具,但也要谨慎使用,以避免引入不必要的复杂性。

下载示例代码

Gin 框架入门精讲与实战案例代码

相关文章:

8-Gin 中间件 --[Gin 框架入门精讲与实战案例] 【文末有测试代码】

路由中间件 Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。它以性能好、中间件支持灵活著称,非常适合用来构建微服务或 RESTful API 服务。下面我将提供三个使用 Gin 的路由中间件的完整示例。 示例 1: 简单的日志记录中间件 这个中间件会在每个请求处理前后打…...

【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。

目录 一、toString() 方法是啥? (一)默认的 toString() 方法 (二)toString() 方法的作用 二、为啥要重写 toString() 方法? (一)提高代码的可读性 (二)…...

【论文笔记】Contrastive Learning for Sign Language Recognition and Translation

🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Contrastive Learning for…...

Gitlab17.7+Jenkins2.4.91实现Fastapi/Django项目持续发布版本详细操作(亲测可用)

一、gitlab设置: 1、进入gitlab选择主页在左侧菜单的下面点击管理员按钮。 2、选择左侧菜单的设置,选择网络,在右侧选择出站请求后选择允许来自webhooks和集成对本地网络的请求 3、webhook设置 进入你自己的项目选择左侧菜单的设置&#xff…...

一起来看--红黑树

【欢迎关注编码小哥,学习更多实用的编程方法和技巧】 红黑树是一种自平衡的二叉搜索树,广泛应用于计算机科学中,尤其是在实现关联数组和集合时。它的设计旨在确保在最坏情况下,基本动态集合操作(如插入、删除和查找&am…...

SpringBoot整合篇 05、Springboot整合Redission

文章目录 前言Redission详细配置步骤pom依赖application.yaml配置类CacheConfigEnvironmentContext RedissionController单测 前言 本篇博客是SpringBoot整合Redission,若文章中出现相关问题,请指出! 所有博客文件目录索引:博客…...

供应链系统设计-供应链中台系统设计(六)- 商品中心概念篇

概述 我们在供应链系统设计-中台系统设计系列(五)- 供应链中台实践概述 中描述了什么是供应链中台,供应链中台主要包含了那些组成部门。包括业务中台、通用中台等概念。为了后续方便大家对于中台有更深入的理解,我会逐一针对中台…...

胡闹厨房练习(三)

ScriptableObject 一、初步了解 1、实质:是一种特殊类型的Unity对象, 2、作用:用于存储大量数据,而不必依附于游戏场景中的某个GameObject。 3、特点: 可以在不增加场景中对象数量的情况下,管理和存储复杂的数据结构、配置信息、游戏状态等。 4、适用:非常适合用来…...

关于ESD(静电放电)等级的划分

关于ESD(静电放电)等级的划分,主要依据不同的测试模型和测试标准。以下是对HBM(人体模型)和CDM(充电器件模型)两种测试模型下ESD等级划分的详细解释: HBM ESD等级划分 HBM ESD等级…...

探究步进电机与输入脉冲的关系

深入了解步进电机 前言一、 步进电机原理二、 细分三、脉冲数总结 前言 主要是探究以下内容: 1、步进电机的步进角。 2、什么是细分。 3、脉冲的计算。 最后再扩展以下STM32定时器的计算方法。 一、 步进电机原理 其实语言描述怎么样都不直观,我更建议…...

基于YOLOV5+Flask安全帽RTSP视频流实时目标检测

1、背景 在现代工业和建筑行业中,安全始终是首要考虑的因素之一。特别是在施工现场,工人佩戴安全帽是确保人身安全的基本要求。然而,人工监督难免会有疏漏,尤其是在大型工地或复杂环境中,确保每个人都佩戴安全帽变得非…...

Windows内置的服务器IIS(Internet Information Services)托管网站

一. 安装IIS 打开控制面板:在开始菜单搜索“控制面板”并打开它。程序和功能:点击“程序”然后选择“程序和功能”。启用或关闭Windows功能:在左侧菜单中选择“启用或关闭Windows功能”。查找并勾选IIS:在弹出的窗口中&#xff0c…...

虚幻引擎结构之UObject

一. UObject 的介绍 UObject 是虚幻引擎中的核心基础类,所有其他游戏对象和资源类都直接或间接地继承自它。作为虚幻引擎的基石,UObject 提供了多项关键功能,包括内存管理、序列化、反射(introspection)、垃圾回收以及元数据支持。在虚幻引擎中,UObject 类的实例通常被称…...

js的Reflect对象

Reflect 对象是 JavaScript ES6 中引入的一个内建对象,它提供了一系列与对象操作相关的方法。这些方法与 Object 对象上的方法类似,但在行为上有一些差异,并且更加规范和统一。Reflect 对象并不是一个构造函数,不能被 new 操作符调…...

this指向了谁?

看函数在执行的时候是如何调用的, 1 如果这个函数是用普通函数调用模式来进行调用,它内部的this指向了window; 2 如果一个函数在调用的时候是通过对象方法模式来进行调用,则它内部的this就是我们的对象; 3 如果一个函数在调用的时候通过构…...

基于Resnet、LSTM、Shufflenet及CNN网络的Daily_and_Sports_Activities数据集仿真

在深度学习领域,不同的网络结构设计用于解决特定的问题。本文将详细分析四种主流网络结构:卷积神经网络(CNN)、残差网络(ResNet)、长短期记忆网络(LSTM)和洗牌网络(Shuff…...

mac系统vsCode中使用Better Comments在.vue文件里失效

问题:关于Better Comments默认在html、TS、JS中有效,在vue中无效,需要单独进行配置 windows系统可以参考友链Better Comments(注释高亮)在vue文件里失效的问题 关于Better Comments电脑的配置路径: Windows系统&…...

UE5.3 C++ Ceiusm中的POI 制作3DUI 结合坐标转化

一.核心思路WidgetComponent CesiumGloberAnchor 二.先制作POI 创建C Actor来制作,APOI。直接上代码 #pragma once#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "CesiumGlobeAnchorComponent.h" #includ…...

一起学Git【第六节:查看版本差异】

git diff是 Git 版本控制系统中用于展示差异的强大工具。他可以用于查看文件在工作区、暂存区和版本库之间的差异、任意两个指定版本之间的差异和两个分支之间的差异等,接下来进行详细的介绍。 1.显示工作区与暂存区之间的差异 # 显示工作区和暂存区之间的差异,后面不加参数…...

numpy np.newaxis介绍

np.newaxis 是 NumPy 中用于增加数组维度的关键字。它的作用是为数组插入一个新的维度,从而改变数组的形状(shape)。 基本用法 np.newaxis 等价于 None,可以作为索引使用,用于在指定位置增加一个维度。增加的维度的大…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

AI,如何重构理解、匹配与决策?

AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

微服务通信安全:深入解析mTLS的原理与实践

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

Linux安全加固:从攻防视角构建系统免疫

Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

flow_controllers

关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...

Windows 下端口占用排查与释放全攻略

Windows 下端口占用排查与释放全攻略​ 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。​ 一、准…...

【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验

2024年初,人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目(一款融合大型语言模型能力的云端AI编程IDE)时,技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力,TRAE在WayToAGI等…...

EasyRTC音视频实时通话功能在WebRTC与智能硬件整合中的应用与优势

一、WebRTC与智能硬件整合趋势​ 随着物联网和实时通信需求的爆发式增长,WebRTC作为开源实时通信技术,为浏览器与移动应用提供免插件的音视频通信能力,在智能硬件领域的融合应用已成必然趋势。智能硬件不再局限于单一功能,对实时…...