1.在结构体字段上加
orm
标签
定义结构体
golang
type User struct {
Id int `orm:"auto"` // 主键,自动递增
Name string `orm:"size(100)"` // varchar(100)
Email string `orm:"size(100);unique"` // varchar(100) 且唯一索引
Password string `orm:"-"` // "-" 表示不存到数据库
Age int // 默认映射 int 列
Created time.Time `orm:"auto_now_add;type(datetime)"` // 插入记录时自动写入当前时间
}
在程序启动(init
函数里)告诉 ORM "我要映射这个结构体":
golang
func init() {
// 如果要把 struct 存入 session,要先注册(gob)
orm.RegisterModel(new(User))
}
同步创建数据表(可选)
golang
// 同步建表(第二个参数 false:不强制,第三个参数 true:打印日志)
orm.RunSyncdb("default", false, true)
ORM 在查询/插入/更新时,就会把 User
结构体里的字段和上面这些表列自动对上号,帮你生成 SQL。
2.MySQL 驱动跟 Go 的数据库框架绑到一起
mysql驱动插入到go数据库列表里
golang
import _ "github.com/go-sql-driver/mysql"
告诉 Beego ORM 我准备用哪个驱动
golang
orm.RegisterDataBase("default", "mysql", "root:123456@/test?charset=utf8")
-
"default"
:给这个连接起个别名,以后做查询、事务都用它。 -
"mysql"
:告诉 ORM 用上一步注册的 MySQL 驱动。 -
"root:123456@/test?charset=utf8"
:就是数据库地址、用户名、密码和编码设置。
golang
orm.RegisterModel(new(User))
orm.RunSyncdb("default", false, true)
-
RegisterModel
把你的User
结构体跟数据库里user
表对应起来。 -
RunSyncdb
则会用刚才"default"
连接去检查表有没有、字段对不对,不存在就自动建表,打印出执行的 SQL。
3.全局过滤器(登录鉴权、XSRF、日志)
golang
// 全局过滤器注册
beego.InsertFilter("/*", beego.BeforeRouter, loggingFilter)
beego.InsertFilter("/*", beego.BeforeRouter, authFilter)
beego.InsertFilter("/*", beego.BeforeExec, xsrfFilter)
func authFilter(ctx *context.Context) {
if ctx.Input.Session("user") == nil && ctx.Request.RequestURI != "/login" {
ctx.Redirect(302, "/login")
}
}
func xsrfFilter(ctx *context.Context) {
// 只对 POST/PUT/DELETE 做验证
if ctx.Input.IsPost() {
if !ctx.CheckXSRFCookie() {
ctx.Abort("403")
}
}
}
func loggingFilter(ctx *context.Context) {
beego.Informational("Request:", ctx.Request.Method, ctx.Request.RequestURI)
}
在 Beego 里,"全局过滤器"就是一段在每次请求到来时都会被自动调用的小代码,你可以在里面做日志、鉴权、CSRF 校验等统一工作。
- loggingFilter函数:方便以后在日志里追踪请求历史。
- authFilter函数:在路由解析前检查 Session 里有没有登陆标记。
- xsrfFilter函数:在准备执行 Controller 方法前,再检查一次 POST/PUT/DELETE 请求的隐藏
_xsrf
字段是否正确,防止跨站请求伪造。
这种方式能在controller方法之前完成鉴权,日志,安全校验,一次完成这些操作,不用再去每个方法里分别加入。
4.开启session和XSRF
golang
// ---------------------------
// Session & XSRF 全局配置
// ---------------------------
beego.BConfig.WebConfig.Session.SessionOn = true
beego.BConfig.WebConfig.Session.SessionProvider = "memory"
beego.BConfig.WebConfig.EnableXSRF = true
beego.BConfig.WebConfig.XSRFExpire = 3600
可以在main.go里配置,也可以在配置文件 app.conf
里加。
5.Controller执行
golang
// ---------------------------
// 路由 & Controller 注册
// ---------------------------
// 普通路由
beego.Router("/", &MainController{})
// RESTful 自动路由
beego.AutoRouter(&UserController{})
// 自定义路由 + 方法映射
beego.Router("/login", &AuthController{}, "get:Show;post:Login")
// 静态资源
beego.SetStaticPath("/static", "public")
// 启动
beego.Run()
过滤器执行一遍后,开始执行Controller的方法
golang
// MainController 演示多格式输出 & Flash
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
// Flash 示范
flash := beego.ReadFromRequest(&c.Controller)
c.Data["flash"] = flash.Data()
// URL 构建
c.Data["userListURL"] = beego.URLFor("UserController.List", ":page", 1)
c.TplName = "index.tpl"
}
// Error404 自定义 Controller 错误处理
func (c *MainController) Error404(data interface{}) {
c.Data["msg"] = data
c.TplName = "errors/404.tpl"
}
-
beego.Controller匿名方式组合,MainController就可以使用beego.ControllerInterface接口下的方法。
-
Abort(404)函数会调用Error404函数并跳转到404页面。
6.XSRF过滤和登录跳转
golang
// AuthController 登录示范(Session & XSRF)
type AuthController struct {
beego.Controller
}
// Show 登录页面
func (c *AuthController) Show() {
c.Data["xsrfdata"] = template.HTML(c.XSRFFormHTML())
c.TplName = "login.tpl"
}
// Login 处理
func (c *AuthController) Login() {
name := c.GetString("username")
pass := c.GetString("password")
if name == "admin" && pass == "123" {
c.SetSecureCookie("beegosessionid", "user", name)
c.Session("user", &User{Name: name})
c.FlashWrite("notice", "登录成功!")
c.Redirect("/", 302)
} else {
c.FlashWrite("error", "用户名或密码错误")
c.Redirect("/login", 302)
}
}
- 把 CSRF 隐藏字段塞进登录表单
- 拿表单数据验证,对了就「写 Cookie + 写 Session + 一次性提示 + 跳首页」,错了就「一次性提示 + 跳回登录页」。
7.CRUD操作
golang
// ---------------------------
// UserController: CRUD 示例
// ---------------------------
type UserController struct {
beego.Controller
}
func (c *UserController) Prepare() {
// 继承 Prepare,可选
}
// List 展示用户列表(分页示范)
func (c *UserController) List() {
page, _ := c.GetInt("page", 1)
o := orm.NewOrm()
qs := o.QueryTable(new(User))
var users []User
qs.Limit(10, (page-1)*10).All(&users) // QueryBuilder: 分页
c.Data["json"] = users // 多格式输出:JSON
c.ServeJSON()
}
// Create 添加新用户(Raw SQL & 事务示范)
func (c *UserController) Post() {
o := orm.NewOrm()
o.Begin()
defer func() {
if err := recover(); err != nil {
o.Rollback()
c.CustomAbort(500, "创建失败")
}
}()
u := User{Name: c.GetString("name"), Age: c.GetInt("age")}
_, err := o.Raw("INSERT INTO user(name,age,created) VALUES(?,?,?)",
u.Name, u.Age, time.Now()).Exec()
if err != nil {
o.Rollback()
panic(err)
}
o.Commit()
c.Ctx.WriteString("OK")
}
// GetOne 根据 ID 查询单个(URL: /user/:id)
func (c *UserController) GetOne() {
id, _ := c.GetInt(":id")
o := orm.NewOrm()
u := User{Id: id}
if err := o.Read(&u); err != nil {
c.Abort("404")
}
c.Data["json"] = u
c.ServeJSON()
}
// Put 更新用户
func (c *UserController) Put() {
id, _ := c.GetInt(":id")
u := User{Id: id}
if err := c.ParseForm(&u); err != nil {
c.CustomAbort(400, "参数错误")
}
o := orm.NewOrm()
if _, err := o.Update(&u); err != nil {
c.CustomAbort(500, "更新失败")
}
c.Ctx.WriteString("OK")
}
// Delete 删除用户
func (c *UserController) Delete() {
id, _ := c.GetInt(":id")
o := orm.NewOrm()
if _, err := o.Delete(&User{Id: id}); err != nil {
c.CustomAbort(500, "删除失败")
}
c.Ctx.WriteString("OK")
}
- beego.AutoRouter会自动化扫描方法名,注册到router里面,请求方式对应执行那个方法。
- 客户端对
/user
发 GET →List()
返回多条用户 JSON; - 发 POST →
Post()
插入新用户; - 对
/user/123
发 GET →GetOne()
返回 ID=123 的用户; - 发 PUT →
Put()
更新用户; - 发 DELETE →
Delete()
删除用户。
这样就完成了一个标准的 REST 风格用户管理接口。
总结
- 创建User结构体通过ORM模型跟数据表映射
- 全局过滤器在controller前进行鉴别
- ORM注册模型,可以使用内部方法实现CRUD。如果要实现复杂的sql,可以用原生sql语句执行。