拆箱phper最适合入门的go框架beego

2022-12-22 19:43:15 469 技术小虫有点萌

beego

beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API、Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架,但是结合了 Go 本身的一些特性(interface、struct 嵌入等)而设计的一个框架。

为什么使用框架

上帝不可能让每一个人都满意,同样的,并不是所有人都喜欢框架,大概就是有三点吧,框架重,框架不灵活,框架有坑。其实如果写一个hello world,肯定是用不到框架的。框架并不是有人对自己的一堆代码起了个名字就叫框架了。如其说我们使用框架,不如说我们使用了一种规范,然后所有的开发人员一起遵守,另外一点就是开箱即用,解放开发人员,提高开发效率,还有框架提前弥补一些你可能忽略的或者没想到的漏洞,比如安全问题,日志格式等等。

为什么选择beego

beego作为go语言的框架,其实是很适合phper入门学习的。据说beego的作者也是从PHP跨入go语言行列的,而且参考了PHP的laravel框架的设计思想和目录设计。 同样的,和laravel有一样的通病,框架很重,都是追求大而全的思想,既然追求大而全,必然就舍弃了卓越的性能。我们不如先看一下框架目录 很典型的MVC架构,最为phper一看就感到亲切而熟悉。有人说,PHP转go,只需要一周,3天看go语法,3天看beego框架,周末休息一天,周一就可以飞速的crud了。

工具模块

就像laravel的artisan,beego也提供了工具,就是bee,先来看一下bee有哪些命令吧

USAGE
    bee command [arguments]

AVAILABLE COMMANDS

    version     Prints the current Bee version 查看版本号
    migrate     Runs database migrations 数据库迁移
    api         Creates a Beego API application 生成api框架
    bale        Transforms non-Go files to Go source files
    fix         Fixes your application by making it compatible with newer versions of Beego
    pro         Source code generator
    dev         Commands which used to help to develop beego and bee
    dlv         Start a debugging session using Delve
    dockerize   Generates a Dockerfile for your Beego application 通过生成Dockerfile文件实现应用docker化
    generate    Source code generator 自动化生成代码
    hprose      Creates an RPC application based on Hprose and Beego frameworks
    new         Creates a Beego application 创建一个项目
    pack        Compresses a Beego application into a single file 用来发布应用的时候打包,会把项目打包成 zip 包 mac上面打包linux 注意bee pack -be GOOS=linux
    rs          Run customized scripts
    run         Run the application by starting a local development server 在项目目录下执行编译项目
    server      serving static content over HTTP on port
    update      Update Bee 升级版本

Use bee help [command] for more information about a command.这就话很重要

快速入门

  • 安装go,下载地址点击下载
  • 设置GOROOT,GOPATH,PATH
 export GOROOT=/usr/local/go
 export GOPATH=/Users/goRoot:/Users/go
 export PATH=/usr/local/go/bin:/Users/goRoot/bin:$PATH
  • 安装好了,看一下版本
 $  go version
go version go1.17.8 darwin/amd64
  • 安装beego
go get -u github.com/astaxie/beego
go get -u github.com/beego/bee
  • 将GOPATH/bin加入$PATH中
$ echo 'export GOPATH="$HOME/go"' >> ~/.profile # 或者 ~/.zshrc, ~/.cshrc, 您所使用的sh对应的配置文件
# 如果您已经添加了 $GOPATH 变量
$ echo 'export PATH="$GOPATH/bin:$PATH"' >> ~/.profile # 或者 ~/.zshrc, ~/.cshrc, 您所使用的sh对应的配置文件
$ exec $SHELL
  • 上面操作完毕,就可以使用bee了,快速创建一个bee-demo的项目
 bee new bee-demo
在这里插入图片描述

动手部分

  • 这里为了更好的让大家了解,我不适用框架默认的,而是创建新的文件
  • 刚才说过,bee generate 是自动生成代码,我们来看看怎么使用吧
  • 先生成一个控制器
$  bee generate controller user
______
| ___ \
| |_/ /  ___   ___
| ___ \ / _ \ / _ \
| |_/ /|  __/|  __/
\____/  \___| \___| v2.0.2
2022/12/08 14:43:23 INFO     ▶ 0001 Using 'User' as controller name
2022/12/08 14:43:23 INFO     ▶ 0002 Using 'controllers' as package name
        create   /Users/zhangguofu/website/bee-demo/controllers/user.go
