Web 开发之 Beego
使用 go get 安装 bee 工具与 beego
使用 bee 工具初始化 Beego 项目
- 在
$GOPATH/src目录下执行bee create myapp
使用 bee 工具热编译 Beego 项目
- 在
$GOPATH/src/myapp目录下执行bee start myapp
// 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
三个包 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.")
}
为ListenAdnServe第二个参数添加 handler
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.")
}
更底层的写处理 HttpServer
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")
}
对于 mux 的扩展静态服务
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)
}
}
bee 命令的使用
- 新建一个 web 项目
bee new myproject - 通过 api 命令可是用来创建 api 应用
bee api apiproject,其目录结构中我们可以看出少了 static 和 views 目录,多了一个 test 模块,用来做单元测试 bee run命令是监控 beego 的项目,通过 fsnotify 监控文件系统。但是注意该命令必须在$GOPATH/src/appname下执行bee packpack 目录用来发布应用的时候打包,会把项目打包成 zip 包,这样我们部署的时候直接把打包之后的项目上传,解压就可以部署了bee version查看 bee beego 和 go 的版本bee generate命令,用来自动化生成代码的,包含了从数据库一键生成 model,还包含了 scaffold
beego 配置管理
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)
}
模板
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}}
定义模板嵌套
{{define "test"}} 定义的模板块 {{end}}
<html>
<head></head>
<body>
{{template "test"}}
</body>
</html>
实战课 models 的建立
在 models 目录下创建 models.go 文件(别搞混了,和我们之前的那个 xorm 不是一个哈)
// 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()
}
登录及分类管理
拆分模板,将上例中的模板内容拆分成不同块以备后续开发复用使用。如将网页头问提取出来命名为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>首页</title>
</head>
<body style="padding-top: 70px">
{{end}}
</body>
</html>
在 home.html 模板中删除对应的内容,并改为 beego 模板引入语法;定义模板要用{{define "header"}} {{end}}
注意最后面的那个
.,如果在模板中使用使用变量则需要这个点,如果是纯静态资源可以省略
{{template "header" .}}
<!-- 模板输出变量{{.变量名}} -->
这里使用 glide 来做包管理工具,也会碰到 go get golang.org/x/不能下载问题,可以使用添加映像来管理;这里只添加了 tools net sys
~~坑已经狠狠的踩过了,千万不要用 glide~~ 还有个坑就是 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
别改一个标题请使用 dep
github,遇到 golang.org 下载不了问题看这里 。 基本上就是解决 terminal 下科学上网问题
cate 列表业务
<!-- 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" .}}
写业务
// 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