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

goweb框架-gin

文章目录

    • Gin框架概览
      • Gin框架的特点
      • Gin框架的安装和基本使用
        • 安装
        • 基本使用
    • 路由系统
      • 路由的基本概念
      • Gin框架路由的特点
    • Radix Tree(基数树)
      • 基数树的定义和原理
      • 基数树在Gin框架中的应用
        • 节省空间的优化
        • 动态路由和通配符处理
    • 路由树的构建
      • 注册路由的过程
      • 路由树节点的定义和属性
      • 路由树的构建算法
    • 路由匹配机制
      • 路由匹配的入口函数
      • 路由匹配的流程
      • 尾随斜杠重定向(TSR)
    • 中间件机制
      • 中间件的定义和作用
      • Gin框架中间件的注册和执行流程
      • 常用中间件的介绍
    • 中间件的执行顺序和流程
      • 中间件链的构建
      • 中间件的执行逻辑
      • 中间件中的`Next()`方法
    • 源码解析
      • 重点代码段的解析
      • 路由注册和匹配的源码分析
    • 性能优化
      • 路由树的优先级排序
      • 路由匹配的性能考量

gin框架源码解析 - 李文周的博客

Gin框架概览

Gin框架的特点

Gin是一个高性能的Web框架,它具有以下显著特点:

  1. 性能优异:Gin框架在性能上非常出色,能够处理大量的并发请求。
  2. 路由灵活:支持动态路由和正则表达式路由,使得路由定义非常灵活。
  3. 中间件丰富:提供了丰富的中间件支持,如Logger、Recovery等,方便进行日志记录和错误恢复。
  4. 错误处理:内置的错误处理机制,可以方便地进行错误捕捉和响应。
  5. JSON****支持:内置对JSON的绑定和验证,简化了API开发流程。
  6. RESTful API:支持RESTful风格API的开发,符合现代Web API设计原则。
  7. 社区活跃:拥有活跃的社区和丰富的插件生态,便于开发者扩展功能。

Gin框架的安装和基本使用

安装

Gin框架的安装非常简单,通过Go的包管理工具go get即可安装:

bash

go get -u github.com/gin-gonic/gin
基本使用

安装完成后,可以通过以下步骤快速创建一个Gin Web应用:

  1. 导入Gin包:在Go文件中导入Gin框架。

go

import "github.com/gin-gonic/gin"
  1. 创建路由:定义HTTP路由和对应的处理函数。

go

func main() {router := gin.Default()router.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{
{            "message": "hello world"}})})// 启动服务器router.Run()
}
  1. 启动服务器:使用router.Run()启动Gin服务器,默认监听在0.0.0.0:8080端口。
  2. 访问应用:在浏览器或使用工具如curl访问http://localhost:8080,可以看到返回的JSON消息。

路由系统

路由的基本概念

路由是Web框架中用于处理客户端请求并将其映射到特定处理函数的机制。在Web开发中,路由决定了当用户访问某个URL时,应该执行哪些代码。路由系统通常包含以下几个关键概念:

  • URL: 用户请求的网络地址,例如 http://example.com/api/users
  • HTTP方法: 请求的类型,如 GET, POST, PUT, DELETE 等。
  • 路由模式: 可以是静态的,如 /about,也可以是动态的,包含参数,如 /users/:id
  • 处理函数: 与特定路由匹配时执行的函数,用于生成响应。

Gin框架路由的特点

Gin框架的路由系统具有以下特点:

  1. 动态路由****与参数绑定:Gin支持在路由中使用参数,例如 /users/:id,方便获取URL中的数据。
  2. 正则表达式路由:Gin允许使用正则表达式来定义路由模式,提供了更复杂的路由匹配能力。
  3. 路由分组:通过分组可以组织相关路由,同时可以为分组应用中间件,简化配置。
  4. 中间件支持:可以在特定路由或路由组上使用中间件,进行日志记录、鉴权等操作。
  5. 路由匹配顺序:Gin会按照路由定义的顺序进行匹配,直到找到匹配的路由。
  6. 路由优先级:Gin使用基数树(Radix Tree)来优化路由匹配,提高匹配效率。
  7. 自动404处理:如果找不到匹配的路由,Gin会自动返回404错误。
  8. 路由参数验证:Gin支持对路由参数进行自动验证,确保数据的正确性。
  9. RESTful API支持:Gin的路由设计天然支持RESTful API风格,易于构建RESTful服务。
  10. 灵活的路由定义:支持使用GET, POST, PUT, DELETE等HTTP方法定义路由,以及ANY方法匹配所有HTTP方法。