2022/12/08 14:43:23 SUCCESS  ▶ 0003 Controller successfully generated!

执行命令之后,我们就会发现生成了一个RESTful的controller 那么我们怎么让请求路由到这个文件呢,我们看一下main入口文件,发现有一行 _ "bee-demo/routers"说明 项目启动的时候会先初始化routers这个包,通过控制器和路由之间的映射关系,在项目启动时完成注册

  • 我们新起一个路由文件,名字叫web.go,并映射到刚才生成的user控制器,如果不指定方法,默认走Get方法

项目下使用bee run启动项目,默认是8080端口,我们访问/web/index看看


GET http://localhost:8080/web/index

HTTP/1.1 200 OK
Server: beegoServer:2.0.0
Date: Thu, 08 Dec 2022 08:06:50 GMT
Content-Length: 11
Content-Type: text/plain; charset=utf-8

hello world

Response code: 200 (OK); Time: 25ms; Content length: 11 bytes
  • 路由的第二种方式 我们刚才看到,在web.go路由文件里,有一行beego.Include(&controllers.UserController{}),那么我们能否在控制器中声明路由呢,因为include方法里面也有一个addWithMethodParams操作,实际上也是注册了路由,比如在控制器中声明Hello方法,使用路由/web/hello访问
// Hello @router /web/hello [get]
func (c *UserController) Hello() {
 c.Ctx.WriteString("i am Hello")

}

模板

如果是一个web应用,我们怎么在模板赋值呢

  • 首先新建一个view
 $ bee generate view /user
create   /Users/zhangguofu/website/bee-demo/views/user/index.tpl
        create   /Users/zhangguofu/website/bee-demo/views/user/show.tpl
        create   /Users/zhangguofu/website/bee-demo/views/user/create.tpl
        create   /Users/zhangguofu/website/bee-demo/views/user/edit.tpl

  • 修改原来的Get方法
  • 访问
GET http://localhost:8080/web/index

HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/html; charset=utf-8
Server: beegoServer:2.0.0
Date: Thu, 08 Dec 2022 08:28:15 GMT

jack

操作数据库

相关配置文件

在操作数据库之前,我们要知道数据库配置在哪里,这里我们就看一下beego的配置文件,在项目目录的conf文件夹下有一个app.conf,通过beego.AppConfig.String("defaultdb")获取相关的配置

$ cat conf/app.conf 
#项目名字
appname = bee-demo
#项目运行端口
httpport = 8080
#指定运行环境 是dev还是prod
runmode = dev
#通过Ctx.Input.RequestBody获取数据
copyrequestbody = true
#开发环境配置文件
[dev]
    defaultdb = root:guofuBlog@tcp(127.0.0.1:3306)/youku?charset=utf8
#生成环境配置文件
[prod]
    defaultdb = root:guofuBlog@tcp(127.0.0.1:3306)/youku?charset=utf8


使用orm操作数据库

  • 我们先来创建一个user表bee generate migration user,或者手写SQL也可以,我这里使用bee命令创建,执行命令之后,生成文件bee-demo/database/migrations/20221209_105701_user.go
  • 接下来我们根据自己的需求补全这个文件的内容
package main

import (
 "github.com/beego/beego/v2/client/orm/migration"
)

// DO NOT MODIFY
type User_20221209_105701 struct {
 migration.Migration
}

// DO NOT MODIFY
func init() {
 m := &User_20221209_105701{}
 m.Created = "20221209_105701"

 migration.Register("User_20221209_105701", m)
}

// Run the migrations
func (m *User_20221209_105701) Up() {
 // use m.SQL("CREATE TABLE ...") to make schema update
 m.CreateTable("user", "innodb", "utf8mb4")
 m.PriCol("id").SetAuto(true).SetDataType("int").SetUnsigned(true)
 m.NewCol("username").SetDataType("varchar(255)")
 m.NewCol("password").SetDataType("varchar(255)")
 m.NewCol("created_at").SetDataType("datetime").SetDefault("NOW()")
 m.NewCol("updated_at").SetDataType("datetime").SetDefault("NOW()")
 m.SQL(m.GetSQL())

}

