概述
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",
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 实现
通用 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 实现
用户 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 功能开发。
有疑问加站长微信联系(非本文作者)