通过这些特点,Gin框架提供了一个强大而灵活的路由系统,使得Web应用开发更加高效和易于管理。接下来,我们可以深入探讨Gin路由系统的内部实现,特别是基数树的使用和路由匹配机制。

Radix Tree(基数树)

基数树的定义和原理

基数树(Radix Tree),又称前缀树(Trie),是一种用于快速检索的数据结构,特别适用于处理字符串的前缀匹配问题。以下是基数树的一些基本定义和原理:

  • 节点:基数树由多个节点组成,每个节点代表字符串中的一个字符。
  • 根节点:代表空字符串,是树的起点。
  • 路径:从根节点到某一节点的序列,代表一个字符串的前缀。
  • 叶子节点:代表一个完整的字符串或模式。
  • 压缩:如果一个节点的所有子节点都只有一个子节点,该节点可以被压缩,从而节省空间。

基数树的工作原理基于字符串的公共前缀,通过共享这些前缀来减少存储空间。当插入或查询字符串时,树会沿着公共前缀向下遍历,直到达到字符串的末尾或树的末端。

基数树在Gin框架中的应用

节省空间的优化

Gin框架使用定制版本的基数树来优化路由的存储和匹配。以下是一些节省空间的优化措施:

  1. 节点合并:如果一个节点的所有子节点都只有一个子节点,Gin会将这些节点合并,减少节点的数量。
  2. 公共前缀共享:通过共享公共前缀,减少了重复的字符串存储,从而节省内存。
  3. 路径压缩:Gin在构建路由树时,会压缩不必要的路径,避免冗余。
动态路由和通配符处理

Gin框架的基数树还支持动态路由和通配符处理:

  1. 动态路由:Gin允许在路由中使用参数,如 /users/:id,这些参数在基数树中以特殊节点处理,可以匹配任意字符串。
  2. 通配符:Gin支持使用通配符,如 *,来匹配任意数量的任意字符。在基数树中,这通常通过特殊的节点来实现,这些节点可以匹配多个字符或子路径。
  3. 优先级排序:Gin在构建路由树时,会根据请求方法和路径的长度等因素对节点进行排序,以优化路由匹配的效率。

通过使用基数树,Gin框架能够高效地处理大量的路由,同时保持较低的内存占用和快速的匹配速度。基数树的结构使得Gin能够快速地找到匹配的路由,即使在面对复杂的路由配置时也能保持良好的性能。

路由树的构建

注册路由的过程

在Gin框架中,注册路由是一个将URL模式与处理函数相关联的过程。以下是注册路由的基本步骤:

  1. 创建路由实例:首先,创建一个gin.Engine的实例,这是路由注册和管理的核心。

go

router := gin.Default()
  1. 定义路由:使用GET, POST, PUT, DELETE等HTTP方法来定义路由,并指定URL模式。

go

router.GET("/user/:id", getUserByID)
  1. 指定处理函数:为每个路由指定一个处理函数,当路由匹配时,该函数将被调用。

go

func getUserByID(c *gin.Context) {// 处理请求
}
  1. 添加中间件:可以在特定路由或全局添加中间件来处理日志、鉴权等。

go

router.Use(middleware.Logger())
  1. 启动服务器:最后,启动Gin服务器监听和处理请求。

go

router.Run(":8080")

路由树节点的定义和属性

Gin框架中的路由树由多个节点组成,每个节点可能包含以下属性:

  • Path: 节点的路径字符串。
  • Handlers: 与该节点关联的处理函数链。
  • Priority: 节点的优先级,用于路由匹配时的排序。
  • Children: 子节点列表,用于表示路由的下一个字符或通配符。
  • Params: 路由参数列表,用于动态路由。
  • WildCard: 是否包含通配符,如*

路由树的构建算法

