beego Getting Started 2
Adding and Deleting Articles
- Create 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 will use reflection to get all implemented methods in the struct, and you can access the corresponding methods in the following ways.
/object/logincalls the Login method in ObjectController/object/logoutcalls the Logout method in ObjectController
Besides matching the two prefixes /:controller/:method, beego will automatically parse the remaining URLs as parameters and save them in this.Ctx.Input.Params, as follows
/object/blog/2013/09/12 calls the Blog method in ObjectController, with parameters map[0:2013,1:09,2:12]
Now, all similar URLs below can be automatically recognized, and requests will be dispatched to the `simple` method of the controller. The suffix can be obtained via c.Ctx.Input.Param(":ext")
/controller/simple
/controller/simple.html
/controller/simple.json
/controller/simple.xml
There's a small pitfall when adding article categories (Chrome browser): Chrome prevents duplicate form submissions. If you previously added a category on that page, deleted it, and then tried to add it again, you might encounter an issue where the addition doesn't respond. This is because Chrome thinks you are submitting repeatedly. The solution is to add a token. To avoid polluting the interface, you can add an anchor.
Go Native Form Handling
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 File Upload
When uploading attachments, pay attention to the form's enctype="multipart/form-data". Add relevant fields in both AddTopic and ModifyTopic controllers.
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)
}
Native Way
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
}
Internationalization Support
bee new beegoi18n
cd beegoi18n && bee run
go get github.com/beego/i18n
dep ensure -add github.com/beego/i18n
// Nested routing
package controllers
import (
"github.com/astaxie/beego"
"github.com/beego/i18n"
)
// Create base to replace beego.Controller
type baseController struct {
beego.Controller
i18n.Locale
}
// Implemented Prepare() myself
// Specify language
// Register localization files local_en-US.ini or local_zh-CN.ini
func (this *baseController) Prepare() {
// Override
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"
}
// Register in main.go
func main() {
i18n.SetMessage("zh-CN","conf/local_zh-CN.ini")
i18n.SetMessage("en-US","conf/locale_en-US.ini")
// Then you can use Tr in the controller or Tr in the template
// To use in templates, you need to register the template function
beego.Run()
}
Sectioning Feature
about=About
[about]
about=About Us
{{i18n .Lang .About}} <br />
{{i18n .Lang .about.about}}
Custom HTTP Middleware
- As a type
- As a function
- Append response content
- Customize response content
// As a type
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)
}
// As a function
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)
}
// Normal 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) // Normal response
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() // Its purpose is virtual response, not actual response, to get normal response results,
this.handler.ServeHTTP(recoder, r) // recorded to recoder
for k, v := range recoder.Header() {
w.Header()[k] = v
}
// Custom operations
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"
Simple RPC Implementation
- Introduce Go-to-Go communication
- HTTP RPC
- TCP RPC
- JSON-RPC
// Based on HTTP
// server.go
package main
import (
"fmt"
"github.com/kataras/iris/core/errors"
"net/http"
"net/rpc"
)
type Args struct {
A, B int // First letter must be capitalized
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
// Division
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.go The types here can be extracted into a common reference
package main
import (
"fmt"
"log"
"net/rpc"
"os"
)
type Args struct {
A, B int // First letter must be capitalized
}
// Division
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)
}
Run go run http_rpc_client.go localhost in the command line
Based on TCP
// server
package main
import (
"fmt"
"github.com/kataras/iris/core/errors"
"net"
"net/rpc"
"os"
)
type Args struct {
A, B int // First letter must be capitalized
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
// Division
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())
//}
/*
TCP 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 only changed one line
package main
import (
"fmt"
"log"
"net/rpc"
"os"
)
type Args struct {
A, B int // First letter must be capitalized
}
// Division
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]
// Only changed one line: DialHTTP to 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)
}
JSON-RPC
// server
package main
import (
"fmt"
"github.com/kataras/iris/core/errors"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
type Args struct {
A, B int // First letter must be capitalized
}
type Math int
func (m *Math) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
// Division
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 // First letter must be capitalized
}
// Division
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]
// Only changed JSON-RPC
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)
}
Further Learning
- Introduction to REST (GET/POST/PUT/DELETE/PATCH)
- WebSocket
- Gorilla WebSocket Package
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6718