基于Gin封装Web框架 - 7. 控制器优化 - 更好用的控制器模式

简介: 基于Gin封装Web框架 - 7. 控制器优化 - 更好用的控制器模式

基于Gin封装Web框架 - 7. 控制器优化 - 更好用的控制器模式

代码参考: https://github.com/go-jarvis/gin-rum

之前在 业务控制器模型中实现了一个简单的控制器模型, struct 对对象具有 Build() 方法, 就可以在 rum 中注册路由。

// 第一版注册起方法
type Index struct {
    Name string `query:""` 
}

func (index *Index) Build(rum *rum.RumGroup) {
    rum.Handle("GET", "/index", handlerIndex)
}

func handlerIndex(c *gin.Context) {
    name:=c.Query("name")
    c.JSON(200, map[string]string{
        "hello": "gin-rum, " + name,
    })
}

但是这样的控制器模型实现后, 在使用上还是有很多的不方便。

  1. Struct 对象 和将要绑定的 http 方法路由地址 完全割裂, 具体怎么定义需要在 Build() 方法中手工实现。
  2. 要在业务逻辑中实现 handler gin.HandleFunc 方法,逻辑臃肿。
  3. 变量绑定行为冗余, 每个 handler 都需要自己绑定变量并处理错误。

控制器优化

那要如何在 struct 定义的时候, 一站式完成所有需求约束呢? 要这么样 rum 框架帮忙处理这些冗余操作呢?

分析 rum.Handle 的参数, 分别是

  1. http 行为方法
  2. 相对路由地址
  3. 处理业务行为的 handler
rum.Handle("GET", "/index", handlerIndex)

func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc)

重新定义控制器接口

因此可以将 ClassController 结构定义成

  1. Method() string 方法: 返回 http 方法的值
  2. Path() string 方法: 返回相对路由地址
  3. Handler() (interface{}, error) 方法: 业务逻辑行为, 最终将被被 rum 封装成 handler 执行。
type ClassController interface {
    Method() string
    Path() string
    Handler() (interface{}, error)
}

重载 Handle 行为

既然控制器的接口已经变了, 那么响应的行为也需要进行变更。

// Mount 在 RumGroup 上绑定/注册 控制器
func (gg *RumGroup) Mount(group string, classes ...ClassController) *RumGroup {
    grp := newRumGroup(gg, group)

    // 老方法
    // for _, class := range claess {
    //     class.Build(grp)
    // }

    // 新方法
    for _, class := range classes {
        grp.Handle(class)
    }

    return grp
}

之前老方法是将 RumGroup 作为结构体的 Build 方法的参数传递到内部进行处理。新方法中为了能 简化请求参数的绑定和错误处理, 因此不能再将 RumGroup 传递下去了。

重载之后的的 RumGroup.Handle 方法以 结构体对象 作为参数

  1. 通过 Method()Path() 方法获取必要参数
  2. Handler() 方法封装成为 gin.HandlerFunc

    • 使用 ginbinder 库读取 request 中的所有需要参数
    • 根据 Handler() 方法的结构,封装 gin 的返回结果。
// Handle 重载 RumGroup 的 Handle 方法
func (gg *RumGroup) Handle(class ClassController) {

    m := class.Method()
    p := class.Path()
    handler := class.Handler

    // 将业务逻辑封装成为 gin.HandlerFunc
    handlerFunc := func(c *gin.Context) {
        // 绑定参数到对象中
        err := ginbinder.ShouldBindRequest(c, class)
        if err != nil {
            c.JSON(http.StatusBadRequest, err.Error())
            return
        }

        // 执行业务逻辑,获取返回值, 并封装返回结果
        v, err := handler()
        if err != nil {
            c.JSON(http.StatusInternalServerError, err.Error())
            return
        }

        // 以 JSON 格式返回信息
        c.JSON(http.StatusOK, v)
    }

    // 调用 gin RouterGroup 的 Handle 方法注册路由
    gg.RouterGroup.Handle(m, p, handlerFunc)
}

Handler 方法的传参数想法

最开的的想法, 是需要将 *gin.Context 传入到 Handler 方法中的, 这样使用者的行为能更广泛。 但后来思索再三后放弃了, Handler 方法更应该着力于 业务逻辑 而非管理或控制 gin 的行为。

type ClassController interface {
    Method() string
    Path() string
    // Handler(*gin.Context) (interface{}, error)
    Handler() (interface{}, error)
}

