GoFrame第二天

2024-01-11 03:10
文章标签 第二天 goframe

本文主要是介绍GoFrame第二天,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • GoFrame day2
    • 前言
    • Web相关
      • 基本功能
        • 多端口监听
        • 创建多个ghttp实例
        • 域名绑定
      • 路由管理
        • 路由注册参数
        • 精准匹配
        • 动态路由
          • 命名匹配规则
          • 模糊匹配规则
          • 字段匹配规则
          • 优先级控制
        • 路由注册
          • 函数注册
          • 对象注册
          • 分组路由
          • 规范化路由

GoFrame day2

前言

昨天基本的介绍了一遍GoFrame的基本内容,但是实际Web开发中涉及到的知识还有很多,今天就来总结一下GoFrame在Web开发中的一些内容.

Web相关

昨天通过查看源码,可以看到GoFrame主要是通过对http的封装得到ghttp作为功能丰富的Web服务

image-20220604174228530

其中提供了Router,Cookie,Session,路由注册,插件等等功能,还支持很多特性,下面就一一举例

基本功能

多端口监听

如果我们想要服务支持多个端口监听,那就可以在SetPort中设置多个端口号去实现,对于HTTPS的服务我们可以利用SetHTTPSPort来设置多个端口.

package mainimport ("github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)func main() {s := g.Server()s.BindHandler("/", func(r *ghttp.Request) {r.Response.Writefln("Hello World!")})//set Portss.SetPort(8000, 8001, 8002)s.Run()
}

image.png

创建多个ghttp实例

GoFrame还支持创建多个ghttp实例,只需要每次初始实例化的时候传入不同的单例名称.这样的话不仅在一个进程中可以运行多个实例,还可以保证每个实例的唯一性,在不同的goroutine甚至不同模块中都能确保使用的是同一个实例.

域名绑定

Server支持多个域名绑定,这样可以实现不同域名下的同一个路由会有不同的服务

package mainimport ("github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)func main() {s := g.Server()s.Domain("127.0.0.1").BindHandler("/", func(r *ghttp.Request) { r.Response.Writefln("127.0.0.1: Hello") })s.Domain("localhost").BindHandler("/", func(r *ghttp.Request) { r.Response.Writefln("localhost: Hello") })s.Run()
}

]

但是这里的域名必须是准确的,不能使用带有通配符*等的泛域名作为输入.

路由管理

前面提到GoFrame提供了非常强大的路由功能,这部分就讲讲GoFrame是怎么解析路由参数,匹配路由以及路由注册的.

路由注册参数

昨天的那个基本例子使用了BindHandler(),下面是它的方法原型

image.png

今天就来好好分析一下路由注册的参数使用,参数格式如下

[HTTPMethod:]路由规则[@域名]

HTTP方法例如GET,PUT,DELETE都已经封装好了,当然这些并不是必需参数,默认没有的话就是ALL也就是支持所有的HTTP方法.域名也是类似,如果给了就是只在给定的域名下生效,否则就是默认全部都生效.更多的时候我们还是使用上面对Server对象的域名绑定来指定路由注册,很少使用参数中的域名设置.

精准匹配

像路由中使用固定的名称/index这种就是精准匹配

动态路由

动态路由分为命名匹配规则,模糊匹配规则,字段匹配规则.动态路由底层是哈希表和双向链表构成的路由树,可以高效匹配URI并且可以进行路由优先级控制.同时使用了缓存,可以不用重复执行相同路由的匹配.关于这部分的构造可以看看下面的源码

image.png

image.png

命名匹配规则

使用:xxx进行匹配,也就是该URI层级必须有值,然后对应的匹配参数会被解析为路由参数传递给路由使用

模糊匹配规则

使用*xxx进行匹配,对URI指定位置之后其他规则之前的所有参数进行模糊匹配,该URI层可以为空

字段匹配规则

使用{xxx}进行匹配,可以对URI任意位置的参数进行截取匹配,这层URI必须有值,并且在这一层可以进行多个字段的匹配