// Reverse the migrations
func (m *User_20221209_105701) Down() {
 // use m.SQL("DROP TABLE ...") to reverse schema update
 m.SQL("DROP TABLE IF EXISTS user")

}
  • 执行命令生成数据表bee migrate -driver=mysql -conn="root:guofuBlog@tcp(127.0.0.1:3306)/bee_db"

那么使用migrate有什么好处呢?

  • 我们看一下库,会发现有两个表,一个是我们创建的user表,一个是migrations表,里面记录了我们的建表语句,方便我们快速完成数据迁移

配置数据库

  • 我们在app.conf中加入bee_db库的链接配置beedb = root:guofuBlog@tcp(127.0.0.1:3306)/bee_db
  • 在main函数中完成数据库的初始化
func init() {
 defaultdb, _ := beego.AppConfig.String("beedb")
 fmt.Println(defaultdb)
 orm.RegisterDriver("mysql", orm.DRMySQL)
 orm.RegisterDataBase("default", "mysql", defaultdb)
 orm.Debug = true
}

增删改查

  • 以下操作遵循RESTful风格
添加数据
  • 添加路由,这里我们通过form表单传参的方式
 //获取列表 添加用户
 beego.Router("/user", &controllers.UserController{})
 //get:GetOne 请求方式:请求方法  更新 删除  获取单个用户
 beego.Router("/user/:id", &controllers.UserController{},"get:GetOne")
  • 创建modelbee generate model user -fields="name:string"
  • 修改控制器
type ReturnApi struct {
 //tag:json 表示返回json格式的字段名
 Code int `json:"code"`
 Msg  string `json:"msg"`
 Data interface{} `json:"data"`
}

func SuccessApi() *ReturnApi {
 return &ReturnApi{Code: 200,Data:""}
}
func FailedApi() *ReturnApi {
 return &ReturnApi{Code: 9999,Data:""}
}

func (c *UserController) Post() {

 username := c.GetString("username")
 password := c.GetString("password")
 //定义一个json返回失败和成功的结构体
 if username == "" || password == "" {
  data := FailedApi()
  data.Msg = "参数不全"
  log.Println(data)
  c.Data["json"] = &data
  c.ServeJSON()
  return
 }
 m := models.User{
  Username: username,
  Password: password,
 }
 id, err := models.AddUser(&m)
 if err != nil {
  data := FailedApi()
  data.Msg = "插入数据失败"
  data.Data = ""
  c.Data["json"] = data
  c.ServeJSON()
  return
 }
 data := SuccessApi()
 data.Msg = "插入成功"
 data.Data = id
 c.Data["json"] = data
 c.ServeJSON()
 return
}

在这里插入图片描述
  • 这是我们用bee model生成的model里面自带的方法,接下来我们使用原生sql写一下,分享一下model的代码
func AddUserRaw(username string,password string) (id int64,err error) {
 o := orm.NewOrm()
 res,errRes:=o.Raw("insert into User set username=?,password=? ", username, password).Exec()
 if errRes != nil {
  err=errors.New("插入失败")
  id=0
  return
 }
 err=nil
 id,_=res.LastInsertId()
 return
}
查询一条数据
func (c *UserController) GetOne() {
 id_str := c.Ctx.Input.Param(":id")
 id, _ := strconv.ParseInt(id_str, 10, 64)

 log.Println(id)
 if id < 1  {
  data := FailedApi()
  data.Msg = "该用户不存在"
  log.Println(data)
  c.Data["json"] = &data
  c.ServeJSON()
  return
 }
 data := SuccessApi()
 data.Msg = "获取成功"
 user, err := models.GetUserById(id)
 if err != nil {
  data := FailedApi()
  data.Msg = "该用未注册"
  log.Println(data)
  c.Data["json"] = &data
  c.ServeJSON()
  return
 }
 data.Data = user
 c.Data["json"] = &data
 c.ServeJSON()
 return

}

  • orm和原生写法
// GetUserById retrieves User by Id. Returns error if
// Id doesn't exist
func GetUserById(id int64) (v *User, err error) {
 o := orm.NewOrm()
 v = &User{Id: id}
 if err = o.QueryTable(new(User)).Filter("Id", id).RelatedSel().One(v); err == nil {
  return v, nil
 }
 return nil, err
}

func GetUserByIdRaw(id int64) (v *User, err error) {
 o := orm.NewOrm()
 v = &User{}
 err=o.Raw("select `id`,`username` from user where id=? limit 1",id).QueryRow(&v)
 if err != nil {
  return nil,err
 }
 return v, err
}

