Programming Fundamentals 0003_Web_beego Development

Web Development with Beego

Install the bee tool and beego using go get

Initialize a Beego project using the bee tool

  • Execute bee create myapp in the $GOPATH/src directory

Hot compile a Beego project using the bee tool

  • Execute bee start myapp in the $GOPATH/src/myapp directory
// 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

Documentation

  • 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 run command monitors Beego projects by watching the file system with fsnotify. However, note that this command must be executed in the $GOPATH/src/appname directory.
  • The bee pack command 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 version command checks the versions of bee, beego, and Go.
  • The bee generate command 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

(0)
Walker的头像Walker
上一篇 12 hours ago
下一篇 15 hours ago

Related Posts

EN
简体中文 繁體中文 English