Golang-学习笔记-魂宗[一]
一、Beego初识
1.1、Beego概述
出处,作者在写书《Go Web 编程》的时候想写一个框架。设计灵感,来源于tornado,sinatra和flask
是一个http的框架。适用于各种服务:api服务、后端服务、游戏开发...
BeeGo特点:
- 高性能,是目前最快的go框架?
- 快速开发
- 文档完整
- 使用简单,适合新手
- 国人开发,国内最火的框架,社区活跃,文档齐全
- 模块化,典型的mvc框架,提供的模块众多。比如session、orm、日志、cache、性能监测等
- 智能化、智能监控、智能router、可监控cpu、memory、goroutine
- ...
课程大纲:
- 入门:
- 环境搭建
- 第一个beego项目
- 运行逻辑介绍
- controller 运行原理
- 结构体详解
- Beego数据交互
- 字符串渲染
- 模板渲染简介
- 其他数据类型数据渲染
- 静态文件使用
- ajax数据交互
- form解析到结构体
- 多种格式数据输出
- flash数据传递
- controller模块
- 配置文件详解
- 路由配置
- controller方法
- 跨站请求伪造xsrf
- 文件上传
- session
- 自定义过滤器
- urlfor过滤器
- 表单验证
- 错误处理
- views模块
- 模板语法
- 模板中的基本函数
- 自定义模板函数
- 模板处理
- layout设计
- renderform
- 静态文件处理
- model模块
- orm使用
- 模型定义
- CRUD
- exper表达式
- QueryTable接口
- 原生sql
- 命令行自动建表
- 一对一
- 一对多
- 多对多
- 构造查询
- 关联查询
- 子查询
- 日志模块:
- 日志模块介绍
- beego自带日志处理
- 日志规范
- 日志模块的使用
- 常用日志模板
- 日志模板封装
- cache模块
- 缓存介绍
- cache模块的使用
- 引擎设置
- 开发自己的引擎
- httplib模块
- httplib的使用
- 请求参数
- 发送大片数据
- 设置header信息
- 设置transport
- 实战:
- 涉及内容:
- 登录、验证码
- 用户管理
- 报表录入
- 消息通知
- 内容发布
- 申请、审核
- 到期提醒、已阅读等
- 角色管理
- 权限管理、权限树
- 菜单动态显示
- 图表(Echarts)
- 项目部署
- 独立部署
- supervisor部署
- Nginx部署
- Apache部署
- 涉及内容:
- git版本控制
- gitlab介绍
- 在开发工具中使用git
- 拉取提交代码
- 解决冲突
- 查看提交日志
- 分支
1.2、环境准备
- Go 安装和环境变量配置:
GOROOT/GOPATH/PATH/
git
安装- bee工具,管理beego项目
go get github.com/beego/bee
- 安装
beego
go get github.com/beego/bee/v2
在GOBIN
目录下会有一个bee.exe
- 安装goland IDE
1.3、第一个beego项目
执行:bee new beego_project
D:\Program_language\Project1\src>bee new beego_project
2021/10/22 14:59:46 INFO ▶ 0001 generate new project support go modules.
2021/10/22 14:59:46 INFO ▶ 0002 Creating application...
create D:\Program_language\Project1\src\beego_project\go.mod
create D:\Program_language\Project1\src\beego_project\
create D:\Program_language\Project1\src\beego_project\conf\
create D:\Program_language\Project1\src\beego_project\controllers\
create D:\Program_language\Project1\src\beego_project\models\
create D:\Program_language\Project1\src\beego_project\routers\
create D:\Program_language\Project1\src\beego_project\tests\
create D:\Program_language\Project1\src\beego_project\static\
create D:\Program_language\Project1\src\beego_project\static\js\
create D:\Program_language\Project1\src\beego_project\static\css\
create D:\Program_language\Project1\src\beego_project\static\img\
create D:\Program_language\Project1\src\beego_project\views\
create D:\Program_language\Project1\src\beego_project\conf\app.conf
create D:\Program_language\Project1\src\beego_project\controllers\default.go
create D:\Program_language\Project1\src\beego_project\views\index.tpl
create D:\Program_language\Project1\src\beego_project\routers\router.go
create D:\Program_language\Project1\src\beego_project\tests\default_test.go
create D:\Program_language\Project1\src\beego_project\main.go
2021/10/22 14:59:46 SUCCESS ▶ 0003 New application successfully created!
主要以在当前路径下生成go项目文件,可能是因为开了go mod模式,如果不开可能只会在src/目录下生成,待测试
启动:
D:\Program_language\Project1\src\beego_project>bee run
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.2
2021/10/22 15:03:53 INFO ▶ 0001 Using 'beego_project' as 'appname'
2021/10/22 15:03:53 INFO ▶ 0002 Initializing watcher...
go: downloading golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
go: downloading golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58
go: downloading github.com/pkg/errors v0.9.1
go: downloading golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f
go: downloading golang.org/x/net v0.0.0-20201021035429-f5854403a974
go: downloading golang.org/x/text v0.3.3
go: downloading golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
go: downloading golang.org/x/mod v0.3.0
github.com/beego/beego/v2
golang.org/x/sys/internal/unsafeheader
golang.org/x/mod/semver
golang.org/x/xerrors/internal
golang.org/x/text/transform
github.com/pkg/errors
github.com/beego/beego/v2/server/web/session
github.com/beego/beego/v2/server/web/grace
golang.org/x/sys/windows
golang.org/x/crypto/acme
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
golang.org/x/tools/go/internal/gcimporter
github.com/beego/beego/v2/core/admin
github.com/beego/beego/v2/core/logs
github.com/beego/beego/v2/server/web/context
github.com/prometheus/client_golang/prometheus
golang.org/x/tools/internal/event/label
golang.org/x/text/secure/bidirule
golang.org/x/tools/internal/typesinternal
golang.org/x/tools/go/gcexportdata
golang.org/x/xerrors
github.com/beego/beego/v2/core/config
github.com/beego/beego/v2/server/web/context/param
github.com/prometheus/client_golang/prometheus/promhttp
golang.org/x/tools/internal/event/keys
golang.org/x/net/idna
golang.org/x/tools/internal/event/core
golang.org/x/crypto/acme/autocert
golang.org/x/tools/internal/event
golang.org/x/tools/internal/gocommand
golang.org/x/tools/internal/packagesinternal
golang.org/x/tools/go/internal/packagesdriver
golang.org/x/tools/go/packages
github.com/beego/beego/v2/server/web
beego_project/controllers
beego_project/routers
beego_project
2021/10/22 15:04:37 SUCCESS ▶ 0003 Built Successfully!
2021/10/22 15:04:37 INFO ▶ 0004 Restarting 'beego_project.exe'...
2021/10/22 15:04:37 SUCCESS ▶ 0005 './beego_project.exe' is running...
2021/10/22 15:04:44.703 [I] [parser.go:413] generate router from comments
2021/10/22 15:04:44.724 [I] [server.go:241] http server Running on http://:8080
浏览器打开:http://127.0.0.1:8080
或者在项目工作目录内使用: go run main.go
运行
目录解析:
D:\Program_language\Project1\src\beego_project>tree /F
D:.
│ go.mod
│ go.sum
│ main.go #程序主入口
├─conf
│ app.conf #配置文件信息
├─controllers
│ default.go #业务逻辑
├─models #模型,和orm相关
├─routers #路由
│ router.go
├─static #静态文件
│ ├─css
│ ├─img
│ └─js
│ reload.min.js
├─tests
│ default_test.go #测试文件,自动化测试等
└─views
index.tpl #代码视图
1.4、controller概述
>>>>>>>>>>>>>>>>>>>>>>>>router.GO
package routers
import (
"beego_project/controllers"
beego "github.com/beego/beego/v2/server/web"
)
func init() {
beego.Router("/", &controllers.MainController{}) //这俩的"/"对应http的路径,可以修改为其他的,则对应访问的url也要变
}
//针对 访问 ”/"的请求,由 ontrollers.MainController 处理
>>>>>>>>>>>>>>>>>>>>>> controller/default.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() { //对前端浏览器访问为get请求,则对应该函数处理
c.Data["Website"] = "icewake"
c.Data["Email"] = "icewake@xx.com"
c.TplName = "index.tpl"
}
>>>>>>>>>>>>>>>controller.go文件
type Controller struct { //这个是 MainController 引入的beego的匿名字段,beego.Controller 有很多方法
// context data
Ctx *context.Context
Data map[interface{}]interface{}
// route controller info
controllerName string
actionName string
methodMapping map[string]func() //method:routertree
AppController interface{}
// template data
TplName string
ViewPath string
Layout string
LayoutSections map[string]string // the key is the section name and the value is the template name
TplPrefix string
TplExt string
EnableRender bool
// xsrf data
_xsrfToken string
XSRFExpire int
EnableXSRF bool
// session
CruSession session.Store
}
func (c *Controller) Get() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
func (c *Controller) Post() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
}
...
第一个controller编写
步骤1:创建controller ,文件 controllers/default.go
type UserController struct { //新增 UserController
beego.Controller //必须要添加的匿名字段
}
func (u *UserController) Get(){
u.TplName = "user.html"
u.Data["user"] = "小明"
u.Data["age"] = 18
}
步骤2:创建router,文件routers/router.go
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/user", &controllers.UserController{}) //新增
}
步骤3:创建视图文件,文件views/user.html
<!DOCTYPE html>
<html lange="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
用户页面
用户名: {{ .user }}
年龄:{{ .age }}
</body>
</html>
二、数据交互
2.1、数据类型渲染
设置view路径:
- 方法1在
main.go
中设置:beego.SetViewsPath("静态文件存放路径")
,注意要在beego.Run()
之前设置 - 方法2在
conf/app.conf
中设置:viewpath="存放路径"
beego采用了Go内置的模板引擎
- 指定模板:
u.TplName = 'user.html'
- 默认支持
tpl
和html
- beego.AddTemplateExt设置其他后缀
- beego.AddTemplateExt("后缀名")
- 如果不设置该参数,那么默认会去到模板目录的
Controller/<方法名>.tpl
查找,例如上面的没有指定u.TplName = "user.html"
则默认会找views/usercontroller/get.tpl
- 默认支持
2.1.1、字符串渲染
func (u *UserController) Get(){ //controller中编写
u.TplName = "user.html"
u.Data["user"] = "小明"
u.Data["age"] = 18
}
<!DOCTYPE html> //在user.html中渲染
<html lange="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
用户页面
用户名: {{ .user }}
年龄:{{ .age }}
</body>
</html>
2.1.2、结构体渲染
>>>>>>>>>>>>>>>> controllers/default.go中添加用户的结构体
type UserStruct struct {
Id int
Name string
Age int
}
func (u *UserController) Get(){
u.TplName = "user.html"
user1 := UserStruct{Id:1,Age:18,Name:"令狐冲"}
u.Data["user"] = user1
}
>>>>>>>>>>>>>>> 修改user.html
<!DOCTYPE html>
<title >Icewake</title>
<html lange="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
用户页面
{{/*ID : {{ .user.Id }}*/}}
用户名: {{ .user.Name }}
年龄:{{ .user.Age }}
</body>
</html>
2.1.3、数组渲染
>>>>>>>>>>>>>>>> controllers/default.go中添加数组
func (u *UserController) Get(){
u.TplName = "user.html"
//u.Data["user"] = "小明"
//u.Data["age"] = 18
user1 := UserStruct{Id:1,Age:18,Name:"令狐冲"}
ary := [...]int{7,8,10,11}
u.Data["user"] = user1
u.Data["arry"] = ary
}
>>>>>>>>>>>>>>> 修改user.html
<!DOCTYPE html>
<title >Icewake</title>
<html lange="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
用户页面
{{/*ID : {{ .user.Id }}*/}}
用户名: {{ .user.Name }}
年龄:{{ .user.Age }}
<br>
====================================<br>
// 遍历方式1
{{ range .arry}}
{{ .}}
{{ end}}
<br>
====================================<br>
// 遍历方式2
{{ range $i,$v := .arry}}
<br>
{{$i}}={{$v}}
{{ end}}
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>> 效果如下:
用户页面 用户名: 令狐冲 年龄:18
====================================
// 遍历方式1 7 8 10 11
====================================
// 遍历方式2
0=7
1=8
2=10
3=11
2.1.4、结构体数组渲染
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go中添加数组
func (u *UserController) Get(){
u.TplName = "user.html"
user1 := UserStruct{Id:1,Age:18,Name:"令狐冲"}
ary := [...]int{7,8,10,11}
aryStruct := [3]UserStruct{{Id:1,Age:55,Name:"岳不群"},{Id:2,Name:"岳灵珊",Age:20}}
u.Data["aryStruct"] = aryStruct
u.Data["user"] = user1
u.Data["arry"] = ary
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 修改user.html
<!DOCTYPE html>
<title >Icewake</title>
<html lange="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
用户页面
{{/*ID : {{ .user.Id }}*/}}
用户名: {{ .user.Name }}
年龄:{{ .user.Age }}
<br>
====================================<br>
// 遍历方式1
{{ range .arry}}
{{ .}}
{{ end}}
<br>
====================================<br>
// 遍历方式2
{{ range $i,$v := .arry}}
<br>
{{$i}}={{$v}}
{{ end}}
====================================<br>
// 结构体数组遍历1
{{ range .aryStruct}}
<br>
{{.}}
{{ end}}
====================================<br>
// 结构体数组遍历2
{{ range .aryStruct}}
{{.Id}}
{{.Name}}
{{.Age}}
{{end}}
====================================<br>
// 结构体数组遍历3,会自动判别是一个参数还是两个参数接收
{{/*{{ range $i,$v := .aryStruct}}*/}}
{{ range $v := .aryStruct}}
<br>
{{ $v.Id}} {{ $v.Name}} {{ $v.Age}}
{{ end}}
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 效果
用户页面 用户名: 令狐冲 年龄:18
====================================
// 遍历方式1 7 8 10 11
====================================
// 遍历方式2
0=7
1=8
2=10
3=11
====================================
// 结构体数组遍历1
{1 岳不群 55}
{2 岳灵珊 20}
{0 0}
====================================
// 结构体数组遍历2 1 岳不群 55 2 岳灵珊 20 0 0
====================================
// 结构体数组遍历3,会自动判别是一个参数还是两个参数接收
1 岳不群 55
2 岳灵珊 20
0 0
2.1.5、map渲染
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go中添加数组
func (u *UserController) Get(){
u.TplName = "user.html"
...
//map渲染
map01 := map[string]string{"name":"iceman","age":"18","email":"aa@icemail.com"}
u.Data["map01"] = map01
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 修改user.html 增加如下内容
// map 遍历 方法1
{{ .map01.name }}
{{ .map01.age }}
{{ .map01.email }}
<br>
// map 遍历 方法2
{{ range .map01}}
{{.}}
{{ end }}
<br>
// map 遍历 方法3
{{ range $k,$v := .map01}}
{{$k}}={{$v}}
{{ end }}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 效果
// map 遍历 方法1 iceman 18 aa@icemail.com
// map 遍历 方法2 18 aa@icemail.com iceman
// map 遍历 方法3 age=18 email=aa@icemail.com name=iceman
2.1.6、结构体渲染
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go中添加数组
//结构体map渲染
map02 := make(map[int]UserStruct)
map02[1] = UserStruct{101,"萧峰",28}
map02[2] = UserStruct{102,"段誉",20}
map02[3] = UserStruct{103,"虚竹",26}
u.Data["map02"] = map02
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 修改user.html 增加如下内容
// 数组map渲染1 - 这种方法是不行的
{{/*{{ .map02.1.Id}}*/}}
{{/*{{ .map02.2.Name}}*/}}
{{/*{{ .map02.3.Age}}*/}}
{{ range .map02 }}
{{.}}
{{ end}}
<br>
{{ range $k,$v := .map02 }}
{{$k}}={{$v}}
{{$v.Name}}
{{ end}}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 效果
// 数组map渲染1 - 这种方法是不行的 {101 萧峰 28} {102 段誉 20} {103 虚竹 26}
1={101 萧峰 28} 萧峰 2={102 段誉 20} 段誉 3={103 虚竹 26} 虚竹
2.1.7、切片渲染
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go中添加数组
//切片渲染
slices := []int{9,8,7,6,11,23}
u.Data["slices"] = slices
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 修改user.html 增加如下内容
// 切片渲染
{{ range .slices }}
{{.}}
{{end}}
<br>
{{ range $k,$v := .slices }}
{{$v}}
{{end}}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 效果
// 切片渲染 9 8 7 6 11 23 9 8 7 6 11 23
2.1.8、小结
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
beego.Controller
}
type UserStruct struct {
Id int
Name string
Age int
}
type UserController struct { //新增 UserController
beego.Controller //必须要添加的匿名字段
}
func (c *MainController) Get() {
c.Data["Website"] = "icewake"
c.Data["Email"] = "icewake@xx.com"
c.TplName = "index.tpl"
}
func (u *UserController) Get(){
u.TplName = "user.html"
//u.Data["user"] = "小明"
//u.Data["age"] = 18
user1 := UserStruct{Id:1,Age:18,Name:"令狐冲"}
ary := [...]int{7,8,10,11}
aryStruct := [3]UserStruct{{Id:1,Age:55,Name:"岳不群"},{Id:2,Name:"岳灵珊",Age:20}}
u.Data["aryStruct"] = aryStruct
u.Data["user"] = user1
u.Data["arry"] = ary
//map渲染
map01 := map[string]string{"name":"iceman","age":"18","email":"aa@icemail.com"}
u.Data["map01"] = map01
//结构体map渲染
map02 := make(map[int]UserStruct)
map02[1] = UserStruct{101,"萧峰",28}
map02[2] = UserStruct{102,"段誉",20}
map02[3] = UserStruct{103,"虚竹",26}
u.Data["map02"] = map02
//切片渲染
slices := []int{9,8,7,6,11,23}
u.Data["slices"] = slices
}
- user.html
<!DOCTYPE html>
<title >Icewake</title>
<html lange="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
用户页面
{{/*ID : {{ .user.Id }}*/}}
用户名: {{ .user.Name }}
年龄:{{ .user.Age }}
<br>
====================================<br>
// 遍历方式1
{{ range .arry}}
{{ .}}
{{ end}}
<br>
====================================<br>
// 遍历方式2
{{ range $i,$v := .arry}}
<br>
{{$i}}={{$v}}
{{ end}}
<br>
====================================<br>
// 结构体数组遍历1
{{ range .aryStruct}}
<br>
{{.}}
{{ end}}
<br>
====================================<br>
// 结构体数组遍历2
{{ range .aryStruct}}
{{.Id}}
{{.Name}}
{{.Age}}
{{end}}
<br>
====================================<br>
// 结构体数组遍历3,会自动判别是一个参数还是两个参数接收
{{/*{{ range $i,$v := .aryStruct}}*/}}
{{ range $v := .aryStruct}}
<br>
{{ $v.Id}} {{ $v.Name}} {{ $v.Age}}
{{ end}}
<br>
====================================<br>
// map 遍历 方法1
{{ .map01.name }}
{{ .map01.age }}
{{ .map01.email }}
<br>
// map 遍历 方法2
{{ range .map01}}
{{.}}
{{ end }}
<br>
// map 遍历 方法3
{{ range $k,$v := .map01}}
{{$k}}={{$v}}
{{ end }}
<br>
====================================<br>
// 数组map渲染1 - 这种方法是不行的
{{/*{{ .map02.1.Id}}*/}}
{{/*{{ .map02.2.Name}}*/}}
{{/*{{ .map02.3.Age}}*/}}
{{ range .map02 }}
{{.}}
{{ end}}
<br>
{{ range $k,$v := .map02 }}
{{$k}}={{$v}}
{{$v.Name}}
{{ end}}
<br>
====================================<br>
// 切片渲染
{{ range .slices }}
{{.}}
{{end}}
<br>
{{ range $k,$v := .slices }}
{{$v}}
{{end}}
</body>
</html>
- 效果
用户页面 用户名: 令狐冲 年龄:18
====================================
// 遍历方式1 7 8 10 11
====================================
// 遍历方式2
0=7
1=8
2=10
3=11
====================================
// 结构体数组遍历1
{1 岳不群 55}
{2 岳灵珊 20}
{0 0}
====================================
// 结构体数组遍历2 1 岳不群 55 2 岳灵珊 20 0 0
====================================
// 结构体数组遍历3,会自动判别是一个参数还是两个参数接收
1 岳不群 55
2 岳灵珊 20
0 0
====================================
// map 遍历 方法1 iceman 18 aa@icemail.com
// map 遍历 方法2 18 aa@icemail.com iceman
// map 遍历 方法3 age=18 email=aa@icemail.com name=iceman
====================================
// 数组map渲染1 - 这种方法是不行的 {101 萧峰 28} {102 段誉 20} {103 虚竹 26}
1={101 萧峰 28} 萧峰 2={102 段誉 20} 段誉 3={103 虚竹 26} 虚竹
====================================
// 切片渲染 9 8 7 6 11 23 9 8 7 6 11 23
2.2、静态文件
2.2.1、css使用
>>>>>>>>>>>>>>>>>>>>>>>>>>>> router.go
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/static01", &controllers.StaticStruct{}) //新增,注意这里不能直接为 "/static"(可能是和内置的冲突) 会报错"403 forbiden
beego.Router("/user", &controllers.UserController{})
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/router.go
...
type StaticStruct struct {
beego.Controller
}
func (s *StaticStruct) Get(){
s.TplName = "static02.html"
}
...
>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/static02.html
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/static02.css">
</head>
<body>
<span style="color: #0000FF"> 测试静态文件-蓝色</span>
<span class="sy"> 试静态文件-红色</span>
<span id="syt"> 试静态文件-红色</span>
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>>>>>> static/css/static_test.css #通过新建StyleSheet新建
.sy {
color: #FD482C;
}
#syt {
color: #FD482C;
}
<link rel="stylesheet" href="/static/css/static02.css"> 引入css文件,class标签对应 css的".sy",id标签,对应css文件中"#syt"标签
css更多用法:https://www.runoob.com/css/css-tutorial.html
2.2.2、js使用
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> static/js/static_test.js
alert("你好,世界")
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/static02.css">
<script src="/static/js/static_test.js"></script>
</head>
<body>
<span style="color: #0000FF"> 测试静态文件-蓝色</span>
<span class="sy"> 试静态文件-红色</span>
</body>
</html>
<script src="/static/js/static_test.js"></script> 引用js文件,效果为一个弹窗提示“你好,世界”
更多js用法:https://www.runoob.com/js/js-tutorial.html
2.2.3、img使用
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> static/css/static02.css
.sy {
color: #FD482C;
}
#syt {
color: #FD482C;
}
.img_style {
height: 300px;
width: 400px;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> static/img/xxxx.png
存放照片
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/static02.html
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/static02.css">
<script src="/static/js/static_test.js"></script>
</head>
<body>
<span style="color: #0000FF"> 测试静态文件-蓝色</span>
<span class="sy"> 试静态文件-红色</span>
<span id="syt"> 试静态文件-红色</span>
<br>
<img src="/static/img/Dingtalk_20211026100143.jpg" class="img_style">
<br>
<img src="/static/img/Dingtalk_20211026100143.jpg" class="img_style" style="width: 300px;height: 300px">
</body>
</html>
除了引用css样式调整图片外,也可以在html中设置属性
注意:如果修改后不能立即生效,就使用shift + f5
多是浏览器缓存。强制刷新缓存就可以看到效果了
设置static
路径:
- 方法1在
main.go
中设置:beego.SetStaticPath()
,注意要在beego.Run()
之前设置 - 方法2在
conf/app.conf
中设置:viewpath="存放路径"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> main.go
func main() {
beego.SetStaticPath("/static","front")
beego.SetStaticPath("/aaa","front")
beego.Run()
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
beego.Router("/static01", &controllers.StaticStruct{}) //注意这里不能直接为 "/static"(可能是和内置的冲突) 会报错"403 forbiden
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controller/default.go
type StaticStruct struct {
beego.Controller
}
func (s *StaticStruct) Get(){
s.TplName = "static02.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/static02.html
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/static02.css">
<script src="/static/js/static_test.js"></script>
</head>
<body>
<span style="color: #0000FF"> 测试静态文件-蓝色</span>
<span class="sy"> 试静态文件-红色</span>
<span id="syt"> 试静态文件-红色</span>
<br>
<img src="/static/img/Dingtalk_20211026100143.jpg" class="img_style">
<br>
<img src="/static/img/Dingtalk_20211026100143.jpg" class="img_style" style="width: 300px;height: 300px">
</body>
</html>
注意:这里虽然 src="/static/js/static_test.js" 和href="/static/css/static02.css" 但是beego.SetStaticPath("/static","front") ,但是$src/beego_project/ 不存在 front目录,所以css和js不会展示出效果。
右键“static“目录,ctrl+c,ctrl+v 修改目录名为"front"就可以展示出来效果了
beego.SetStaticPath("/static","front") //对于引用静态路径为 /static的映射到 front目录下
beego.SetStaticPath("/aaa","static") //对于引用静态路径为 /aaa的映射到 static 路径下
2.3、前后端数据交互
Get请求的两种方式:http://127.0.0.1:8080/param?name=arg1
和http://127.0.0.1:8080/param/arg1
- 方式1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
...
beego.Router("/param", &controllers.ParamController{})
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
//新建controller
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
//针对 http://127.0.0.1:8080/param?name=令狐冲
name := p.GetString("name")
fmt.Println("===============================",name) //获取方式1
name1,_ := p.Input()
v := name1.Get("name")
fmt.Println("===============================",v) //获取方式2
p.TplName = "param_test.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
请求:http://127.0.0.1:8080/param/name=令狐冲 在日志中会打印出来结果
- 方式2
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
...
beego.Router("/param/?:id", &controllers.ParamController{})
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
//新建controller
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
//针对 http://127.0.0.1:8080/param/id 方式 request2
v1 := p.GetString(":id")
fmt.Println("v1===============================",v1)
v2,_ := p.Input()
v3 := v2.Get(":name")
fmt.Println("v3===============================",v3) //获取方式3,获取不到值
v4 := p.Ctx.Input.Param(":id")
fmt.Println("v4===============================",v4) //获取方式4,建议使用
p.TplName = "param_test.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
请求:http://127.0.0.1:8080/param/name=令狐冲 获取到的结果是
v1=============================== name=令狐冲
v3===============================
v4=============================== name=令狐冲
请求:http://127.0.0.1:8080/param/123456,结果
v1=============================== 123456
v3===============================
v4=============================== 123456
- 混合请求
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controller/default.go
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
//针对 http://127.0.0.1:8080/param/id 方式 request2
v1 := p.GetString(":provience")
v2 := p.GetString(":city")
v3 := p.GetString("num")
fmt.Printf("%v省%v市%v号\n",v1,v2,v3)
p.TplName = "param_test.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
beego.Router("/param/?:provience/?:city", &controllers.ParamController{})
//beego.Router("/param/?:id:int", &controllers.ParamController{})
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 请求
http://127.0.0.1:8080/param/河南7/郑州%?num=12306
打印:河南省郑州市12306号
2.4、Post请求
2.4.1、简单实现
>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
...
beego.Router("/param", &controllers.ParamController{})
}
>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
p.TplName = "param_test.html"
}
func (p *ParamController) Post(){
//1、获取数据方法1
input1 := p.GetString("username")
input2 := p.GetString("userage")
fmt.Printf("用户名: %v 年龄: %v\n",input1,input2)
p.TplName = "success.html"
//2、获取数据方法2
v,_ := p.Input()
s1 := v.Get("username")
s2 := v.Get("userage")
fmt.Printf("用户名: %v 年龄: %v\n",s1,s2)
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/param_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
测试页面
<form action="/param" method="post">
用户名: <input type="text" name="username"> <br>
年  龄: <input type="text" name="userage"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
提交成功
</body>
</html>
效果,提交后会提示“提交成功”,
注意,这里写 <form action="/param" method="post"> 中的method为get或者post都可以解析
2.4.2、其他类型数据
>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
p.TplName = "param_test.html"
}
func (p *ParamController) Post(){
input1 := p.GetString("username")
users := p.GetStrings("username") //匹配多个"username"
input2,_ := p.GetInt8("userage")
input3,_ := p.GetFloat("price")
input4,_ := p.GetBool("is_true")
fmt.Printf("用户名: %v 年龄: %v 价格: %v 已婚:%v\n",input1,input2,input3,input4)
fmt.Println(users)
p.TplName = "success.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/param_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
测试页面
<form action="/param" method="post">
用户名: <input type="text" name="username"> <br>
用户名: <input type="text" name="username"> <br>
用户名: <input type="text" name="username"> <br>
年  龄: <input type="text" name="userage"> <br>
价  格: <input type="text" name="price"> <br>
已婚:   是:<input type="radio" name="isTrue" value="true">
否:<input type="radio" name="isTrue" value="false"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
注意,如果提交的数据类型不匹配会使用零值代替。
2.4.3、解析表单到结构体
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
type UserStruct struct {
Id int
Name string `form:"username"`
Age int `form:"userage"`
Married bool `form:"isTrue"`
}
//新建controller
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
p.TplName = "param_test.html"
}
func (p *ParamController) Post(){
user := UserStruct{}
input1 := p.GetStrings("price")
if err := p.ParseForm(&user) ;err == nil {
fmt.Printf("用户名: %v 年龄: %v 价格: %v 已婚:%v\n",user.Name,user.Age,input1,user.Married)
} else {
fmt.Println(err)
}
p.TplName = "success.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/param_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
测试页面
<form action="/param" method="post">
用户名: <input type="text" name="username"> <br>
年  龄: <input type="text" name="userage"> <br>
价  格: <input type="text" name="price"> <br>
已婚:   是:<input type="radio" name="isTrue" value="true">
否:<input type="radio" name="isTrue" value="false"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
注:html书写技巧,输入关键字,按住tab
会自动补全格式,注意不需要手动写<
2.5、Ajax(有问题username一直渲染不出来,不知道哪里问题)
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行
前提:config/app.conf 设置,copyrequestbody = true
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
package controllers
import (
"encoding/json"
"fmt"
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
beego.Controller
}
type UserStruct struct {
Id int
Name string `form:"username"`
Age int `form:"age"`
Married bool `form:"isTrue"`
}
type UserController struct { //新增 UserController
beego.Controller //必须要添加的匿名字段
}
func (c *MainController) Get() {
c.Data["Website"] = "icewake"
c.Data["Email"] = "icewake@xx.com"
c.TplName = "index.tpl"
}
type StaticStruct struct {
beego.Controller
}
func (s *StaticStruct) Get(){
s.TplName = "static02.html"
}
//新建controller
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
p.TplName = "param_test.html"
}
func (p *ParamController) Post(){
//user := UserStruct{}
//input1 := p.GetStrings("price")
//if err := p.ParseForm(&user) ;err == nil {
// fmt.Printf("用户名: %v 年龄: %v 价格: %v 已婚:%v\n",user.Name,user.Age,input1,user.Married)
//} else {
// fmt.Println(err)
//}
//
//p.TplName = "success.html" //使用ajax提交不能再使用模板
//获取ajax数据
var user UserStruct
body := p.Ctx.Input.RequestBody //二进制的json数据
err := json.Unmarshal(body,&user)
fmt.Println("错误信息为:",err)
fmt.Println(user)
result := map[string]string{"code":"200","message":"解析成功"}
p.Data["json"] = result
p.ServeJSON() //返回json格式
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/param_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/js/jquery.min.js"></script>
</head>
<body>
测试页面
{{/*<form action="/param" method="post">*/}}
<form>
用户名: <input type="text" name="username" id="username"> <br>
年  龄: <input type="text" name="userage" id="userage"> <br>
价  格: <input type="text" name="price"> <br>
已  婚:   是<input type="radio" name="isTrue" value="true">
否<input type="radio" name="isTrue" value="false"><br>
<input type="button" value="提交" id="bt1">
</form>
<script>
var bt = document.getElementById("bt1");
bt.onclick = function (ev) {
var username = document.getElementById("username").value;
var age = document.getElementById("userage").value;
alert(username)
alert(userage)
$.ajax({
url:"/param",
type:"POST",
data:JSON.stringify({
"username":username,
"age":Number(age)
}),
dataType:"JSON",
success:function (data) {
alert("处理成功")
},
error:function (data) {
alert("处理异常")
}
})
}
</script>
</body>
</html>
2.6、其他格式数据传输
- json
>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
...
beego.Router("/other", &controllers.OtherType{})
}
>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
type UserStruct struct {
Id int
Name string `form:"username"`
Age int `form:"age"`
Married bool `form:"isTrue"`
}
type OtherType struct {
beego.Controller
}
func (o *OtherType) Get(){
user := UserStruct{Id:1,Name:"令狐冲",Age:28}
//json 方式
//o.Data["json"] = &user
//o.ServeJSON()
//xml方式
//o.Data["xml"] = &user
//o.ServeXML()
//jsonp格式
//o.Data["jsonp"] = &user
//o.ServeJSONP()
//yaml格式
o.Data["yaml"] = &user
o.ServeYAML()
}
>>>>>>>>>>>>>>>>>>>>>>>>> web界面 http://127.0.0.1:8080/other
{
"Id": 1,
"Name": "令狐冲",
"Age": 28,
"Married": false
}
- xml
web访问:http://127.0.0.1:8080/other
<UserStruct>
<Id>1</Id>
<Name>令狐冲</Name>
<Age>28</Age>
<Married>false</Married>
</UserStruct>
- yaml
web访问:http://127.0.0.1:8080/other 会下载一个文件
id: 1
name: 令狐冲
age: 28
married: false
2.7、flash动作
需求:用户在控制台传递用户名和密码,判断用户名和密码,成功则跳转到成功页面,失败则跳转到错误页面,并给出提示信息。使用flash实现
>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
...
beego.Router("/flashdata", &controllers.FlashController{})
}
- controller代码
type FlashController struct {
beego.Controller
}
func (f *FlashController) Get(){
flash := beego.ReadFromRequest(&f.Controller)
notice := flash.Data["notice"]
err := flash.Data["error"]
if len(notice) != 0 {
f.TplName = "success.html"
} else if len(err) != 0 {
f.TplName = "error.html"
} else {
f.TplName = "flash.html"
}
}
func (f *FlashController) Post(){
//如果判断用户名和密码不对,如果在前端提示错误?
flash := beego.NewFlash() //初始化flash
username := f.GetString("username")
pwd := f.GetString("pwd")
fmt.Println(username,pwd)
/*
flash对象有三个级别,
Notice 提示信息,对应模板中 {{.flash.notici }}
Warning 警告 对应模板中 {{ .flash.warining }}
Error 错误信息 对应模板中 {{ .flash.error }}
*/
if strings.Contains(username," ") || len(username) == 0 {
fmt.Println("用户名不能为空或者包含空格")
flash.Error("用户为不能为空或者包含空格")
flash.Store(&f.Controller)
f.Redirect("/flashdata",302)
} else if pwd != "123456" {
fmt.Println("密码错误")
flash.Error("密码错误")
flash.Store(&f.Controller)
f.Redirect("/flashdata",302)
} else {
flash.Notice("登录成功")
flash.Store(&f.Controller) //保存数据
f.Redirect("/flashdata",302)
}
}
- 前端页面
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/succeess.html
package controllers
import (
"encoding/json"
"fmt"
beego "github.com/beego/beego/v2/server/web"
"strings"
)
type MainController struct {
beego.Controller
}
type UserStruct struct {
Id int
Name string `form:"username"`
Age int `form:"age"`
Married bool `form:"isTrue"`
}
type UserController struct { //新增 UserController
beego.Controller //必须要添加的匿名字段
}
func (c *MainController) Get() {
c.Data["Website"] = "icewake"
c.Data["Email"] = "icewake@xx.com"
c.TplName = "index.tpl"
}
type StaticStruct struct {
beego.Controller
}
func (s *StaticStruct) Get(){
s.TplName = "static02.html"
}
//新建controller
type ParamController struct {
beego.Controller
}
func (p *ParamController) Get(){
p.TplName = "param_test.html"
}
func (p *ParamController) Post(){
//user := UserStruct{}
//input1 := p.GetStrings("price")
//if err := p.ParseForm(&user) ;err == nil {
// fmt.Printf("用户名: %v 年龄: %v 价格: %v 已婚:%v\n",user.Name,user.Age,input1,user.Married)
//} else {
// fmt.Println(err)
//}
//
//p.TplName = "success.html" //使用ajax提交不能再使用模板
//获取ajax数据
var user UserStruct
body := p.Ctx.Input.RequestBody //二进制的json数据
err := json.Unmarshal(body,&user)
fmt.Println("错误信息为:",err)
fmt.Println(user)
result := map[string]string{"code":"200","message":"解析成功"}
p.Data["json"] = result
p.ServeJSON() //返回json格式
}
type OtherType struct {
beego.Controller
}
func (o *OtherType) Get(){
user := UserStruct{Id:1,Name:"令狐冲",Age:28}
//json 方式
//o.Data["json"] = &user
//o.ServeJSON()
//xml方式
//o.Data["xml"] = &user
//o.ServeXML()
//jsonp格式
//o.Data["jsonp"] = &user
//o.ServeJSONP()
//yaml格式
user2 := struct {
id int
address string
info UserStruct
}{10001,"河南省郑州市",user}
o.Data["yaml"] = &user2
o.ServeYAML()
}
type FlashController struct {
beego.Controller
}
func (f *FlashController) Get(){
flash := beego.ReadFromRequest(&f.Controller)
notice := flash.Data["notice"]
err := flash.Data["error"]
if len(notice) != 0 {
f.TplName = "success.html" //成功页面
} else if len(err) != 0 {
f.TplName = "error.html" //错误页面
} else {
f.TplName = "flash.html" //默认GET 界面
}
}
func (f *FlashController) Post(){
//如果判断用户名和密码不对,如果在前端提示错误?
flash := beego.NewFlash() //初始化flash
username := f.GetString("username")
pwd := f.GetString("pwd")
fmt.Println(username,pwd)
/*
flash对象有三个级别,
Notice 提示信息,对应模板中 {{.flash.notici }}
Warning 警告 对应模板中 {{ .flash.warining }}
Error 错误信息 对应模板中 {{ .flash.error }}
*/
if strings.Contains(username," ") || len(username) == 0 {
fmt.Println("用户名不能为空或者包含空格")
flash.Error("用户为不能为空或者包含空格")
flash.Store(&f.Controller)
f.Redirect("/flashdata",302)
} else if pwd != "123456" {
fmt.Println("密码错误")
flash.Error("密码错误")
flash.Store(&f.Controller)
f.Redirect("/flashdata",302)
} else {
flash.Notice("登录成功")
flash.Store(&f.Controller) //保存数据
f.Redirect("/flashdata",302)
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{.flash.error}}
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> views/flash.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/flashdata" method="post">
<input type="text" name="username"><br>
<input type="text" name="pwd"><br>
<input type="submit" name="提交">
</form>
</body>
</html>
三、Controller
3.1、配置文件读取
在 app.conf
中设置的参数,可以在项目中使用类似port,_ := beego.AppConfig.Int("httpport")
的方式读取。
>>>>>>>>>>>>>>>>>>>> confg/app.conf
appname = beego_project
httpport = 8080
runmode = dev
copyrequestbody = true //用户区分运行模式,可以对不同的运行模式配置不同的参数值
include "mysql.conf" //引入其他配置文件
mysql_port = "3333"
[dev]
username = dev
passwd = dev
[test]
username = test
passwd = test
>>>>>>>>>>>>>>>>>>>> confg/msyql.conf ,和主配置中参数重复时,采用主配置文件的
mysql_host = "127.0.0.1"
mysql_port = "3306"
>>>>>>>>>>>>> main.go代码
package main
import (
_ "beego_project/routers"
"fmt"
beego "github.com/beego/beego/v2/server/web"
)
func main() {
port,_ := beego.AppConfig.Int("httpport")
uname,_ := beego.AppConfig.String("username")
mode,_ := beego.AppConfig.String("runmode")
msyql_port,_ := beego.AppConfig.String("mysql_port")
msyql_host,_ := beego.AppConfig.String("msyql_host")
fmt.Println("监听端口是:",port,"用户名:",uname,"运行环境:",mode) //结果为: 监听端口是: 8080 用户名: dev 运行环境: dev
fmt.Printf("mysql地址:%v 端口:%v\n",msyql_host,msyql_port) //mysql地址:127.0.0.1 端口:3333
beego.Run()
}
更多的配置
3.2、Routers配置
- 固定路由
beego.Router("/", &controllers.MainController{})
beego.Router("/static01", &controllers.StaticStruct{}) //注意这里不能直接为 "/static"(可能是和内置的冲突) 会报错"403 forbiden
beego.Router("/user", &controllers.UserController{})
- 正则路由
beego.Router("/param/?:provience/?:city", &controllers.ParamController{}) //对于http://127.0.0.1:8080/param/河南/郑州,会把 河南保存到proviece上,把 郑州保存到city上。 ?的含义是出现1或者0次,对于该条http路由条目,加上? 对于http://127.0.0.1:8080/param的也会匹配,不加? 则对对于http://127.0.0.1:8080/param 提示 404
/param/?:id:int //限制为int类型,如果不是int则提示 404,其他类型同理
:id[0-9]+ 或者 :id([\d]+) 或者 :id:int 都表示匹配int类型
:username([\w]+) 或者 :username:string 表示string
获取:this.GetString(":username"),this.Ctx.Input.Param(":id")
. 匹配除换行符的任意字符
\w 匹配字母数字或下划线 等价于[^A-Za-z0-9_]
\d 等价于数字
- 自动路由
注册路由时不需要指定url,只需要注册控制器即可,自动匹配
>>>>>>>>>>>>>>>>>>>>>>>>>>>> controllers/default.go
beego.AutoRouter( &controllers.ParamController{}) //注册自动路由
使用的时候需要按照规则来。
/控制器名/方法名/后面的都是参数 ,比如: http://127.0.0.1:8080/param/get
对于 controllers.ParamController{} 则 控制器名为 param ,方法名看后端定义了几种方法
-
自定义路由
注册自定义路由的时候可以指定第三个参数,这个参数就是用来自定义路由的。
- 用法:method,函数名
- post:Login post请求的时候访问Login函数
- get:User get请求的时候访问User函数
- *.LoginOut 所有请求方法都访问LoginOut函数
- put:UpdateFile put请求的时候访问UpdateFile函数
- get,post:Login get和post请求的时候访问Login函数 和
get:Login,post:Login
同义
- 可用的http方法
- get,post,put,delete,patch
- 用法:method,函数名
beego.Router("/param",&controllers.ParamController{},"get:Get1") //对于前端的get请求,映射到后端的Get1方法
3.3、获取请求方法和终止逻辑
>>>>>>>>>>>>>>>>>>>>>>>> routers/router.go
func init() {
...
beego.Router("/test_router/?:id:int",&controllers.RouterControllers{},"get,post:Get")
//把get和post请求都映射到 get方法中
}
>>>>>>>>>>>>>>>>>>>>>>>> views/test_router_post.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
test_router 测试界面
<form action="/test_router" method="post">
<input type="submit" value="提交">
</form>
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>> views/test_routert.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
test_router post 请求 测试界面
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>> controllers/test_router.go
package controllers
import (
"fmt"
beego "github.com/beego/beego/v2/server/web"
)
type RouterControllers struct {
beego.Controller
}
func (r *RouterControllers) Get() {
if r.Ctx.Request.Method == "POST" {
//r.StopRun() //不继续往下执行,加上 get界面的提交按钮,会 白屏,一般用在用户认证失败...
r.TplName = "test_router_post.html"
} else {
r.TplName = "test_router.html"
}
id := r.Ctx.Input.Param(":id")
fmt.Println("========================>")
fmt.Println(id)
}
3.4、跨站请求伪造XSRF
防护XSRF的方式:post请求之类伪造请求
- 定义:每一个用户一个cookie,所有请求都需要验证这个cookie,如果没有这个cookie,则被认为跨站请求伪造
- 挟持用户在当前已经登录的Web应用程序上执行非本意的操作的攻击方法
- XSRF利用的是网站对用户网页浏览器的信任
配置文件配置:
enablexsrf = true
xsrfkey = jdijfiblnlxmljodksjiDj
xsfrexpire = 3600 //单位秒,默认1h
代码中配置
beego.BConfig.WebConfig.EnableXSRF = true
beego.BConfig.WebConfig.XSRFKey = "djfidjsbcmJbdcAZZZjdf"
beego.BConfig.WebConfig.XSRFExpire = 360
3.4.1、开启效果展示
- Controller
package controllers
import beego "github.com/beego/beego/v2/server/web"
type XsfrController struct {
beego.Controller
}
func (x *XsfrController) Get(){
x.TplName = "test_xsrf.html"
}
func (x *XsfrController) Post(){
x.TplName = "test_xsrf_success.html"
}
- 页面
>>>>>>>>>>>>>>>>>>>>>> test_xsrf_success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
xsfr 成功页面
</body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> test_xsrf.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
xsrf测试界面
<form action="/xsrf" method="post">
<input type="submit" value="提交">
</form>
</body>
</html>
- router
func init() {
beego.Router("/xsrf",&controllers.XsfrController{})
}
- main.go
func main() {
...
beego.BConfig.WebConfig.EnableXSRF = true
beego.Run()
}
页面点击提交后,报错
这里没有传递 xsrf,所以会报错
3.4.2、form表单的xsrf
- controller 修改
type XsfrController struct {
beego.Controller
}
func (x *XsfrController) Get(){
x.Data["xsrfdata"] = template.HTML(x.XSRFFormHTML()) //传递数据到form表单中
x.TplName = "test_xsrf.html"
}
func (x *XsfrController) Post(){
x.TplName = "test_xsrf_success.html"
}
- html页面调整
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
xsrf测试界面
<form action="/xsrf" method="post">
{{.xsrfdata}}
<input type="submit" value="提交">
</form>
</body>
</html>
3.4.3、controller级别关闭xsrf
- 全局开启
// main.go
func main() {
beego.BConfig.WebConfig.EnableXSRF = true
beego.BConfig.WebConfig.XSRFKey = "ABCDEFGabcdefghijkmz" //默认key beegoxsrf, 基于key进行加密
beego.BConfig.WebConfig.XSRFExpire = 10 //默认3600s
beego.Run()
}
- controller级别关闭
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
"html/template"
)
type XsfrController struct {
beego.Controller
}
func (x *XsfrController) Get(){
x.Data["xsrfdata"] = template.HTML(x.XSRFFormHTML()) //传递数据到form表单中
x.TplName = "test_xsrf.html"
}
func (x *XsfrController) Post(){
x.TplName = "test_xsrf_success.html"
}
func (x *XsfrController) Prepare(){ //controller实现Prepare方法,和实现GET或者POST方法一样
x.EnableXSRF = false //controller级别关闭
x.TplName = "test_xsrf_success.html"
}
3.5、文件上传
3.5.1、form表单方式上传
- router
func init() {
...
beego.Router("/upload",&controllers.UploadController{})
}
- main.go
func main() {
...
beego.BConfig.WebConfig.EnableXSRF = true
beego.BConfig.WebConfig.XSRFKey = "ABCDEFGabcdefghijkmz" //默认key beegoxsrf, 基于key进行加密
beego.BConfig.WebConfig.XSRFExpire = 30 //默认3600s
beego.Run()
}
- upload controller
package controllers
import (
"fmt"
beego "github.com/beego/beego/v2/server/web"
"html/template"
"strconv"
"time"
)
type UploadController struct {
beego.Controller
}
func (u *UploadController) Get(){
u.Data["xsrfdata"] = template.HTML(u.XSRFFormHTML()) //记得传递xsrfdata
u.TplName = "upload.html"
}
func (u *UploadController) Post(){
//获取请求数据 ,f是文件的fd,h对应文件的描述信息
f,h,err := u.GetFile("upload_file")
defer f.Close()
if err != nil {
fmt.Println("ERROR,发生了错误",err)
return
}
fileName := h.Filename
fmt.Println("文件名:",fileName)
//保存到本地
//文件名添加时间戳,方式文件名上传重复覆盖
t1 := time.Now().Unix()
t2 := strconv.FormatInt(t1,10)
u.SaveToFile("upload_file","static/upload/"+(t2+"_"+fileName)) //upload为新建目录
u.TplName = "success.html"
}
- upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
上传页面
<form action="/upload" method="post" enctype="multipart/form-data">
{{.xsrfdata}}
<input type="file" name="upload_file"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
3.5.2、ajax上传文件
需要使用Fromdata,可以通过js用一些键值来模拟一系列表单控件
-
var formData = new FormData();
-
此时可以调用append()方法来添加数据
-
main.go
package main
import (
_ "beego_project/routers"
beego "github.com/beego/beego/v2/server/web"
)
func main() {
...
beego.BConfig.WebConfig.EnableXSRF = true
beego.BConfig.WebConfig.XSRFKey = "ABCDEFGabcdefghijkmz" //默认key beegoxsrf, 基于key进行加密
beego.BConfig.WebConfig.XSRFExpire = 30 //默认3600s
beego.Run()
}
- controller
package controllers
import (
"fmt"
beego "github.com/beego/beego/v2/server/web"
"html/template"
"strconv"
"time"
)
type UploadController struct {
beego.Controller
}
func (u *UploadController) Get(){
u.Data["xsrfdata"] = template.HTML(u.XSRFFormHTML()) //记得传递xsrfdata
u.TplName = "upload.html"
//u.TplName = "ajax_upload.html"
}
func (u *UploadController) Post(){
//获取请求数据 ,f是文件的fd,h对应文件的描述信息
f,h,err := u.GetFile("upload_file")
defer f.Close()
if err != nil {
fmt.Println("ERROR,发生了错误",err)
return
}
fileName := h.Filename
fmt.Println("文件名:",fileName)
//保存到本地
//文件名添加时间戳,方式文件名重复上传
t1 := time.Now().Unix()
t2 := strconv.FormatInt(t1,10)
u.SaveToFile("upload_file","static/upload/"+(t2+"_"+fileName)) //upload为新建目录
//u.TplName = "success.html"
u.Data["json"] = map[string]string{"code":"200","meesage":"操作成功"}
u.ServeJSON()
}
func (u *UploadController) Prepare() { //这里不直到为何必须得关闭,开启后上传就会http 422,可能是html页面发现的问题
u.EnableXSRF = false
}
- upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/js/jquery.min.js"></script>
</head>
上传页面
<body>
<form>
{{.xsrfdata}} <!-- 获取get请求时后端传过来的xsrf防护的key -->
<input type="file" name="upload_file" id="upload_file"><br>
<input type="button" value="提交" id="btn">
</form>
<script>
var btn = document.getElementById("btn");
btn.onclick = function (ev) { //在btn这个事件发生后,执行的动作
console.log($("upload_file")); //
var formData = new FormData();
formData.append("upload_file",$("#upload_file")[0].files[0]); //#根据id获取,
$.ajax({
url:"/upload",
type:"POST",
data:formData,
contentType:false,
processData:false,
success:function (data) { //回调函数,等待服务端返回
if (data["code"] == "200") {
alert(data["meesage"])
}
},
error:function (data) {
alert(data["meesage"])
}
})
}
</script>
</body>
</html>
ajax暂不做下关系了解,有时再操作。
3.5.3、其他
文件上传之后一般是放在内存中的,可以设置缓存中内存大小;
- main.go
beego.BConfig.MaxMemory = 1 <22
为1GB - 配置文件中配置:
maxmemmory= 1<22
单位是B - 默认的缓存内存是64M
3.6、session和cookie
Session:
- sessions是在无状态的HTTP协议下,服务端记录用户状态时用于标识具体用户的机制
- 它是在服务端保存的用来跟踪用户的状态的数据结构,可以保存在文件,数据库或者集群中
- 在浏览器关闭后这次的session就消失了,下次打开就不再拥有session,其实并不是Session消失了,而是session id变了
Cookie:
- Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息
- 每次HTTP请求时,客户端都会发送相应的Cookie信息到服务端,它的过期时间可以任意设置,如果你不主动清除它,在很长一段时间都可以保存着,即便中间把电脑关机了
session和cookie
- Cookie在客户端(浏览器),session在服务端
- Cookie的安全性一般,他人可以通过分析存放在本地的cookie并进行cookie欺骗。在安全性第一的前提下,选择session更优,重要交互信息比如权限等要放在session中,一般的信息放在cookie就好了
- 单个cookie的保存的数据大小不能超过4k,很多浏览器限制一个站点最多保存20个cookie
- Session可以放在文件、数据库或内存中
- 用户验证这种场合一般会用Session。因此,维持一个会话的核心就是客户端的唯一标识,即session id
- session的运行机制依赖Session id。而session id是存放在Cookie中的,也就是说。如果浏览器用了Cookie,session也会失效(但是可以通过其他方式实现,比如在url中传递Session id)
beego中使用的session:
- 开启方式:
- main.go:
beego.BConfig.WebConfig.Session.SessionOn = true
- 配置文件中:
sessionon = true
- main.go:
- 设置Sesion:
beego.BConfig.WebConfig.Session.SessionCookieLifeTime
超时Cookie过期时间beego.BConfig.WebConfig.Session.SessionGCMaxLifetime
设置session过期时间,默认3600sbeego.BConfig.WebConfig.Session.SessionName
设置cookie名字,session默认是在浏览器cookie里的,默认名是beegosessionID,配置文件对应的参数名是:sessionName
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> UploadController 负责设置session
type UploadController struct {
beego.Controller
}
func (u *UploadController) Get(){
//设置session
u.SetSession("username","icewake")
u.TplName = "upload.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> XsfrController 负责查看和删除session
type XsfrController struct {
beego.Controller
}
func (x *XsfrController) Get(){
//打印session
fmt.Println("删除前============================>",x.GetSession("username"))
x.DelSession("username")
fmt.Println("删除后============================>",x.GetSession("username"))
x.TplName = "test_xsrf.html"
}
测试的时候,先访问UploadController,然后再访问XsrfController看效果
3.7、过滤器(作业没有实现)
对没有满足条件的请求进行拦截
func InsertFilter(pattern string, pos int, filter FilterFunc, opts ...FilterOpt) *HttpServer { return BeeApp.InsertFilter(pattern, pos, filter, opts...) }
- 第一个参数:匹配的路由规则,支持通配符
- 第二个参数:过滤器的未知,beego支持的5种
- BeforeStatic: 静态地址之前
- BeforeRouter: 寻找路由之前
- BeforeExec: 找到路由之后,开始执行相应的Controller之前
- AfterExec:执行完controller逻辑之后执行的过滤器
- FinishRouter:执行完逻辑之后执行的过滤器
- 第三个函数:
func(*context.Context)
参数必须context.Context
- 第四个参数:
- 第一个设置
returnOnOutPut
的值,默认true,即如果有输出是否跳过其他过滤器,默认只要有输出就不再执行其他过滤器,即执行完controller之后不会执行后面的过滤器 - 第二个设置表示是否重置过滤器的参数,默认是false
- 第一个设置
注意:使用session和Filter必须在BeforeStatic之后才能获得,因为session没有在这之前初始化。
示例:如果session不正确或者没有session就跳转到login界面,有问题
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> mian.go 逻辑
func main() {
...
beego.BConfig.WebConfig.Session.SessionOn = true
beego.InsertFilter("/*",beego.BeforeRouter,controllers.Filter_user)
beego.Run()
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> router
func init() {
...
beego.Router("/upload",&controllers.UploadController{})
beego.Router("/ajax_upload",&controllers.AjaxUploadController{})
beego.Router("/login",&controllers.LoginController{})
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LoginController
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type LoginController struct {
beego.Controller
}
func (l *LoginController) Get() {
l.SetSession("username","icewake")
l.TplName = "login.html"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> testFilter逻辑
package controllers
import (
"fmt"
context "github.com/beego/beego/v2/server/web/context"
)
//如果不携带session,或者session不对,则跳转到login界面
func Filter_user(ctx *context.Context) {
login := LoginController{}
fmt.Printf("===========>%v======%T\n",login,login)
if login.GetSession("username") != "icewake" && ctx.Request.RequestURI != "/login" { //这里有问题,待确认
ctx.Redirect(302,"/login")
}
}
3.8、URL反转
动态构建url,就是根据方法名生成对应的url,原来是通过url找到对应的方法,现在我们要通过方法找到对应的url,这就是url反转,带来的好处就是:url改变不需要改变代码
beego.Router("/login",&controllers.LoginController{})
正常是根据url /login
找到对应的controller,现在反过来根据 controllers.LoginController{}
找到对应的/login
- controller
type UploadController struct {
beego.Controller
}
func (u *UploadController) Get(){
fmt.Println("++++++++++++++++++++++++++++++++") //UploadController 反转url到 LoginController
fmt.Println(beego.URLFor("LoginController.Get")) //打印内容为"/login"
u.TplName = "upload.html"
}
- html前端反转
<a href="{{urlfor "LoginController.GET"}}">URL反转</a>
带参数的url反转
修改controller部分内容为:
fmt.Println(beego.URLFor("LoginController.Get","name","icewake","age",20)) //打印内容为/login?name=icewake&age=20
前端页面调整为:
<a href="{{urlfor "LoginController.GET" "name" "icewake" "age" 18}}">URL反转</a>
3.9、表单数据校验
3.9.1、合法性校验
- validta.go
package controllers
import (
"fmt"
"github.com/beego/beego/v2/core/validation"
beego "github.com/beego/beego/v2/server/web"
)
type ValiddataController struct {
beego.Controller
}
func (v *ValiddataController) Get() {
v.TplName = "validata.html"
}
func (v *ValiddataController) Post() {
username := v.GetString("username")
age := v.GetString("age")
email := v.GetString("email")
phone := v.GetString("phone")
fmt.Println(username,age,email,phone)
valid := validation.Validation{}
//校验数据,数据为空校验
valid.Required(username,"是必填字段") //第二个key是提示的字段名,如果没有传递提示"用户名是必填字段-- Can not be empty"
valid.Required(age,"是必填字段")
valid.Required(email,"Email").Message("邮箱地址不能为空!") //自定义meeage内容,如果email为空,默认提示信息为 "Can not be empty"
valid.Mobile(phone,"Phone").Message("号码不合法")
valid.Email(email,"Email").Message("格式不合法")
//还可以校验IP、Min、max、范围、长度、数字、AlphaNum、Match、Alpha、Tel固话
//AlphaNumeric字符或数字、AlphaDash字符或数字或_,-
if valid.HasErrors() {
for _,er := range valid.Errors {
fmt.Printf("%s--%s\n",er.Key,er.Message)
//示例:age是必填字段-- Can not be empty
}
}
v.TplName = "validata_post.html"
}
- validata.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/vailddata" method="post">
用户名: <input type="text" name="username"><br>
年龄: <input type="text" name="age"><br>
Email: <input type="text" name="email"><br>
电话: <input type="text" name="phone"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
3.9.2、结构体校验
解析前端数据到结构体并校验
- 校验方式1,使用上一节的方式
package controllers
import (
"fmt"
"github.com/beego/beego/v2/core/validation"
beego "github.com/beego/beego/v2/server/web"
)
type ValiddataController struct {
beego.Controller
}
func (v *ValiddataController) Get() {
v.TplName = "validata.html"
}
type Userstruct struct {
Username string `form:"username"`
Age int `form:"age"`
Email string `form:"email"`
Phone int `form:"phone"`
}
func (v *ValiddataController) Post() {
user := Userstruct{}
v.ParseForm(&user)
fmt.Println("==========>",user)
valid := validation.Validation{}
//校验数据,数据为空校验
valid.Required(user.Username,"用户名").Message("不能为空")
valid.Required(user.Age,"年龄").Message("不能为空")
valid.Required(user.Email,"邮箱").Message("不能为空")
valid.Required(user.Phone,"电话").Message("不能为空")
if valid.HasErrors() {
for _,er := range valid.Errors {
fmt.Printf("%s--%s\n",er.Key,er.Message)
}
}
v.TplName = "validata_post.html"
}
- 校验方式2:使用struct tag的方式校验
- 验证函数写在
valid:tag
的标签里 - 各个函数之间使用;分隔,分号后可以有空格
- 参数用"()"括起来,多个参数之间用","分开,逗号后可以有空格
- 正则函数(Match)的匹配模式用两斜杠"/"括起来
- 各个函数的结果的key值为字段名.验证函数名
- 验证函数写在
package controllers
import (
"fmt"
"github.com/beego/beego/v2/core/validation"
beego "github.com/beego/beego/v2/server/web"
)
type ValiddataController struct {
beego.Controller
}
func (v *ValiddataController) Get() {
v.TplName = "validata.html"
}
type Userstruct struct {
Username string `form:"username" valid:"Required"` //多个标签使用 空格分开,form标签用于从html中解析post请求
Age int `form:"age" valid:"Required"`
Email string `form:"email" valid:"Email"`
Phone int `form:"phone" valid:"Phone"`
}
func (v *ValiddataController) Post() {
//重写错误信息
var message = map[string]string {
"Required": "不能为空",
"MinSize": "最短长度不能为 %d",
"Length": "长度必须为 %d",
"Numeric": "必须是有效的数字",
"Email": "必须是有效的邮箱",
"Mobile": "必须是有效的手机号",
}
user := Userstruct{}
v.ParseForm(&user)
fmt.Println("==========>",user)
valid := validation.Validation{}
validation.SetDefaultMessage(message)
//校验方式2:使用struct tag的方式
b,err := valid.Valid(&user) //b表示是否验证通过,err是 要解析的结构体是否有问题
fmt.Println("b,err======>",b,err)
if !b { //如果有错误
for _,er := range valid.Errors {
fmt.Printf("%s--%s\n",er.Key,er.Message)
}
}
v.TplName = "validata_post.html"
}
3.9.3、错误处理
自定义错误,需要重写controller
- controllers/test_abort.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type AbortController struct {
beego.Controller
}
func (a *AbortController) Get() {
a.Abort("700") //如果在 tplName之前执行了 Abort,则不会显示 templatename指定的页面看,可以自定义
//默认的401或者其他 错误界面,在 beego/server/web/error.go的 中定义,内容如下
/*
func unauthorized(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
401,
"<br>The page you have requested can't be authorized."+
"<br>Perhaps you are here because:"+
"<br><br><ul>"+
"<br>The credentials you supplied are incorrect"+
"<br>There are errors in the website address"+
"</ul>",
)
}
*/
a.TplName = "login.html"
}
type ErrorController struct {
beego.Controller
}
func(e *ErrorController) Error700() { //其他的状态码同理,也可以这样玩儿
e.Data["message"] = "数据库链接错误"
e.TplName = "db_error.html"
}
- main.go
func main() {
...
beego.ErrorController(&controllers.ErrorController{}) //注册error controller
beego.Run()
}
- db_error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{.message}}
</body>
</html>
- abort.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
abort页面
</body>
</html>
router.go中添加路由
四、Views
4.1、模板基础用法
go统一使用了{{ 和 }}
作为html中引用后端数据的左右标签,可以修改为其他的符号
在main.go中设置为其他字符
func main(){
...
beego.BConfig.WebConfig.TemplateLeft = "##"
beego.BConfig.WebConfig.TemplateRight = "##"
bee.Run()
}
-
基本语法:
.
表示当前位置的上下文$
引用当前模板根级的上下文$.
引用模板中根级的上下文
-
go语言支持的符号
- 字符串:
{{ "icewake" }}
- 原始字符串: "{{ 反引号 icewake 反引号}}"
- 字节类型:
{{ 'a'}}
--> 97 - nil:
{{ print nil}}
只有nil会报错,nil is not a command
- 字符串:
-
pipeline: 可以是上下文的变量,也可以是函数通过管道传递的返回值
- {{ .Age }} 是上下文变量的输出,是个pipeline
- {{ "0000" | len }} 是函数通过管道传递的返回值,是个pipeline
- pipeline会被认为是空的情况,当pipeline的值等于:
- false 或 0
- nil的指针或interface
- 长度为0的array,slice,map,string
-
基础函数:
eq/ne/lt/le/gt/ge
;eq不同于其他函数,支持多个参数{{ if eq true .Var1 .Var2 .Var3 }} {{end}}
view1.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type TemplateController struct {
beego.Controller
}
func (t *TemplateController) Get() {
t.Data["name"] = "icewake"
t.Data["value"] = []int{1,2,3,4,5,6}
t.TplName = "template1.html"
}
template1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
前端语法1: ## .name ## <br>
前端语法2:
## range .value ##
## . ##
## end ## <br>
前端语法3(引用当前模板根):
## range $i,$v := .value ##
## $i ## = ## $v ##
## end ## <br>
前端语法4(引用根):
## range .value ##
## $.value ##
## end ## <br>
5、支持go语言的符号: <br>
字符串:## "符号1" ## <br>
原始字符串:## "\\符号1" ##<br>
原始字符串:## `\\符号1` ##<br>
字节: ## 'a' ## <br>
NIL: ## print nil ## <br>
6、PIPELINE管道:<br>
求长度:## "icewake" | len ## <br>
</body>
</html>
web结果:
前端语法1: icewake
前端语法2: 1 2 3 4 5 6
前端语法3(引用当前模板根): 0 = 1 1 = 2 2 = 3 3 = 4 4 = 5 5 = 6
前端语法4(引用根): [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6]
5、支持go语言的符号:
字符串:符号1
原始字符串:\符号1
原始字符串:\\符号1
字节: 97
NIL: <nil>
6、PIPELINE管道:
求长度:7
4.2、模板语法
4.2.1、if语法
if ... end
;if ... else ..end
;嵌套使用
- controller
type TemplateController struct {
beego.Controller
}
func (t *TemplateController) Get() {
t.Data["name"] = "icewake"
t.Data["value"] = []int{1,2,3,4,5,6}
t.Data["age"] = 19
t.Data["is_vip"] = true
t.TplName = "template1.html"
}
- template.html
...
7、进入网吧条件,必须是18岁,必须有会员卡 <br>
## if ge .age 18 ##
大于18岁
## if eq .is_vip true ##
可以进入网卡
## else ##
不能进入网吧
## end ##
## end ##
...
- web界面效果
7、进入网吧条件,必须是18岁,必须有会员卡
大于18岁 可以进入网卡
4.2.2、range
## range .value ##
## . ##
## end ## <br>
## range $i,$v := .value ##
## $i ## = ## $v ##
## end ## <br>
range也支持else
{{ range .total }}
{{ else }}
{{ 执行}} //当total为空或者长度为0时会执行这里
{{ end }}
4.2.3、with
伴随,用于重定向pipeline
- controller
type Student struct {
Id int
Name string
Age int
}
func (t *TemplateController) Get() {
t.Data["name"] = "icewake"
t.Data["value"] = []int{1,2,3,4,5,6}
t.Data["stu1"] = Student{1001,"令狐冲",28}
t.Data["age"] = 19
t.Data["is_vip"] = true
t.TplName = "template1.html"
}
- template.html
9、with用法1<br>
## with .stu1 ##
## .Id ##
## .Name ##
## .Age ##
## end ## <br>
9、with用法2<br>
## with .name1 ##
## . ##
## else ##
没有该值
## end ## <br>
效果
9、with用法1
1001 令狐冲 28
9、with用法2
没有该值
4.2.4、template
- controller
type Student struct {
Id int
Name string
Age int
}
func (t *TemplateController) Get() {
t.Data["name"] = "icewake"
t.Data["value"] = []int{1,2,3,4,5,6}
t.Data["stu1"] = Student{1001,"令狐冲",28}
t.Data["age"] = 19
t.Data["is_vip"] = true
t.TplName = "template1.html"
}
- template1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
前端语法1: ## .name ## <br>
前端语法2:
## range .value ##
## . ##
## end ## <br>
前端语法3(引用当前模板根):
## range $i,$v := .value ##
## $i ## = ## $v ##
## end ## <br>
前端语法4(引用根):
## range .value ##
## $.value ##
## end ## <br>
5、支持go语言的符号: <br>
字符串:## "符号1" ## <br>
原始字符串:## "\\符号1" ##<br>
原始字符串:## `\\符号1` ##<br>
字节: ## 'a' ## <br>
NIL: ## print nil ## <br>
6、PIPELINE管道:<br>
求长度:## "icewake" | len ## <br>
7、进入网吧条件,必须是18岁,必须有会员卡 <br>
## if ge .age 18 ##
大于18岁
## if eq .is_vip true ##
可以进入网卡
## else ##
不能进入网吧
## end ##
## end ## <br>
8、range用法<br>
9、with用法1<br>
## with .stu1 ##
## .Id ##
## .Name ##
## .Age ##
## end ## <br>
9、with用法2<br>
## with .name1 ##
## . ##
## else ##
没有该值
## end ## <br>
10、template用法<br>
引入模板: ## template "template2.html" . ## <br>
两个参数,第一个参数模板名称,第二个参数上下文,引入上下文后,就可以在"template2.html"中引用后端数据了 <br>
11、define用法,可用来自定义模板,用于模板定义和模板嵌套<br>
## define "MyDefine" ##
<ul><li>##.stu1 ##</li></ul>
<ul><li>##.stu1 ##</li></ul>
<ul><li>##.stu1 ##</li></ul>
## end ##
## template "MyDefine" . ## <br>
</body>
</html>
- template2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是模板文件,需要在template中引入的,引入的stu1: ## .stu1 ##
</body>
</html>
- 效果
前端语法1: icewake
前端语法2: 1 2 3 4 5 6
前端语法3(引用当前模板根): 0 = 1 1 = 2 2 = 3 3 = 4 4 = 5 5 = 6
前端语法4(引用根): [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6] [1 2 3 4 5 6]
5、支持go语言的符号:
字符串:符号1
原始字符串:\符号1
原始字符串:\\符号1
字节: 97
NIL: <nil>
6、PIPELINE管道:
求长度:7
7、进入网吧条件,必须是18岁,必须有会员卡
大于18岁 可以进入网卡
8、range用法
9、with用法1
1001 令狐冲 28
9、with用法2
没有该值
10、template用法
引入模板: 这是模板文件,需要在template中引入的,引入的stu1: {1001 令狐冲 28}
两个参数,第一个参数模板名称,第二个参数上下文,引入上下文后,就可以在"template2.html"中引用后端数据了
11、define用法,可用来自定义模板,用于模板定义和模板嵌套
{1001 令狐冲 28}
{1001 令狐冲 28}
{1001 令狐冲 28}
4.3、模板基础函数
- print对应
fmt.Sprint
//fmt.Sprint和fmt.Print区别在于Sprint用于接收变量并赋值以给新变量,Sprint有返回值,- {{ ”icewake“ }} 和 {{ print "icewake" }} 效果是一样的
- printf对应
fmt.Sprintf
- println对应
fmt.Sprintln
- and
- 会逐个判断每个参数,将返回第一个为空的参数,否则就返回最后一个非空参数
- 只要有一个为空,则整体为空,如果都不为空,则返回最后一个
- or
- 会逐个判断每个参数,将返回第一个非空的参数,否则就返回最后 一个参数
- call:可以调用函数,并传入参数
{{ call .Field .Arg1 .Arg2}}
- 调用的函数需要返回1个值或者2个值,返回两个值时,第二个值用于返回error类型的错误。返回的错误不等于nil时,执行终止
- index:读取指定类型对应下标的值
- 支持map、slice、string
- this.Date["maps"] = map[string]string
- {{ index .Maps "name"}} //如果不提供"name" 及 下标,则默认返回所有的
- 支持map、slice、string
- len: 返回对应类型的长度
- 支持类型:map、stirng、array、chan、slice
- not:返回输入参数的否定值
- urlquery:有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了。
http://www.baidu.com
- 编码后:
http%3A%2F%2Fwww.baidu.com
- %后面的就是16进制的字符编码
- eq/ne/lt/le/gt/ge
- eq特殊,支持多个参数
1、controller.go
package controllers
import (
"fmt"
beego "github.com/beego/beego/v2/server/web"
)
type Template2Controller struct {
beego.Controller
}
func (t *Template2Controller) Get() {
t.Data["name"] = "icewake"
t.Data["a"] = 0
t.Data["b"] = "icewake"
t.Data["c"] = []int{}
t.Data["func_test"] = Test //注意返回函数名称即可,不要添加()
t.Data["func_test2"] = Test2
//index
t.Data["data_map"] = map[string]string{"天下第一":"铁蛋深厚","天下第二":"不败顽童"}
t.Data["data_slice"] = []int{9,4,65}
t.Data["data_string"] = "icewake"
t.Data["data_string2"] = "北京欢迎你"
t.Data["is_true"] = true
t.Data["is_true2"] = "true"
t.TplName = "template2.html"
}
func Test() string {
return "hello icewake"
}
func Test2(name string) string {
str1 := fmt.Sprintf("你好,世界! 你好 %s !",name)
return str1
}
2、template2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
模板文件示例<br>
1、Print用法: {{ .name | printf "%s"}} <br>
2、括号用法: {{ printf "%s,%d" (printf "%d-%d" 2 4) 6}} <br>
3、and用法:{{ .a}} {{ .b }} {{ .c}}<br> //输出:0 icewake []
{{ and .a .b .c}} //返回0 <br>
4、or用法: <br>
{{ or .a .b .c}} //返回 icewake <br>
5、call函数: <br>
{{ call .func_test}} <br>
6、call函数2: <br>
{{ call .func_test2 "icewake2"}} <br>
7、index函数: <br>
{{ index .data_map "天下第一"}} <br>
所有:{{ index .data_slice }} <br>
单个:{{ index .data_slice 0}} <br>
字符串:{{ index .data_string2 }} <br>
字符串:{{ index .data_string2 2}} //返回的是151 而不是 "欢" <br>
7、len函数: <br>
{{ .data_string2 | len }} //一个中文三个字符,共15个 <br>
{{ len .data_map }} //返回2,因为data_map中只有两个元素<br>
8、not函数<br>
{{ not .is_true }}
{{ not .is_true2 }} //两个都是false <br>
9、urlquery函数<br>
{{ urlquery "http://www.baidu.com" }}
10、eq/ne/lt/le/gt/ge <br>
{{ eq 1 2}} <br>
{{ le 1 2}} <br>
{{ eq 3 8 8 3}} //true,只要有一个和3相等即为true <br>
</body>
</html>
3、效果
模板文件示例
1、Print用法: icewake
2、括号用法: 2-4,6
3、and用法:0 icewake []
//输出:0 icewake [] 0 //返回0
4、or用法:
icewake //返回 icewake
5、call函数:
hello icewake
6、call函数2:
你好,世界! 你好 icewake2 !
7、index函数:
铁蛋深厚
所有:[9 4 65]
单个:9
字符串:北京欢迎你
字符串:151 //返回的是151 而不是 "欢"
7、len函数:
15 //一个中文三个字符,共15个
2 //返回2,因为data_map中只有两个元素
8、not函数
false false //两个都是false
9、urlquery函数
http%3A%2F%2Fwww.baidu.com
10、eq/ne/lt/le/gt/ge
false
true
true //true,只要有一个和3相等即为true
4.4、内置模板函数
-
dateformat:
- 实现了时间的格式化,返回字符串
- 使用方法:
- 使用方法:
{{ d ateformat.Time "2006/01/02/ 15:04:05"}}
{{ dateformat.Time "2006/01/02/ 3:04:05 PM"}}
- 设置时间格式比较特殊,需要按照如下格式
- "2006/01/02 15:04:05"
- "2006/01/02 03:04:05 PM"
- 使用方法:
-
date
- 根据字符串返回时间
- 使用方法
{{ date .T "YY-m-d H:i:s"}}
Y
: 四位年y
两位年,m
月份数字,M
月份英文,d
日(两位),D
星期几英文,i
数字分钟,I
英文星期
-
compare
- 实现了比较两个对象的比较,如果相同返回
true
,否则返回false
,使用方法{{ compare .A .B}}
- 实现了比较两个对象的比较,如果相同返回
-
compare_not
- 和
compare
相同的,不相等返回true
,相等返回false
{ { compare_not 'a' 97 }}
- 和
-
not_nil
- 判断是不是为空,如果为空返回
false
,否则返回true
- 判断是不是为空,如果为空返回
-
not_null : 同
not_nil
-
substr: 用于截取字符串
- 使用方法:
{{ substr "我是中国人" 0 4}}
,左闭右开区间
- 使用方法:
-
html2str
- 实现了把html转化为字符串,剔除一些script,css之类的元素,返回纯文本信息,使用方法
{{ html2str.Htmlinfo }}
{{ html2str "<a href="www.baidu.com" a>百度</a>}}
\
- 实现了把html转化为字符串,剔除一些script,css之类的元素,返回纯文本信息,使用方法
-
str2html
- 实现了把str转换为html,不转义
-
htmlquote
- 实现了基本html字符转义,使用方法
{{ htmlquote.quote}}
- 只转义特殊字符,比如
< >
' ' 等
- 实现了基本html字符转义,使用方法
-
renderform 看renderform章节
- 根据StructTag 直接生成对应的表单,使用方法
{{ &struct | renderform}}
- 根据StructTag 直接生成对应的表单,使用方法
-
assets_js
- 为js文件生成一个