编程基础 0003_Web_beego开发

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 pack pack 目录用来发布应用的时候打包,会把项目打包成 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

(0)
Walker的头像Walker
上一篇 12小时前
下一篇 15小时前

相关推荐

  • Go工程师体系课 018

    API 网关与持续部署入门(Kong & Jenkins) 对应资料目录《第 2 章 Jenkins 入门》《第 3 章 通过 Jenkins 部署服务》,整理 Kong 与 Jenkins 在企业级持续交付中的实战路径。即便零基础,也能顺着步骤搭建出自己的网关 + 持续部署流水线。 课前导览:什么是 API 网关 API 网关位于客户端与后端微服务…

  • Go工程师体系课 002

    GOPATH 与 Go Modules 的区别 1. 概念 GOPATH 是 Go 的早期依赖管理机制。 所有的 Go 项目和依赖包必须放在 GOPATH 目录中(默认是 ~/go)。 一定要设置 GO111MODULE=off 项目路径必须按照 src/包名 的结构组织。 不支持版本控制,依赖管理需要手动处理(例如 go get)。 查找依赖包的顺序是 g…

    13小时前
    100
  • Go工程师体系课 015

    Docker 容器化 —— Go 项目实战指南 一、Docker 核心概念 1.1 什么是 Docker Docker 是一个开源的容器化平台,它可以将应用程序及其所有依赖项打包到一个标准化的单元(容器)中,从而实现"一次构建,到处运行"。对于 Go 开发者而言,Docker 解决了以下痛点: 开发环境与生产环境不一致 依赖管理复杂(数据库、缓存、消息队列等…

  • Go资深工程师讲解(慕课) 002

    go(二) string 字符串 package main import ( "fmt" "unicode/utf8" ) func main() { s := "Yes我爱Go语言" fmt.Println(len(s)) for _, b := range []byte(s) { fmt.Pri…

    后端开发 22小时前
    100
  • Go工程师体系课 008

    订单及购物车 先从库存服务中将 srv 的服务代码框架复制过来,查找替换对应的名称(order_srv) 加密技术基础 对称加密(Symmetric Encryption) 原理: 使用同一个密钥进行加密和解密 就像一把钥匙,既能锁门也能开门 加密速度快,适合大量数据传输 使用场景: 本地文件加密 数据库内容加密 大量数据传输时的内容加密 内部系统间的快速通…

简体中文 繁体中文 English