查列表

  • 路由beego.Router("/user/list", &controllers.UserController{},"get:GetAll")
  • 控制器

func (c *UserController) GetAll() {
 list:=models.GetAllUser()
 data := SuccessApi()
 data.Msg = "获取成功"
 data.Data=list
 log.Println(data)
 c.Data["json"] = &data
 c.ServeJSON()
 return
}
  • model
func GetAllUser() ([]User) {
 var (
  users []User
 )
 o := orm.NewOrm()
 qs := o.QueryTable(new(User))
 qs = qs.Filter("id__gt", 7)
 qs = qs.Limit(2)
 qs = qs.OrderBy("-id")
 qs.All(&users, "id", "username")
 return users
}

删数据

  • 路由 beego.Router("/user/:id", &controllers.UserController{}, "Delete:Delete")
  • 控制器
func (c *UserController) Delete() {
 id_str := c.Ctx.Input.Param(":id")
 id, _ := strconv.ParseInt(id_str, 10, 64)
 err:=models.DelUserRaw(id)
 if err != nil {
  data := FailedApi()
  data.Msg = "删除失败"
  log.Println(data)
  c.Data["json"] = &data
  c.ServeJSON()
  return
 }
 data := SuccessApi()
 data.Msg = "删除成功"
 log.Println(data)
 c.Data["json"] = &data
 c.ServeJSON()
 return
}
  • model

func DeleteUser(id int64) (err error) {
 o := orm.NewOrm()
 v := User{Id: id}
 // ascertain id exists in the database
 if err = o.Read(&v); err == nil {
  var num int64
  if num, err = o.Delete(&User{Id: id}); err == nil {
   fmt.Println("Number of records deleted in database:", num)
  }
 }
 return
}

func DelUserRaw(id int64) (err error) {
 o := orm.NewOrm()
 res, errRes := o.Raw("delete from  User where id=?",id).Exec()
 if errRes != nil {
  err = errors.New("插入失败")
  id = 0
  return
 }
 err = nil
 id, _ = res.LastInsertId()
 return
}

bee的其他命令

  • generate 命令 这个命令是用来自动化的生成代码的,包含了从数据库一键生成 model,还包含了 scaffold 的,通过这个命令,让大家开发代码不再慢
    bee generate scaffold [scaffoldname] [-fields=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]   
    // 此处是一个批处理命令,生成model,controller、view、doc以及生成数据迁移文件,并进行数据迁移
    // The generate scaffold command will do a number of things for you.
    // -fields: a list of table fields. Format: field:type, ...
    // -driver: [mysql | postgres | sqlite], the default is mysql
    // -conn:   the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
    
    例子: bee generate scaffold post -fields="title:string,body:text" -conn="root:root@tcp(127.0.0.1:3306)/beego_api"
    例子中的命令会 根据-fields="title:string,body:text" 来创建model,controller、view、以及生成数据迁移文件,并进行数据迁移(即在数据库中生成对应的数据表)。以上操作都会询问yes或者no

bee generate model [modelname] [-fields=""]     // 根据fields列表来生成model文件
    // generate RESTful model based on fields
    // -fields: a list of table fields. Format: field:type, ...

bee generate controller [controllerfile]       // 生成controller文件(根据对应的model文件)
    // generate RESTful controllers

bee generate view [viewpath]                   // 生成view文件,
    // generate CRUD view in viewpath

bee generate migration [migrationfile] [-fields=""]        // 生成数据迁移文件
    // generate migration file for making database schema update
    // -fields: a list of table fields. Format: field:type, ...

bee generate docs                             // 生成文档
    // generate swagger doc file

bee generate test [routerfile]                // 根据路由生成测试用例(没试过)
    // generate testcase

bee generate appcode [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3]    // 这里就是文章介绍的,根据数据表生成model文件等
    // generate appcode based on an existing database
    // -tables: a list of table names separated by ',', default is empty, indicating all tables
    // -driver: [mysql | postgres | sqlite], the default is mysql
    // -conn:   the connection string used by the driver.
    //         default for mysql:    root:@tcp(127.0.0.1:3306)/test
    //         default for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
    // -level:  [1 | 2 | 3], 1 = models; 2 = models,controllers; 3 = models,controllers,router