package mainimport ("github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)func main() {s := g.Server()s.BindHandler("/api/:attr/{object}/*act", func(r *ghttp.Request) {r.Response.Writeln("attr: ", r.Get("attr"))r.Response.Writeln("object: ", r.Get("object"))r.Response.Writeln("act: ", r.Get("act"))})s.SetPort(8080)s.Run()
}

image.png

优先级控制

路由的优先级控制也是非常重要的,往往没有设计好路由的优先级就有可能导致某些路由永远不能被访问到(被其他路由匹配覆盖)

优先级控制按照深度优先策略,主要是下面几个规则

  • 层级越深的规则优先级越高
  • 同一层级下精准匹配优先级高于动态路由规则的优先级
  • 同一层级下,动态路由规则优先级如下 字段匹配>命名匹配>模糊匹配,即{xxx}>:xxx>*xxx
路由注册
函数注册

函数注册BindHandler()最常见的方式有三种

  1. 像之前的例子一样,使用回调函数注册
  2. 也可以在注册外面自己实现处理器方法,然后注册自己写的处理器方法
  3. 实例化一个gtype对象,然后包装这个对象的一些方法,接着注册时注册对象的方法.关于gtype会在后面详细介绍
对象注册

对象注册会注册一个实例化对象,以后的每一次请求都会交给这个对象来处理,主要的方法如下

func (s *Server) BindObject(pattern string, object interface{}, methods ...string) error
func (s *Server) BindObjectMethod(pattern string, object interface{}, method string) error
func (s *Server) BindObjectRest(pattern string, object interface{}) error

这里我们同样是定义一个对象,并且实现一些对象的方法使得针对不同路由调用不同的方法名.这里注意一个问题,因为URI默认不支持大小写区分,所以当方法名带有多个单词时(以大写字符区分),会自动将解析的路由名全部改为小写,并且以-连接这些小写单词.看看下面这个例子

package mainimport ("github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)type Control struct{}func (c *Control) Index(r *ghttp.Request) {r.Response.Writeln("Control Index")
}func (c *Control) ShowData(r *ghttp.Request) {r.Response.Writeln("Control Show Data")
}func main() {s := g.Server()c := new(Control)s.BindObject("/{xxx}", c)s.SetPort(8080)s.Run()
}

image.png

当然如果我们想方法名对应路由的话框架也支持

UriTypeDefault  = 0 // (默认)全部转为小写,单词以'-'连接符号连接
UriTypeFullName = 1 // 不处理名称,以原有名称构建成URI
UriTypeAllLower = 2 // 仅转为小写,单词间不使用连接符号
UriTypeCamel    = 3 // 采用驼峰命名方式

当然如果我们的对象有多个方法,但是只想注册其中的部分方法,那我们可以在BindObject()中添加方法名来注册我们想要的,例如s.BindObject("/{xxx}",c,"ShowData"),这里方法名需要对应上区分大小写

BindObjectMethod()就可以更加具体,将具体的对象方法绑定注册到对应的路由上.还有更加严格的RESTful路由设计对应的方法,要求对象的方法名必须是HTTP的Method,然后将类方法对应映射.

在对象注册中还有隐藏的方法,那就是InitShut,这两个方法可以实现对象绑定时隐式自动调用.比如我们的对象需要初始化加载一些内容,这个时候就可以写在Init中自动实现;同样的,当我们对象销毁时需要释放一些资源可以将这部分操作写在Shut中.

分组路由

当我们有大量路由需要控制时,如果一个个注册是很难管理的.这个时候就需要设置一些路由组,拥有相同前缀的路由可以分在同一个路由组下,这样统一注册,方便了管理也减少了出错.

// 创建分组路由
func (s *Server) Group(prefix string, groups ...func(g *RouterGroup)) *RouterGroup
func (d *Domain) Group(prefix string, groups ...func(g *RouterGroup)) *RouterGroup// 注册Method路由
func (g *RouterGroup) ALL(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) GET(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) PUT(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) POST(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) DELETE(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) PATCH(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) HEAD(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) CONNECT(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) OPTIONS(pattern string, object interface{}, params...interface{})
func (g *RouterGroup) TRACE(pattern string, object interface{}, params...interface{})// 中间件绑定
func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup// REST路由
func (g *RouterGroup) REST(pattern string, object interface{})// 批量注册
func (g *RouterGroup) Map(m map[string]interface{})
func (g *RouterGroup) ALLMap(m map[string]interface{}) // 规范化路由方式,自动绑定Handler或者路由对象
func (g *RouterGroup) Bind(handlerOrObject ...interface{}) *RouterGroup

我们可以创建一个路由组对象,然后在路由组中实现不同的方法.

package mainimport ("github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)func main() {s := g.Server()group := s.Group("/api")group.ALL("/all", func(r *ghttp.Request) {r.Response.Write("all")})group.GET("/get", func(r *ghttp.Request) {r.Response.Write("get")})group.POST("/post", func(r *ghttp.Request) {r.Response.Write("post")})s.SetPort(8080)s.Run()
}

当然除了简单的路由组,还支持层级注册.层级注册也就是回调函数中不再使用简单的ghttp.Request而是使用ghttp.RouterGroup实现不同的路由层级,这样一来可以很轻易的使用RouterGroup对象创建不同的层级,并且支持不同的路由注册方法和中间件;如果觉得还是不够清晰,还可以尝试批量注册ALLMap,这样可以清晰地看到每个路由组下对应的路由以及调用的方法,比层级注册更加清楚但是貌似无法限制每个路由对应的请求方法,都是ALL.

规范化路由

昨天看到源码发现有openapi的字样,当时就在想难道GoFrame也支持这个接口协议?那不就可以生成接口文档了.今天学习果然支持了这个功能.这个功能之前在FastAPI中就体验过,很轻松就能理清每一个API的功能以及调用方式,这为前后端的协调提供了很好的帮助.

由于默认是关闭接口文档功能的,所以我们需要先在config.yaml设置文件中添加设置

server:address: "8088"openapiPath: "/api.json"swaggerPath: "/swagger"

然后写个例子

package mainimport ("context""fmt""github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)type HelloReq struct {g.Meta `path:"/hello" method:"get"`Name   string `v:"required" dc:"Your name"`
}
type HelloRes struct {Reply string `dc:"Reply content"`
}type Hello struct{}func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {g.Log().Debugf(ctx, `receive say: %+v`, req)res = &HelloRes{Reply: fmt.Sprintf(`Hi %s`, req.Name),}return
}func main() {s := g.Server()s.Use(ghttp.MiddlewareHandlerResponse)s.Group("/", func(group *ghttp.RouterGroup) {group.Bind(new(Hello),)})s.SetPort(8080)s.Run()
}

image.png

但是最新版本的已经更改为redoc支持了,并不能像原来swagger一样方便在页面上直接做简单测试,根据官网的例子我们还是可以通过自定义UI来解决这个问题

package mainimport ("context""fmt""github.com/gogf/gf/v2/frame/g""github.com/gogf/gf/v2/net/ghttp"
)const (swaggerUIPageContent = `
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="SwaggerUI"/><title>SwaggerUI</title><link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@latest/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@latest/swagger-ui-bundle.js" crossorigin></script>
<script>window.onload = () => {window.ui = SwaggerUIBundle({url:    '/api.json',dom_id: '#swagger-ui',});};
</script>
</body>
</html>
`
)type HelloReq struct {g.Meta `path:"/hello" method:"get"`Name   string `v:"required" dc:"Your name"`
}
type HelloRes struct {Reply string `dc:"Reply content"`
}type Hello struct{}func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {g.Log().Debugf(ctx, `receive say: %+v`, req)res = &HelloRes{Reply: fmt.Sprintf(`Hi %s`, req.Name),}return
}func main() {s := g.Server()s.Group("/", func(group *ghttp.RouterGroup) {group.GET("/swagger", func(r *ghttp.Request) {r.Response.Write(swaggerUIPageContent)})group.Bind(new(Hello),)})s.SetOpenApiPath("/api.json")s.SetPort(8080)s.Run()
}

image.png

这样熟悉的swagger页面就展示在我们眼前了

这篇关于GoFrame第二天的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/592957

相关文章

Java基础回顾系列-第二天-面向对象编程

面向对象编程 Java类核心开发结构面向对象封装继承多态 抽象类abstract接口interface抽象类与接口的区别深入分析类与对象内存分析 继承extends重写(Override)与重载(Overload)重写(Override)重载(Overload)重写与重载之间的区别总结 this关键字static关键字static变量static方法static代码块 代码块String类特

idea插件开发的第二天-写一个时间查看器

介绍 Demo说明 本文基于maven项目开发,idea版本为2022.3以上,jdk为1.8本文在Tools插件之上进行开发 Tools插件说明 Tools插件是一个Idea插件,此插件提供统一Spi规范,极大的降低了idea插件的开发难度,并提供开发者模块,可以极大的为开发者开发此插件提供便利Tools插件安装需要idea2022.3以上版本插件下载连接: https://downlo

第二天旅游线路规划和预览

第二天:从克拉玛依市乌尔禾区到五彩滩,晚上住宿贾登峪; 规划结果见下图: 1、行程安排 根据上面的耗时情况,规划一天的行程安排如下: 1)早上7:30起床,吃完早饭,8:30出发; 2)从克拉玛依市乌尔禾区到五彩滩风景区,路程229公里,车程3小时,中午12:00左右到达五彩滩景区; 3)中午吃饭1小时; 3)五彩滩游玩时间约3小时,在五彩滩游玩到16:00; 4)乘车前往阿勒泰地区布尔津县

寒假集训第二天——线性表

现在时间是北京时间1点23分,第二天集训。。。 昨天花了老长时间把线性表看了下,表示很有压力,不大会用。。。 先说下我学到的线性表的皮毛。。。 首先是链表的构建,构建有两种方式: 顺序链表(尾插法建单链表) #include<stdio.h>struct node{int date;struct node *next;};int main(){int i,n;node *he

实战docker第二天——cuda11.8,pytorch基础环境docker打包

在容器化环境中打包CUDA和PyTorch基础环境,可以将所有相关的软件依赖和配置封装在一个Docker镜像中。这种方法确保了在不同环境中运行应用程序时的一致性和可移植性: Docker:提供了容器化技术,通过将应用程序及其所有依赖打包在一个镜像中,确保不同环境下的运行一致性。 CUDA:NVIDIA的并行计算平台和编程模型,用于加速计算密集型应用程序,如深度学习。 PyTorch:流行的

HTML+CSS面试题总结:(第二天)

目录 5.CSS选择器优先级 6.标准盒模型和IE盒子模型的区别? 7.CSS margin重叠问题 8.网页布局有哪几种,有什么区别? 5.CSS选择器优先级 !important > 内联样式 > ID选择器 > 类选择器(属性选择器、伪类选择器)> 元素选择器(伪元素选择器)> 通配符选择器  6.标准盒模型和IE盒子模型的区别? 首先盒子模型包含四部分内

【60天备战软考高级系统架构设计师——第二天:软件工程生命周期模型】

开篇 软件生命周期模型是软件工程的重要内容之一,决定了开发团队如何组织和规划软件的开发过程。选择合适的生命周期模型是成功管理项目的关键之一。今天,我将详细介绍几种常见的软件生命周期模型及其优缺点,并结合一些考试题目来帮助理解。 软件生命周期模型的类型 瀑布模型: 传统的开发模型,强调严格的阶段性顺序执行,从需求分析到设计、开发、测试和维护。优点:简单、易于管理,有明确的文档和阶段交付物。缺

行为识别实战第二天——Yolov5+SlowFast+deepsort: Action Detection(PytorchVideo)

Yolov5+SlowFast+deepsort 一、简介 YoloV5+SlowFast+DeepSort 是一个结合了目标检测、动作识别和目标跟踪技术的视频处理框架。这一集成系统利用了各自领域中的先进技术,为视频监控、体育分析、人机交互等应用提供了一种强大的解决方案。 1. 组件说明: YoloV5: Yolo(You Only Look Once)是一个流行的实时目标检测