beego ORM 是一個強大的 Go 語言 ORM 框架,目前該框架已支持 MySQL、PostgreSQL、Sqlite3 數據庫驅動。mysql
go get github.com/astaxie/beego/orm
複製代碼
使用 bee 工具的安裝 api 命令 bee api apiproject
建立 apiproject 項目,具體使用方法查看 beego api 命令。git
# 外鍵始終在子表上
# 一個用戶對應一個簡介;一個簡介對應一個用戶;
one2one:User(子表) -> Profile(主表);one2one:Profile -> User
複製代碼
type User struct {
Id int `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
Profile *Profile `orm:"rel(one)" json:"profile"` // OneToOne relation
}
type Profile struct {
Id int `json:"id"`
Gender int `json:"gender"`
Age int `json:"age"`
Address string `json:"address"`
Email string `json:"email"`
User *User `orm:"reverse(one)" json:"-"` // 設置一對一反向關係(可選)
}
複製代碼
使用標籤`orm:"column(id)`對屬性進行標註,用於解析。 `orm:"rel(one)"` 表示one2one `orm:"reverse(one)"` `orm:"reverse(one)"` 標註反向關係 複製代碼
註冊 model:github
orm.RegisterModel(new(User), new(Profile))
複製代碼
自定義表名:sql
func (u *User) TableName() string {
return "users"
}
func (u *Profile) TableName() string {
return "users_profiles"
}
複製代碼
自動建表:數據庫
orm.RunSyncdb("default", false, true)
複製代碼
數據表結構:json
mysql> show tables;
+-------------------+
| Tables_in_play_db |
+-------------------+
| users |
| users_profiles |
+-------------------+
2 rows in set (0.01 sec)
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(255) | NO | | | |
| password | varchar(255) | NO | | | |
| profile_id | int(11) | NO | UNI | NULL | |
+------------+--------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)
mysql> desc users_profiles;
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| gender | int(11) | YES | | 0 | |
| age | int(11) | YES | | 0 | |
| address | varchar(255) | YES | | | |
| email | varchar(255) | YES | | | |
+---------+--------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
複製代碼
/apiproject/conf/app.confapi
appname = apiproject
httpport = 8090
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn = root:123456@/play_db?charset=utf8
複製代碼
分頁:
/apiproject/utils/page.gobash
package utils
var (
PageSize int = 10
)
type Page struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
TotalPage int `json:"totalPage"`
TotalCount int `json:"totalCount"`
FirstPage bool `json:"firstPage"`
LastPage bool `json:"lastPage"`
List interface{} `json:"list"`
}
func Pagination(count int, page int, pageSize int, list interface{}) Page {
tp := count / pageSize
if count%pageSize > 0 {
tp = count/pageSize + 1
}
return Page{Page: page, PageSize: pageSize, TotalPage: tp, TotalCount: count, FirstPage: page == 1, LastPage: page == tp, List: list}
}
複製代碼
/apiproject/main.goapp
package main
import (
_ "apiproject/routers"
"github.com/astaxie/beego/orm"
"github.com/astaxie/beego"
_ "github.com/go-sql-driver/mysql"
)
func init() {
// 參數1 driverName
// 參數2 數據庫類型
// 這個用來設置 driverName 對應的數據庫類型
// mysql / sqlite3 / postgres 這三種是默認已經註冊過的,因此能夠無需設置
// orm.RegisterDriver("mysql", orm.DRMySQL)
// ORM 必須註冊一個別名爲 default 的數據庫,做爲默認使用。
// 參數1 數據庫的別名,用來在 ORM 中切換數據庫使用
// 參數2 driverName
// 參數3 對應的連接字符串
orm.RegisterDataBase("default", "mysql", beego.AppConfig.String("sqlconn"))
}
func main() {
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
}
// 開啓 orm 調試模式:開發過程當中建議打開,release時須要關閉
orm.Debug = true
beego.Run()
}
複製代碼
RESTful Controller 路由,初始化 namespace:
/apiproject/routers/router.go框架
// @APIVersion 1.0.0
// @Title apiproject API
// @License Apache 2.0
package routers
import (
"apiproject/controllers"
"github.com/astaxie/beego"
)
func init() {
ns := beego.NewNamespace("/v1",
beego.NSNamespace("/object",
beego.NSInclude(
&controllers.ObjectController{},
),
),
beego.NSNamespace("/user",
beego.NSInclude(
&controllers.UserController{},
),
),
)
beego.AddNamespace(ns)
}
複製代碼
/apiproject/routers/commentsRouter_controllers.go
package routers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context/param"
)
func init() {
beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
beego.ControllerComments{
Method: "Post",
Router: `/`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
beego.ControllerComments{
Method: "GetAll",
Router: `/`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
beego.ControllerComments{
Method: "Get",
Router: `/:uid`,
AllowHTTPMethods: []string{"get"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
beego.ControllerComments{
Method: "Put",
Router: `/:uid`,
AllowHTTPMethods: []string{"put"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["apiproject/controllers:UserController"] = append(beego.GlobalControllerRouter["apiproject/controllers:UserController"],
beego.ControllerComments{
Method: "Delete",
Router: `/:uid`,
AllowHTTPMethods: []string{"delete"},
MethodParams: param.Make(),
Filters: nil,
Params: nil})
}
複製代碼
通用 controller base:
/apiproject/controllers/base.go
package controllers
import (
"github.com/astaxie/beego"
)
type BaseController struct {
beego.Controller
}
// Response 結構體
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
// Error Response 結構體
type ErrResponse struct {
Code int `json:"code"`
Message string `json:"message"`
}
複製代碼
自定義錯誤代碼編碼:
/apiproject/controllers/code.go
package controllers
var (
// Common errors
SUCCESS = &Errno{Code: 0, Message: "成功"}
InternalServerError = &Errno{Code: 10001, Message: "內部服務錯誤"}
ErrBind = &Errno{Code: 10002, Message: "參數錯誤"}
ErrDatabase = &Errno{Code: 20001, Message: "數據庫錯誤"}
ErrToken = &Errno{Code: 20002, Message: "簽發令牌出錯"}
ErrNoPermission = &Errno{Code: 20003, Message: "無權限"}
// user errors
ErrUserNotFound = &Errno{Code: 20101, Message: "用戶未註冊"}
ErrUserExist = &Errno{Code: 20102, Message: "用戶已存在"}
)
複製代碼
通用錯誤處理:
/apiproject/controllers/errno.go
package controllers
import "fmt"
type Errno struct {
Code int
Message string
}
func (err Errno) Error() string {
return err.Message
}
// Err represents an error
type Err struct {
Code int
Message string
Err error
}
func New(errno *Errno, err error) *Err {
return &Err{Code: errno.Code, Message: errno.Message, Err: err}
}
func (err *Err) Add(message string) error {
err.Message += " " + message
return err
}
func (err *Err) Addf(format string, args ...interface{}) error {
err.Message += " " + fmt.Sprintf(format, args...)
return err
}
func (err *Err) Error() string {
return fmt.Sprintf("Err - code: %d, message: %s, error: %s", err.Code, err.Message, err.Err)
}
func IsErrUserNotFound(err error) bool {
code, _ := DecodeErr(err)
return code == ErrUserNotFound.Code
}
func DecodeErr(err error) (int, string) {
if err == nil {
return SUCCESS.Code, SUCCESS.Message
}
switch typed := err.(type) {
case *Err:
return typed.Code, typed.Message
case *Errno:
return typed.Code, typed.Message
default:
}
return InternalServerError.Code, err.Error()
}
複製代碼
用戶 controller 模塊:
/apiproject/controllers/user.go
package controllers
import (
"apiproject/models"
"apiproject/utils"
"encoding/json"
"strconv"
)
// Operations about Users
type UserController struct {
BaseController
}
// @Title CreateUser
// @Description create users
// @Param body body models.User true "body for user content"
// @Success 200 {int} models.User.Id
// @Failure 403 body is empty
// @router / [post]
func (u *UserController) Post() {
var user models.User
_ = json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uid, _ := models.AddUser(user)
u.Data["json"] = map[string]int64{"uid": uid}
u.ServeJSON()
}
// @Title GetAll
// @Description get all Users
// @Success 200 {object} models.User
// @router / [get]
func (u *UserController) GetAll() {
currentPage, _ := strconv.Atoi(u.Ctx.Input.Query("page"))
if currentPage == 0 {
currentPage = 1
}
pageSize := utils.PageSize
d , err:= models.GetAllUsers(currentPage,pageSize)
code, message := DecodeErr(err)
if err != nil {
u.Data["json"] = ErrResponse{code, message}
} else {
u.Data["json"] = Response{code, message, d}
}
u.ServeJSON()
}
// @Title Get
// @Description get user by uid
// @Param uid path string true "The key for staticblock"
// @Success 200 {object} models.User
// @Failure 403 :uid is empty
// @router /:uid [get]
func (u *UserController) Get() {
uid, _ := u.GetInt(":uid")
if uid > 0 {
user, err := models.GetUser(uid)
code, message := DecodeErr(err)
if err != nil {
u.Data["json"] = ErrResponse{code, message}
} else {
u.Data["json"] = Response{code, message, user}
}
}
u.ServeJSON()
}
// @Title Update
// @Description update the user
// @Param uid path string true "The uid you want to update"
// @Param body body models.User true "body for user content"
// @Success 200 {object} models.User
// @Failure 403 :uid is not int
// @router /:uid [put]
func (u *UserController) Put() {
uid, _ := u.GetInt(":uid")
if uid > 0 {
var user models.User
_ = json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uu, err := models.UpdateUser(uid, &user)
code, message := DecodeErr(err)
if err != nil {
u.Data["json"] = ErrResponse{code, message}
} else {
u.Data["json"] = Response{code, message, uu}
}
}
u.ServeJSON()
}
// @Title Delete
// @Description delete the user
// @Param uid path string true "The uid you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 uid is empty
// @router /:uid [delete]
func (u *UserController) Delete() {
uid, _ := u.GetInt(":uid")
b, err := models.DeleteUser(uid)
code, message := DecodeErr(err)
if err != nil {
u.Data["json"] = ErrResponse{code, message}
} else {
u.Data["json"] = Response{code, message, b}
}
u.ServeJSON()
}
複製代碼
用戶 model 模塊,orm 實現 增刪改查:
/apiproject/models/user.go
package models
import (
"apiproject/utils"
"errors"
"github.com/astaxie/beego/orm"
"strconv"
)
type User struct {
Id int `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
Profile *Profile `orm:"rel(one)" json:"profile"` // OneToOne relation
}
type Profile struct {
Id int `json:"id"`
Gender int `json:"gender"`
Age int `json:"age"`
Address string `json:"address"`
Email string `json:"email"`
User *User `orm:"reverse(one)" json:"-"` // 設置一對一反向關係(可選)
}
// 自定義表名
func (u *User) TableName() string {
return "users"
}
func (u *Profile) TableName() string {
return "users_profiles"
}
// 新增用戶
func AddUser(u User) (id int64, err error) {
// one2one 插入
// 建立一個 ormer 對象
o := orm.NewOrm()
// 開啓事務
err = o.Begin()
// 插入主表
profile := Profile{
Gender: u.Profile.Gender,
Age: u.Profile.Age,
Address: u.Profile.Address,
Email: u.Profile.Email}
id, err = o.Insert(&profile)
if err != nil {
// 回滾事務
err = o.Rollback()
}
// 插入子表
user := User{
Username: u.Username,
Password: u.Password,
Profile: &Profile{Id: int(id)}}
_, err = o.Insert(&user)
if err != nil {
// 回滾事務
err = o.Rollback()
}
// 提交事務
err = o.Commit()
return id, err
}
// 查詢指定用戶
func GetUser(uid int) (u *User, err error) {
o := orm.NewOrm()
user := &User{Id: uid}
err = o.Read(user)
// 已經取得了 Users 對象,查詢 UserProfiles
if user.Profile != nil {
err = o.Read(user.Profile)
}
return user, err
}
// 分頁查詢用戶
func GetAllUsers(p int, size int) (u utils.Page, err error) {
o := orm.NewOrm()
user := new(User)
var users []User
qs := o.QueryTable(user)
count, _ := qs.Limit(-1).Count()
_, err = qs.RelatedSel().Limit(size).Offset((p - 1) * size).All(&users)
for _, u := range users {
if u.Profile != nil {
err = o.Read(u.Profile)
}
}
c, _ := strconv.Atoi(strconv.FormatInt(count, 10))
return utils.Pagination(c, p, size, users), err
}
// 更新指定用戶
func UpdateUser(uid int, uu *User) (a *User, err error) {
o := orm.NewOrm()
user := User{Id: uid}
profile := Profile{Id: uid}
if o.Read(&user) == nil {
if uu.Username != "" {
user.Username = uu.Username
}
if uu.Password != "" {
user.Password = uu.Password
}
if o.Read(&profile) == nil {
if uu.Profile.Age > 0 {
profile.Age = uu.Profile.Age
}
if uu.Profile.Address != "" {
profile.Address = uu.Profile.Address
}
if uu.Profile.Gender == 0 || uu.Profile.Gender == 1 {
profile.Gender = uu.Profile.Gender
}
if uu.Profile.Email != "" {
profile.Email = uu.Profile.Email
}
}
user.Profile = &profile
// 開啓事務
err = o.Begin()
if _, err := o.Update(&user); err != nil {
return nil, errors.New("修改失敗")
}
if _, err := o.Update(&profile); err != nil {
return nil, errors.New("修改失敗")
}
if err != nil {
err = o.Rollback()
} else {
err = o.Commit()
}
return &user, nil
}
return nil, err
}
// 刪除指定用戶
func DeleteUser(uid int) (b bool, err error) {
// one2one 刪除
// 建立一個 ormer 對象
o := orm.NewOrm()
// 開啓事務
err = o.Begin()
// 刪除主表
profile := Profile{Id: uid}
_, err = o.Delete(&profile)
if err != nil {
// 回滾事務
err = o.Rollback()
}
// 刪除子表
user := User{Id: uid}
_, err = o.Delete(&user)
if err != nil {
// 回滾事務
err = o.Rollback()
}
// 提交事務
err = o.Commit()
return b, err
}
// 註冊 model
func init(){
orm.RegisterModel(new(User), new(Profile))
}
複製代碼
以上示例實現用戶模塊的增、刪、改、查應用接口 API 功能開發。