RumGroup.Handle 重载引起的 Fairing 控制器行为不兼容

之前在实现 Fairing 控制器的时候,为了方便 RumRumGroup 加载中间件的行为,使用了 gin.IRoutes 进行参数约束。

func attachFairings(iroute gin.IRoutes, fairs ...Fairing) {
    for _, fair := range fairs {
        fair := fair
        // 创建一个临时中间件 handler
        handler := func(c *gin.Context) {
            _ = fair.OnRequest(c)
            c.Next()
        }
        // 使用 中间件
        iroute.Use(handler)
    }
}

但是在重载 RumGroup 的 Handle 方法之后签名发生了改变, 由 Handle(string, string, ...HandlerFunc) IRoutes 变成了 Handle(class ClassController)。 因此引发了不兼容的情况。

type Rum struct {
    *gin.Engine
    rootGrp *RumGroup
}

因此最 Attach 也做了响应的改造。 将 Fairing 的接收者直接设置为了 RumGroup 。

func (gg *RumGroup) attach(fairs ...Fairing) {
    for _, fair := range fairs {
        fair := fair

        // 创建一个临时中间件 handler
        handler := func(c *gin.Context) {
            _ = fair.OnRequest(c)
            c.Next()
        }

        // 使用 中间件
        gg.Use(handler)
    }
}
相关文章
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
52 4
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
138 3
|
2月前
|
Web App开发 前端开发 JavaScript
探索Python科学计算的边界:利用Selenium进行Web应用性能测试与优化
【10月更文挑战第6天】随着互联网技术的发展,Web应用程序已经成为人们日常生活和工作中不可或缺的一部分。这些应用不仅需要提供丰富的功能,还必须具备良好的性能表现以保证用户体验。性能测试是确保Web应用能够快速响应用户请求并处理大量并发访问的关键步骤之一。本文将探讨如何使用Python结合Selenium来进行Web应用的性能测试,并通过实际代码示例展示如何识别瓶颈及优化应用。
130 5
|
2月前
|
SQL 安全 PHP
PHP 自发布以来一直在 Web 开发领域占据重要地位,PHP 8 更是带来了属性、刚性类型等新特性。
【10月更文挑战第1天】PHP 自问世以来,凭借其易用性和灵活性,在 Web 开发领域迅速崛起。从简单的网页脚本语言逐步演进为支持面向对象编程的现代语言,尤其自 PHP 5.3 引入命名空间后,代码组织和维护变得更加高效。PHP 7 的性能优化和 PHP 8 的新特性(如属性和刚性类型)进一步巩固了其地位。框架如 Laravel、Symfony、Yii2 和 CodeIgniter 等简化了开发流程,提高了效率和安全性。
50 2
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
151 45
|
1月前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP是一种流行的服务器端脚本语言,自诞生以来在Web开发领域占据重要地位。从简单的网页脚本到支持面向对象编程的现代语言,PHP经历了多次重大更新。本文探讨PHP的现代演进历程,重点介绍其在Web开发中的应用及框架创新,如Laravel、Symfony等。这些框架不仅简化了开发流程,还提高了开发效率和安全性。
26 3
|
1月前
|
前端开发 JavaScript 开发工具
从框架到现代Web开发实践
从框架到现代Web开发实践
39 1
|
1月前
|
SQL 安全 PHP
探索PHP的现代演进:从Web开发到框架创新
PHP 自发布以来一直在 Web 开发领域占据重要地位,历经多次重大更新,从简单的脚本语言进化为支持面向对象编程的现代语言。本文探讨 PHP 的演进历程,重点介绍其在 Web 开发中的应用及框架创新。自 PHP 5.3 引入命名空间后,PHP 迈向了面向对象编程时代;PHP 7 通过优化内核大幅提升性能;PHP 8 更是带来了属性、刚性类型等新特性。
27 3
|
1月前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
51 2
|
2月前
|
机器学习/深度学习 缓存 监控
利用机器学习优化Web性能和用户体验
【10月更文挑战第16天】本文探讨了如何利用机器学习技术优化Web性能和用户体验。通过分析用户行为和性能数据,机器学习可以实现动态资源优化、预测性缓存、性能瓶颈检测和自适应用户体验。文章还介绍了实施步骤和实战技巧,帮助开发者更有效地提升Web应用的速度和用户满意度。