# Gee_v1.0 **Repository Path**: lyrLearning/Gee_v1.0 ## Basic Information - **Project Name**: Gee_v1.0 - **Description**: Gee框架,基于HTTP协议,实现了Gin框架的部分功能。 - **Primary Language**: Go - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-04-17 - **Last Updated**: 2023-04-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Gee框架 ## 使用说明 - 在你的项目运行 `go get gitee.com/lyrLearning/Gee_v1.0` 即可把这个框架引入到你的项目中。 ```go package main import ( "fmt" "gitee.com/lyrLearning/Gee_v1.0/gee" "gitee.com/lyrLearning/Gee_v1.0/iface" "html/template" "net/http" "time" ) type student struct { Name string Age int8 } func FormatAsDate(t time.Time) string { year, month, day := t.Date() return fmt.Sprintf("%d-%02d-%02d", year, month, day) } func main() { t1() } func t1() { r := gee.New() //设置参数要在加载模板前进行 r.SetFuncMap(template.FuncMap{ "FormatAsDate": FormatAsDate, }) r.LoadHTMLGlob("templates/*") r.Static("/assets", "./static") stu1 := &student{Name: "GeekTutu", Age: 20} stu2 := &student{Name: "Jack", Age: 22} r.GET("/", func(c iface.IContext) { c.HTML(http.StatusOK, "css.html", nil) }) r.GET("/students", func(c iface.IContext) { c.HTML(http.StatusOK, "arr.html", gee.H{ "title": "gee", "stuArr": [2]*student{stu1, stu2}, }) }) r.GET("/date", func(c iface.IContext) { c.HTML(http.StatusOK, "custom_func.html", gee.H{ "title": "gee", "now": time.Date(2022, 04, 29, 10, 9, 8, 7, time.UTC), }) }) if err := r.Run(":9999"); err != nil { panic(err) } } ``` 代码中涉及的文件并没用给出,需要读者自行创建。 ## 介绍 Gee框架是一个Web框架,用于帮助开发者更好的管理和处理前端发送过来的请求。使用该框架,开发者获取前端发送过来的请求数据、返回结果、管理请求路由,对路由进行分组、引入中间件对请求进行前置处理和后置处理、通过HTML模板解析和静态资源服务功能、请求过程中的错误捕获与恢复。 ## 优势 1. 在Go提供的HTTP服务基础上进行封装,使得请求处理更加简单。 2. 路由管理使用了前缀树这个数据结果,优化了路由查询的性能。 3. 对请求处理过程中进行的错误,提升了用户的使用体验。 4. 分组控制,让同一组的路由可以配置同一个中间件进行前置、后置处理,减少了代码冗余。 ## 实现介绍 ### 1. 上下文 - 接口:IContext,实现类:Context - 开发者可以使用框架提供的IContext来处理客户端过来的请求 - 框架做的事情: - 客户端的请求过来之后,把 `req`, `resp`, `请求参数`, `请求路径`, `此请求涉及的中间件`全部封装到Context中 - 首先在engine的ServeHTTP封装好涉及的中间件部分属性 - 然后在router的handle封装好其他部分属性 - 最后在router的handle执行开发者先前定义好的中间件和请求处理逻辑 ### 2. 前缀树路由 - 实现的逻辑在 `gee/trie.go` 里面,每个trie的节点node有 `pattern` `part` `isWild` `children`,每个节点都有search和insert方法。 - 缺点:唯一性得靠开发者注册得合理来保证,框架代码并不能保证insert进去的路径不会让客户端请求可以匹配到多个处理逻辑。 - trie.go被整合到router模块,router给每个请求方法都提供一个root的node节点 - router的addRoute方法用到root的insert操作 - router的handle方法使用到root的search操作 ### 3. 分组控制 - 接口:IRouterGroup,实现类:routerGroup - engine本身也是IRouterGroup,并且它管理了所有分组 - 每个分组可以使用 `GET`, `POST`, `USE`, `Static`等 ### 4. 中间件 - 中间件本质上还是 `type HandlerFunc func(IContext)`,只不过用户注册中间件时需要实现`IHandler`接口,然后被我转成前面那个类型 - 使用`newHandlerFunc`转即可 - 在use那里转,即在routerGroup那里转 - 中间件在engine的ServeHTTP那里就会被按需封装到Context里面 - 然后在我们使用router的handle方法时,找到满足前缀的请求就会被执行。 ### 5. 错误恢复 - 本质上就是在engine这个路由分组上加入一个middleware, 并让它作为首个被所有请求依赖的中间件。这样,所有出现的错误最后panic到它的next上,然后被它捕获。 ### 6. 静态文件加载 - 在IRouterGroup接口上加入 `Static(relativePath, fileRoot string)` 方法,fileRoot表示所有静态文件在的文件夹 - 假设 relativePath = /assets,路由分组的前缀为 /v1 , lin.css 在 fileRoot/lin/ye/run/lin.css 处,那么想要获取lin.css需要的请求方式为 `/v1/assets/lin/ye/run/lin.css` - 实现 - 使用 `http.StripPrefix` 这个函数来创建handler,然后使用闭包将这个handler封装成 `type HandlerFunc func(IContext)` 这个类型。 - 最后将这个封装好的处理函数加入到前缀树中 ### 7. HTML模板渲染 - HTML模板渲染相关的属性放在了 `global.go` 里面 - `funcMap template.FuncMap`:给用户提供了设置自定义渲染函数, 需要在将模板加入内存前进行设置 - `htmlTemplate *template.Template`:给用户提供来将所有的模板加载进内存 - 最后它们在Context的HTML里面被使用