这一章节主要学习通过go-admin-core 快速开发一个简单的web项目并做好三层模型分层。
gin
gin 是一个web框架,我们通过 go mod 来使用gin框架进行http接口的开发:
代码语言:javascript复制go mod init go-test
go get -u github.com/gin-gonic/gin
我们写一个main方法启动一个http接口。在go 中main 方法必须在main包之下,不同于java中的包必须是物理包,go中的包可以是逻辑包:
代码语言:javascript复制package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "TEST",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
运行 go mod tidy
更新依赖,启动main方法,访问8080接口:
gorm
接下来我们学习gorm的基本使用,安装gorm 和驱动包:
代码语言:javascript复制go get -u github.com/jinzhu/gorm
go get -u gorm.io/driver/mysql
测试连接数据库:
代码语言:javascript复制username := "root" // 账号
password := "123456" // 密码
host := "127.0.0.1" // 地址
port := 3306 // 端口
DBname := "test" // 数据库名称
timeout := "10s" // 连接超时,10秒
str := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
db, err := gorm.Open(mysql.Open(str), &gorm.Config{})
if err != nil {
panic("failed to connect mysql.")
}
至于gorm的查询api用法在后续的web开发中介绍。
go-admin-core
基本了解了上面两大框架,我们直接进入实战,前文说说过,关于go的一些语法细节我们边开发边学习,不必太担心。go-admin-core 是集成并封装了 log,gorm,gin,简化了我们的开发难度,感兴趣的同学可以去阅读一下源码。这里我展示一下这个框架的怎么去使用。main.go源码:
代码语言:javascript复制package main
import (
"poseidon-go/app/admin/router"
)
func main() {
router.InitRouter()
}
router.go源码:
代码语言:javascript复制package router
import (
"github.com/gin-gonic/gin"
_ "github.com/gin-gonic/gin"
log "github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"os"
"poseidon-go/app/admin/config"
)
var RouterList = make([]func(*gin.RouterGroup), 0)
// InitRouter 路由初始化,不要怀疑,这里用到了
func InitRouter() {
var r *gin.Engine
h := sdk.Runtime.GetEngine()
if h == nil {
h = gin.New()
sdk.Runtime.SetEngine(h)
}
switch h.(type) {
case *gin.Engine:
r = h.(*gin.Engine)
default:
log.Fatal("not support other engine")
os.Exit(-1)
}
db, err := gorm.Open(mysql.Open("root:root@tcp/vcp_saas?charset=utf8&parseTime=True&loc=Local"), &gorm.Config{})
if err != nil {
log.Error(err)
}
sdk.Runtime.SetDb("*", db)
// 这个必须在路由组之前设置,否则无效
config.InitMiddleware(r)
// 可根据业务需求来设置接口版本
v1 := r.Group("/api/v1")
for _, f := range RouterList {
f(v1)
}
r.Run(":8080")
}
在这里有几个知识点
- p,p,&p 的区别:不同于java ,go 中内存和内存指针是分开的。p 代表当前的内存,p代表当前内存的指针,&p代表当前内存的地址也就是指针的值。
举例:
代码语言:javascript复制func main() {
var p *int
p = new(int)
*p = 1
fmt.Println(p, &p, *p)
}
输出
0xc04204a080 0xc042068018 1
扩展一下,如果我再设置一个 *p=2,它的内存地址是变还不变?我们知道,go也是有垃圾回收器的,对比java,我们给一个对象变量赋新值,它是新开辟内存还是覆盖原来的内存,小伙伴们可以思考一下go和java在这个语法上的差别。
- 类型, .()被称为类型断言,可以将一个interface{}类型的变量转换成其它类型 ,type 关键字是类型关键字,用于定义类型和结构体。示例:
var i interface{}
i="sss"
fmt.Println(i.(string))
router.InitRouter()
- go 中的包,包是通过import导入的,可以给包起别名,可以直接通过包名调用包中的大写字母开头的所有方法,示例:
package main
import (
v1 "poseidon-go/app/admin/router"
)
func main() {
v1.InitRouter()
v1.Test()
}
InitRouter 方法和Test方法并不在同一个go文件中,但是同包。语法介绍完了,我们写一个三层分层的接口:先注册路由器
代码语言:javascript复制package router
import (
"github.com/gin-gonic/gin"
"poseidon-go/app/admin/apis"
)
func init() {
RouterList = append(RouterList, registerTestRouter)
}
func registerTestRouter(v1 *gin.RouterGroup) {
api := apis.Test{}
r := v1.Group("/test")
{
r.GET("/a", api.GetPage)
}
}
然后写一个controller,实现数据绑定和调service
代码语言:javascript复制package apis
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-admin-team/go-admin-core/sdk/api"
"poseidon-go/app/admin/model/dto"
"poseidon-go/app/admin/service"
)
type Test struct {
api.Api
}
// 函数名称前面的括号是Go定义这些函数将在其上运行的对象的方式
func (e Test) GetPage(c *gin.Context) {
req := dto.TestReq{}
// 结构体初始化
s := service.Test{}
// IOC 手动挡
err := e.MakeContext(c).
MakeOrm().
Bind(&req, binding.Form).
MakeService(&s.Service).
Errors
if err != nil {
e.Logger.Error(err)
e.Error(500, err, err.Error())
return
}
err = s.Message(&req).Error
e.OK(">>>>", "xxxxxxxxxxxxx")
}
再实现service:
代码语言:javascript复制package service
import (
"errors"
"github.com/go-admin-team/go-admin-core/sdk"
"gorm.io/gorm"
"poseidon-go/app/admin/model/dto"
"github.com/go-admin-team/go-admin-core/sdk/service"
)
type Test struct {
service.Service
}
// GetPage 获取SysApi列表
func (e *Test) Message(req *dto.TestReq) *Test {
db := sdk.Runtime.GetDbByKey("*")
var str, model string
err := db.Model(&str).Scopes().
First(model, req.GetType()).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
err = errors.New("查看对象不存在或无权查看")
e.Log.Errorf("Service GetSysApi error:%s", err)
_ = e.AddError(err)
return e
}
if err != nil {
e.Log.Errorf("db error:%s", err)
_ = e.AddError(err)
return e
}
return e
}
这里的知识点主要是方法和结构体的绑定 func (e *Test) Message
。方法前面的括号就是将该方法和结构体绑定在一起。
小结
上面代码介绍了基于go-admin-core 实现的三层分层的web代码,下一章节我们接着讲在gin中使用 gorm。
祝大家国庆快乐