GO语言工程实践课后作业| 青训营

50 阅读5分钟

一、依赖管理

Go依赖管理演进

早期 Go 语言没有官方依赖管理工具,开发者常在项目中复制依赖包,导致更新困难、冲突处理复杂。社区因此推出了 Godep 和 glide 等第三方工具,它们管理 vendor 文件夹,记录依赖包版本,但仍存在全局依赖冲突和配置文件格式不统一的问题。 自 Go 1.11 起,Go 官方引入 Go Modules 作为依赖管理解决方案。它通过在项目中添加 go.mod 文件,明确指定依赖包及其版本,解决了全局依赖冲突,支持从代理服务器下载依赖包。Go Modules 不断发展和改进,支持私有仓库、替代模块和版本补丁,提供了更多强大功能。 总的来说,Go 语言的依赖管理经历了从手动复制到第三方工具再到官方 Go Modules 的演进,显著提高了依赖管理水平,提供了更好的开发者体验。

Go Module实践

Go Module 是自 Go 1.11 版本起引入的官方包管理工具,取代了原有的 GOPATH 和 vendor 目录。它将每个项目视为一个模块,拥有独立的模块路径,通过 go.mod 文件记录包依赖关系。

启用 Go Module 需满足以下条件:

  • Go 1.11 或更高版本

  • 环境变量 GO111MODULE 需设置为 on

在项目中启用 Go Module 后,执行以下步骤进行包依赖管理:

  • go mod init 命令初始化新模块,如:go mod init myapp

  • go mod tidy 命令自动分析代码依赖,更新 go.mod 文件

  • go mod vendor 命令将依赖项复制到项目的 vendor 目录

此外,还有其他常用命令和功能:

  • go mod init: 初始化新模块

  • go get: 下载模块源代码,添加依赖

  • go list: 列出所有依赖项

  • go build / go run: 构建或运行项目

  • go mod edit: 手动编辑 go.mod 文件

  • go mod graph: 显示依赖关系图

  • go mod verify: 验证依赖项完整且未被篡改

Go Module 提供灵活且可靠的包管理方式,有助于更好地管理项目依赖关系,确保构建结果一致。它使 Go 语言包管理更现代化,受到开发者广泛欢迎。

二、测试

单元测试

Go 语言,一种实力和受欢迎程度兼备的编程语言,支持测试驱动开发(TDD)。在 Go 中,编写单元测试易如反掌。下面,我将向你展示如何用 Go 编写出色的单元测试。 首先,了解 Go 语言的测试工具。Go 自带一个名为 testing 的测试框架,提供了编写和执行测试所需的函数和工具。测试文件只需以_test.go 作为后缀,Go 编译器便会识别其为测试文件。 接着,来看一个简易示例。假设我们想要编写一个向数据库插入用户的函数 AddUser,以下是该函数及其对应测试的一个简洁示例:

// user_test.go
package module
​
import (
    "fmt"
    "testing"
)
​
func TestAddUser(t *testing.T) {
fmt.Println("测试用户:")
user:=&User{}
user.AddUser()
}
​

// user.go
package module
​
import (
    "fmt"
    "project/web/utils"
)
​
type User struct {
    id int
    username int
    password string
}
​
func(user *User) AddUser() error{
    sqlStr:="insert into `table`(user,password) values(?,?) "
    //执行
    _,err:=utils.Db.Exec(sqlStr,2,"ddddd")
    if(err!=nil) {
        fmt.Println("执行异常:",err)
        return err
    }
    return nil
}
​

在上面的示例中,我们首先编写了一个向数据库插入用户的AddUser函数。然后,在user_test.go文件中,我们编写了一个名为TestAddUser的测试函数。

接下来,我们需要执行测试。可以通过在终端中运行以下命令来执行所有的单元测试:

go test

Go 语言自带的测试框架会自动识别并以_test.go 结尾的文件,执行其中的测试函数。测试结果会在终端展示,所有测试通过时,会显示通过的信息。

Go 语言还提供了一些额外的工具和函数,使我们能够编写更复杂和全面的单元测试。例如,我们可以使用 Skip 函数跳过特定的测试,或者使用 Table Driven Tests 功能来简化输入/输出测试的编写。

总的来说,Go 语言的单元测试直观易用,而且测试框架提供了丰富的功能和工具。通过编写有效的单元测试,我们可以保证代码的正确性,提高代码质量,减少后续开发和维护过程中的问题。希望这篇文章能帮助你开始使用 Go 语言的单元测试。祝你编写出更健壮的代码!

三、Gin

Gin框架导包"github.com/gin-gonic/gin"

Gin的使用

自定义拦截器

// 自定义拦截器  
func myHandler() gin.HandlerFunc {  
   return func(context *gin.Context) {  
       context.Set("usersession", "userid-1")  
       context.Next()  
       context.Abort()  
   }  
}
// 传参方式 url?userid=xxx&password=xxxxx  加了中间件  
// myHandler() 没有指定则全部一起用  
ginServer.GET("/user/info", myHandler(), func(context *gin.Context) {  
   // 取出中间件值  
   usersession := context.MustGet("usersession").(string)  
   log.Println("--------------", usersession)
   userid := context.Query("userid")  
   password := context.Query("password")  
   context.JSON(http.StatusOK, gin.H{"userid": userid, "password": password})  
})

设置图标

导包"github.com/thinkerou/favicon"

代码ginServer.Use(favicon.New("./u=G.jpg"))

Restful Api

//javascript代码
//gin restful API
    ginServer.PUT("htllo", func(context *gin.Context) {
        context.JSON(200, gin.H{"msg": "hello,world"})
    })
    ginServer.DELETE("/htllo")

页面加载响应

//加载静态页面
    ginServer.LoadHTMLGlob("templates/*")
​
    //响应一个页面给前端
    ginServer.GET("/index", func(context *gin.Context) {
        context.HTML(http.StatusOK, "index.html", gin.H{"msg": "hello,world"})
    })

传参方式url?userid=xxx&password=xxxxx

//传参方式url?userid=xxx&password=xxxxx
    ginServer.GET("/user/info", func(context *gin.Context) {
        userid := context.Query("userid")
        password := context.Query("password")
        context.JSON(http.StatusOK, gin.H{"userid": userid,
            "password": password})
    })

传参方式user/info/1/kuangshen

    //user/info/1/kuangshen
    ginServer.GET("/user/info/:userid/:username", func(context *gin.Context) {
        userid := context.Param("userid")
        username := context.Param("username")
        context.JSON(http.StatusOK, gin.H{"userid": userid, "username": username})
    })

前端给后端传json

//前端给后端传json
    ginServer.POST("/json", func(context *gin.Context) {
        data, _ := context.GetRawData()
        var m map[string]interface{}
        _ = json.Unmarshal(data, &m)
        context.JSON(http.StatusOK, m)
    })

接收form表单

    //接收form表单
    ginServer.POST("/sdsd", func(context *gin.Context) {
        username := context.PostForm("username")
        password := context.PostForm("password")
        context.JSON(http.StatusOK, gin.H{"username": username, "password": password})
    })
​

路由

//路由
    ginServer.GET("test", func(context *gin.Context) {
        context.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
    })
​

自定义404页面

//404
    ginServer.NoRoute(func(context *gin.Context) {
        context.HTML(http.StatusNotFound, "404.html", nil)
    })

设置路由组

    //路由组
    userGroup := ginServer.Group("/user")
    {
        userGroup.GET("/add")
        userGroup.POST("/login")
        userGroup.POST("/logout")
    }

启动

ginServer.Run(":8080")