Go语言MVC框架Beego

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)
}

  1. session(登录检查) 在任何需要登录以后才能访问的action执行之前都需要进行检查

  1. 如果访问登录页面 检查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"
}
  1. 公共地方检查 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修改

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值