路由树的构建算法是Gin框架高效路由匹配的核心。以下是构建算法的关键步骤:

  1. 初始化:创建根节点,作为路由树的起点。
  2. 遍历路径:对于每个注册的路由,遍历其路径字符串。
  3. 节点创建与合并:对于路径中的每个字符或参数,创建新的节点或与现有节点合并。
  4. 参数处理:识别并处理路由参数(如:id)和通配符(如*)。
  5. 节点插入:将处理函数与相应的节点关联,并根据优先级排序。
  6. 压缩优化:优化树结构,合并连续的单子节点,减少内存占用。
  7. 中间件注册:为路由或路由组注册中间件,并将其与处理函数链合并。
  8. 构建完成:所有路由注册完成后,路由树构建完成,可用于请求匹配。

路由树的构建算法需要考虑多种因素,包括路由的动态性、通配符、中间件的注册顺序等,以确保路由匹配的准确性和效率。

路由匹配机制

路由匹配的入口函数

路由匹配的入口点通常是ServeHTTP方法,这是Gin框架处理每个HTTP请求的起点。ServeHTTP方法会调用路由匹配逻辑来找到并执行相应的处理函数。

go

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {// 省略其他代码c := engine.createContext(req)c.Writer = wengine.handleHTTPRequest(c)
}

handleHTTPRequest方法中,会调用路由树的查找逻辑,以确定哪个处理函数应该被执行。

路由匹配的流程

  1. 初始化上下文:为每个请求创建一个新的上下文对象,其中包含请求和响应相关的信息。
  2. 解析请求路径:提取请求的URL路径,并对其进行必要的解码。
  3. 遍历路由树:从根节点开始,根据请求路径中的每个字符或参数,逐级遍历路由树。
  4. 匹配节点:在遍历过程中,匹配节点的路径与请求路径。如果遇到动态路由或通配符,将捕获相应的参数。
  5. 执行中间件:如果路由匹配成功,会先执行与该路由关联的中间件链。
  6. 执行处理函数:中间件执行完毕后,调用最终的处理函数来生成响应。
  7. 处理不匹配情况:如果找不到匹配的路由,Gin会返回404错误。

尾随斜杠重定向(TSR)

尾随斜杠重定向(Trailing Slash Redirect)是一种常见的Web路由行为,用于处理URL路径末尾的斜杠问题。在Gin中,如果请求的URL路径与某个路由模式匹配,但该模式的末尾有一个斜杠,而请求的URL没有,Gin会自动进行重定向。

  1. 检测尾随斜杠:在路由匹配过程中,如果发现请求路径与某个路由模式匹配,但模式的末尾有斜杠而请求路径没有,或者相反,Gin会触发TSR。
  2. 执行重定向:Gin会构造一个新的URL,将请求重定向到正确的路径。例如,如果请求/users而路由模式是/users/,Gin会重定向到/users/
  3. 配置TSR:Gin允许开发者通过配置禁用或启用TSR行为。

go

router := gin.New()
router.RedirectTrailingSlash = true // 默认为true
  1. 处理重定向响应:客户端接收到重定向响应后,会根据响应头中的Location字段重新发起请求。

通过这种方式,Gin确保了URL的一致性,避免了因尾随斜杠不一致导致的潜在问题。

中间件机制

中间件的定义和作用

中间件在Web框架中充当一个处理链,它能够介入处理HTTP请求和响应的流程。中间件的主要作用包括:

  • 处理请求前逻辑:在主处理函数执行前,进行日志记录、鉴权、跨域处理等。
  • 处理请求后逻辑:在主处理函数执行后,进行响应修改、日志记录、错误处理等。
  • 流程控制:中间件可以决定是否继续执行链中的下一个处理函数或直接结束请求处理。

Gin框架中间件的注册和执行流程

在Gin框架中,中间件的注册和执行遵循以下流程:

  1. 注册中间件:在路由或全局级别注册中间件。

go

// 全局中间件
router.Use(middleware.Logger())
// 特定路由中间件
router.GET("/user/:id", middleware.Auth(), getUserByID)
  1. 创建处理链:Gin将注册的中间件和处理函数组合成一个处理链。
  2. 执行中间件:当请求到来时,Gin会按照注册顺序依次执行中间件。
  3. 调用**Next()**:每个中间件可以调用c.Next()来传递控制权给链中的下一个中间件或处理函数。
  4. 终止链执行:中间件可以通过调用c.Abort()来终止链的进一步执行。
  5. 执行处理函数:如果中间件链执行完毕且没有中间件调用c.Abort(),则执行最终的处理函数。
  6. 响应客户端:处理函数执行完毕后,Gin会发送响应回客户端。

