Beego介绍及使用
介绍
beego web开发框架
beego 是一个快速开发 Go 应用的 HTTP框架,可以用来开发 API、Web 及后端服务等各种应用
地址
github.com/astaxie/beego
beego项目结构
启动服务
beego.Run()
路由
Beego固定路由
web
main.go
package main
// 导入beego包
import (
"fmt"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego"
)
func main() {
// 路由 url => controller
// 处理器函数 处理器: 函数 结构体
// 函数, 结构体
// beego/context/Context
// 绑定函数
// 以GET方式请求/通过绑定函数处理
// 固定路由
beego.Get("/", func(ctx *context.Context) {
// 用户数据的获取
name := ctx.Input.Query("name")
// 给用户响应数据
ctx.Output.Context.WriteString(fmt.Sprintf("你输入的名字是: %s", name))
})
beego.Post("/", func(ctx *context.Context) {
name := ctx.Input.Query("name")
ctx.Output.Context.WriteString(fmt.Sprintf("(POST)你输入的名字是: %s", name))
})
// beego.Delete
// beego.Put
// beego.Options
// beego.Head
// beego.Patch
beego.Any("/any", func(ctx *context.Context) {
name := ctx.Input.Query("name")
ctx.Output.Context.WriteString(fmt.Sprintf("(%s)你输入的名字是: %s", ctx.Input.Method(), name))
})
// 启动beego程序
beego.Run()
}
PS D:\Workspace\Go\src\projects\web> go run main.go
2023/05/11 11:21:41.094 [I] http server Running on http://:8080
Beego正则路由
regexrouter
package main
// 导入beego包
import (
"fmt"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego"
)
func main() {
// 正则路由
// URL中定义正则字符串方式进行匹配
// 匹配 /数字/ 格式的路由 => 并把匹配的值放入到:id参数
beego.Get("/name/?:name(\\w+)/", func(ctx *context.Context) {
name := ctx.Input.Param(":name")
ctx.WriteString(fmt.Sprintf("匹配name: %s", name))
})
beego.Get("/id/:id(\\d+)/", func(ctx *context.Context) {
id := ctx.Input.Param(":id")
ctx.WriteString(fmt.Sprintf("匹配id: %s", id))
})
beego.Get("/any/:content/", func(ctx *context.Context) {
content := ctx.Input.Param(":content")
ctx.WriteString(fmt.Sprintf("匹配context: %s", content))
})
beego.Get("/file/*", func(ctx *context.Context) {
splat := ctx.Input.Param(":splat")
ctx.WriteString(fmt.Sprintf("匹配file: %s", splat))
})
beego.Get("/ext/*.*", func(ctx *context.Context) {
path := ctx.Input.Param(":path")
ext := ctx.Input.Param(":ext")
ctx.WriteString(fmt.Sprintf("匹配ext: %s[%s]", path, ext))
})
// 启动beego程序
beego.Run()
}
MVC配置与实战
restful控制器
restcontroller
package main
// 导入beego包
import (
"github.com/astaxie/beego"
)
// 定义控制器HomeController
type HomeController struct {
beego.Controller
}
// 1. Restful风格的控制器
// api格式
// 一切皆资源 url=> 资源
// 通过动作来表示对资源的操作类型 http method =>
// Post => 创建/更新
// Get => 获取/查询
// Delete => 删除
// Put => 更新
// 可以处理Get请求
func (c *HomeController) Get() {
c.Ctx.WriteString("Get")
}
// 可以处理Post请求
func (c *HomeController) Post() {
c.Ctx.WriteString("Post")
}
func (c *HomeController) Delete() {
c.Ctx.WriteString("Delete")
}
func (c *HomeController) Put() {
c.Ctx.WriteString("Put")
}
func (c *HomeController) Head() {
c.Ctx.WriteString("Head")
}
func (c *HomeController) Options() {
c.Ctx.WriteString("Options")
}
type HostController struct {
beego.Controller
}
func (c *HostController) Get() {
id := c.Ctx.Input.Param(":id")
c.Ctx.WriteString("Host:" + id)
}
func main() {
// url和控制器绑定 => 路由
beego.Router("home/", &HomeController{})
beego.Router("host/?:id/", &HostController{})
// 启动beego程序
beego.Run()
}
自定义控制器方法和路由规则
routerrule
package main
// 导入beego包
import (
"fmt"
"github.com/astaxie/beego"
)
// 自定义控制器方法&路由规则
type TaskController struct {
beego.Controller
}
// 添加任务
func (c *TaskController) Add() {
fmt.Println("add")
c.Ctx.WriteString("add")
}
// 查询任务*查看任务详情
func (c *TaskController) Query() {
fmt.Println("query")
c.Ctx.WriteString("query")
}
// 删除任务
func (c *TaskController) Del() {
fmt.Println("del")
c.Ctx.WriteString("del")
}
// 修改任务
func (c *TaskController) Modify() {
fmt.Println("modify")
c.Ctx.WriteString("modify")
}
func main() {
// GET,HEAD => Query, Post =>Add, Put => Modify, Delete => Del
// 自定义路由规则
// 分号路由规则
// url和控制器绑定 => 路由
beego.Router("/task/", &TaskController{}, "get,head:Query;post:Add;put:Modify;delete:Del")
// 启动beego程序
beego.Run()
}
自动匹配路由
autorouter
package main
// 导入beego包
import (
"fmt"
"github.com/astaxie/beego"
)
// 自定义控制器方法&路由规则
type TaskController struct {
beego.Controller
}
// 添加任务
func (c *TaskController) Add() {
fmt.Println("add")
c.Ctx.WriteString("add")
}
// 查询任务*查看任务详情
func (c *TaskController) Query() {
fmt.Println("query")
c.Ctx.WriteString("query")
}
// 删除任务
func (c *TaskController) Del() {
fmt.Println("del")
c.Ctx.WriteString("del")
}
// 修改任务
func (c *TaskController) Modify() {
fmt.Println("modify")
c.Ctx.WriteString("modify")
}
func main() {
// 自动路由
// url => 控制 controller/action
// task => TaskController
// add => Add方法
beego.AutoRouter(&TaskController{})
// 启动beego程序
beego.Run()
}
数据获取
input
coolie设置和读取
package main
// 导入beego包
import (
"encoding/json"
"fmt"
"github.com/astaxie/beego"
)
const (
cookieKey = "abc123"
)
type InputForm struct {
Name string
Password string `form:"password"`
}
// 自定义控制器方法&路由规则
type InputController struct {
beego.Controller
}
func (c *InputController) QueryParams() {
// 方式1
// c.Ctx.Request.ParseForm()
// fmt.Println(c.Ctx.Request.Form)
// 方式2
// fmt.Println(c.Ctx.Input.Query("name"))
// 方式3
// var name string
// c.Ctx.Input.Bind(&name, "name")
// fmt.Println(name)
// 方式4
// fmt.Println(c.GetString("name"))
// 方式5
// var form InputForm
// fmt.Println(c.ParseForm(&form))
// fmt.Printf("%#v\n", form)
// 方式6
fmt.Println(c.Input())
c.Ctx.WriteString("")
}
func (c *InputController) Form() {
// // 方式1
// c.Ctx.Request.ParseForm()
// fmt.Println(c.Ctx.Request.Form)
// 方式2(只能从POst body中获取数据必须用Request.PostForm)
// c.Ctx.Request.ParseForm()
// fmt.Println(c.Ctx.Request.PostForm)
// 方式3
// fmt.Println(c.GetString("name"))
var form InputForm
c.ParseForm(&form)
fmt.Printf("%#v\n", form)
// 方式4 c.Ctx.Input.Bind
// 方式5 c.Input
// 方式6 c.Ctx.Input.Query
c.Ctx.WriteString("")
}
func (c *InputController) File() {
// 1. Request
// 2. GetFile
// c.GetFile("name")
// 3. SaveTo
c.SaveToFile("img", "./upload/a.jpg")
c.Ctx.WriteString("")
}
func (c *InputController) Json() {
var m map[string]interface{}
json.Unmarshal(c.Ctx.Input.RequestBody, &m)
fmt.Printf("%#v\n", m)
c.Ctx.WriteString("")
}
func (c *InputController) Cookie() {
// 获取方式
// 方式1
// cookie, err := c.Ctx.Request.Cookie("name")
// fmt.Println(cookie, err)
// 方式2
// fmt.Println(c.Ctx.Input.Cookie("name"))
// 方式3
fmt.Println(c.Ctx.GetCookie("name"))
// 设置
// 方式1
// http.SetCookie()
// 方法2
c.Ctx.SetCookie("name", "vavvvv")
c.Ctx.WriteString("")
}
func (c *InputController) SecureCookie() {
fmt.Println(c.Ctx.GetSecureCookie(cookieKey, "test"))
c.Ctx.SetSecureCookie(cookieKey, "test", "vvvv")
// c.GetSecureCookie()
// c.SetSecureCookie()
}
func (c *InputController) Header() {
fmt.Println(c.Ctx.Request.Method)
fmt.Println(c.Ctx.Request.URL)
fmt.Println(c.Ctx.Request.Header)
fmt.Println(c.Ctx.Input.URI())
fmt.Println(c.Ctx.Input.Method())
fmt.Println(c.Ctx.Input.IP())
c.Ctx.WriteString("")
}
func main() {
// 提交数据的方式
// GET ?queryparam
// Post ?queryparams
// request body
// content-type: application/x-www-form-urlencoded
// application/json js 客户端
// multipart/form-data
//
beego.AutoRouter(&InputController{})
// 启动beego程序
beego.Run()
}
http://localhost:8080/input/queryparams/?a=1&b=2
2023/05/11 13:26:17.667 [I] http server Running on http://:8080
map[a:[1] b:[2]]
http://localhost:8080/input/form/?Name=wu&password=123
2023/05/11 13:26:17.667 [I] http server Running on http://:8080
main.InputForm{Name:"wu", Password:"123"}
数据响应
output
package main
// 导入beego包
import (
"encoding/xml"
"github.com/astaxie/beego"
)
// 自定义控制器方法&路由规则
type OutputController struct {
beego.Controller
}
func (c *OutputController) CString() {
c.Ctx.WriteString("Context WriteString")
}
func (c *OutputController) OutputBody() {
c.Ctx.Output.Body([]byte("Output Body"))
}
func (c *OutputController) Tpl() {
c.TplName = "output.html"
}
func (c *OutputController) Json() {
c.Data["json"] = map[string]string{"a": "xxx", "b": "yyyy"}
c.ServeJSON()
}
type User struct {
Name string
Addr string
}
func (c *OutputController) Xml() {
c.Data["xml"] = struct {
XMLName xml.Name `xml:"root"`
User User `xml:"user`
}{User: User{Name: "kk", Addr: "127.0.0.1"}}
c.ServeXML()
}
func (c *OutputController) Yaml() {
c.Data["yaml"] = map[string]string{"a": "xxx", "b": "yyyy"}
c.ServeYAML()
}
func (c *OutputController) Redir() {
c.Redirect("http://www.baidu.com", 302)
}
func (c *OutputController) StopRun() {
c.StopRun()
}
func (c *OutputController) Ab() {
c.Abort("404")
}
func main() {
beego.AutoRouter(&OutputController{})
// 启动beego程序
beego.Run()
}
模板
tpl
package main
// 导入beego包
import (
"strings"
"github.com/astaxie/beego"
)
// 自定义控制器方法&路由规则
type HomeController struct {
beego.Controller
}
func (c *HomeController) Index() {
c.Data["name"] = "wu"
c.Data["body"] = true
c.Data["scores"] = []float32{1, 2, 3, 4}
c.Data["user"] = map[int]string{1: "wu", 2: "ww"}
c.Data["content"] = "abc.ABC"
c.TplName = "index.html" // 默认后缀只支持html, tpl
}
func (c *HomeController) Home() {
// 若无任何响应,则加载控制器名称/Action名.tpl文件显示
}
func main() {
beego.AddFuncMap("lower", func(in string) string {
return strings.ToLower(in)
})
beego.AutoRouter(&HomeController{})
// 启动beego程序
beego.Run()
}
views/index.html
{{ .name }}
{{ if .body }}
男
{{ else }}
女
{{ end }}
{{ range .scores }}
{{.}}|
{{ end }}
<br/>
{{ range $index,$value := .scores }}
{{$index}} = {{$value}} <br />
{{ end }}
{{ range .users }}
{{ . }}
{{ end }}
{{ range $key, $value := .users }}
{{ $key }} = {{ $value }} <br/>
{{ end }}
{{ lower .content }}
{{ .content|lower }}
{{ define "lower" }}
输入内容: {{ .|lower }}
{{ end }}
{{ template "lower" .content }}
{{ template "lower" .content }}
{{ template "lower" .content }}
{{ template "lower" .content }}
{{ template "lower" .content }}
{{ template "lower" .content }}
<br />
{{ template "bar.html" .content}}
{{ template "bar.html" .content}}
{{ template "bar.html" .content}}
{{ template "bar.html" .content}}
{{ template "bar.html" .content}}
views/bar.html
bar: {{ .|lower }}
views/homecontroller/home.tpl
xxxxx
基本配置
config
package main
// 导入beego包
import (
"fmt"
"github.com/astaxie/beego"
)
// 自定义控制器方法&路由规则
type HomeController struct {
beego.Controller
}
func (c *HomeController) Index() {
}
func main() {
fmt.Println(beego.AppConfig.String("mysql::MYSQL_HOST"))
fmt.Println(beego.AppConfig.Int("mysql::MYSQL_PORT"))
fmt.Println(beego.AppConfig.DefaultBool("mysql::MYSQL_PARSETIME", true))
beego.AutoRouter(&HomeController{})
// 启动beego程序
beego.Run()
}
beego详细配置
config\conf\app.conf
# 应用配置
AppName=配置测试
#运行, 生产模式prod[默认], 开发模式dev
RunMode=${RunMode||prod}
#拷贝body数据
CopyRequestBody=true
#上传文件缓冲内存大小
MaxMemory=104857600
#修改服务器banner信息
ServerName=cc
#WEB配置
AutoRender=true
ViewsPath=views
StaticDir=static
# 监控配置
HTTPPort=${HTTPPort||9999}
HTTPAddr=127.0.0.1
[dev]
HTTPPort=8888
[prod]
HTTPPort=80
include "mysql.conf"
config\conf\mysql.conf
[mysql]
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=golang
MYSQL_PASSWORD=golang@2023
PS D:\Workspace\Go\src\projects\config> go run main.go
127.0.0.1
3306 <nil>
true
2023/05/11 14:49:31.469 [I] [asm_amd64.s:1571] http server Running on http://127.0.0.1:80
cmdb系统
conf\app.conf
AppName=CMDB系统
RunMode=${RunMode||dev}
include "mysql.conf"
conf\mysql.conf
[mysql]
Host=192.168.204.130
Port=3306
User=root
Password=1234
controllers\auth.go
package controllers
import (
"cmdb/base/errors"
"net/http"
"github.com/astaxie/beego"
)
// AuthController 认证控制器
type AuthController struct {
beego.Controller
}
// Login 认证登录
func (c *AuthController) Login() {
form := &forms.LoginForm{}
errs := errors.New()
// Get请求直接加载页面
// Post请求进行数据验证
if c.Ctx.Input.IsPost() {
// 获取用户提交数据
if err := c.ParseForm(form); err == nil {
user := models.GetUserByName(form.Name)
if user == nil {
errs.Add("default", "用户名或密码错误")
// 用户不存在
} else if user.ValidPassword(form.Password) {
c.Redirect("/home/index", http.StatusFound)
} else {
// 用户密码不正确
errs.Add("default", "用户名或密码错误")
}
} else {
errs.Add("default", "用户名或密码错误")
}
}
c.Data["form"] = form
c.Data["errors"] = errs
// 定义加载页面
c.TplName = "auth/login.html"
}
views\auth\login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{ config "String" "AppName" "CMDB" }}</title>
</head>
<body>
<form action="{{ urlfor `AuthController.Login` }}" method="POST">
<label>用户名:</label><input type="text" name="name" value="{{ .form.Name }}" /> <br/>
<label>密码:</label><input type="password" name="password" value="" /> <br/>
{{ if .errors.HasErrors }}
{{ range .errors.Errors }}
{{ index . 0 }}
{{ end }}
<br/>
{{ end }}
<input type="submit" value="登录"/>
</form>
</body>
</html>
routers\router.go
package routers
import (
"cmdb/controllers"
"github.com/astaxie/beego"
)
// 先到内置
// 第三方
// 当前项目
func init() {
beego.AutoRouter(&controllers.AuthController{})
beego.AutoRouter(&controllers.HomeController{})
}
路由导入
_ "cmdb/routers"
main.go
package main
import (
"github.com/astaxie/beego"
_ "github.com/go-sql-driver/mysql"
_ "cmdb/routers"
)
func main() {
beego.Run()
}
启动程序
PS D:\Workspace\Go\src\go-demo\cmdb> go run main.go
2023/05/11 15:48:41.185 [I] [asm_amd64.s:1571] http server Running on http://:8080
2023/05/11 15:49:07.373 [D] [server.go:2916] | ::1| 200 | 1.9414ms| match| GET /auth/login r:/auth/login/*
2023/05/11 15:49:13.088 [D] [server.go:2916] | ::1| 200 | 3.9823ms| match| POST /auth/login r:/auth/login/*
forms\auth.go
package forms
// LoginForm 用户登录表单
type LoginForm struct {
Name string `form:"name"`
Password string `form:"password"`
}
models\user.go
package models
import (
"cmdb/utils"
"fmt"
)
const (
sqlQueryByName = "select id, name, password from user where name=?"
)
// User 用户对象
type User struct {
ID int
StaffID string
Name string
Nickname string
Password string
Gender int
Tel string
Addr string
Email string
Department string
Status int
}
// ValidPassword 验证用户密码是否正确
func (u *User) ValidPassword(password string) bool {
fmt.Println(password, u.Password)
return u.Password == utils.Md5Text(password)
}
// GetUserByName 通过用户名获取用户
func GetUserByName(name string) *User {
user := &User{}
if err := db.QueryRow(sqlQueryByName, name).Scan(&user.ID, &user.Name, &user.Password); err == nil {
return user
}
return nil
}
models\db.go
package models
import (
"database/sql"
"fmt"
"log"
"github.com/astaxie/beego"
)
var db *sql.DB
func init() {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/cmdb?charset=utf8mb4&loc=PRC&parseTime=true",
beego.AppConfig.DefaultString("mysql::User", "root"),
beego.AppConfig.DefaultString("mysql::Password", "1234"),
beego.AppConfig.DefaultString("mysql::Host", "192.168.204.130"),
beego.AppConfig.DefaultInt("mysql::Port", 3306),
)
var err error
db, err = sql.Open("mysql", dsn)
if err != nil {
log.Fatal(err)
}
if err = db.Ping(); err != nil {
log.Fatal(err)
}
}
controllers\home.go
package controllers
import "github.com/astaxie/beego"
type HomeController struct {
beego.Controller
}
func (c *HomeController) Index() {
c.TplName = "home/index.html"
}
views\home\index.html
index
base\errors\errors.go
package errors
type Errors struct {
errors map[string][]string
}
func (e *Errors) Add(key, err string) {
if _, ok := e.errors[key]; !ok {
e.errors[key] = make([]string, 0, 5)
}
e.errors[key] = append(e.errors[key], err)
}
func (e *Errors) Errors() map[string][]string {
return e.errors
}
func (e *Errors) ErrorsByKey(key string) []string {
return e.errors[key]
}
func (e *Errors) HasErrors() bool {
return len(e.errors) != 0
}
func New() *Errors {
return &Errors{
errors: make(map[string][]string),
}
}
utils\md5.go
package utils
import (
"crypto/md5"
"fmt"
)
func Md5Text(text string) string {
return fmt.Sprintf("%x", md5.Sum([]byte(text)))
}
创建数据库cmdb
sqls\init.sql
create database if not exists cmdb default charset utf8mb4;
create table if not exists user(
id bigint primary key auto_increment,
name varchar(64) not null default '',
password varchar(1024) not null default ''
)engine=innodb default charset utf8mb4;
insert into user(name, password) values("wu", md5("123456"));
PS D:\Workspace\Go\src\go-demo\cmdb> go run main.go
2023/05/11 16:51:18.841 [I] [asm_amd64.s:1571] http server Running on http://:8080
2023/05/11 16:51:31.608 [D] [server.go:2916] | ::1| 200 | 1.7608ms| match| GET /auth/login r:/auth/login/*
123456 e10adc3949ba59abbe56e057f20f883e
2023/05/11 16:51:47.114 [D] [server.go:2916] | ::1| 302 | 2.437ms| match| POST /auth/login r:/auth/login/*
2023/05/11 16:51:47.121 [D] [server.go:2916] | ::1| 200 | 1.3104ms| match| GET /home/index r:/home/index/*
MVC: M=>Model: 模型 V=>View: 视图 C=>Controller: 控制器 分层原则 客户端请求: http协议 => url, method, params 服务器处理客户端过程: url => handler => params => db => template => html a. 定义处理器 params b. 处理器调用数据库对数据进行处理(增/删/改/查) c. 处理器调用模板基础去渲染页面 d. 定义url处理器管理 客户端渲染: http渲染页面
通过beego建立一个博客系统,包括博客浏览、添加、修改、删除等操作。
Beego进阶与实战
登录成功后显示用户列表
url->用户列表页面展示
Controller => Model(获取用户数据) => View => Router
用户列表显示
用户查询
session和cookie
用户鉴权改写
controllers\user.go
package controllers
import (
"fmt"
"github.com/astaxie/beego"
"cmdb/models"
)
// UserController 用户管理控制器
type UserController struct {
beego.Controller
}
// Query 查询用户
func (c *UserController) Query() {
fmt.Println("query")
q := c.GetString("q")
users := models.QueryUser(q)
c.Data["users"] = users
c.Data["q"] = q
c.TplName = "user/query.html"
}
models\user.go
package models
import (
"cmdb/utils"
"fmt"
)
const (
sqlQueryByName = "select id, name, password from user where name=?"
sqlQuery = "select id, staff_id, name, nickename, gender, tel, email, addr, department, status from user"
)
// User 用户对象
type User struct {
ID int
StaffID string
Name string
Nickname string
Password string
Gender int
Tel string
Addr string
Email string
Department string
Status int
}
// ValidPassword 验证用户密码是否正确
func (u *User) ValidPassword(password string) bool {
fmt.Println(password, u.Password)
return u.Password == utils.Md5Text(password)
}
// GetUserByName 通过用户名获取用户
func GetUserByName(name string) *User {
user := &User{}
if err := db.QueryRow(sqlQueryByName, name).Scan(&user.ID, &user.Name, &user.Password); err == nil {
return user
}
return nil
}
// QueryUser 查询用户
func QueryUser(q string) []*User {
users := make([]*User, 0, 10)
sql := sqlQuery
params := []interface{}{}
q = utils.Like(q)
if q != "" {
sql += "WHERE staff_id like ? ESCAPE '/' OR name like ? ESCAPE '/' OR nickname like ? ESCAPE '/' OR tel like ? ESCAPE '/' OR email like ? ESCAPE '/' OR addr like ? ESCAPE '/' OR department like ? ESCAPE '/'"
params = append(params, q, q, q, q, q, q, q)
}
rows, err := db.Query(sql, params...)
if err != nil {
return users
}
for rows.Next() {
user := &User{}
if err := rows.Scan(&user.ID, &user.StaffID, &user.Name, &user.Nickname, &user.Gender, &user.Tel, &user.Email, &user.Addr, &user.Department, &user.Status); err == nil {
users = append(users, user)
fmt.Printf("%#v\n", user)
}
}
return users
}
views\user\query.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>用户管理</title>
</head>
<body>
<form action="{{ urlfor `UserController.Query`}}" method="GET">
<input name="q" value="{{ .q }}" />
<input type="submit" value="查询"/>
</form>
<a href="{{ urlfor `AuthController.Logout`}}">退出登录</a>
<table>
<thead>
<tr>
<th>员工编号</th>
<th>用户名</th>
<th>姓名</th>
<th>部门</th>
<th>性别</th>
<th>联系方式</th>
<th>邮箱</th>
<th>联系地址</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{ range .users }}
<tr>
<td>{{ .StaffID }}</td>
<td>{{ .Name }}</td>
<td>{{ .Nickname }}</td>
<td>{{ .Department }}</td>
<td>{{ .GenderText }}</td>
<td>{{ .Tel }}</td>
<td>{{ .Email }}</td>
<td>{{ .Addr }}</td>
<td>{{ .StatusText }}</td>
<td>
编辑
删除
</td>
</tr>
{{ end }}
</tbody>
</table>
</body>
</html>
routers\router.go
package routers
// 先到内置
// 第三方
// 当前项目
import (
"github.com/astaxie/beego"
"cmdb/controllers"
)
func init() {
beego.AutoRouter(&controllers.AuthController{})
beego.AutoRouter(&controllers.HomeController{})
beego.AutoRouter(&controllers.UserController{})
}
utils\sql.go
package utils
import (
"fmt"
"strings"
)
// Like sql查询字符串前后加%
func Like(q string) string {
q = strings.TrimSpace(q)
if q == "" {
return ""
}
q = strings.Replace(q, "/", "//", -1)
q = strings.Replace(q, "%", "/%", -1)
q = strings.Replace(q, "_", "/_", -1)
return fmt.Sprintf("%%%s%%", q)
}
sqls\init.sql
create database if not exists cmdb default charset utf8mb4;
create table if not exists user(
id bigint primary key auto_increment,
staff_id varchar(32) not null default '',
name varchar(64) not null default '',
nickname varchar(64) not null default '',
password varchar(1024) not null default '',
gender int not null default 0 comment '0: 女, 1: 男',
tel varchar(32) not null default '',
email varchar(64) not null default '',
addr varchar(128) not null default '',
department varchar(128) not null default '',
status int not null default 0 comment '0: 正常, 1: 锁定, 2: 离职',
created_at datetime not null,
updated_at datetime not null,
deleted_at datetime
)engine=innodb default charset utf8mb4;
insert into user(staff_id, name, nickname, password, gender, tel, email, addr, department, status, created_at, updated_at) values("K00001", "wu", "wu", md5("123456"), 1, "13622222222", "iamwu@outlook.com", "北京市", "研发一部", 0, now(), now());
models\user.go
package models
import (
"fmt"
"time"
"cmdb/utils"
)
const (
sqlQueryByName = "select id, name, password from user where name=?"
sqlQuery = "select id, staff_id, name, nickname, gender, tel, email, addr, department, status from user"
)
// User 用户对象
type User struct {
ID int
StaffID string
Name string
Nickname string
Password string
Gender int
Tel string
Addr string
Email string
Department string
Status int
CreatedAt *time.Time
UpdatedAt *time.Time
DeletedAt *time.Time
}
// ValidPassword 验证用户密码是否正确
func (u *User) ValidPassword(password string) bool {
fmt.Println(password, u.Password)
return u.Password == utils.Md5Text(password)
}
// GenderText 性别显示
func (u *User) GenderText() string {
if u.Gender == 0 {
return "女"
}
return "男"
}
// StatusText 状态显示
func (u *User) StatusText() string {
switch u.Status {
case 0:
return "正常"
case 1:
return "锁定"
case 2:
return "离职"
}
return "未知"
}
// GetUserByName 通过用户名获取用户
func GetUserByName(name string) *User {
user := &User{}
if err := db.QueryRow(sqlQueryByName, name).Scan(&user.ID, &user.Name, &user.Password); err == nil {
return user
}
return nil
}
// QueryUser 查询用户
func QueryUser(q string) []*User {
users := make([]*User, 0, 10)
sql := sqlQuery
params := []interface{}{}
q = utils.Like(q)
if q != "" {
sql += " WHERE staff_id like ? ESCAPE '/' OR name like ? ESCAPE '/' OR nickname like ? ESCAPE '/' OR tel like ? ESCAPE '/' OR email like ? ESCAPE '/' OR addr like ? ESCAPE '/' OR department like ? ESCAPE '/'"
params = append(params, q, q, q, q, q, q, q)
}
rows, err := db.Query(sql, params...)
if err != nil {
return users
}
for rows.Next() {
user := &User{}
if err := rows.Scan(&user.ID, &user.StaffID, &user.Name, &user.Nickname, &user.Gender, &user.Tel, &user.Email, &user.Addr, &user.Department, &user.Status); err == nil {
users = append(users, user)
fmt.Printf("%#v\n", user)
}
}
return users
}
用户认证 记录用户状态? 记录在哪里?
HTTP无状态? 下一次请求
cookie session机制
状态记录 => session
在什么时间记录(代码什么位置)?
登录成功 记录状态 (session) sessionid
controllers\auth.go
// Login 认证登录
func (c *AuthController) Login() {
form := &forms.LoginForm{}
errs := errors.New()
// Get请求直接加载页面
// Post请求进行数据验证
if c.Ctx.Input.IsPost() {
// 获取用户提交数据
if err := c.ParseForm(form); err == nil {
user := models.GetUserByName(form.Name)
if user == nil {
errs.Add("default", "用户名或密码错误")
// 用户不存在
} else if user.ValidPassword(form.Password) {
// 用户密码正确
// 记录用户状态(session 记录服务器端)
c.SetSession("user", user.ID)
// c.Redirect("/home/index", http.StatusFound)
c.Redirect(beego.URLFor("UserController.Query"), http.StatusFound)
} else {
// 用户密码不正确
errs.Add("default", "用户名或密码错误")
}
} else {
errs.Add("default", "用户名或密码错误")
}
}
c.Data["form"] = form
c.Data["errors"] = errs
// 定义加载页面
c.TplName = "auth/login.html"
}
setcookie sessionid
状态的跟踪 => (sessionid) => cookie
登录状态
无sessionid
有sessionid sessionid无对应session信息
有sessionid sessionid无session登录状态
未登录(无session登录标识)
跳转到登录页面
已登录 => 正常逻辑
用户鉴权
beego
开启: 配置 SessionOn=true/false
存储位置: 内存,文件,数据库
SessionProvider: file/mysql/redis
存储的地址
SessionProviderConfig
cookie中存储sessionid的名字
SessionName
失效时间
SessionGCMaxLifetime = 3600 s
操作
存储session
controller: SetSession key value 可以是任意类型的
持久化的编码方式 gob 注册
获取session
controller: GetSession key => value interface{}
断言
销毁session
key1
key2
controller: DelSession(key)
DestorySession()
conf\app.conf
AppName=CMDB系统
RunMode=${RunMode||dev}
SessionOn=true
SessionName=sid
SessionProvider=file
SessionProviderConfig=./tmp/session
include "mysql.conf"
controllers\user.go
// Query 查询用户
func (c *UserController) Query() {
sessionUser := c.GetSession("user")
if sessionUser == nil {
// 无session信息(未登录)
// sessionUser断言 => int
// user状态 => 禁用/已离职
c.Redirect(beego.URLFor("AuthController.Login"), http.StatusFound)
// c.StopRun()
return
}
fmt.Println("Query")
q := c.GetString("q")
users := models.QueryUser(q)
c.Data["users"] = users
c.Data["q"] = q
c.TplName = "user/query.html"
}
controllers\auth.go
// Logout 用户退出登录
func (c *AuthController) Logout() {
c.DestroySession()
c.Redirect(beego.URLFor("AuthController.Login"), http.StatusFound)
}
-
session(登录检查) 在任何需要登录以后才能访问的action执行之前都需要进行检查
-
如果访问登录页面 检查session已存在(用户已登录,就不在打开登录页面,直接跳转到首页)
controllers\auth.go
// Login 认证登录
func (c *AuthController) Login() {
sessionUser := c.GetSession("user")
if sessionUser != nil {
c.Redirect(beego.URLFor("UserController.Query"), http.StatusFound)
return
}
form := &forms.LoginForm{}
errs := errors.New()
// Get请求直接加载页面
// Post请求进行数据验证
if c.Ctx.Input.IsPost() {
// 获取用户提交数据
if err := c.ParseForm(form); err == nil {
user := models.GetUserByName(form.Name)
if user == nil {
errs.Add("default", "用户名或密码错误")
// 用户不存在
} else if user.ValidPassword(form.Password) {
// 用户密码正确
// 记录用户状态(session 记录服务器端)
c.SetSession("user", user.ID)
// c.Redirect("/home/index", http.StatusFound)
c.Redirect(beego.URLFor("UserController.Query"), http.StatusFound)
} else {
// 用户密码不正确
errs.Add("default", "用户名或密码错误")
}
} else {
errs.Add("default", "用户名或密码错误")
}
}
c.Data["form"] = form
c.Data["errors"] = errs
// 定义加载页面
c.TplName = "auth/login.html"
}
-
公共地方检查 beego的执行过程
controllers\home.go
package controllers
import (
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
type HomeController struct {
beego.Controller
}
func (c *HomeController) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
c.Controller.Init(ctx, controllerName, actionName, app)
fmt.Println("Init:", controllerName, actionName)
}
func (c *HomeController) Prepare() {
fmt.Println("HomeController.Prepare")
}
func (c *HomeController) Index() {
fmt.Println("Index")
// session检查
c.TplName = "home/index.html"
}
func (c *HomeController) Test() {
fmt.Println("Test")
c.Ctx.WriteString("test")
}
func (c *HomeController) Render() error {
fmt.Println("Render")
return c.Controller.Render()
}
func (c *HomeController) Finish() {
fmt.Println("Finish")
}
controllers\user.go
func (c *UserController) Prepare() {
sessionUser := c.GetSession("user")
if sessionUser == nil {
// 无session信息(未登录)
// sessionUser断言 => int
// user状态 => 禁用/已离职
c.Redirect(beego.URLFor("AuthController.Login"), http.StatusFound)
c.StopRun()
}
}
controllers\home.go
组合
type AuthorizationController struct {
beego.Controller
}
func (c *AuthorizationController) Prepare() {
fmt.Println("AuthorizationController.Prepare")
sessionUser := c.GetSession("user")
if sessionUser == nil {
c.Redirect(beego.URLFor("AuthController.Login"), http.StatusFound)
c.StopRun()
}
}
type HomeController struct {
AuthorizationController
}
匿名组合,执行func (c *AuthorizationController) Prepare() {}
// 删除Prepare()
// func (c *HomeController) Prepare() {
// fmt.Println("HomeController.Prepare")
// }
优化
base\controllers\base\base.go
package base
import (
"github.com/astaxie/beego"
)
// BaseController 所有业务控制器基础控制器
type BaseController struct {
beego.Controller
}
base\controllers\auth\authorization.go
package auth
import (
"cmdb/base/controllers/base"
"net/http"
"github.com/astaxie/beego"
)
// AuthorizationController 所有需要认证才能访问的基础控制器
type AuthorizationController struct {
base.BaseController
}
// Prepare 用户认证检查
func (c *AuthorizationController) Prepare() {
sessionKey := beego.AppConfig.DefaultString("auth::SessionKey", "user")
user := c.GetSession(sessionKey)
if user == nil {
action := beego.AppConfig.DefaultString("auth::LoginAction",
"AthController.Login")
c.Redirect(beego.URLFor(action), http.StatusFound)
}
}
conf\auth.conf
[auth]
SessionKey=user
LoginAction=AuthController.Login
HomeAction=UserController.Query
LogoutAction=AuthController.Login
controllers\auth.go
// Login 认证登录
func (c *AuthController) Login() {
sessionKey := beego.AppConfig.DefaultString("auth::SessionKey", "user")
sessionUser := c.GetSession(sessionKey)
if sessionUser != nil {
action := beego.AppConfig.DefaultString("auth::HomeAction", "HomeController.Index")
c.Redirect(beego.URLFor(action), http.StatusFound)
return
}
form := &forms.LoginForm{}
errs := errors.New()
// Get请求直接加载页面
// Post请求进行数据验证
if c.Ctx.Input.IsPost() {
// 获取用户提交数据
if err := c.ParseForm(form); err == nil {
user := models.GetUserByName(form.Name)
if user == nil {
errs.Add("default", "用户名或密码错误")
// 用户不存在
} else if user.ValidPassword(form.Password) {
// 用户密码正确
// 记录用户状态(session 记录服务器端)
sessionKey := beego.AppConfig.DefaultString("auth::SessionKey", "user")
action := beego.AppConfig.DefaultString("auth::HomeAction", "HomeController.Index")
c.SetSession(sessionKey, user.ID)
c.Redirect(beego.URLFor(action), http.StatusFound)
} else {
// 用户密码不正确
errs.Add("default", "用户名或密码错误")
}
} else {
errs.Add("default", "用户名或密码错误")
}
}
c.Data["form"] = form
c.Data["errors"] = errs
// 定义加载页面
c.TplName = "auth/login.html"
}
// Logout 用户退出登录
func (c *AuthController) Logout() {
c.DestroySession()
action := beego.AppConfig.DefaultString("auth::LogoutAction", "AuthController.Login")
c.Redirect(beego.URLFor(action), http.StatusFound)
}
controllers\home.go
package controllers
import (
"cmdb/base/controllers/auth"
)
// HomeController 首页控制器
type HomeController struct {
auth.AuthorizationController
}
// Index 首页显示方法
func (c *HomeController) Index() {
c.TplName = "home/index.html"
}
utils\password.go
package utils
import "golang.org/x/crypto/bcrypt"
// GeneratePassword 生成bcrypt hash
func GeneratePassword(password string) string {
hash, err := bcrypt.GenerateFromPassword([]byte(password), 0)
if err != nil {
panic(err.Error())
}
return string(hash)
}
// CheckPassword 检查密码正确性
func CheckPassword(password, hash string) bool {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil
}
models\user.go
// ValidPassword 验证用户密码是否正确
func (u *User) ValidPassword(password string) bool {
return utils.CheckPassword(password, u.Password)
}
数据操作
存储: Table
数据 增/删/改/查
数据定义 Table => 列,类型 => 数据 => 增,删,改,查
面向对象 类 => 属性(属性名, 类型) => 实例 => 方法调用
ORM
orm表同步
orm标签
ormcurd
orm查询
orm批量操作
orm执行原始sql
orm其他介绍
cmdb修改