beego 开始 2
文章的添加与删除
- 创建 TopicController
// controllers中添加topic.go
package controllers
import "github.com/astaxie/beego"
type TopicController struct {
beego.Controller
}
func (c *TopicController) Get() {
c.Data["Title"] = "文章"
c.Data["IsTopic "] = true
c.TplName = "topic.html"
}
//路由routers中添加
beego.Router("/topic", &controllers.TopicController{})
// beego有一个自动路由功能
beego.AutoRouter(&controllers.TopicController{})
beego 就会通过反射获取结构体中所有实现的方法,你就可以通过如下的方式访问到对应的方法。
/object/login调用 ObjectController 中的 Login 方法/object/logout调用 ObjectController 中的 Logout 方法
除了前缀两个/:controller/:method的匹配之外,剩下的 url beego 会帮你自动化解析为参数,保存在 this.Ctx.Input.Params 中,如下
/object/blog/2013/09/12 调用 ObjectController 中的 Blog 方法,参数是 map[0:2013,1:09,2:12]
现在已经可以通过自动识别出来下面类似的所有 url,都会把请求分发到 controller 的 simple 方法, 可以通过c.Ctx.Input.Param(":ext")获取后缀名
/controller/simple
/controller/simple.html
/controller/simple.json
/controller/simple.xml
文章添类别添加时有个小坑(chrome 浏览器)chrome 有防止表单重复提交,如果你在该页面上之前添加过一个类别,删掉后再添加后出现,无法响应添加的问题,这是因为 chrome 认为你在重复提交。解决方法就是加个 token。为了不污染接口可以加锚点
go 原生表单处理
package main
import (
"fmt"
"html/template"
"net/http"
)
const tpl = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/" method="post">
name <input type="text" name="username"><br/>
pass <input type="password" name="pwd">
<button type="submit">提交</button>
</form>
</body>
</html>
`
func main() {
http.HandleFunc("/", SimpleForm)
http.ListenAndServe(":9898", nil)
}
func SimpleForm(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
fmt.Println(r.Method)
t:=template.New("hey")
t.Parse(tpl)
t.Execute(w,nil)
} else {
fmt.Println(r.FormValue("username"))
fmt.Println(r.FormValue("pwd"))
}
}
beego 文件上传
附件上传时注意表单的enctype="multipart/form-data",AddTopic 和 ModifyTopic 两个 controller 中添加相关字段
func (c *TopicController) Post() {
if !checkAccount(c.Ctx) {
c.Redirect("/login", 302)
return
}
//添加还是修改
title := c.Input().Get("title")
content := c.Input().Get("content")
tid := c.Input().Get("tid")
cate := c.Input().Get("cate")
labels := c.Input().Get("labels")
// ========上传================
//是否文件上传
_, fh, err := c.GetFile("attachment") //fh filehandler
if err != nil {
beego.Error(err)
}
var attachment string
if fh != nil {
//
attachment = fh.Filename
beego.Info(attachment)
err=c.SaveToFile("attachment",path.Join("attachment",attachment))
}
//=========上传结束(注意修改时要如果上传新的,要把旧的删除)==================
if len(tid) == 0 {
err = models.AddTopic(title, cate, labels, content,attachment)
} else {
err = models.ModifyTopic(tid, cate, title, labels, content,attachment)
}
if err != nil {
beego.Error(err)
return
}
c.Redirect("/topic", 302)
}
原生写法
func (c *Controller) SaveToFile(fromfile, tofile string) error {
file, _, err := c.Ctx.Request.FormFile(fromfile)
if err != nil {
return err
}
defer file.Close()
f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
io.Copy(f, file)
return nil
}
国际化支持
bee new beegoi18n
cd beegoi18n && bee run
go get github.com/beego/i18n
dep ensure -add github.com/beego/i18n
//嵌套路由
package controllers
import (
"github.com/astaxie/beego"
"github.com/beego/i18n"
)
//创建base 替代beego.Controller
type baseController struct {
beego.Controller
i18n.Locale
}
//自己实现了Prepare()
//指定语言
//注册本地化文件 local_en-US.ini 或 local_zh-CN.ini
func (this *baseController) Prepare() {
//重写
lang := this.GetString("lang")
if lang == "zh-CN" {
this.Lang = lang
} else {
this.Lang = "en-US"
}
}
type MainController struct {
baseController
}
func (c *MainController) Get() {
c.Data["Website"] = "beego.me"
c.Data["Email"] = "astaxie@gmail.com"
c.Data["Hi"] = "hi"
c.Data["Bye"]="bye"
c.TplName = "index.tpl"
}
// main.go中注册
func main() {
i18n.SetMessage("zh-CN","conf/local_zh-CN.ini")
i18n.SetMessage("en-US","conf/locale_en-US.ini")
//然后可以在控制器中Tr或在模板中Tr
// 在模板中使用要注册一下模板函数
beego.Run()
}
分区功能
about=About
[about]
about=About Us
{{i18n .Lang .About}} <br />
{{i18n .Lang .about.about}}
自建 HTTP 中间件
- 以类型形式
- 以函数形式
- 追回响应内容
- 自定义响应内容
// 以类型的形式
package main
import "net/http"
type SingleHost struct {
handler http.Handler
allowedHost string
}
func (this *SingleHost) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Host == this.allowedHost {
this.handler.ServeHTTP(w, r)
} else {
w.WriteHeader(403)
}
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello World!"))
}
func main() {
single := &SingleHost{
handler: http.HandlerFunc(myHandler),
allowedHost: "example.com",
}
http.ListenAndServe(":8080", single)
}
// 以函数的形式
package main
import "net/http"
func SingleHost(handler http.Handler, allowedHost string) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if r.Host == allowedHost {
handler.ServeHTTP(w, r)
} else {
w.WriteHeader(403)
}
}
return http.HandlerFunc(fn)
}
//正常处理的handler
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
func main() {
single := SingleHost(http.HandlerFunc(myHandler), "localhost:8080")
http.ListenAndServe(":8080", single)
}
package main
import "net/http"
type AppendMiddleware struct {
handler http.Handler
}
func (this *AppendMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
this.handler.ServeHTTP(w, r) //正常响应
w.Write([]byte("Hey, this is middleware!"))
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world"))
}
func main() {
mid := &AppendMiddleware{http.HandlerFunc(myHandler)}
http.ListenAndServe(":8080", mid)
}
package main
import (
"net/http"
"net/http/httptest"
)
type ModifierMiddleware struct {
handler http.Handler
}
func (this *ModifierMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
recoder := httptest.NewRecorder() //它的作用是虚拟响应,不是真正响应,获取正常的响应结果,
this.handler.ServeHTTP(recoder, r) //记录到recoder
for k, v := range recoder.Header() {
w.Header()[k] = v
}
// 自定义的一些操作
w.Header().Set("go-web-foundation", "vip")
w.WriteHeader(418)
w.Write([]byte("hey,this is middleware! "))
//
w.Write(recoder.Body.Bytes())
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
func main() {
mid := ModifierMiddleware{http.HandlerFunc(myHandler)}
http.ListenAndServe(":8080", &mid)
}
//curl --head "localhost:8080"
简易 RPC 实现
- 介绍一个 go--go 的通信
- http rpc
- tcp rpc
- json rpc
// 基于http
// server.go
package main
import (
"fmt"
"github.com/kataras/iris/core/errors"
"net/http"
"net/rpc"
)
type Args struct {
A, B int //首字母要大写
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
//除法
type Quotient struct {
Quo, Rem int
}
func (m *Math) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
math := new(Math)
rpc.Register(math)
rpc.HandleHTTP()
err := http.ListenAndServe(":1234", nil)
if err != nil {
fmt.Println(err.Error())
}
}
//client.og 类型这里可以抽成公共引用
package main
import (
"fmt"
"log"
"net/rpc"
"os"
)
type Args struct {
A, B int //首字母要大写
}
//除法
type Quotient struct {
Quo, Rem int
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage:", os.Args[0], "server")
os.Exit(1)
}
serverAddr := os.Args[1]
client, err := rpc.DialHTTP("tcp", serverAddr+":1234")
if err != nil {
log.Fatal("dialog:", err)
}
args := Args{17, 8}
var reply int
err = client.Call("Math.Multiply", args, &reply)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Println("Math:%d*%d=%d\n", args.A, args.B, reply)
var quo Quotient
err = client.Call("Math.Divide", args, &quo)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Println("Math:%d/%d=%d\n", args.A, args.B, quo.Quo, quo.Rem)
}
命令行下运行go run http_rpc_client.go localhost
基于 tcp 的
// server
package main
import (
"fmt"
"github.com/kataras/iris/core/errors"
"net"
"net/rpc"
"os"
)
type Args struct {
A, B int //首字母要大写
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
//除法
type Quotient struct {
Quo, Rem int
}
func (m *Math) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
math := new(Math)
rpc.Register(math)
//rpc.HandleHTTP()
//err := http.ListenAndServe(":1234", nil)
//if err != nil {
// fmt.Println(err.Error())
//}
/*
tpc的rpc
*/
tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
if err != nil {
fmt.Println("Fatal error:", err)
os.Exit(2)
}
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
fmt.Println("Fatal error:", err)
os.Exit(2)
}
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("conn error:", err)
continue
}
rpc.ServeConn(conn)
}
}
// client 只改了一行
package main
import (
"fmt"
"log"
"net/rpc"
"os"
)
type Args struct {
A, B int //首字母要大写
}
//除法
type Quotient struct {
Quo, Rem int
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage:", os.Args[0], "server")
os.Exit(1)
}
serverAddr := os.Args[1]
//只改一行DialHTTP改成Dial
client, err := rpc.Dial("tcp", serverAddr+":1234")
if err != nil {
log.Fatal("dialog:", err)
}
args := Args{17, 8}
var reply int
err = client.Call("Math.Multiply", args, &reply)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Println("Math:%d*%d=%d\n", args.A, args.B, reply)
var quo Quotient
err = client.Call("Math.Divide", args, &quo)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Println("Math:%d/%d=%d\n", args.A, args.B, quo.Quo, quo.Rem)
}
jsonrpc
// server
package main
import (
"fmt"
"github.com/kataras/iris/core/errors"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
type Args struct {
A, B int //首字母要大写
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
//除法
type Quotient struct {
Quo, Rem int
}
func (m *Math) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func main() {
math := new(Math)
rpc.Register(math)
tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234")
if err != nil {
fmt.Println("Fatal error:", err)
os.Exit(2)
}
listener, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
fmt.Println("Fatal error:", err)
os.Exit(2)
}
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("conn error:", err)
continue
}
jsonrpc.ServeConn(conn)
//rpc.ServeConn(conn)
}
}
// client
package main
import (
"fmt"
"log"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
type Args struct {
A, B int //首字母要大写
}
//除法
type Quotient struct {
Quo, Rem int
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage:", os.Args[0], "server")
os.Exit(1)
}
serverAddr := os.Args[1]
//只改jsonrpc
client, err := jsonrpc.Dial("tcp", serverAddr+":1234")
if err != nil {
log.Fatal("dialog:", err)
}
args := Args{17, 8}
var reply int
err = client.Call("Math.Multiply", args, &reply)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Println("Math:%d*%d=%d\n", args.A, args.B, reply)
var quo Quotient
err = client.Call("Math.Divide", args, &quo)
if err != nil {
log.Fatal("Math error:", err)
}
fmt.Println("Math:%d/%d=%d\n", args.A, args.B, quo.Quo, quo.Rem)
}
扩展学习
- REST 简介 (GET/POST/PUT/DELETE/PATCH)
- WebSocket
- Gorilla WebSocket 包
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6718