常用中间件的介绍

Gin框架提供了一些常用的中间件,以下是几个示例:

  1. Logger:记录请求的日志信息,包括时间、方法、路径、状态码等。
  2. Recovery:恢复panic状态,确保服务稳定性,记录panic信息。
  3. Auth:一个示例中间件,用于进行用户认证。
  4. Cors:处理跨源资源共享(CORS)问题,允许跨域请求。
  5. Gzip:对响应内容进行Gzip压缩,减少传输数据量。
  6. RateLimit:限流中间件,控制客户端请求频率。
  7. Secure:增强应用安全性,如设置HTTP头部以防止某些类型的攻击。
  8. Session:管理用户会话,存储用户状态。
  9. BasicAuth:提供基本的HTTP认证。
  10. JWTAuth:使用JSON Web Tokens进行用户认证。

中间件的使用可以使Web应用更加模块化和灵活,开发者可以根据需要选择和组合不同的中间件来构建功能丰富的Web服务。

中间件的执行顺序和流程

中间件链的构建

在Gin框架中,中间件链的构建是通过将多个中间件函数按顺序注册到路由或全局处理器上实现的。以下是构建中间件链的步骤:

  1. 定义中间件:编写中间件函数,这些函数将接收一个*gin.Context作为参数。

go

func MyMiddleware(c *gin.Context) {// 在这里编写中间件逻辑
}
  1. 注册中间件:使用Use方法将中间件添加到全局中间件链,或添加到特定路由的中间件链。

go

// 注册全局中间件
engine.Use(middleware.Logger())
// 注册特定路由中间件
engine.GET("/user/:id", MyMiddleware, getUserByID)
  1. 组合中间件:中间件可以被组合,形成一个处理链,请求将按注册顺序依次通过它们。
  2. 创建处理链:Gin内部会根据注册的中间件和最终的处理函数,构建一个完整的处理链。

中间件的执行逻辑

中间件的执行遵循以下逻辑:

  1. 接收请求:当一个请求到达服务器时,Gin会创建一个新的Context
  2. 执行第一个中间件:Gin开始执行中间件链的第一个中间件。
  3. 调用**Next()**:如果中间件需要将控制权传递给下一个中间件或最终的处理函数,它会调用c.Next()

go

func MyMiddleware(c *gin.Context) {// 执行中间件逻辑c.Next() // 传递给下一个中间件或处理函数
}
  1. 按顺序执行:Gin会按注册顺序继续执行下一个中间件,直到最后一个中间件。
  2. 执行处理函数:最后一个中间件调用c.Next()后,Gin会执行最终的处理函数。
  3. 响应客户端:处理函数执行完毕后,Gin会构建HTTP响应并发送给客户端。

中间件中的Next()方法

Next()方法是中间件中的关键,它的作用是:

  • 继续执行链:告诉Gin继续执行中间件链中的下一个中间件或处理函数。
  • 控制流程:如果中间件中没有调用Next(),那么链中的后续中间件和处理函数将不会被执行。

使用Next()的示例:

go

func MyMiddleware(c *gin.Context) {// 执行一些前置逻辑// 继续执行中间件链c.Next()// 执行一些后置逻辑
}

如果中间件需要提前终止中间件链的执行,可以使用c.Abort()

go

func MyMiddleware(c *gin.Context) {// 执行一些逻辑,如果需要终止链执行c.Abort()// 后面的中间件和处理函数将不会执行
}

中间件的执行顺序和流程对于构建高效、可维护的Web服务至关重要。正确使用中间件可以提供额外的功能,如日志记录、鉴权、错误处理等,同时保持代码的清晰和组织性。

源码解析

重点代码段的解析

在Gin框架中,路由注册和匹配是核心功能,涉及到的源码主要集中在engine.gotree.go等文件中。以下是一些重点代码段的解析:

  1. 路由注册 (engine.go):
    1. Gin框架使用Engine结构体来维护路由信息,其中包括一个trees字段,用于存储不同的HTTP方法对应的路由树。

go

func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {tree := engine.trees.get(method)if tree == nil {tree = NewMethodTree()engine.trees.set(method, tree)}tree.addRoute(path, handlers)
}
  1. 路由树的添加逻辑 (tree.go):
    1. MethodTree是存储特定HTTP方法路由的树结构,addRoute方法用于向树中添加新的路由。

