Web Development with Beego
Install the bee tool and beego using go get
Initialize a Beego project using the bee tool
- Execute
bee create myappin the$GOPATH/srcdirectory
Hot compile a Beego project using the bee tool
- Execute
bee start myappin the$GOPATH/src/myappdirectory
// hello world
package main
import (
"github.com/astaxie/beego"
)
type HomeController struct {
beego.Controller
}
// 注意Get首字母大写。要不会报method not allow
func (this *HomeController) Get() {
this.Ctx.WriteString("Hello World")
}
func main() {
beego.Router("/",&HomeController)
beego.Run()
}
Go HTTP
Three packages: io/log/net/http
package main
import (
"io"
"log"
"net/http"
)
func main() {
http.HandleFunc("/",sayHello)
err:=http.ListenAndServe(":8080",nil)
if err!=nil {
log.Fatal(err)
}
}
func sayHello(w http.ResponseWriter,r *http.Request) {
io.WriteString(w,"Hello world,this is is version 1.")
}
Add a handler to the second parameter of ListenAdnServe
package main
import (
"io"
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.Handle("/", &myHandler{})
mux.HandleFunc("/hello",SayHelloV2) //处理func
err := http.ListenAndServe("0.0.0.0:8080", mux)
if err!=nil {
log.Fatal(err)
}
}
type myHandler struct{}
func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "URL:"+r.URL.String())
}
// 同样mux也可以HandleFunc
func SayHelloV2(w http.ResponseWriter,r *http.Request) {
io.WriteString(w,"Hello world, this is version No.2.")
}
Lower-level HTTP server handling
package main
import (
"io"
"log"
"net/http"
"time"
)
//手动处理路由,在handler中只有一个ServerHTTP
var mx map[string]func(w http.ResponseWriter,r *http.Request)
func main() {
server:=http.Server{
Addr:":8080",
Handler: &myHandler1{},
ReadHeaderTimeout:5*time.Second,
}
//路由注册
mx = make(map[string]func(w http.ResponseWriter,r *http.Request))
mx["/hello"] =sayHello
mx["/saybye"] = sayBye
err:=server.ListenAndServe()
if err!=nil {
log.Fatal(err)
}
}
type myHandler1 struct{}
func (*myHandler1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//io.WriteString(w, "URL:"+r.URL.String())
//这里来做路由转发
if h,ok:=mx[r.URL.String()];ok{
h(w,r)
return
}
io.WriteString(w, "妹找到-->URL:"+r.URL.String())
}
func sayHello (w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"Hello world, this is version no 3")
}
func sayBye(w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"Bye bye, this is version no 3")
}
Extending mux for static file serving
func main() {
mux := http.NewServeMux()
mux.Handle("/", &myHandler{})
mux.HandleFunc("/hello", SayHelloV2)
//创建静态服务
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
mux.Handle("/static/",
http.StripPrefix("/static/", http.FileServer(http.Dir(wd))))
err = http.ListenAndServe("0.0.0.0:8080", mux)
if err != nil {
log.Fatal(err)
}
}
Using bee commands
- Create a new web project
bee new myproject - The api command can be used to create API applications
bee api apiproject. From its directory structure, we can see that the static and views directories are missing, and a test module has been added for unit testing. - The
bee runcommand monitors Beego projects by watching the file system with fsnotify. However, note that this command must be executed in the$GOPATH/src/appnamedirectory. - The
bee packcommand is used to package the application for deployment. It will package the project into a zip file, so when we deploy, we can directly upload and unzip the packaged project. - The
bee versioncommand checks the versions of bee, beego, and Go. - The
bee generatecommand is used for automated code generation, including one-click model generation from the database, and also includes scaffolding.
Beego Configuration Management
How to get conf/app.conf?
package controllers
import (
"strconv"
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
// c.Data["Website"] = "beego.me"
// c.Data["Email"] = "astaxie@gmail.com"
// c.TplName = "index.tpl"
c.Ctx.WriteString("appName:"+beego.AppConfig.String("appname")+
"\nhttpport"+beego.AppConfig.String("httpport")+
"\nrunmode"+beego.Appconfig.String("runmode"))
// 系统默认参数方式 貌似不带这种方式了
/* hp:=strcovItoa(beego.HttpPort)
c.Ctx.WriteString("appName:"+beego.AppName+
"\nhttpport"+hp+
"\nrunmode"+beego.RunMode) */
// 日志 及日志级别
/*
LevelEmergency = iota // 紧急级别
LevelAlert // 报警级别
LevelCritical // 严重错误级别
LevelError // 错误级别
LevelWarning // 警告级别
LevelNotice // 注意级别
LevelInformational // 报告级别
LevelDebug // 除错级别
*/
log:=logs.NewLogger(10000)
log.SetLevel(logs.LevelDebug)
}
Templates
package controllers
import (
"strconv"
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
c.Data["name"] = "name"
// 模板中的条件判断
c.Data["TrueCond"] = true
c.Data["FalseCond"] = false
// 打印一个结构
type u struct{
Name string
age int
Sex string
}
user:=&u{
Name:"Joe",
Age:20,
Sex:"Male"
}
c.Data["User"] = user
// 循环输出
nums:=[]int{1,2,3,4,5,6,7,8,9,0}
c.Data["Nums"] = nums
// 给模板变量赋值
c.Data["TplVar"] = "hey guys"
// 内置模板函数的功能
c.Data["Html"] = "<div>Hello Beego</div>"
c.Data["Pipe"] = "<div>Hello Beego</div>"
}
<!-- tpl -->
<div>
<!-- 条件判断 判断值只能是True 或 false不能用表达式 -->
{{if .TrueCond}} true condition content {{end}}
</div>
<div>
<!-- 条件判断 判断值只能是True 或 false不能用表达式 -->
{{if .FalseCond}} {{else}} false condition content {{end}}
</div>
<div>
<!-- 结构显示 -->
{{.User.Name}} {{.User.Age}} {{.User.Sex}}
<!-- 嵌套输出 -->
{{with .User}} {{.Name}} {{.Age}} {{.Sex}} {{end}}
</div>
<div>
<!-- 单数组 只输入一个.就可以了 -->
{{range .Nums}} {{.}} {{end}}
<!-- 如果是对象的话,因为兼顾了with功能,所以只写对象属性就可以了`.属性名` -->
</div>
<div>
<!-- 模板变量使用$定义 -->
{{$tplVar = .TplVar}} ==> {{$tplVar}}
</div>
<div>
{{.html}}
<!-- 模板函数 -->
{{str2Html .html}}
</div>
<!-- 编码 htmlquote函数-->
{{.Pipe | htmlquote}}
Defining Template Nesting
{{define "test"}} 定义的模板块 {{end}}
<html>
<head></head>
<body>
{{template "test"}}
</body>
</html>
Practical Lesson: Creating Models
Create models.go file in the models directory (don't confuse it with our previous xorm one)
// controllers/default.go
package controllers
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
c.TplName = "home.html"
}
// models/models.go 注意orm中后面是带双引号
type Category struct {
Id int64
Title string
Created time.Time `orm:"index;auto_now_add;type(datetime)"`
Views int64 `orm:"index"`
TopicTime time.Time `orm:"index;auto_now_add;type(datetime)"`
TopicCount int64
TopicLastUserId int64
}
type Topic struct {
Id int64
Uid int64
Title string
Content string `orm:size(5000)`
Attachment string
Created time.Time `orm:"index;auto_now_add;type(datetime)"`
Updated time.Time `orm:"index;auto_now_add;type(datetime)"`
Views int64 `orm:"index"`
Author string
ReplyTime time.Time
ReplyCount int64
ReplyLastUserId int64
}
func RegisterDB() {
if !com.IsExist(_DB_NAME) {
os.MkdirAll(path.Dir(_DB_NAME), os.ModePerm)
os.Create(_DB_NAME)
}
orm.RegisterModel(new(Category), new(Topic))
orm.RegisterDriver(_SQLITE3_DERIVER, orm.DRSqlite)
// 强制要求必须有一个数据库叫default 不管你有几个数据库 最大连接数10
orm.RegisterDataBase("default", _SQLITE3_DERIVER, _DB_NAME, 10)
}
// main.go
package main
import (
"beeapp/controllers"
"beeapp/models"
_ "beeapp/routers"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
orm.Debug = true //调度模式
//自动建表
orm.RunSyncdb("default",false,true)
beego.Router("/",&controllers.MainController{})
beego.Run()
}
Login and Category Management
Split templates, breaking down the template content from the previous example into different blocks for future development and reuse. For example, extract the webpage header and name it T_header.tpl
{{define "header"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="shortcut icon" href="/static/img/favicon.ico" />
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<title>Home</title>
</head>
<body style="padding-top: 70px">
{{end}}
</body>
</html>
Delete the corresponding content in the home.html template and replace it with Beego template import syntax; define templates using {{define "header"}} {{end}}
Note the trailing
.; if you use variables in the template, this dot is required, but it can be omitted for pure static resources.
{{template "header" .}}
<!-- 模板输出变量{{.变量名}} -->
Here, glide is used as a package management tool, and you might encounter issues where go get golang.org/x/ cannot download packages. You can manage this by adding mirrors; here, only tools, net, and sys were added. ~~I've stepped on this pitfall hard, definitely do not use glide~~ Another pitfall is proxying for the terminal.
glide mirror set https://golang.org/x/mobile https://github.com/golang/mobile --vcs git
glide mirror set https://golang.org/x/crypto https://github.com/golang/crypto --vcs git
glide mirror set https://golang.org/x/net https://github.com/golang/net --vcs git
glide mirror set https://golang.org/x/tools https://github.com/golang/tools --vcs git
glide mirror set https://golang.org/x/text https://github.com/golang/text --vcs git
glide mirror set https://golang.org/x/image https://github.com/golang/image --vcs git
glide mirror set https://golang.org/x/sys https://github.com/golang/sys --vcs git
Don't change a title, please use dep
github, if you encounter issues downloading from golang.org, see here. It's basically about solving proxy issues for the terminal.
Category List Business Logic
<!-- category模板 -->
{{template "header" .}} {{template "navbar" .}}
<div class="container">
<form class="form-inline" action="/cate" method="get">
<div class="form-group">
<label for="cate_name">类别名称</label>
<input
type="text"
style="width: 260px"
class="form-control"
id="cate_name"
name="catename"
placeholder="Please enter category name"
/>
<input type="hidden" name="op" value="add" />
</div>
<button type="submit" class="btn btn-default>添加</button>
</form>
<table class="table table-striped">
<thead>
<th>#</th>
<th>名称</th>
<th>文章数</th>
<th>操作</th>
</thead>
<tbody>
{{range .Categories}}
<td>{{.Id}}</td>
<td>{{.Title}}</td>
<td>{{.TopicCount}}</td>
<td>
<a href="/cate?op=del&id={{.Id}}">删除</a>
</td>
{{end}}
</tbody>
</table>
</div>
{{template "footer" .}}
Writing Business Logic
// CategoryController
package controllers
import (
"beeapp/models"
"github.com/astaxie/beego"
)
type CategoryController struct {
beego.Controller
}
func (c *CategoryController) Get() {
op := c.Input().Get("op")
// 添加 删除 显示列表
switch op {
case "add":
name := c.Input().Get("catename")
if len(name) == 0 {
break
}
err := models.AddCategory(name)
if err != nil {
beego.Error(err)
}
//添加成功 重定向cate
c.Redirect("/cate", 301)
// 记得return
return
case "del":
id := c.Input().Get("id")
if len(id) == 0 {
break
}
err := models.DeleteCategory(id)
if err != nil {
beego.Error(err)
}
c.Redirect("/cate", 301)
return
}
c.Data["Title"] = "分类"
c.Data["IsCategory"] = true
c.TplName = "category.html"
var err error
c.Data["Categories"], err = models.GetAllCategories()
if err != nil {
beego.Error(err)
}
}
// models中添加如下方法
// 添加分类
func AddCategory(name string) error {
o := orm.NewOrm()
cate := &Category{Title: name}
qs := o.QueryTable("category")
err := qs.Filter("title", name).One(cate)
if err == nil {
//err为空说明找到了
return err
}
// 不存在 要做一个insert
_, err = o.Insert(cate)
if err != nil {
return err
}
return nil
}
func GetAllCategories() ([]*Category, error) {
o := orm.NewOrm()
cates := make([]*Category, 0)
qs := o.QueryTable("category")
//注意下面的取址符号
_, err := qs.All(&cates)
return cates, err
}
func DeleteCategory(id string) error {
cid, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return err
}
o := orm.NewOrm()
cate := &Category{Id: cid}
_, err = o.Delete(cate)
return err
}
Simple HTTP Coookie
package main
import (
"io"
"strings"
"net/http"
)
func main() {
http.HandleFunc("/",Cookie)
http.HandleFunc("/2",Cookie2)
http.ListenAndServe(":9090",nil)
}
func Cookie(w http.ResponseWriter, r *http.Request) {
//第一种设置方法
ck := &http.Cookie{
Name: "myCookie",
Value: "hello",
Path: "/",
Domain: "localhost",
MaxAge: 120,
}
http.SetCookie(w, ck)
ck2, err := r.Cookie("myCookie")
if err != nil {
io.WriteString(w, err.Error())
return
}
io.WriteString(w, ck2.Value)
}
func Cookie2(w http.ResponseWriter, r *http.Request) {
//第二种设置方法
ck := &http.Cookie{
Name: "myCookie",
Value: strings.Replace("hello World"," ","%20",-1), //空格在cookie中是非法字符,需要替换处理,将其替换成非空格字符,注意cookie中的非法字符
Path: "/",
Domain: "localhost",
MaxAge: 120,
}
w.Header().Set("Set-Cookie",ck.String())
ck2, err := r.Cookie("myCookie")
if err != nil {
io.WriteString(w, err.Error())
return
}
io.WriteString(w, ck2.Value)
}
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6717