使用 orm 實現增刪改查 - beego 框架使用筆記
阿新 • • 發佈:2019-12-31
概述
beego ORM 是一個強大的 Go 語言 ORM 框架,目前該框架已支援 MySQL、PostgreSQL、Sqlite3 資料庫驅動。
安裝 ORM
go get github.com/astaxie/beego/orm
複製程式碼
初始化
建立專案
使用 bee 工具的安裝 api 命令 bee api apiproject
建立 apiproject 專案,具體使用方法檢視 beego api 命令。
模型關係
# 外來鍵始終在子表上
# 一個使用者對應一個簡介;一個簡介對應一個使用者;
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)"` 標註反向關係
複製程式碼
database 資訊
註冊 model:
orm.RegisterModel(new(User),new(Profile))
複製程式碼
自定義表名:
func (u *User) TableName() string {
return "users"
}
func (u *Profile) TableName() string {
return "users_profiles"
}
複製程式碼
自動建表:
orm.RunSyncdb("default",false,true)
複製程式碼
資料表結構:
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.conf
appname = apiproject
httpport = 8090
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn = root:123456@/play_db?charset=utf8
複製程式碼
通用 utils
分頁:
/apiproject/utils/page.go
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}
}
複製程式碼
main 入口
/apiproject/main.go
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",AllowHTTPMethods: []string{"get"},beego.ControllerComments{
Method: "Get",Router: `/:uid`,beego.ControllerComments{
Method: "Put",AllowHTTPMethods: []string{"put"},beego.ControllerComments{
Method: "Delete",AllowHTTPMethods: []string{"delete"},Params: nil})
}
複製程式碼
controller 實現
通用 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,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,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,b}
}
u.ServeJSON()
}
複製程式碼
model 實現
使用者 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))
}
複製程式碼
END
以上示例實現使用者模組的增、刪、改、查應用介面 API 功能開發。