go

func (tree *MethodTree) addRoute(path string, handlers HandlersChain) {node := tree.rootfor _, p := range path {// 遍历路径,构建树结构// ...}node.handlers = append(node.handlers, handlers)
}
  1. 请求处理 (engine.go):
    1. handleRequest是处理请求的核心方法,它使用路由树来匹配请求路径,并执行相应的处理函数。

go

func (engine *Engine) handleRequest(c *Context) {handlers := engine.trees.get(c.Request.Method).getValue(c.Request.URL.Path, c.Params)if handlers != nil {// 执行匹配到的路由的处理函数和中间件// ...} else {// 没有找到匹配的路由,调用404处理函数// ...}
}
  1. 路由匹配 (tree.go):
    1. getValue是路由树中用于匹配请求路径的方法,它返回与路径匹配的路由的处理函数和参数。

go

func (node *node) getValue(path string, params *Params) HandlersChain {for _, n := range node.children {if n.path == path {// 匹配到路由return n.handlers}}// 没有匹配到路由return nil
}

路由注册和匹配的源码分析

  1. 路由注册:
    1. 用户通过调用GET, POST等方法注册路由时,Gin会调用addRoute方法,将路由信息添加到对应的HTTP方法树中。
  2. 构建路由树:
    1. 路由树的构建是通过递归地为每个路径片段创建或找到节点来完成的。如果路径片段是动态的(如:id),则会创建一个特殊的节点来存储参数。
  3. 请求处理:
    1. 当请求到达时,Gin会根据请求的HTTP方法和URL路径,在相应的路由树中查找匹配的路由。
  4. 执行匹配的路由:
    1. 如果找到匹配的路由,Gin会执行该路由对应的处理函数和中间件链。如果没有找到匹配的路由,则会执行404或其他错误处理函数。
  5. 中间件的执行:
    1. 中间件的执行是通过HandlersChain来管理的,每个中间件可以决定是否调用c.Next()来继续执行链中的下一个处理函数。

性能优化

路由树的优先级排序

路由树的优先级排序是Gin框架性能优化的关键策略之一。以下是优先级排序的一些要点:

  1. 优先级的定义:在Gin中,路由的优先级通常由其在路由树中的位置决定。优先级高的路由会先被匹配。
  2. 最长路径优先:Gin框架倾向于先匹配最长的路径,以减少不必要的节点遍历,提高匹配效率。
  3. 静态路由优先于动态路由:在路由树中,静态路由(即不包含参数的路由)通常具有比动态路由(包含参数的路由)更高的优先级。
  4. 精确匹配优先:如果存在精确匹配的路由,Gin会优先选择精确匹配而不是通配符匹配。
  5. 中间件的影响:中间件的使用也会影响路由的优先级。例如,如果一个路由注册了多个中间件,那么这个路由的匹配可能会稍微慢一些,因为需要执行更多的中间件逻辑。
  6. 路由树的构建:在构建路由树时,Gin会根据路由的注册顺序和上述规则来安排节点的顺序,优化匹配性能。

路由匹配的性能考量

  1. 减少节点遍历:Gin通过优先匹配最长路径和静态路由来减少节点的遍历次数,从而提高匹配速度。
  2. 避免重复匹配:Gin框架的设计避免了对同一请求路径的重复匹配,每个请求只会在路由树中匹配一次。
  3. 使用Radix树:Radix树(基数树)的结构使得Gin能够在O(m)时间复杂度内完成路由匹配,其中m是URL路径的长度。
  4. 缓存机制:Gin框架可以使用缓存中间件来缓存常见的请求结果,减少处理时间和数据库查询。
  5. 并发处理:Gin框架支持高并发处理,通过使用goroutines来同时处理多个请求。
  6. 中间件链优化:合理组织中间件链,避免在链中执行耗时的操作,或者将耗时操作放在处理链的末尾。
  7. 错误处理:Gin框架提供了错误处理中间件,可以统一处理错误,避免在每个处理函数中重复错误处理逻辑。
  8. 监控和分析:使用性能监控工具来分析路由匹配的性能瓶颈,并根据分析结果进行优化。

通过这些性能优化策略,Gin框架能够在保持易用性的同时,提供高性能的Web服务。

相关文章:

goweb框架-gin

文章目录 Gin框架概览Gin框架的特点Gin框架的安装和基本使用安装基本使用 路由系统路由的基本概念Gin框架路由的特点 Radix Tree(基数树)基数树的定义和原理基数树在Gin框架中的应用节省空间的优化动态路由和通配符处理 路由树的构建注册路由的过程路由树…...

2024年接口测试高频面试题及答案

1. 什么是接口测试? •接口测试就是通过测试不同情况下的入参与之相应的出参信息来判断接口是否符合或满足相应的功能性、安全性要求 •测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系 2. 为什么要做接口…...

ESP32-C3在MQTT访问时出现“transport_base: Poll timeout or error”问题的分析(8)

接前一篇文章:ESP32-C3在MQTT访问时出现“transport_base: Poll timeout or error”问题的分析(7) 前边几回分析了笔者在MQTT测试时所遇到的问题: 最终定位到了是由于components\components\tcp_transport\transport_ssl.c的base_poll_write函数中调用的select函数超时返回…...

Linux: 忘记密码的解决方法,passwd

https://www.redhat.com/sysadmin/recover-root-passwd 这里的方法很简单,就是通过console进去,添加一个启动参数,加载sysroot,然后用passwd命令修改密码。这个是RHEL7适用。 https://access.redhat.com/solutions/1192 这个是提…...

36. 有效的数独【 力扣(LeetCode) 】

一、题目描述 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图…...

机器学习中的没有免费午餐定理

嘿,各位机器学习的爱好者们!今天,让我们一起深入探讨机器学习中那个神秘而又重要的概念——没有免费午餐定理。 一、定理引入:探索算法森林的钥匙 在广阔无垠的机器学习领域中,免费午餐定理就如同一把神奇的钥匙&…...

高级java每日一道面试题-2024年8月21日-框架篇[Spring篇]-使用IOC容器应该注意哪些?

如果有遗漏,评论区告诉我进行补充 面试官: 使用IOC容器应该注意哪些? 我回答: 1. 理解IOC的基本概念 控制反转:在传统的编程模式中,程序会主动控制依赖关系的创建和管理。而在IoC容器中,这种控制权被反转给了容器本身。程序员只需要声明…...

LLM训练推理相关概念

1. 有监督微调(Supervised Fine-Tuning)与指令微调(Instruction Fine-Tuning)对模型参数的影响 **有监督微调(Supervised Fine-Tuning, SFT)和指令微调(Instruction Fine-Tuning, Instruct-Tun…...

IP in IP 协议

IP in IP 是一种多重IP协议,即:客户机可以发送一个IP协议内部在嵌套一个IP协议到某个特定的主机上,在由具体的主机作为路由进行转发的协议。 例如: IP in IP帧协议结构为,第一层为发送到IP in IP 路由主机的报文&…...

DAY2: HTTP请求报文和响应报文是怎样的,有哪些常见的字段?| HTTP有哪些请求方式?| GET请求和POST请求的区别

目录 HTTP请求报文和响应报文是怎样的,有哪些常见的字段? 请求报文 响应报文 HTTP有哪些请求方式? GET请求和POST请求的区别 HTTP请求报文和响应报文是怎样的,有哪些常见的字段? HTTP报文分为请求报文和响应报文…...

线性代数:每日一题1/特征值与相似对角化

设A, B 为二阶矩阵,且 AB BA , 则“A有两个不相等的特征值”是“B可对角化"的() A. 充分必要条件 B. 充分不必要条件 C.必要不充分条件 D.既不充分也不必要条件 知识点: 特征向量与特征值的关系 相似矩阵的定义和性质 n阶…...

Android UI:PopupWindow:API

文章目录 类操作 对PopupWindow的操作 创建PopupWindow对象的操作添加并显示PopupWindow的操作移除PopupWindow的操作更新PopupWindow的操作显示内容的相关操作 布局的相关操作进入退出动画的相关操作 Transition设置进入动画的相关操作Transition设置退出动画的相关操作XML设置…...

什么是DevUI?

DevUI是面向企业中后台产品的开源前端解决方案,其设计价值观基于"高效、开放、可信、乐趣"四种自然与人文相结合的理念,旨在为设计师、前端开发者提供标准的设计体系,并满足各类落地场景,是一款企业级开箱即用的产品。 …...

DAY53

作业: 运行1个服务器和2个客户端 实现效果: 服务器和2个客户端互相聊天,服务器和客户端都需要使用select模型去实现 服务器要监视2个客户端是否连接,2个客户端是否发来消息以及服务器自己的标准输入流 客户端要监视服务器是否发来…...

python中len是什么

Python len() 方法返回字符串长度。 len()方法语法: len( str ) 返回值: 返回字符串长度。 以下实例展示了len()的使用方法: #!/usr/bin/python str "this is string example....wow!!!"; print "字符串长度: ", len…...

推荐一个开源的kafka可视化客户端GUI工具(Kafka King)

大佬的博客地址: https://blog.ysboke.cn/posts/tools/kafka-king Github地址: https://github.com/Bronya0/Kafka-King Kafka-King功能清单 查看集群节点列表(完成)支持PLAINTEXT、SASL PLAINTEXT用户名密码认证(完…...

day 10 贪心算法

455. 分发饼干 饼干从大的开始利用&#xff0c;优先满足胃口大的&#xff1b; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(),g.end());sort(s.begin(),s.end());int res0;int indexs.size()-1;for…...

网络安全审计技术原理与应用

网络安全审计概述 概念 定义:对网络信息系统的安全相关活动信息进行获取、记录、存储、分析和利用的工作 作用:建立“事后”安全保障措施,保存网络安全事件及行为信息,为网络安全事件分析提供线索及证据,以便发现潜在网络安全威胁行为,开展网络安全风险分析及管理 常…...

计算机网络之TCP序号,确认序号和报文传输时间

开篇提示 本篇适合于了解基础知识&#xff0c;进行扩展提高的使用&#xff0c;附带考研习题以及解析。 TCP序号和确认序号的区别 TCP首部中有序号和确认序号&#xff0c;他们都是4个字节&#xff08;4B&#xff09;&#xff0c;且在数据传输中有很重要的意义&#xff0c;那么两…...

HTML优化方法

HTML编码规范 代码格式化与缩进 1.缩进规则 ​ 推荐使用空格缩进而不是Tab&#xff0c;因为不同环境下空格的效果更加一致。常见缩进量为2个或4个空格 2.标签对齐 ​ 在嵌套的HTML结构中&#xff0c;子标签应当缩进&#xff0c;以清晰地展示层级关系。 3.属性的排列 ​ …...

Codeforces Round 961 D. Cases 【SOS DP、思维】

D. Cases 题意 有一个长度为 n n n 且仅由前 c c c 个大写字母组成的字符串&#xff0c;问最少选取多少种字母为每个单词的结尾&#xff0c;使得每个单词长度不超过 k k k 思路 首先注意到最后一个字母一定要选择&#xff0c;接下来我们给出一个断言&#xff1a;如果一个…...

VirtualBox上的Oracle Linux虚拟机安装Docker全流程

1.安装docker依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 2.安装docker仓库 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 生成docker的yum源配置到在 /etc/yum.repos.d/docker-ce.repo 3.安装D…...

LNMP安装部署

目录 一、Nginx安装部署 1.安装包下载 2.下载相关依赖工具 3. 创建运行用户 4.编译安装 5.优化路径 6.将nginx添加至系统服务 7.文件赋权 二、MySQL部署安装 1.解压 2.安装相关工具 3.创建运行用户 4.编译安装 5.修改配置文件 6.更改mysql安装目录和配置文件的属…...

django之自定义序列化器用法

在Django中&#xff0c;自定义序列化器方法通常用于处理复杂的数据转换逻辑&#xff0c;特别是在使用Django REST framework&#xff08;DRF&#xff09;时。自定义序列化器方法可以帮助你在序列化和反序列化过程中执行特定的逻辑&#xff0c;比如格式化日期、计算字段值、或者…...

20240821给飞凌OK3588-C的核心板刷Rockchip原厂的Buildroot并挂载1TB的exFAT格式的TF卡

fdisk -l df -h df -t df -T mount 20240821给飞凌OK3588-C的核心板刷Rockchip原厂的Buildroot并挂载1TB的exFAT格式的TF卡 2024/8/21 18:06 【切记&#xff0c;对于Rockchip原厂的Buildroot&#xff0c;如果你没有针对性的适配DTS&#xff1a;修改其中的GPIO口供电&#xff0c…...

多模态学习Multimodal Learning:人工智能中的多模态原理与技术介绍初步了解

多模态学习&#xff08;Multimodal Learning&#xff09;是机器学习中的一个前沿领域&#xff0c;旨在综合处理和理解来自不同模态的数据。模态可以包括文本、图像、音频、视频等。随着数据多样性和复杂性增加&#xff0c;多模态学习在自然语言处理、计算机视觉、语音识别等领域…...

外部环境连接kafka

修改配置文件外部环境连接kafka 1、kafka的docker官方镜像地址2、kafka官方介绍的三种连接方式3、方式一&#xff1a;Default configs默认配置4、方式二&#xff1a;File input&#xff08;文件输入&#xff1a;外部配置文件替换docker容器内的配置文件&#xff09;4.1、首先查…...

结合了MySQL数据库、Elasticsearch和Redis,构建一个产品搜索和推荐系统

1. 数据库设置&#xff08;MySQL&#xff09; 首先&#xff0c;我们需要创建两个表来存储产品信息和产品类别信息。 CREATE DATABASE product_system;USE product_system;CREATE TABLE categories (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) NOT NULL,created_at…...

白酒与素食:健康与美味的双重享受

在美食的世界里&#xff0c;白酒与素食的搭配仿佛是一场跨界的盛宴。豪迈白酒&#xff08;HOMANLISM&#xff09;的醇香与精致素食的清新&#xff0c;在不经意间交织出了一幅美妙的画卷&#xff0c;让人在品味中感受到健康与美味的双重享受。 素食&#xff0c;以其清淡、自然的…...

工厂现场多功能帮手,三防平板改善管理体验

随着制造业的智能化变革&#xff0c;信息化、自动化和智能化逐渐成为工厂管理的新常态。在这一波技术浪潮中&#xff0c;三防平板作为一种多功能的工作工具&#xff0c;正在逐步改善工厂现场的管理体验。 一、三防平板的定义与特点 三防平板&#xff0c;顾名思义&#xff0c;是…...

甘肃手机网站建设/seo算法是什么

新人大礼包&#xff0c;30G Java架构资料&#xff0c;免费领取​zhuanlan.zhihu.comTomcat性能调优&#xff1a;找到Tomcat根目录下的conf目录&#xff0c;修改server.xml文件的内容。对于这部分的调优&#xff0c;我所了解到的就是无非设置一下Tomcat服务器的最大并发数和Tomc…...

南昌市做网站公司/网站加速

第一课用Python编程一、资料&#xff1a;1、Python语言中的语句就是Python命令。2、打开Python Shell&#xff0c;在提示符“>>>”的后面输入Python命令并按回车键&#xff0c;该命令就会立即执行并显示结果。3、凡是加上了引号(单引号和双引号都可以)的字符、数字等都…...

地图素材如何做ppt模板下载网站/销售平台

干掉庞大的Binlog文件 想要恢愎数据库以前的资料,执行:show binlog events;屏幕就开始闪,闪的人眼花,心里烦(那有这么多没有用的破LOG^0^),还是删除一些去吧!1.查找binary logs mysql> show binary logs; --------------------------- | Log_name | File_size | -----…...

郑州网站建设方案报价/网上做广告推广

在phpmyadmin中显示上传文件最大问8M&#xff0c;可我的单个sql文件超过50M&#xff0c;尝试上传&#xff0c;上传依然可以进行&#xff0c;但上传到8M即操作终止&#xff0c;phpmyadmin提示上传失败。该问题实际上是php的配置问题&#xff0c;在php.ini中有两个参数需要关注&a…...

福州专业网站建设/天津百度网站排名优化

lambda表达式含义 函数式接口 1.什么是函数式接口 2.自定义函数 3.作为参数传递Lambda表达式 4.四大内置核心函数式接口 方法引用与构造器引用 方法引用 构造器引用&#xff08;了解&#xff09; 数组引用&#xff08;了解&#xff09; lambda表达式含义 lambda表达…...

免费的ppt网站推荐/视频网站推广

在使用spring创建bean的时候需要在指定bean的生命周期&#xff0c;bean的声明周期有一下几种&#xff1a; singleton 表示在spring容器中的单例&#xff0c;通过spring容器获得该bean时总是返回唯一的实例prototype表示每次获得bean都会生成一个新的对象request表示在一次http请…...