├── VERSION
├── zh-CN
├── database.md
├── middleware
│ ├── recovery.md
│ ├── accesslog.md
│ ├── nocache.md
│ ├── gzip.md
│ ├── static.md
│ ├── session.md
│ └── requestcache.md
├── component.md
├── component
│ ├── bat.md
│ ├── router.md
│ ├── log.md
│ ├── setting.md
│ ├── render.md
│ ├── pongo2.md
│ ├── pool.md
│ └── cache.md
├── log.md
├── middleware.md
├── di.md
├── baa.md
├── README.md
├── project.md
├── context.md
└── router.md
├── code
├── README.md
├── baa.go
├── middleware
│ ├── recovery.go
│ ├── accesslog.go
│ ├── nocache.go
│ ├── static.go
│ ├── middleware.go
│ ├── gzip.go
│ ├── requestcache.go
│ └── session.go
├── context
│ ├── main.go
│ └── template
│ │ └── index.html
├── di
│ └── di.go
├── component
│ └── cache.go
└── router
│ └── router.go
├── README.md
└── en-US
└── README.md
/VERSION:
--------------------------------------------------------------------------------
1 | 1.2.24
--------------------------------------------------------------------------------
/zh-CN/database.md:
--------------------------------------------------------------------------------
1 | # 数据库
2 |
3 | baa 本身并不提供任何数据库的内容,仅列出一些常见的数据库ORM库供参考:
4 |
5 | * [gorm](http://jinzhu.me/gorm/)
6 | * [xorm](http://xorm.io/)
7 | * [mgo](https://labix.org/mgo)
8 |
--------------------------------------------------------------------------------
/code/README.md:
--------------------------------------------------------------------------------
1 | # Baa
2 |
3 | an express Go web framework with routing, middleware, dependency injection, http context.
4 |
5 | Baa is ``no reflect``, ``no regexp``.
6 |
7 | ## Code
8 |
9 | example code for baa document
10 |
--------------------------------------------------------------------------------
/code/baa.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/go-baa/baa"
5 | )
6 |
7 | func main() {
8 | app := baa.Default()
9 | app.Get("/", func(c *baa.Context) {
10 | c.String(200, "Hello, 世界")
11 | })
12 | app.Run(":1323")
13 | }
14 |
--------------------------------------------------------------------------------
/code/middleware/recovery.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/recovery"
5 | "github.com/go-baa/baa"
6 | )
7 |
8 | func mainRecovery() {
9 | app := baa.Default()
10 | app.Use(recovery.Recovery())
11 |
12 | app.Get("/", func(c *baa.Context) {
13 | c.String(200, "Hello, 世界")
14 | })
15 |
16 | app.Run(":1323")
17 | }
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Baa
2 |
3 | an express Go web framework with routing, middleware, dependency injection, http context.
4 |
5 | Baa is ``no reflect``, ``no regexp``.
6 |
7 | ## Document
8 |
9 | * [简体中文](https://github.com/go-baa/doc/tree/master/zh-CN)
10 | * [English](https://github.com/go-baa/doc/tree/master/en-US)
11 | * [Doc Code](https://github.com/go-baa/doc/tree/master/code)
--------------------------------------------------------------------------------
/code/context/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import baa "github.com/go-baa/baa"
4 |
5 | func main() {
6 | app := baa.New()
7 | app.Get("/", func(c *baa.Context) {
8 | c.Set("title", "this is title")
9 | c.Set("content", "this is content")
10 | c.Set("show", true)
11 | c.Set("list", []string{"111", "222", "333"})
12 | c.HTML(200, "template/index.html")
13 | })
14 | app.Run(":1323")
15 | }
16 |
--------------------------------------------------------------------------------
/code/middleware/accesslog.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/accesslog"
5 | "github.com/baa-middleware/recovery"
6 | "github.com/go-baa/baa"
7 | )
8 |
9 | func mainAccesslog() {
10 | app := baa.Default()
11 | app.Use(recovery.Recovery())
12 | app.Use(accesslog.Logger())
13 |
14 | app.Get("/", func(c *baa.Context) {
15 | c.String(200, "Hello, 世界")
16 | })
17 |
18 | app.Run(":1323")
19 | }
20 |
--------------------------------------------------------------------------------
/code/di/di.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "os"
6 |
7 | "github.com/go-baa/baa"
8 | )
9 |
10 | func main() {
11 | app := baa.Default()
12 | app.SetDI("logger", log.New(os.Stderr, "[BaaDI] ", log.LstdFlags))
13 |
14 | app.Get("/", func(c *baa.Context) {
15 | // use di
16 | logger := c.DI("logger").(*log.Logger)
17 | logger.Println("i am use logger di")
18 |
19 | c.String(200, "Hello, 世界")
20 | })
21 |
22 | app.Run(":1323")
23 | }
24 |
--------------------------------------------------------------------------------
/code/middleware/nocache.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/accesslog"
5 | "github.com/baa-middleware/nocache"
6 | "github.com/baa-middleware/recovery"
7 | "github.com/go-baa/baa"
8 | )
9 |
10 | func mainNocache() {
11 | app := baa.Default()
12 | app.Use(recovery.Recovery())
13 | app.Use(accesslog.Logger())
14 | app.Use(nocache.New())
15 |
16 | app.Get("/", func(c *baa.Context) {
17 | c.String(200, "Hello, 世界")
18 | }, nocache.NewFunc())
19 |
20 | app.Run(":1323")
21 | }
22 |
--------------------------------------------------------------------------------
/code/middleware/static.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/accesslog"
5 | "github.com/baa-middleware/recovery"
6 | "github.com/baa-middleware/static"
7 | "github.com/go-baa/baa"
8 | )
9 |
10 | func mainStatic() {
11 | app := baa.Default()
12 | app.Use(recovery.Recovery())
13 | app.Use(accesslog.Logger())
14 |
15 | // static
16 | app.Use(static.Static("/assets", "public/assets", false, nil))
17 |
18 | app.Get("/", func(c *baa.Context) {
19 | c.String(200, "Hello, 世界")
20 | })
21 |
22 | app.Run(":1323")
23 | }
24 |
--------------------------------------------------------------------------------
/code/middleware/middleware.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/go-baa/baa"
7 | )
8 |
9 | func main() {
10 | app := baa.Default()
11 | app.Use(func(c *baa.Context) {
12 | // 进入,记录时间
13 | start := time.Now()
14 |
15 | // 接着执行其他中间件
16 | c.Next()
17 |
18 | // 执行完其他的,最后,输出请求日志
19 | c.Baa().Logger().Printf("%s %s %s %v %v", c.RemoteAddr(), c.Req.Method, c.URL(false), c.Resp.Status(), time.Since(start))
20 | })
21 |
22 | app.Get("/", func(c *baa.Context) {
23 | c.String(200, "Hello, 世界")
24 | })
25 |
26 | app.Run(":1323")
27 | }
28 |
--------------------------------------------------------------------------------
/code/middleware/gzip.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/accesslog"
5 | "github.com/baa-middleware/gzip"
6 | "github.com/baa-middleware/recovery"
7 | "github.com/go-baa/baa"
8 | )
9 |
10 | func mainGzip() {
11 | app := baa.Default()
12 | app.Use(recovery.Recovery())
13 | app.Use(accesslog.Logger())
14 |
15 | if baa.Env == baa.PROD {
16 | app.Use(gzip.Gzip(gzip.Options{
17 | CompressionLevel: 9,
18 | }))
19 | }
20 |
21 | app.Get("/", func(c *baa.Context) {
22 | c.String(200, "Hello, 世界")
23 | })
24 |
25 | app.Run(":1323")
26 | }
27 |
--------------------------------------------------------------------------------
/zh-CN/middleware/recovery.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 错误恢复
2 |
3 | `github.com/baa-middleware/recovery`
4 |
5 | 错误恢复中间件提供了当业务逻辑`Panic`时记录日志和返回500错误,并且`recovey`Go的程序,防止一个业务中的错误导致应用崩溃。
6 |
7 | ## 使用
8 |
9 | ```
10 | package main
11 |
12 | import (
13 | "github.com/baa-middleware/recovery"
14 | "github.com/go-baa/baa"
15 | )
16 |
17 | func main() {
18 | app := baa.Default()
19 | app.Use(recovery.Recovery())
20 |
21 | app.Get("/", func(c *baa.Context) {
22 | c.String(200, "Hello, 世界")
23 | })
24 |
25 | app.Run(":1323")
26 | }
27 | ```
28 |
29 | 建议该中间件的注册顺序为`第一`,防止其他中间件本身就有错误导致应用崩溃。
30 |
--------------------------------------------------------------------------------
/zh-CN/component.md:
--------------------------------------------------------------------------------
1 | # Baa 组件
2 |
3 | 在日常工作,我们结合 baa 开发了一些常用组件。
4 |
5 | * baa开发工具 [bat](https://github.com/go-baa/doc/tree/master/zh-CN/component/bat.md)
6 | * 缓存库 [cache](https://github.com/go-baa/doc/tree/master/zh-CN/component/cache.md)
7 | * 连接池 [pool](https://github.com/go-baa/doc/tree/master/zh-CN/component/pool.md)
8 | * pongo2插件 for baa [pongo2](https://github.com/go-baa/doc/tree/master/zh-CN/component/pongo2.md)
9 | * 增强的模板渲染 for baa [render](https://github.com/go-baa/doc/tree/master/zh-CN/component/render.md)
10 | * 正则路由 for baa [router](https://github.com/go-baa/doc/tree/master/zh-CN/component/router.md)
11 |
--------------------------------------------------------------------------------
/code/context/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ .title }}
6 |
7 |
8 |
9 |
10 | {{ .content}}
11 |
12 |
13 |
14 |
15 | {{ if .show}}
16 | i want show!
17 | {{ else }}
18 | i was hidden
19 | {{ end }}
20 |
21 |
22 |
23 |
24 | {{ range .list }}
25 | {{ . }}
26 | {{ end }}
27 |
28 |
29 |
30 | {{ . }}
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/code/component/cache.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/go-baa/baa"
5 | "github.com/go-baa/cache"
6 | )
7 |
8 | func main() {
9 | // new app
10 | app := baa.New()
11 |
12 | // register cache
13 | app.SetDI("cache", cache.New(cache.Options{
14 | Name: "cache",
15 | Prefix: "MyApp",
16 | Adapter: "memory",
17 | Config: map[string]interface{}{},
18 | }))
19 |
20 | // router
21 | app.Get("/", func(c *baa.Context) {
22 | ca := c.DI("cache").(cache.Cacher)
23 | ca.Set("test", "baa", 10)
24 | var v string
25 | ca.Get("test", &v)
26 | c.String(200, v)
27 | })
28 |
29 | // run app
30 | app.Run(":1323")
31 | }
32 |
--------------------------------------------------------------------------------
/zh-CN/component/bat.md:
--------------------------------------------------------------------------------
1 | # Baa bat
2 |
3 | `https://github.com/go-baa/bat`
4 |
5 | bat 是一个帮助快速开发 baa 程序的小工具。
6 |
7 | 代码fork自 [beego](https://github.com/astaxie/beego/) 的 [bee](https://github.com/beego/bee)。
8 |
9 | ## 使用
10 |
11 | ### 安装
12 |
13 | ```
14 | go get -u github.com/go-baa/bat
15 | ```
16 |
17 | ## 运行baa程序
18 |
19 | ```
20 | bat run [-x=.go -x=.ini] [-a=../model] [-e=Godeps -e=folderToExclude] [-tags=goBuildTags]
21 | ```
22 |
23 | 默认情况下监控运行目录下的 `.go`文件,发生变化就会重新编译并运行。
24 |
25 | ### godeps
26 |
27 | bat 默认开启了 `godeps` 支持,如果项目下存在 `Godeps`目录,每次重新构建都会重建 `Godeps`。
28 |
29 | 可以通过以下参数关闭该特性:
30 |
31 | ```
32 | bat run -godeps=false
33 | ```
34 |
--------------------------------------------------------------------------------
/zh-CN/middleware/accesslog.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 访问日志
2 |
3 | `github.com/baa-middleware/accesslog`
4 |
5 | 访问日志中间件提供了简单的HTTP访问日志,记录了请求方法,来源IP,URL地址,响应码,发送数据,以及访问时间。
6 |
7 | 可以应付简单的日志需求,而且这个中间件只有三行代码,你可以任意定制修改。
8 |
9 | 这个中间件是学习中间件姿势的`范例`。
10 |
11 | ## 使用
12 |
13 | ```
14 | package main
15 |
16 | import (
17 | "github.com/baa-middleware/accesslog"
18 | "github.com/baa-middleware/recovery"
19 | "github.com/go-baa/baa"
20 | )
21 |
22 | func main() {
23 | app := baa.Default()
24 | app.Use(recovery.Recovery())
25 | app.Use(accesslog.Logger())
26 |
27 | app.Get("/", func(c *baa.Context) {
28 | c.String(200, "Hello, 世界")
29 | })
30 |
31 | app.Run(":1323")
32 | }
33 | ```
34 |
35 | 建议该中间件的注册顺序为`第二`,可以更加精准的获取业务的执行时间。
36 |
--------------------------------------------------------------------------------
/zh-CN/component/router.md:
--------------------------------------------------------------------------------
1 | # Baa router
2 |
3 | `https://github.com/go-baa/router`
4 |
5 | 路由项目提供了额外的路由器实现。
6 |
7 | * regexp 完全使用正则表达式的路由器,在复杂路由多为正则表达式的情况下,效率稍好。
8 | * regtree 使用正则表达式和基数树组合优化的路由器,在多数路由为普通路由,少量正则路由条目的情况下,效率较好。
9 |
10 | 如果没有大量的正则表达式路由条目,建议使用 `regtree` 作为默认的 `正则路由`。
11 |
12 | ## 使用
13 |
14 | 通过 `DI` 替换掉全局的 `router` 即可。
15 |
16 | ```
17 | package main
18 |
19 | import (
20 | "github.com/go-baa/router/regtree"
21 | "github.com/go-baa/baa"
22 | )
23 |
24 | func main() {
25 | app := baa.Default()
26 | app.SetDI("router", regtree.New(app))
27 |
28 | app.Get("/view-:id(\\d+)", func(c *baa.Context) {
29 | c.String(200, c.Param("id"))
30 | })
31 | app.Get("/view-:id(\\d+)/project", func(c *baa.Context) {
32 | c.String(200, c.Param("id")+"/project")
33 | })
34 | app.Run(":1323")
35 | }
36 | ```
37 |
--------------------------------------------------------------------------------
/zh-CN/middleware/nocache.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 强制不缓存
2 |
3 | `github.com/baa-middleware/nocache`
4 |
5 | 强制不缓存中间件给所有请求增加了NO-CACHE Header头,防止浏览器或CDN缓存。
6 |
7 | ## 使用
8 |
9 | ```
10 | package main
11 |
12 | import (
13 | "github.com/baa-middleware/accesslog"
14 | "github.com/baa-middleware/nocache"
15 | "github.com/baa-middleware/recovery"
16 | "github.com/go-baa/baa"
17 | )
18 |
19 | func main() {
20 | app := baa.Default()
21 | app.Use(recovery.Recovery())
22 | app.Use(accesslog.Logger())
23 | app.Use(nocache.New())
24 |
25 | app.Get("/", func(c *baa.Context) {
26 | c.String(200, "Hello, 世界")
27 | }, nocache.NewFunc())
28 |
29 | app.Run(":1323")
30 | }
31 |
32 | ```
33 |
34 | 强制不缓存中间件提供了两个方法:
35 |
36 | ```
37 | nocache.New()
38 | ```
39 |
40 | 返回一个中间件,用于中间件注册。
41 |
42 | ```
43 | nocache.NewFunc()
44 | ```
45 |
46 | 返回一个路由处理函数,用于给指定的路由请求增加NO-CACHE设定。
47 |
--------------------------------------------------------------------------------
/zh-CN/component/log.md:
--------------------------------------------------------------------------------
1 | # Baa log
2 |
3 | `https://github.com/go-baa/log`
4 |
5 | 一个增强的日志管理器实现。
6 |
7 | 相比标准库中的 `log` 增加了如下特性:
8 |
9 | * 可配置日志级别,Info/Warn/Error/Debug
10 | * 更多的日志方法
11 | * 优化的日志写入
12 | * 开箱即用的设置
13 |
14 | ## 安装
15 |
16 | * 依赖 [setting](github.com/go-baa/setting) 包
17 | * 可选配置文件:`conf/app.ini`
18 |
19 | ```
20 | go get -u github.com/go-baa/setting
21 | go get -u github.com/go-baa/log
22 | ```
23 |
24 | ## 使用
25 |
26 | ```
27 | package main
28 |
29 | import (
30 | "github.com/go-baa/log"
31 | )
32 |
33 | func main() {
34 | log.Println("xx")
35 | log.Debugln("xx")
36 | }
37 | ```
38 |
39 | ## 配置
40 |
41 | 配置,依赖 `setting` 配置文件,请在配置文件中加入以下配置:
42 |
43 | ```
44 | // conf/app.ini
45 | [default]
46 | # output log to os.Stderr or filepath
47 | log.file = os.Stderr
48 | # 0 off, 1 fatal, 2 panic, 5 error, 6 warn, 10 info, 11 debug
49 | log.level = 11
50 | ```
51 |
52 | `log.file` 指定日志输出路径,可以是具体的文件,也可以是 `os.Stderr` 或 `os.Stdout`
53 | `log.level` 日志级别,默认是 `5`,级别越大输出的错误越详细
54 |
--------------------------------------------------------------------------------
/code/middleware/requestcache.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/accesslog"
5 | "github.com/baa-middleware/recovery"
6 | "github.com/baa-middleware/requestcache"
7 | "github.com/go-baa/baa"
8 | "github.com/go-baa/cache"
9 | )
10 |
11 | func mainRequestcache() {
12 | app := baa.Default()
13 | app.Use(recovery.Recovery())
14 | app.Use(accesslog.Logger())
15 |
16 | // request cache middleware
17 | app.Use(requestcache.Middleware(requestcache.Option{
18 | Enabled: true,
19 | Expires: requestcache.DefaultExpires, // 1 minute
20 | Headers: map[string]string{
21 | "X-DIY": "baa",
22 | },
23 | ContextRelated: false,
24 | }))
25 |
26 | // request cache depend cacher
27 | app.SetDI("cache", cache.New(cache.Options{
28 | Name: "pageCache",
29 | Prefix: "MyApp",
30 | Adapter: "memory",
31 | Config: map[string]interface{}{
32 | "bytesLimit": int64(128 * 1024 * 1024), // 128m
33 | },
34 | }))
35 |
36 | app.Get("/", func(c *baa.Context) {
37 | c.String(200, "Hello, 世界")
38 | })
39 |
40 | app.Run(":1323")
41 | }
42 |
--------------------------------------------------------------------------------
/zh-CN/component/setting.md:
--------------------------------------------------------------------------------
1 | # Baa setting
2 |
3 | `https://github.com/go-baa/setting`
4 |
5 | 应用配置和配置文件管理
6 |
7 | > 注意: 配置文件被硬编码为 `./conf/app.ini`,必须放在这个路径
8 |
9 | ## 示例
10 |
11 | ```
12 | // conf/app.ini
13 | [default]
14 | # app
15 | app.name = baaBlog
16 | app.version = 0.1
17 | app.url = ""
18 | debug = false
19 |
20 | # http
21 | http.address = 0.0.0.0
22 | http.port = 80
23 | http.access_open = off
24 |
25 | # output log to os.Stderr
26 | log.file = os.Stderr
27 | # 0 off, 1 fatal, 2 panic, 5 error, 6 warn, 10 info, 11 debug
28 | log.level = 11
29 |
30 | # development mode overwrite default config
31 | [development]
32 | debug = true
33 |
34 | # production mode overwrite default config
35 | [production]
36 | debug = false
37 | ```
38 |
39 | ## 使用
40 |
41 | ```
42 | package main
43 |
44 | import "github.com/go-baa/setting"
45 |
46 | func main() {
47 | appName := setting.AppName
48 | httpAddress := setting.Config.MustString("http.address", "127.0.0.1")
49 | httpPort := setting.Config.MustInt("http.port", 1323)
50 | httpAccessOpen := setting.Config.MustBool("http.access_open", false)
51 | }
52 | ``
53 |
--------------------------------------------------------------------------------
/zh-CN/middleware/gzip.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 Gzip
2 |
3 | `github.com/baa-middleware/gzip`
4 |
5 | Gzip中间件提供了HTTP内容输出的Gzip配置和处理,可以减小网络传输。
6 |
7 | ## 使用
8 |
9 | ```
10 | package main
11 |
12 | import (
13 | "github.com/baa-middleware/accesslog"
14 | "github.com/baa-middleware/gzip"
15 | "github.com/baa-middleware/recovery"
16 | "github.com/go-baa/baa"
17 | )
18 |
19 | func main() {
20 | app := baa.Default()
21 | app.Use(recovery.Recovery())
22 | app.Use(accesslog.Logger())
23 |
24 | if baa.Env == baa.PROD {
25 | app.Use(gzip.Gzip(gzip.Options{
26 | CompressionLevel: 9,
27 | }))
28 | }
29 |
30 | app.Get("/", func(c *baa.Context) {
31 | c.String(200, "Hello, 世界")
32 | })
33 |
34 | app.Run(":1323")
35 | }
36 | ```
37 |
38 | 在该示例中,注册了 gzip 仅在baa的产品模式开启,因为调试模式下开启gzip会导致500错误时不能正常浏览错误信息。这算不算这个BUG?
39 |
40 | ## 配置
41 |
42 | ### CompressionLevel `int`
43 |
44 | 压缩级别,参数值范围 -1 ~ 9,在 官方包中有定义,还给出了几个常量值的意义:
45 |
46 | https://golang.org/pkg/compress/flate/#pkg-constants
47 |
48 | ```
49 | const (
50 | NoCompression = 0
51 | BestSpeed = 1
52 | BestCompression = 9
53 | DefaultCompression = -1
54 | )
55 | ```
56 |
57 |
--------------------------------------------------------------------------------
/zh-CN/log.md:
--------------------------------------------------------------------------------
1 | # Baa 日志
2 |
3 | baa 中的日志默认使用的是标准包中的 `log`,可以通过 `DI` 来替换全局的日志器。
4 |
5 | 新的日志器要求实现 `baa.Logger` 接口,并且注册的 `DI` 名称为 `logger`,如果不更换默认的日志则名称任意。
6 |
7 | ## 日志接口
8 |
9 | ```
10 | type Logger interface {
11 | Print(v ...interface{})
12 | Printf(format string, v ...interface{})
13 | Println(v ...interface{})
14 | Fatal(v ...interface{})
15 | Fatalf(format string, v ...interface{})
16 | Fatalln(v ...interface{})
17 | Panic(v ...interface{})
18 | Panicf(format string, v ...interface{})
19 | Panicln(v ...interface{})
20 | }
21 | ```
22 |
23 | 这个接口其实是对标准包`log`的抽象,最基础的日志接口。
24 |
25 | ## 日志方法
26 |
27 | 假如你实现了新的日志管理,使用的姿势像这样:
28 |
29 | ```
30 | app := baa.New()
31 | app.SetDI("logger", newLogger.New())
32 | app.Get("/", func(c *baa.Context) {
33 | lg := c.DI("logger").(*newLogger.Logger)
34 | lg.Println("log line")
35 | })
36 | ```
37 |
38 | 其中 `newLogger` 意为你实现的新的日志器。
39 |
40 | ### 记录日志
41 |
42 | `func (b *Baa) Logger() Logger`
43 |
44 | baa 提供的全局日志器可以通过`app.Logger()` 获得到。
45 |
46 | 举个例子:
47 |
48 | ```
49 | app := baa.New()
50 | app.Get("/", func(c *baa.Context) {
51 | lg := c.Baa().Logger()
52 | lg.Println("log line")
53 | })
54 | ```
55 |
56 | 除了 `Println` 你可以使用日志接口中的所有方法。
57 |
--------------------------------------------------------------------------------
/zh-CN/middleware/static.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 静态资源优先
2 |
3 | `github.com/baa-middleware/static`
4 |
5 | 静态资源优先中间件,根据配置的`prefix`拦截路由,如果能匹配到静态资源则直接返回静态资源,否则进入路由匹配。
6 |
7 | 因为 `baa` 是一个自由的web开发框架,默认的路由行为就是一切都是 `404`,并不像 nginx/apache 等web服务器,只要有对应路径的静态文件就会显示。
8 |
9 | ## 使用
10 |
11 | ```
12 | package main
13 |
14 | import (
15 | "github.com/baa-middleware/accesslog"
16 | "github.com/baa-middleware/recovery"
17 | "github.com/baa-middleware/static"
18 | "github.com/go-baa/baa"
19 | )
20 |
21 | func mainStatic() {
22 | app := baa.Default()
23 | app.Use(recovery.Recovery())
24 | app.Use(accesslog.Logger())
25 |
26 | // static
27 | app.Use(static.Static("/assets", "public/assets", false, nil))
28 |
29 | app.Get("/", func(c *baa.Context) {
30 | c.String(200, "Hello, 世界")
31 | })
32 |
33 | app.Run(":1323")
34 | }
35 | ```
36 |
37 | ## 配置
38 |
39 | ```
40 | func Static(prefix, dir string, index bool, h baa.HandlerFunc) baa.HandlerFunc
41 | ```
42 |
43 | ### prefix `string`
44 |
45 | URI匹配前缀,如:/public, /assets
46 |
47 | ### dir `string`
48 |
49 | 静态资源路径,可以使用绝对路径,或者相对于运行路径的路径。
50 |
51 | ### index `bool`
52 |
53 | 是否运行列出目录。
54 |
55 | ### h `baa.HandlerFunc`
56 |
57 | 附件方法,传入一个 baa.Context 运行对输入和输出做处理。
58 |
59 |
--------------------------------------------------------------------------------
/code/middleware/session.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/baa-middleware/accesslog"
5 | "github.com/baa-middleware/recovery"
6 | "github.com/baa-middleware/session"
7 | "github.com/go-baa/baa"
8 | )
9 |
10 | func mainSession() {
11 | app := baa.Default()
12 | app.Use(recovery.Recovery())
13 | app.Use(accesslog.Logger())
14 |
15 | // session config
16 | redisOptions := session.RedisOptions{}
17 | redisOptions.Addr = "127.0.0.1:6379"
18 | redisOptions.Prefix = "Prefix:"
19 |
20 | memoryOptions := session.MemoryOptions{
21 | BytesLimit: 1024 * 1024,
22 | }
23 |
24 | app.Use(session.Middleware(session.Options{
25 | Name: "BAASESSIONID",
26 | Provider: &session.ProviderOptions{
27 | Adapter: "memory", // redis / memory
28 | Config: memoryOptions,
29 | },
30 | }))
31 |
32 | app.Get("/", func(c *baa.Context) {
33 | // get the session handler
34 | session := c.Get("session").(*session.Session)
35 | session.Set("hi", "baa")
36 |
37 | c.String(200, "Hello, 世界")
38 | })
39 |
40 | app.Get("/session", func(c *baa.Context) {
41 | // get the session handler
42 | session := c.Get("session").(*session.Session)
43 | c.String(200, "SessionID: "+session.ID()+", hi, "+session.Get("hi").(string))
44 | })
45 |
46 | app.Run(":1323")
47 | }
48 |
--------------------------------------------------------------------------------
/zh-CN/component/render.md:
--------------------------------------------------------------------------------
1 | # Baa render
2 |
3 | `https://github.com/go-baa/render`
4 |
5 | render 是一个 增强型模板引擎,相对 baa 内置的模板引擎有如下特性:
6 |
7 | - 模板容器,可以使用 `template` 语法加载模板片段.
8 | - 模板缓存,在程序启动时即加载所有模板到内存中执行预编译,并且可以感知文件变化自动重新编译.
9 | - 可定制模板目录,模板文件扩张名,支持扩充模板函数.
10 |
11 | ## 使用
12 |
13 | 通过 `DI` 注册 `render` 即可。
14 |
15 | ```
16 | package main
17 |
18 | import (
19 | "github.com/go-baa/render"
20 | "github.com/go-baa/baa"
21 | )
22 |
23 | func main() {
24 | // new app
25 | app := baa.New()
26 |
27 | // register render
28 | // render is template DI for baa, must this name.
29 | app.SetDI("render", render.New(render.Options{
30 | Baa: app,
31 | Root: "templates/",
32 | Extensions: []string{".html", ".tmpl"},
33 | }))
34 |
35 | // router
36 | app.Get("/", func(c *baa.Context) {
37 | c.HTML(200, "index")
38 | })
39 |
40 | // run app
41 | app.Run(":1323")
42 | }
43 | ```
44 |
45 | ## 配置 `render.Options`
46 |
47 | ### Baa `*baa.Baa`
48 |
49 | render 需要传递 baa 实例
50 |
51 | ### Root `string`
52 |
53 | 模板目录,指定模板目录,`c.HTML` 渲染模板时将从该目录下查找目录,不需要在渲染是指定目录名。
54 |
55 | ### Extensions `[]string`
56 |
57 | 模板文件扩展名,可以指定多个,渲染模板时无需指定扩展名,将根据配置寻找对应的文件。
58 |
59 | ### Functions `map[string]interface{}`
60 |
61 | 扩展函数,参考:[FuncMap](https://godoc.org/html/template#FuncMap)
62 |
63 | ## 扩展语法
64 |
65 | ### 加载模板片段
66 |
67 | ```
68 | {{ template "share/footer" }}
69 | ```
70 |
--------------------------------------------------------------------------------
/zh-CN/middleware.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件
2 |
3 | baa 支持通过 `中间件` 机制注入请求过程,实现类似插件的功能。
4 |
5 | 根据注册的顺序依次执行,在整个执行过程中通过共享 `Context` 来实现数据传递和流程控制。
6 |
7 | 多个中间件的交替运行以 `Context.Next()` 和 `Context.Break()` 方法来控制和转换。
8 |
9 | > 路由执行时,中间件和路由方法会组成链式操作,中间件优先路由方法先进入执行。
10 |
11 | ## 编写中间件
12 |
13 | ```
14 | func (b *Baa) Use(m ...Middleware)
15 | ```
16 |
17 | 通过 `Use` 方法就可以注册一个中间件,接收多个 `Middleware` 类型。
18 |
19 | ```
20 | type Middleware interface{}
21 | ```
22 |
23 | 举个例子
24 |
25 | ```
26 | package main
27 |
28 | import (
29 | "time"
30 |
31 | "github.com/go-baa/baa"
32 | )
33 |
34 | func main() {
35 | app := baa.Default()
36 |
37 | app.Use(func(c *baa.Context) {
38 | // 进入,记录时间
39 | start := time.Now()
40 |
41 | // 接着执行其他中间件
42 | c.Next()
43 |
44 | // 执行完其他的,最后,输出请求日志
45 | c.Baa().Logger().Printf("%s %s %s %v %v", c.RemoteAddr(), c.Req.Method, c.URL(false), c.Resp.Status(), time.Since(start))
46 | })
47 |
48 | app.Get("/", func(c *baa.Context) {
49 | c.String(200, "Hello, 世界")
50 | })
51 |
52 | app.Run(":1323")
53 | }
54 | ```
55 |
56 | 看上面的例子,整个中间件只有三句代码,要说明的是,输出日志放在了 `c.Next()` 之后执行时为了获得业务的执行时间,并没有要求必须放在那儿,只要有 `c.Next()` 就可以了。
57 |
58 | 最后,在中间件过程中,如果要中断路由操作提前退出,可以使用 `c.Break()`。
59 |
60 | > 其实,上面的示例就是我们的 [accesslog](https://github.com/baa-middleware/accesslog) 中间件。
61 |
62 | ## 使用中间件
63 |
64 | 我们已经编写了一些常用的中间件,可以直接引入使用。
65 |
66 | 1. import
67 | 2. Use
68 |
69 | 使用示例:
70 |
71 | ```
72 | package main
73 |
74 | import (
75 | "github.com/baa-middleware/accesslog"
76 | "github.com/go-baa/baa"
77 | )
78 |
79 | func main() {
80 | app := baa.Default()
81 | app.Use(accesslog.Logger())
82 |
83 | app.Get("/", func(c *baa.Context) {
84 | c.String(200, "Hello, 世界")
85 | })
86 |
87 | app.Run(":1323")
88 | }
89 | ```
90 |
91 | 不同的中间件在引入的时候,可能有不同的参数,注意看各个组件部分的文档介绍。
92 |
--------------------------------------------------------------------------------
/en-US/README.md:
--------------------------------------------------------------------------------
1 | # Baa
2 |
3 | an express Go web framework with routing, middleware, dependency injection, http context.
4 |
5 | Baa is ``no reflect``, ``no regexp``.
6 |
7 | ## Getting Started
8 |
9 | Install:
10 |
11 | ```
12 | go get -u github.com/go-baa/baa
13 | ```
14 |
15 | Example:
16 |
17 | ```
18 | // baa.go
19 | package main
20 |
21 | import (
22 | "github.com/go-baa/baa"
23 | )
24 |
25 | func main() {
26 | app := baa.New()
27 | app.Get("/", func(c *baa.Context) {
28 | c.String(200, "Hello, 世界")
29 | })
30 | app.Run(":1323")
31 | }
32 | ```
33 |
34 | Run:
35 |
36 | ```
37 | go run baa.go
38 | ```
39 |
40 | Explore:
41 |
42 | ```
43 | http://127.0.0.1:1323/
44 | ```
45 |
46 | ## Features
47 |
48 | * route support static, param, group
49 | * route support handler chain
50 | * route support static file serve
51 | * middleware supoort handle chain
52 | * dependency injection support*
53 | * context support JSON/JSONP/XML/HTML response
54 | * centralized HTTP error handling
55 | * centralized log handling
56 | * whichever template engine support(emplement baa.Renderer)
57 |
58 | ## Examples
59 |
60 | https://github.com/go-baa/example
61 |
62 | * [blog](https://github.com/go-baa/example/tree/master/blog)
63 |
64 | ## Middlewares
65 |
66 | * [gzip](https://github.com/baa-middleware/gzip)
67 | * [accesslog](https://github.com/baa-middleware/accesslog)
68 | * [recovery](https://github.com/baa-middleware/recovery)
69 | * [session](https://github.com/baa-middleware/session)
70 | * [static](https://github.com/baa-middleware/static)
71 | * [requestcache](https://github.com/baa-middleware/requestcache)
72 | * [nocache](https://github.com/baa-middleware/nocache)
73 | * [jwt](https://github.com/baa-middleware/jwt)
74 | * [cors](https://github.com/baa-middleware/cors)
75 |
76 | ## Components
77 |
78 | * [cache](https://github.com/go-baa/cache)
79 | * [render](https://github.com/go-baa/render)
80 | * [pongo2](https://github.com/go-baa/pongo2)
81 | * [router](https://github.com/go-baa/router)
82 | * [pool](https://github.com/go-baa/pool)
83 | * [bat](https://github.com/go-baa/bat)
84 |
85 |
--------------------------------------------------------------------------------
/code/router/router.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/go-baa/baa"
7 | "github.com/go-baa/router/regtree"
8 | )
9 |
10 | func main() {
11 | app := baa.New()
12 | app.SetDI("router", regtree.New(app))
13 |
14 | // normal
15 | app.Get("/", func(c *baa.Context) {
16 | c.String(200, "Hello, 世界")
17 | })
18 | app.Post("/", func(c *baa.Context) {
19 | c.String(200, c.Req.Method)
20 | })
21 | app.Get("/admin", func(c *baa.Context) {
22 | if c.GetCookie("login_id") != "admin" {
23 | c.Redirect(302, "/login")
24 | c.Break()
25 | }
26 | }, func(c *baa.Context) {
27 | c.String(200, "恭喜你,看到后台了")
28 | })
29 | app.Get("/login", func(c *baa.Context) {
30 | c.Resp.Header().Set("Content-Type", "text/html; charset=utf-8")
31 | c.SetCookie("login_id", "admin", 3600, "/")
32 | c.Resp.Write([]byte("登录成功,点击进入后台"))
33 | })
34 |
35 | // static route
36 | app.Get("/foo", func(c *baa.Context) {
37 | c.String(200, c.URL(true))
38 | })
39 | app.Get("/bar", func(c *baa.Context) {
40 | c.String(200, c.URL(true))
41 | })
42 |
43 | // param route
44 | app.Get("/user/:id", func(c *baa.Context) {
45 | c.String(200, "My user id is: "+c.Param("id"))
46 | })
47 | app.Get("/user/:id/project/:pid", func(c *baa.Context) {
48 | id := c.ParamInt("id")
49 | pid := c.ParamInt("pid")
50 | c.String(200, fmt.Sprintf("user id: %d, project id: %d", id, pid))
51 | })
52 |
53 | // regexp route
54 | app.Get("/user-:id(\\d+)", func(c *baa.Context) {
55 | c.String(200, "My user id is: "+c.Param("id"))
56 | })
57 | app.Get("/user-:id(\\d+)-project-:pid(\\d+)", func(c *baa.Context) {
58 | id := c.ParamInt("id")
59 | pid := c.ParamInt("pid")
60 | c.String(200, fmt.Sprintf("user id: %d, project id: %d", id, pid))
61 | })
62 |
63 | // group
64 | app.Group("/group", func() {
65 | app.Get("/", func(c *baa.Context) {
66 | c.String(200, "我是组的首页")
67 | })
68 | app.Group("/user", func() {
69 | app.Get("/", func(c *baa.Context) {
70 | c.String(200, "我是组的用户")
71 | })
72 | app.Get("/:id", func(c *baa.Context) {
73 | c.String(200, "in group, user id: "+c.Param("id"))
74 | })
75 | })
76 | app.Get("/:gid", func(c *baa.Context) {
77 | c.String(200, "in group, group id: "+c.Param("gid"))
78 | })
79 | }, func(c *baa.Context) {
80 | // 我是组内的前置检测,过不了我这关休想访问组内的资源
81 | })
82 |
83 | app.Run(":1323")
84 | }
85 |
--------------------------------------------------------------------------------
/zh-CN/middleware/session.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 session
2 |
3 | `github.com/baa-middleware/session`
4 |
5 | Go中的HTTP包默认提供了对cookie的管理,但是session并没有,需要各显神通,这就是一个简单的实现。
6 |
7 | session 中间件提供了对session的管理和使用,支持 redis/memory 适配器。
8 |
9 | ## 使用
10 |
11 | ```
12 | package main
13 |
14 | import (
15 | "github.com/baa-middleware/accesslog"
16 | "github.com/baa-middleware/recovery"
17 | "github.com/baa-middleware/session"
18 | "github.com/go-baa/baa"
19 | )
20 |
21 | func main() {
22 | app := baa.Default()
23 | app.Use(recovery.Recovery())
24 | app.Use(accesslog.Logger())
25 |
26 | // session config
27 | redisOptions := session.RedisOptions{}
28 | redisOptions.Addr = "127.0.0.1:6379"
29 | redisOptions.Prefix = "Prefix:"
30 |
31 | memoryOptions := session.MemoryOptions{
32 | BytesLimit: 1024 * 1024,
33 | }
34 |
35 | app.Use(session.Middleware(session.Options{
36 | Name: "BAASESSIONID",
37 | Provider: &session.ProviderOptions{
38 | Adapter: "memory", // redis / memory
39 | Config: memoryOptions,
40 | },
41 | }))
42 |
43 | app.Get("/", func(c *baa.Context) {
44 | // get the session handler
45 | session := c.Get("session").(*session.Session)
46 | session.Set("hi", "baa")
47 |
48 | c.String(200, "Hello, 世界")
49 | })
50 |
51 | app.Get("/session", func(c *baa.Context) {
52 | // get the session handler
53 | session := c.Get("session").(*session.Session)
54 | c.String(200, "SessionID: "+session.ID()+", hi, "+session.Get("hi").(string))
55 | })
56 |
57 | app.Run(":1323")
58 | }
59 | ```
60 |
61 | 在该示例中,注册了 gzip 仅在baa的产品模式开启,因为调试模式下开启gzip会导致500错误时不能正常浏览错误信息。这算不算这个BUG?
62 |
63 | ## 配置
64 |
65 | ### Name `string`
66 |
67 | Session 的名称
68 |
69 | ### IDLength `int`
70 |
71 | SessionID 的长度,默认 `16` 位
72 |
73 | ### Provider `*ProviderOptions`
74 |
75 | Session的存储器选项
76 |
77 | #### Adapter `string`
78 |
79 | 存储器的适配器类型,支持 `redis` 和 `memory`
80 |
81 | > 注意:`memory` 适配器类型,如果应用重启session将全部失效,在集群模式下也不能共享session。
82 |
83 | #### Config `interface{}`
84 |
85 | 存储器的适配器配置,不同的适配器类型应使用不同的配置, `session.RedisOptions{}` 或者 `session.MemoryOptions{}`
86 |
87 | ### Cookie `*CookieOptions`
88 |
89 | Session的Cookie配置
90 |
91 | #### Domain `string`
92 |
93 | Cookie有效域名,默认 空
94 |
95 | #### Path `string`
96 |
97 | Cookie有效路径,默认 `/`
98 |
99 | #### Secure `bool`
100 |
101 | Cookie是否加密,默认 `false`
102 |
103 | #### LifeTime `int64`
104 |
105 | Cookie有效期,默认 `0`,即是一个浏览器会话类型,关闭响应的页面即失效。
106 |
107 | #### HttpOnly `bool`
108 |
109 | Cookie是否仅浏览器有效,默认 `false`
110 |
111 | ### GCInterval `int64`
112 |
113 | Session GC频率,仅在 `memory` 存储器类型下有效
114 |
115 | ### MaxLifeTime `int64`
116 |
117 | Session有效期,默认 `0`
118 |
--------------------------------------------------------------------------------
/zh-CN/middleware/requestcache.md:
--------------------------------------------------------------------------------
1 | # Baa 中间件 请求缓存控制
2 |
3 | `github.com/baa-middleware/requestcache`
4 |
5 | 请求缓存控制中间件可以针对全局或某个路由以请求的URI为KEY进行服务端内容缓存。
6 |
7 | ## 使用
8 |
9 | ```
10 | package main
11 |
12 | import (
13 | "github.com/baa-middleware/accesslog"
14 | "github.com/baa-middleware/recovery"
15 | "github.com/baa-middleware/requestcache"
16 | "github.com/go-baa/cache"
17 | "github.com/go-baa/baa"
18 | )
19 |
20 | func mainRequestcache() {
21 | app := baa.Default()
22 | app.Use(recovery.Recovery())
23 | app.Use(accesslog.Logger())
24 |
25 | // request cache middleware
26 | app.Use(requestcache.Middleware(requestcache.Option{
27 | Enabled: true,
28 | Expires: requestcache.DefaultExpires, // 1 minute
29 | Headers: map[string]string{
30 | "X-DIY": "baa",
31 | },
32 | ContextRelated: false,
33 | }))
34 |
35 | // request cache depend cacher
36 | app.SetDI("cache", cache.New(cache.Options{
37 | Name: "pageCache",
38 | Prefix: "MyApp",
39 | Adapter: "memory",
40 | Config: map[string]interface{}{
41 | "bytesLimit": int64(128 * 1024 * 1024), // 128m
42 | },
43 | }))
44 |
45 | app.Get("/", func(c *baa.Context) {
46 | c.String(200, "Hello, 世界")
47 | })
48 |
49 | app.Run(":1323")
50 | }
51 | ```
52 |
53 | 建议该中间件的注册顺序为`最后一个`,避免由于其他中间件的逻辑缓存错误的内容。
54 |
55 | ## 配置
56 |
57 | > 本中间件依赖名为 `cache` 的 DI,需要注册一个 [Cacher](https://github.com/go-baa/cache),cacher 的配置见:[依赖注入/缓存](https://github.com/go-baa/doc/tree/master/zh-CN/component/cache.md)
58 |
59 | ### Enabled `bool`
60 |
61 | 是否开启请求缓存控制,默认值:`false`
62 |
63 | ### Expires `int64`
64 |
65 | 缓存过期时间,单位:秒,默认值:`600`
66 |
67 | ### Headers `map[string]string`
68 |
69 | 附加返回头部,默认值:`nil`
70 |
71 | ### ContextRelated `bool`
72 |
73 | 是否将HTTP上下文中传递的数据加入KEY组合,默认 `false`
74 |
75 | 如果开启,通过 `c.Set()` 设置的内容将会作为缓存KEY的一部分,默认缓存的kEY是URI
76 |
77 | ## 更多姿势
78 |
79 | ### 全局使用
80 |
81 | 配置为最后一个中间件。
82 |
83 | ```
84 | if baa.Env == baa.PROD {
85 | // Gzip
86 | b.Use(gzip.Gzip(gzip.Options{CompressionLevel: 4}))
87 |
88 | // Request Cache
89 | b.Use(requestcache.Middleware(requestcache.Option{
90 | Enabled: true,
91 | Expires: requestcache.DefaultExpires,
92 | }))
93 | }
94 | ```
95 |
96 | ### 路由使用
97 |
98 | 配置为某一具体路由使用。
99 |
100 | ```
101 | cache := requestcache.Middleware(requestcache.Option{
102 | Enabled: !b.Debug(),
103 | Expires: requestcache.DefaultExpires,
104 | })
105 |
106 | b.Group("/some-prefix", func() {
107 | // ...
108 | }, cache)
109 | ```
110 |
111 | ### 使用多个配置
112 |
113 | 可以在不同的路由中使用不同的配置。
114 |
115 | ```
116 | cache1 := requestcache.Middleware(requestcache.Option{
117 | Enabled: !b.Debug(),
118 | Expires: 60 * 10,
119 | })
120 |
121 | b.Group("/some-prefix", func() {
122 | // ...
123 | }, cache1)
124 |
125 | cache2 := requestcache.Middleware(requestcache.Option{
126 | Enabled: !b.Debug(),
127 | Expires: 60 * 30,
128 | })
129 |
130 | b.Group("/some-prefix-2", func() {
131 | // ...
132 | }, cache2)
133 | ```
134 |
--------------------------------------------------------------------------------
/zh-CN/component/pongo2.md:
--------------------------------------------------------------------------------
1 | # Baa pongo2
2 |
3 | `https://github.com/go-baa/pongo2`
4 |
5 | pongo2 是 一个将 [Pongo2](https://github.com/flosch/pongo2) 模板引擎应用到 baa的助手库。
6 |
7 | ## 使用
8 |
9 | 通过 `DI` 注册 `render` 即可。
10 |
11 | ```
12 | package main
13 |
14 | import (
15 | "github.com/go-baa/pongo2"
16 | "github.com/go-baa/baa"
17 | )
18 |
19 | func main() {
20 | // new app
21 | app := baa.New()
22 |
23 | // register pongo2 render
24 | // render is template DI for baa, must be this name.
25 | app.SetDI("render", pongo2.New(pongo2.Options{
26 | Baa: b,
27 | Root: "templates/",
28 | Extensions: []string{".html"},
29 | Functions: map[string]interface{}{},
30 | Context: map[string]interface{}{
31 | "SITE_NAME": "Yet another website",
32 | },
33 | }))
34 |
35 | // router
36 | app.Get("/", func(c *baa.Context) {
37 | c.HTML(200, "index")
38 | })
39 |
40 | // run app
41 | app.Run(":1323")
42 | }
43 | ```
44 |
45 | ## 配置 `pongo2.Options`
46 |
47 | ### Baa `*baa.Baa`
48 |
49 | render 需要传递 baa 实例
50 |
51 | ### Root `string`
52 |
53 | 模板目录,指定模板目录,`c.HTML` 渲染模板时将从该目录下查找目录,不需要在渲染是指定目录名。
54 |
55 | ### Extensions `[]string`
56 |
57 | 模板文件扩展名,可以指定多个,渲染模板时无需指定扩展名,将根据配置寻找对应的文件。
58 |
59 | ### Functions `map[string]interface{}`
60 |
61 | 扩展函数,参考:[FuncMap](https://godoc.org/html/template#FuncMap)
62 |
63 | ### Context `map[string]interface{}`
64 |
65 | 预置数据,模板变量
66 |
67 | ## 扩展语法
68 |
69 | ### 输出变量
70 |
71 | ```
72 | {{ name }}
73 | ```
74 |
75 | ### 加载模板片段
76 |
77 | ```
78 | {% include "path/to/tpl.html" %}
79 | ```
80 |
81 | 带参数加载
82 |
83 | ```
84 | {% include "relative/path/to/tpl.html" with foo=var %}
85 | {% include "relative/path/to/tpl.html" with foo="bar" %}
86 | ```
87 |
88 | > 嵌入的模板接收的参数将作为 `string` 类型。
89 |
90 | ### 条件语句
91 |
92 | ```
93 | {% if vara %}
94 | {% elif varb %}
95 | {% else %}
96 | {% endif %}
97 | ```
98 |
99 | ### 循环语句
100 |
101 | ```
102 | {% for item in items %}
103 | {{ forloop.Counter }} {{ forloop.Counter0 }} {{ forloop.First }} {{ forloop.Last }} {{ forloop.Revcounter }} {{ forloop.Revcounter0 }}
104 | {{ item }}
105 | {% endfor %}
106 | ```
107 |
108 | ### 内置过滤器
109 |
110 | * escape
111 | * safe
112 | * escapejs
113 | * add
114 | * addslashes
115 | * capfirst
116 | * center
117 | * cut
118 | * date
119 | * default
120 | * default_if_none
121 | * divisibleby
122 | * first
123 | * floatformat
124 | * get_digit
125 | * iriencode
126 | * join
127 | * last
128 | * length
129 | * length_is
130 | * linebreaks
131 | * linebreaksbr
132 | * linenumbers
133 | * ljust
134 | * lower
135 | * make_list
136 | * phone2numeric
137 | * pluralize
138 | * random
139 | * removetags
140 | * rjust
141 | * slice
142 | * stringformat
143 | * striptags
144 | * time
145 | * title
146 | * truncatechars
147 | * truncatechars_html
148 | * truncatewords
149 | * truncatewords_html
150 | * upper
151 | * urlencode
152 | * urlize
153 | * urlizetrunc
154 | * wordcount
155 | * wordwrap
156 | * yesno
157 | * float
158 | * integer
159 |
160 | ### extends / block / macro and so on ...
161 |
162 | 更多内容,参见 [django](https://docs.djangoproject.com/en/dev/ref/templates/language/).
163 |
--------------------------------------------------------------------------------
/zh-CN/component/pool.md:
--------------------------------------------------------------------------------
1 | # Baa pool
2 |
3 | `https://github.com/go-baa/pool`
4 |
5 | pool 是一个通用的链接池管理库。
6 |
7 | ## 安装
8 |
9 | ```
10 | go get -u github.com/go-baa/pool
11 | ```
12 |
13 | ## 示例
14 |
15 | ```
16 | package main
17 |
18 | import (
19 | "log"
20 | "net"
21 |
22 | "github.com/go-baa/pool"
23 | )
24 |
25 | func main() {
26 | // create, initialize cap, max cap, create function
27 | pl, err := pool.New(2, 10, func() interface{} {
28 | addr, _ := net.ResolveTCPAddr("tcp4", "127.0.0.1:8003")
29 | cli, err := net.DialTCP("tcp4", nil, addr)
30 | if err != nil {
31 | log.Fatalf("create client connection error: %v\n", err)
32 | }
33 | return cli
34 | })
35 | if err != nil {
36 | log.Fatalf("create pool error: %v\n", err)
37 | }
38 |
39 | pl.Ping = func(conn interface{}) bool {
40 | // check connection status
41 | return true
42 | }
43 |
44 | pl.Close = func(conn interface{}) {
45 | // close connection
46 | conn.(*net.TCPConn).Close()
47 | }
48 |
49 | // get conn from pool
50 | c, err := pl.Get()
51 | if err != nil {
52 | log.Printf("get client error: %v\n", err)
53 | }
54 | conn := c.(*net.TCPConn)
55 | conn.Write([]byte("PING"))
56 | result := make([]byte, 4)
57 | n, err := conn.Read(result)
58 | if err != nil || n < 4 {
59 | log.Printf("read data error: %v, size: %d\n", err, n)
60 | }
61 | log.Printf("got data: %s\n", result)
62 |
63 | // put, back for reuse
64 | pl.Put(conn)
65 |
66 | // len
67 | log.Printf("total connections: %d\n", pl.Len())
68 |
69 | // destroy, close all connections
70 | pl.Destroy()
71 | }
72 | ```
73 |
74 | 完整的示例代码 [pool_test.go](https://github.com/go-baa/pool/blob/master/pool_test.go)
75 |
76 | ## 使用
77 |
78 | ### 初始化
79 |
80 | `func New(initCap, maxCap int, newFunc func() interface{}) (*Pool, error)`
81 |
82 | 设定初始化连接数 `initCap`,最大连接数 `maxCap` 和 初始化函数 `newFunc`,返回 连接池和可能的错误。
83 |
84 | ### 连接检测 `Ping`
85 |
86 | `func(interface{}) bool`
87 |
88 | 可以指定一个函数用于连接池获取和存储连接时对连接进行检测,出错的将剔除掉。
89 |
90 | 连接检测函数接受一个参数 `当前连接`,类型为 初始化函数返回的类型,根据检测结果返回 true/false。
91 |
92 | 示例:
93 |
94 | ```
95 | pl, err := pool.New(2, 10, func() interface{} {
96 | return nil
97 | })
98 | pl.Ping = func(conn) bool {
99 | return true
100 | }
101 | ```
102 |
103 | ### 连接关闭 `Close`
104 |
105 | `func(interface{})`
106 |
107 | 可以指定一个函数用于连接池剔除连接时执行关闭动作。
108 |
109 | 连接关闭函数接受一个参数 `当前连接`,类型为 初始化函数返回的类型。
110 |
111 | 示例:
112 |
113 | ```
114 | pl, err := pool.New(2, 10, func() interface{} {
115 | return nil
116 | })
117 | pl.Close = func(conn) {
118 | conn.Close()
119 | }
120 | ```
121 |
122 | ### 使用连接
123 |
124 | 使用时,先从连接池中获取一个连接,使用完毕需要还回来。
125 |
126 | 获取:
127 |
128 | ```
129 | func (p *Pool) Get() (interface{}, error)
130 | ```
131 |
132 | 返还:
133 |
134 | ```
135 | func (p *Pool) Put(v interface{})
136 | ```
137 |
138 | 示例:
139 |
140 | ```
141 | // get conn from pool
142 | c, err := pl.Get()
143 | if err != nil {
144 | log.Printf("get client error: %v\n", err)
145 | }
146 |
147 | // do something
148 | // ...
149 |
150 | pl.Put(c)
151 | ```
152 |
153 | 也可以使用 `defer`来确保不忘记返还。
154 |
155 | ### 当前连接数
156 |
157 | `func (p *Pool) Len() int`
158 |
159 | 返回当前保持的连接数量。
160 |
161 | ### 销毁连接池
162 |
163 | `func (p *Pool) Destroy()`
164 |
165 | 销毁连接池时,将依次调用连接的 `Close` 方法。
166 |
167 |
--------------------------------------------------------------------------------
/zh-CN/di.md:
--------------------------------------------------------------------------------
1 | # Baa 依赖注入
2 |
3 | 依赖注入(dependency injection)简称 DI,是 baa 实现的核心,baa 所有组件基于DI组装起来的。
4 |
5 | 默认的 日志、路由、模板 都是通过 DI 注册进来的,在 [Baa核心#更换内置引擎](https://github.com/go-baa/doc/blob/master/zh-CN/baa.md#更换内置引擎)一节也介绍过。
6 |
7 | Baa的初始化函数是这样写的:
8 |
9 | ```
10 | // New create a baa application without any config.
11 | func New() *Baa {
12 | b := new(Baa)
13 | b.middleware = make([]HandlerFunc, 0)
14 | b.pool = sync.Pool{
15 | New: func() interface{} {
16 | return NewContext(nil, nil, b)
17 | },
18 | }
19 | if Env != PROD {
20 | b.debug = true
21 | }
22 | b.SetDIer(NewDI())
23 | b.SetDI("router", NewTree(b))
24 | b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
25 | b.SetDI("render", newRender())
26 | b.SetNotFound(b.DefaultNotFoundHandler)
27 | return b
28 | }
29 | ```
30 |
31 | 代码出处,[baa.go](https://github.com/go-baa/baa/blob/master/baa.go)
32 |
33 | ## 注册
34 |
35 | `func (b *Baa) SetDI(name string, h interface{})`
36 |
37 | DI 的注册和使用都依赖于注册的名称,比如要更换内置组件必须注册为指定的名称。
38 |
39 | ### name string
40 |
41 | 依赖的名称
42 |
43 | ### h interface{}
44 |
45 | 依赖的实例,可以是任意类型
46 |
47 | 使用示例:
48 |
49 | ```
50 | package main
51 |
52 | import (
53 | "log"
54 | "os"
55 |
56 | "github.com/go-baa/baa"
57 | )
58 |
59 | func main() {
60 | app := baa.Default()
61 | app.SetDI("logger", log.New(os.Stderr, "[BaaDI] ", log.LstdFlags))
62 |
63 | app.Get("/", func(c *baa.Context) {
64 | c.String(200, "Hello, 世界")
65 | })
66 |
67 | app.Run(":1323")
68 | }
69 | ```
70 |
71 | ## 使用
72 |
73 | `func (b *Baa) GetDI(name string) interface{}`
74 |
75 | `func (c *Context) DI(name string) interface{}`
76 |
77 |
78 | 可以通过 `baa.GetDI` 或者 `c.DI` 来获取已经注册的依赖,如果未注册,返回 `nil`
79 |
80 | 由于注册的依赖可能是任意类型,故返回类型为 `interface{}`,所以获取后,需要做一次类型断言再使用。
81 |
82 | 使用示例:
83 |
84 | ```
85 | package main
86 |
87 | import (
88 | "log"
89 | "os"
90 |
91 | "github.com/go-baa/baa"
92 | )
93 |
94 | func main() {
95 | app := baa.Default()
96 | app.SetDI("logger", log.New(os.Stderr, "[BaaDI] ", log.LstdFlags))
97 |
98 | app.Get("/", func(c *baa.Context) {
99 | // use di
100 | logger := c.DI("logger").(*log.Logger)
101 | logger.Println("i am use logger di")
102 |
103 | c.String(200, "Hello, 世界")
104 | })
105 |
106 | app.Run(":1323")
107 | }
108 | ```
109 |
110 | ### 日志
111 |
112 | baa 将日志抽象为 `baa.Logger` 接口,只要实现了该接口,就可以注册为全局日志器。
113 |
114 | baa 内置的日志器使用的是标准包的 `log` 实例。
115 |
116 | 更换全局日志器:
117 |
118 | ```
119 | app := baa.New()
120 | baa.SetDI("logger", newLogger)
121 | ```
122 |
123 | > logger 是内置名称,该命名被用于全局日志器。
124 | >
125 | > 如果不是要更换全局日志,而是注册一个新的日志器用于其他用途,只需更改注册名称即可,而且也不需要实现 `baa.Logger` 接口。
126 |
127 | ### 路由
128 |
129 | 只要实现接口 `baa.Router` 接口即可。
130 |
131 | ```
132 | app := baa.New()
133 | baa.SetDI("router", newRender)
134 | ```
135 |
136 | > router 是内置名称,,该命名被用于全局路由器。
137 |
138 | baa 除了内置的 tree路由,还新增了两个路由器可用,见 [router](https://github.com/go-baa/router)
139 |
140 | ```
141 | package main
142 |
143 | import (
144 | "github.com/go-baa/router/regtree"
145 | "github.com/go-baa/baa"
146 | )
147 |
148 | func main() {
149 | app := baa.Default()
150 | app.SetDI("router", regtree.New(app))
151 |
152 | app.Get("/view-:id(\\d+)", func(c *baa.Context) {
153 | c.String(200, c.Param("id"))
154 | })
155 | app.Get("/view-:id(\\d+)/project", func(c *baa.Context) {
156 | c.String(200, c.Param("id")+"/project")
157 | })
158 | app.Run(":1323")
159 | }
160 | ```
161 |
162 | ### 模板
163 |
164 | 只要实现接口 `baa.Renderer` 接口即可。
165 |
166 | ```
167 | app := baa.New()
168 | baa.SetDI("render", newRender)
169 | ```
170 |
171 | > render 是内置名称,该命名被用于模板渲染。
172 |
173 | baa 除了内置的 render简单模板渲染,还新增了两个模板渲染引擎:
174 |
175 | * [render](https://github.com/go-baa/doc/tree/master/zh-CN/component/render.md)
176 | * [pongo2](https://github.com/go-baa/doc/tree/master/zh-CN/component/pongo2.md)
177 |
178 | ### 缓存
179 |
180 | 缓存不是 baa内置依赖,作为一个常用组件实现,具体见:
181 |
182 | [baa组件/缓存](https://github.com/go-baa/doc/tree/master/zh-CN/component/cache.md)
183 |
--------------------------------------------------------------------------------
/zh-CN/baa.md:
--------------------------------------------------------------------------------
1 | # Baa 核心
2 |
3 | ## 创建应用
4 |
5 | `func New() *Baa`
6 |
7 | 快速创建一个新的应用实例。
8 |
9 | `func Instance(name string) *Baa`
10 |
11 | 获取一个命名实例,如果实例不存在则调用 `New()` 创建并且命名。
12 |
13 | 命名实例 用于不同模块间共享 baa实例的场景。在 入口中创建,在其他模块中 `baa.Instance(name)` 可获取指定的实例。
14 |
15 | `func Default() *Baa`
16 |
17 | 使用默认的应用实例。
18 |
19 | Default 是 `Instance` 的一个默认实现,是全局唯一的实例。在共享场景下,不需要传递 baa 直接调用 `baa.Default()` 即可访问同一实例。
20 |
21 | 使用示例:
22 |
23 | ```
24 | app := baa.New()
25 | app := baa.Default()
26 | app := baa.Instance("myApp")
27 | myApp := baa.Instance("myApp")
28 | ```
29 |
30 | ## 路由管理
31 |
32 | baa 基于 http resetfull 模式设计了路由管理器,具体见 [路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md) 一节。
33 |
34 | ## 中间件
35 |
36 | baa 支持通过 中间件 机制,注入请求过程,实现类似插件的功能,具体见 [中间件](https://github.com/go-baa/doc/tree/master/zh-CN/middleware.md) 一节。
37 |
38 | ## 依赖注入
39 |
40 | 依赖注入(dependency injection)简称 DI,是 baa 实现的核心,baa 所有组件基于DI组装起来的。
41 |
42 | baa组件的更换,见 [更换内置引擎](#更换内置引擎) 一节。
43 |
44 | DI的具体使用,见 [依赖注入](https://github.com/go-baa/doc/tree/master/zh-CN/di.md) 一节。
45 |
46 | ## 运行应用
47 |
48 | `func (b *Baa) Run(addr string)`
49 |
50 | 指定一个监听地址,启动一个HTTP服务。
51 |
52 | 示例:
53 |
54 | ```
55 | app := baa.Default()
56 | app.Run(":1323")
57 | ```
58 |
59 | `func (b *Baa) RunTLS(addr, certfile, keyfile string)`
60 |
61 | 指定监听地址和TLS证书,启动一个HTTPS服务。
62 |
63 | 示例:
64 |
65 | ```
66 | app := baa.Default()
67 | app.RunTLS(":8443", "cert/cert.cert", "cert/server.key")
68 | ```
69 |
70 | ## 环境变量
71 |
72 | `BAA_ENV`
73 |
74 | baa 通过 系统环境变量 `BAA_ENV` 来设置运行模式。
75 |
76 | `baa.Env`
77 |
78 | 外部程序可以通过 `baa.Env` 变量来获取 baa 当前的运行模式。
79 |
80 | 运行模式常量
81 |
82 | ```
83 | // DEV mode
84 | DEV = "development"
85 | // PROD mode
86 | PROD = "production"
87 | // TEST mode
88 | TEST = "test"
89 | ```
90 |
91 | * baa.DEV 开发模式
92 | * baa.PROD 产品模式
93 | * baa.TEST 测试模式
94 |
95 | 示例代码:
96 |
97 | ```
98 | if baa.Env == baa.PROD {
99 | // 应用运行在产品模式
100 | }
101 | ```
102 |
103 | ## 调试
104 |
105 | `func (b *Baa) Debug() bool`
106 |
107 | 返回是否是调试模式,应用可以根据是否运行在调试模式,来输出调试信息。
108 |
109 | `func (b *Baa) SetDebug(v bool)`
110 |
111 | 默认根据运行环境决定是否开启调试模式,可以通过该方法开启/关闭调试模式。
112 |
113 | > 在 产品模式 下,默认关闭调试模式,其他模式下默认开启调试模式。
114 |
115 | `func (b *Baa) Logger() Logger`
116 |
117 | 返回日志器,在应用中可以调用日志器来输出日志。
118 |
119 | 示例:
120 |
121 | ```
122 | app := baa.New()
123 | log := app.Logger()
124 | log.Println("test")
125 | ```
126 |
127 | ## 错误处理
128 |
129 | > 错误输出,只是给浏览器返回错误,但并不会阻止接下来绑定的方法。
130 |
131 | `func (b *Baa) NotFound(c *Context)`
132 |
133 | 调用该方法会直接 输出 404错误。
134 |
135 | `func (b *Baa) Error(err error, c *Context)`
136 |
137 | 调用该方法会直接输出 500错误,并根据运行模式决定是否在浏览器中返回具体错误。
138 |
139 | 示例
140 |
141 | ```
142 | app := baa.New()
143 | app.Get("/", func(c *baa.Context) {
144 | c.Baa().NotFound(c)
145 | })
146 | app.Get("/e", func(c *baa.Context) {
147 | c.Baa().Error(errors.New("something error"), c)
148 | })
149 |
150 | ```
151 |
152 | ## 更换内置引擎
153 |
154 | baa 采用以DI为核心的框架设计,内置模块均可使用新的实现通过DI更换。
155 |
156 | ### 日志器
157 |
158 | baa 将日志抽象为 `baa.Logger` 接口,只要实现了该接口,就可以注册为日志器。
159 |
160 | baa 内置的日志器使用的是标准包的 `log` 实例。
161 |
162 | 更换日志器:
163 |
164 | ```
165 | app := baa.New()
166 | baa.SetDI("logger", newLogger)
167 | ```
168 |
169 | > logger 是内置名称,该命名被用于全局日志器。
170 |
171 | ### 路由器
172 |
173 | 只要实现接口 `baa.Router` 接口即可。
174 |
175 | ```
176 | app := baa.New()
177 | baa.SetDI("router", newRouter)
178 | ```
179 |
180 | > router 是内置名称,该命名被用于全局路由器。
181 |
182 | baa 除了内置的 tree路由,还新增了两个路由器可用,见 [router](https://github.com/go-baa/router)
183 |
184 | ### 模板引擎
185 |
186 | 只要实现接口 `baa.Renderer` 接口即可。
187 |
188 | ```
189 | app := baa.New()
190 | baa.SetDI("render", newRender)
191 | ```
192 |
193 | > render 是内置名称,该命名被用于模板渲染。
194 |
195 | ### DIer
196 |
197 | 甚至依赖注入管理器,自己也能被替换,只要实现 `baa.Dier` 接口即可。
198 |
199 | 请注意要在第一个设置,并且重设以上三个引擎,因为你的注入管理器中默认并没有内置引擎,BAA将发生错误。
200 |
201 | ```
202 | app := baa.New()
203 | app.SetDIer(newDIer)
204 | app.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
205 | app.SetDI("render", new(baa.Render))
206 | app.SetDI("router", baa.NewTree(app))
207 | ```
208 |
--------------------------------------------------------------------------------
/zh-CN/component/cache.md:
--------------------------------------------------------------------------------
1 | # Baa 缓存
2 |
3 | `github.com/go-baa/cache`
4 |
5 | 缓存组件提供了通用的缓存管理能力,采用适配器模式开发,目前支持 memory, memcache, redis 三种存储。
6 |
7 | 支持常用操作命令:Get/Set/Incr/Decr/Delete/Exist/Flush
8 |
9 | ## 使用
10 |
11 | 缓存组件是通用的,和`baa`的结合通过`DI`来引入:
12 |
13 | ```
14 | package main
15 |
16 | import (
17 | "github.com/go-baa/cache"
18 | "github.com/go-baa/baa"
19 | )
20 |
21 | func main() {
22 | // new app
23 | app := baa.New()
24 |
25 | // register cache
26 | app.SetDI("cache", cache.New(cache.Options{
27 | Name: "cache",
28 | Prefix: "MyApp",
29 | Adapter: "memory",
30 | Config: map[string]interface{}{},
31 | }))
32 |
33 | // router
34 | app.Get("/", func(c *baa.Context) {
35 | ca := c.DI("cache").(cache.Cacher)
36 | ca.Set("test", "baa", 10)
37 | var v string
38 | ca.Get("test", &v)
39 | c.String(200, v)
40 | })
41 |
42 | // run app
43 | app.Run(":1323")
44 | }
45 | ```
46 |
47 | `memory`适配器是默认引入的,使用其他适配器需要先导入:
48 |
49 | ```
50 | import(
51 | "github.com/go-baa/baa"
52 | "github.com/go-baa/cache"
53 | _ "github.com/go-baa/cache/memcache"
54 | _ "github.com/go-baa/cache/redis"
55 | )
56 | ```
57 |
58 | ### 存储 Set
59 |
60 | `func Set(key string, v interface{}, ttl int64) error`
61 |
62 | 根据 `key` 存储 `v` 的值,缓存有效期为 `ttl`秒,返回 `nil` 或者 `error`
63 |
64 | > `ttl` 等于0,表示永不过期,如果是内存适配器,在应用重启后数据将丢失
65 |
66 | ### 获取 Get
67 |
68 | `func Get(key string, out interface{}) error`
69 |
70 | 根据 `key` 获取存储的值赋给 `out`,返回 `nil` 或者 `error`
71 |
72 | > 要求 `out` 为 `引用类型`,Go语言中是按值传递,如果不是引用类型外部无法获取到数据
73 |
74 | ### 删除 Delete
75 |
76 | `func Delete(key string) error`
77 |
78 | 删除指定 `key` 的缓存数据,返回 `nil` 或者 `error`
79 |
80 | ### 递增 Incr
81 |
82 | `func Incr(key string) (int64, error)`
83 |
84 | 根据 `key` 将存储的值 `加1` 更新存储并返回,额外返回 `nil` 或者 `error`
85 |
86 | > `key` 的值应为 数值类型,否则将发生错误
87 |
88 | ### 递减 Decr
89 |
90 | `func Decr(key string) (int64, error)`
91 |
92 | 根据 `key` 将存储的值 `减1` 更新存储并返回,额外返回 `nil` 或者 `error`
93 |
94 | > `key` 的值应为 数值类型,否则将发生错误
95 |
96 | ### 检测是否存在 Exist
97 |
98 | `func Exist(key string) bool`
99 |
100 | 根据 `key` 检查是否存在有效的缓存数据,返回 `true` 表示存在,`false` 表示不存在
101 |
102 | ### 清空缓存 Flush
103 |
104 | `func Flush() error`
105 |
106 | 清空缓存中的数据
107 |
108 | ## 配置
109 |
110 | ### Name `string`
111 |
112 | 缓存实例名称
113 |
114 | ### Prefix `string`
115 |
116 | 缓存索引前缀
117 |
118 | ### Adapter `string`
119 |
120 | 适配器名称,目前支持 memory, memcache, redis 三种存储
121 |
122 | ### Config `map[string]interface{}`
123 |
124 | 适配器配置,不同的适配器有不同的配置。
125 |
126 | ### 适配器 Memory
127 |
128 | #### bytesLimit `int64`
129 |
130 | 内存适配器,只有一个配置参数,内存大小限制,单位 字节,默认为 `128m`
131 |
132 | #### 使用示例
133 |
134 | ```
135 | app.SetDI("cache", cache.New(cache.Options{
136 | Name: "cache",
137 | Prefix: "MyApp",
138 | Adapter: "memory",
139 | Config: map[string]interface{}{
140 | "bytesLimit": int64(128 * 1024 * 1024), // 128m
141 | },
142 | }))
143 | ```
144 |
145 | ### 适配器 Memcache
146 |
147 | #### host `string`
148 |
149 | memcached 服务器IP地址,默认为 `127.0.0.1`
150 |
151 | #### port `string`
152 |
153 | memcached 服务器端口,默认为 `11211`
154 |
155 | #### 使用示例
156 |
157 | ```
158 | app.SetDI("cache", cache.New(cache.Options{
159 | Name: "cache",
160 | Prefix: "MyApp",
161 | Adapter: "memcache",
162 | Config: map[string]interface{}{
163 | "host": "127.0.0.1",
164 | "port": "11211",
165 | },
166 | }))
167 | ```
168 |
169 | ### 适配器 Redis
170 |
171 | #### host `string`
172 |
173 | redis 服务器IP地址,默认为 `127.0.0.1`
174 |
175 | #### port `string`
176 |
177 | redis 服务器端口,默认为 `6379`
178 |
179 | #### password `string`
180 |
181 | redis 服务器连接密码,默认 `空`
182 |
183 | #### poolsize `int`
184 |
185 | redis 库连接池限制,默认保持 `10` 个连接
186 |
187 | #### 使用示例
188 |
189 | ```
190 | app.SetDI("cache", cache.New(cache.Options{
191 | Name: "cache",
192 | Prefix: "MyApp",
193 | Adapter: "redis",
194 | Config: map[string]interface{}{
195 | "host": "127.0.0.1",
196 | "port": "6379",
197 | "password": "",
198 | "poolsize": 10,
199 | },
200 | }))
201 | ```
202 |
--------------------------------------------------------------------------------
/zh-CN/README.md:
--------------------------------------------------------------------------------
1 | # Baa
2 |
3 | 一个简单高效的Go web开发框架。主要有路由、中间件,依赖注入和HTTP上下文构成。
4 |
5 | Baa 不使用 ``反射`` 和 ``正则``,没有魔法的实现。
6 |
7 | ## 特性
8 |
9 | * 支持静态路由、参数路由、组路由(前缀路由/命名空间)和路由命名
10 | * 路由支持链式操作
11 | * 路由支持文件/目录服务
12 | * 中间件支持链式操作
13 | * 支持依赖注入*
14 | * 支持JSON/JSONP/XML/HTML格式输出
15 | * 统一的HTTP错误处理
16 | * 统一的日志处理
17 | * 支持任意更换模板引擎(实现baa.Renderer接口即可)
18 |
19 | ## 文档目录
20 |
21 | * [Baa核心](https://github.com/go-baa/doc/tree/master/zh-CN/baa.md)
22 | * [路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md)
23 | * [常规路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#常规路由)
24 | * [路由语法](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#路由语法)
25 | * [静态路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#静态路由)
26 | * [参数路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#参数路由)
27 | * [正则路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#正则路由)
28 | * [路由选项](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#路由选项)
29 | * [组路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#组路由)
30 | * [链式处理](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#链式处理)
31 | * [命名路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#命名路由)
32 | * [文件路由](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#文件路由)
33 | * [自定义错误](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#自定义错误)
34 | * [500错误](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#500错误)
35 | * [404错误](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#404错误)
36 | * [Websocket](https://github.com/go-baa/doc/tree/master/zh-CN/router.md#websocket)
37 | * [中间件](https://github.com/go-baa/doc/tree/master/zh-CN/middleware.md)
38 | * [编写中间件](https://github.com/go-baa/doc/blob/master/zh-CN/middleware.md#编写中间件)
39 | * [使用中间件](https://github.com/go-baa/doc/blob/master/zh-CN/middleware.md#使用中间件)
40 | * [错误恢复](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/recovery.md)
41 | * [访问日志](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/accesslog.md)
42 | * [gzip](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/gzip.md)
43 | * [session](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/session.md)
44 | * [静态资源优先](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/static.md)
45 | * [请求缓存控制](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/requestcache.md)
46 | * [强制不缓存](https://github.com/go-baa/doc/blob/master/zh-CN/middleware/nocache.md)
47 | * [依赖注入 DI](https://github.com/go-baa/doc/tree/master/zh-CN/di.md)
48 | * [注册](https://github.com/go-baa/doc/tree/master/zh-CN/di.md#注册)
49 | * [使用](https://github.com/go-baa/doc/tree/master/zh-CN/di.md#使用)
50 | * [日志](https://github.com/go-baa/doc/tree/master/zh-CN/di.md#日志)
51 | * [路由](https://github.com/go-baa/doc/tree/master/zh-CN/di.md#路由)
52 | * [模板](https://github.com/go-baa/doc/tree/master/zh-CN/di.md#模板)
53 | * [缓存](https://github.com/go-baa/doc/tree/master/zh-CN/component/cache.md)
54 | * [HTTP上下文](https://github.com/go-baa/doc/tree/master/zh-CN/context.md)
55 | * [Request](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#request)
56 | * [URL参数](https://github.com/go-baa/doc/blob/master/zh-CN/context.md#url参数)
57 | * [路由参数](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#路由参数)
58 | * [Cookie](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#cookie)
59 | * [文件上传](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#文件上传)
60 | * [Response](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#response)
61 | * [数据存储](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#数据存储)
62 | * [内容输出](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#内容输出)
63 | * [有用的函数](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#有用的函数)
64 | * [模板渲染](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#模板渲染)
65 | * [模板语法](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#模板语法)
66 | * [模板接口](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#模板接口)
67 | * [render](https://github.com/go-baa/doc/tree/master/zh-CN/component/render.md)
68 | * [pongo2](https://github.com/go-baa/doc/tree/master/zh-CN/component/pongo2.md)
69 | * [日志](https://github.com/go-baa/doc/tree/master/zh-CN/log.md)
70 | * [日志接口](https://github.com/go-baa/doc/tree/master/zh-CN/log.md#日志接口)
71 | * [日志方法](https://github.com/go-baa/doc/tree/master/zh-CN/log.md#日志方法)
72 | * [数据库](https://github.com/go-baa/doc/tree/master/zh-CN/database.md)
73 | * [gorm](http://jinzhu.me/gorm/)
74 | * [xorm](http://xorm.io/)
75 | * [mgo](https://labix.org/mgo)
76 | * [组件](https://github.com/go-baa/doc/tree/master/zh-CN/component.md)
77 | * [bat](https://github.com/go-baa/doc/tree/master/zh-CN/component/bat.md)
78 | * [cache](https://github.com/go-baa/doc/tree/master/zh-CN/component/cache.md)
79 | * [pongo2](https://github.com/go-baa/doc/tree/master/zh-CN/component/pongo2.md)
80 | * [pool](https://github.com/go-baa/doc/tree/master/zh-CN/component/pool.md)
81 | * [render](https://github.com/go-baa/doc/tree/master/zh-CN/component/render.md)
82 | * [router](https://github.com/go-baa/doc/tree/master/zh-CN/component/router.md)
83 | * [log](https://github.com/go-baa/doc/tree/master/zh-CN/component/log.md)
84 | * [setting](https://github.com/go-baa/doc/tree/master/zh-CN/component/setting.md)
85 | * [工程化](https://github.com/go-baa/doc/tree/master/zh-CN/project.md)
86 | * [目录结构](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#目录结构)
87 | * [控制器](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#控制器)
88 | * [数据模型](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#数据模型)
89 | * [配置文件](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#配置文件)
90 | * [模板](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#模板)
91 | * [静态资源](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#静态资源)
92 | * [打包发布](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#打包发布)
93 | * [依赖管理](https://github.com/go-baa/doc/tree/master/zh-CN/project.md#依赖管理)
94 |
95 |
96 | ## 快速上手
97 |
98 | ### 安装
99 |
100 | ```
101 | go get -u github.com/go-baa/baa
102 | ```
103 |
104 | ### 代码
105 |
106 | ```
107 | // baa.go
108 | package main
109 |
110 | import (
111 | "github.com/go-baa/baa"
112 | )
113 |
114 | func main() {
115 | app := baa.New()
116 | app.Get("/", func(c *baa.Context) {
117 | c.String(200, "Hello, 世界")
118 | })
119 | app.Run(":1323")
120 | }
121 | ```
122 |
123 | ### 运行
124 |
125 | ```
126 | go run baa.go
127 | ```
128 |
129 | ### 浏览
130 |
131 | ```
132 | http://127.0.0.1:1323/
133 | ```
134 |
135 | ### 使用中间件
136 |
137 | ```
138 | package main
139 |
140 | import (
141 | "github.com/baa-middleware/accesslog"
142 | "github.com/baa-middleware/recovery"
143 | "github.com/go-baa/baa"
144 | )
145 |
146 | func main() {
147 | app := baa.Default()
148 | app.Use(recovery.Recovery())
149 | app.Use(accesslog.Logger())
150 |
151 | app.Get("/", func(c *baa.Context) {
152 | c.String(200, "Hello, 世界")
153 | })
154 |
155 | app.Run(":1323")
156 | }
157 | ```
158 |
159 | ## 示例
160 |
161 | https://github.com/go-baa/example
162 |
163 | * [blog](https://github.com/go-baa/example/tree/master/blog)
164 | * [api](http://github.com/go-baa/example/tree/master/api)
165 | * [websocket](http://github.com/go-baa/example/tree/master/websocket)
166 |
--------------------------------------------------------------------------------
/zh-CN/project.md:
--------------------------------------------------------------------------------
1 | # Baa 工程化
2 |
3 | 所谓工程化,不是baa的功能,而是在使用baa的过程中总结出的一种姿势,姑且称之为:最佳实践。
4 |
5 | 按照一般MVC的开发规范,一个程序通常会有 数据模型、模板视图、业务控制,辅助的还要有 前端资源文件,应用配置文件,可能还要记录日志文件。
6 |
7 | ## 目录结构
8 |
9 | ```
10 | project
11 | |-- conf
12 | |-- app.ini
13 | |-- controller
14 | |-- index.go
15 | |-- article.go
16 | |-- user.go
17 | |-- data
18 | |-- log
19 | |-- model
20 | |-- base
21 | |-- base.go
22 | |-- cache.go
23 | |-- base.go
24 | |-- article.go
25 | |-- user.go
26 | |-- module
27 | |-- util
28 | |-- util.go
29 | |-- template
30 | |-- template.go
31 | |-- public
32 | |-- assets
33 | |-- css
34 | |-- images
35 | |-- js
36 | |-- upload
37 | |-- robots.txt
38 | |-- router
39 | |-- init.go
40 | |-- router.go
41 | |-- template
42 | |-- share
43 | |-- header.html
44 | |-- footer.html
45 | |-- article
46 | |-- index.html
47 | |-- show.html
48 | |-- user
49 | |-- show.html
50 | |-- index.html
51 | |-- main.go
52 | |-- README.md
53 | ```
54 |
55 | 结构说明
56 |
57 | | 路径 | 说明 | 备注 |
58 | |-----------------------------|--------------|--------|
59 | | conf | 配置文件目录 | -- |
60 | | conf/app.ini | 应用配置文件 | [setting](https://github.com/go-baa/setting) 配置库要求的配置文件路由
61 | | controller | 业务控制器目录 | -- |
62 | | controller/*.go | 具体控制器 | 建议每个功能一个控制器文件 |
63 | | data | 数据目录 | -- |
64 | | data/log | 日志目录 | 建议路径,可在配置文件中指定 [log](https://github.com/go-baa/log) 输出路径 |
65 | | model | 数据模型目录 | -- |
66 | | model/base | 数据模型基类 | 提供对于数据库连接,缓存连接等基础操作 |
67 | | model/base.go | 模型基类 | 导入 `model/base` 初始化数据库,是其他模型的基础 |
68 | | model/article.go | 业务模型 | 具体的业务模型,建议每个表对应一个模型文件,命名和表名一致 |
69 | | module | 扩展功能模块 | -- |
70 | | module/util | 助手模块 | 一些常用的功能函数,文件操作,URL操作,加解密等 |
71 | | module/util/util.go | 助手函数 | 常用函数库 |
72 | | module/template | 模板扩展 | -- |
73 | | module/template/template.go | 模板函数库 | 结合 [render](https://github.com/go-baa/render) 模板引擎,可以扩展模板函数 |
74 | | public | 静态资源目录 | -- |
75 | | public/assets | 前端资源目录 | -- |
76 | | public/assets/css,images,js | 前端文件目录 | -- |
77 | | public/uplaod | 上传文件目录 | -- |
78 | | public/robots.txt | 静态文件 | 其他静态文件,可以放在资源目录下 |
79 | | router | 路由设定目录 | -- |
80 | | router/init.go | baa初始化 | 初始化baa,加载中间件,模板组件,缓存组件等 |
81 | | router/router.go | 路由配置 | 独立了路由配置在一个文件中,结构更清晰 |
82 | | template | 模板目录 | -- |
83 | | template/share | 共享目录 | 存储共享的模板片段 |
84 | | template/article | 业务模板 | 具体的业务模板,建议和控制一一对应,每个控制一个目录,每个方法一个文件 |
85 | | template/index.html | 首页模板 | 应用的首页文件 |
86 | | main.go | 应用入口 | -- |
87 | | README.md | 应用说明 | -- |
88 |
89 | 完整结构,参见示例 [blog](https://github.com/go-baa/example/tree/master/blog)
90 |
91 | ## 控制器
92 |
93 | 控制器中按业务划分成了不同的文件,不同的操作还应该有不同的方法对应,在实现上有两种考虑:
94 |
95 | - 一个控制器中所有方法都是函数,使用控制器的名字作为函数名前置防止多个控制中的命名冲突。
96 | - 将一个控制器视为一个类,所有方法都是类的方法,虽然Go中没有明确的类,但也可以实现面向对象编程。
97 |
98 | 两种声音都有支持,你可以根据自己喜欢来做,我们选择了第二种姿势,看起来更舒服一些。
99 |
100 | 最终,一个控制文件可能是这样的:
101 |
102 | ```
103 | // api/controller/index.go
104 |
105 | package controller
106 |
107 | import (
108 | "github.com/go-baa/example/api/model"
109 | "github.com/go-baa/log"
110 | "github.com/go-baa/baa"
111 | )
112 |
113 | type index struct{}
114 |
115 | // IndexController ...
116 | var IndexController = index{}
117 |
118 | // Index list articles
119 | func (index) Index(c *baa.Context) {
120 | page := c.ParamInt("page")
121 | pagesize := 10
122 |
123 | rows, total, err := model.ArticleModel.Search(page, pagesize)
124 | if err != nil {
125 | output(c, 1, err.Error(), nil)
126 | return
127 | }
128 |
129 | log.Debugf("rows: %#v, total: %d\n", rows, total)
130 |
131 | output(c, 0, "", map[string]interface{}{
132 | "total": total,
133 | "items": rows,
134 | })
135 | }
136 |
137 | ....
138 |
139 | ```
140 |
141 | > 该文件来自示例程序 [api](http://github.com/go-baa/example/tree/master/api)
142 |
143 | 为了实现面向对象,创建了一个空的结构体作为方法的承载,所有方法都注册给这个结构体。
144 |
145 | **需要解释的一句是,为什么还要声明一个 `IndexController` 呢?**
146 |
147 | 路由注册时需要将每一个URL对应到具体的方法上来,结构体的方法是不能直接用的,需要先声明一个结构体实例才能使用。
148 |
149 | 在哪儿声明呢?一个是路由注册的时候,一个是控制器定义的时候,我们选择了在控制器定义的时候声明,作为控制器开发的一个规范,路由定义时引入包就可以用了。
150 |
151 | ## 数据模型
152 |
153 | baa本身不提供数据模型的处理,在 [api](http://github.com/go-baa/example/tree/master/api) 示例中使用的是 [grom](http://jinzhu.me/gorm/) 来操作MySQL。
154 |
155 | [xorm](http://xorm.io/) 和 [grom](http://jinzhu.me/gorm/) 有什么区别呢?论功能 `xorm` 可能更强大一些,我们觉得 `grom` 使用更舒服一些。
156 |
157 | 虽然他们都做了很好的封装,但一个项目毕竟还要配置数据库信息,数据库连接,还要各种包调用,显然我们还是要做个简单的封装才好。
158 |
159 | 具体的代码不列出,请参考 [api/model](http://github.com/go-baa/example/tree/master/api/model) 中的base处理。
160 |
161 | 在这个基础上,一个数据模型可能长这个样子:
162 |
163 | ```
164 | // api/model/user.go
165 |
166 | package model
167 |
168 | // User user data scheme
169 | type User struct {
170 | ID int `json:"id" gorm:"primary_key; type:int(10) UNSIGNED NOT NULL AUTO_INCREMENT;"`
171 | Name string `json:"name" gorm:"type:varchar(50) NOT NULL DEFAULT '';"`
172 | Email string `json:"email" gorm:"type:varchar(100) NOT NULL DEFAULT '';"`
173 | }
174 |
175 | type userModel struct{}
176 |
177 | // UserModel single model instance
178 | var UserModel = new(userModel)
179 |
180 | // Get find a user info
181 | func (t *userModel) Get(id int) (*User, error) {
182 | row := new(User)
183 | err := db.Where("id = ?", id).First(row).Error
184 | return row, err
185 | }
186 |
187 | // Create create a user
188 | func (t *userModel) Create(name, email string) (int, error) {
189 | row := new(User)
190 | row.Name = name
191 | row.Email = email
192 | err := db.Create(row).Error
193 | if err != nil {
194 | return 0, err
195 | }
196 | return row.ID, nil
197 | }
198 | ```
199 |
200 | > 该文件来自示例程序 [api](http://github.com/go-baa/example/tree/master/api)
201 |
202 | 基本思想和控制器是一样的,先按照表结构声明一个结构体。然后创建一个空结构体将模型的方法进行封装,最后声明了一个 `UserModel`使得在控制器中无需声明就可以直接使用模型。
203 |
204 | **需要注意的是,在模型中每个方法的最后一个参数一定是`error`,表示操作是否出错,不要问为什么,规范,还是规范,这里讲的都是规范。**
205 |
206 | ## 配置文件
207 |
208 | 应用配置文件,只能是 `conf/app.ini`,这个由项目 [setting](https://github.com/go-baa/setting) 决定,为什么把路径写死了呢,为了省事,无论在哪儿引入包就能用,无需配置和传递。
209 |
210 | 更多的配置文件也建议放在 `conf` 目录中,自己去读取。
211 |
212 | 配置示例:
213 |
214 | ```
215 | // conf/app.ini
216 | [default]
217 | # app
218 | app.name = baaBlog
219 | app.version = 0.1
220 | app.url = ""
221 | debug = false
222 |
223 | # http
224 | http.address = 0.0.0.0
225 | http.port = 80
226 | http.access_open = off
227 |
228 | # output log to os.Stderr
229 | log.file = os.Stderr
230 | # 0 off, 1 fatal, 2 panic, 5 error, 6 warn, 10 info, 11 debug
231 | log.level = 11
232 |
233 | # development mode overwrite default config
234 | [development]
235 | debug = true
236 |
237 | # production mode overwrite default config
238 | [production]
239 | debug = false
240 | ```
241 |
242 | > 再次说明,这个配置文件依赖 [setting](https://github.com/go-baa/setting) 项目。
243 |
244 | ## 模板
245 |
246 | 模板最简单,按着结构放就好了。
247 |
248 | 模板的初始化和使用,参考:
249 |
250 | * [模板渲染](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#模板渲染)
251 | * [模板语法](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#模板语法)
252 | * [模板接口](https://github.com/go-baa/doc/tree/master/zh-CN/context.md#模板接口)
253 | * [render](https://github.com/go-baa/doc/tree/master/zh-CN/component/render.md)
254 | * [pongo2](https://github.com/go-baa/doc/tree/master/zh-CN/component/pongo2.md)
255 |
256 | 项目示例,参考:
257 |
258 | * [blog](https://github.com/go-baa/example/tree/master/blog)
259 |
260 | ## 静态资源
261 |
262 | 如果是一个API项目,可能没有静态资源,忽略就行。
263 |
264 | 一般的静态资源,放在那里就好了,然后注册静态资源目录:
265 |
266 | ```
267 | // router/router.go
268 |
269 | app.Static("/assets", "public/assets", false, nil)
270 | app.StaticFile("/robots.txt", "public/robots.txt")
271 | ```
272 |
273 | 如果你的项目采用了前端构建的姿势,那么你就构建吧,和baa也没什么关系,也不影响,
274 |
275 | 就是建议把构建后的资源放置到 `public`下面,比如:`public/assets/build` 然后注册静态目录,开发过程中的文件不建议放在 `public`下,因为是不可访问资源。
276 |
277 | ## 打包发布
278 |
279 | Go程序的一个好处就是,`go build`然后生成一个二进制文件,Copy到服务上就行了。
280 |
281 | 不过需要注意的是,按照以上介绍的姿势,你还要带上 `配置文件`,`模板`,`静态资源`,最后运行的目录应该是这样的:
282 |
283 | ```
284 | project
285 | |-- conf
286 | |-- app.ini
287 | |-- public
288 | |-- assets
289 | |-- build
290 | |-- css
291 | |-- images
292 | |-- js
293 | |-- robots.txt
294 | |-- template
295 | |- share
296 | |-- article
297 | |-- show.html
298 | |-- index.html
299 | |-- project // 二进制文件
300 | ```
301 |
302 | 至于你的发布姿势,是什么发布系统都没关系,要注意,打包的环境和运行的系统环境要一致,mac下编译出来的,linux可不一定能运行。
303 |
304 | > PS:我们发布时采用 gitlab + jenkins 构建 Docker镜像的方式。
305 |
306 | ### 运行
307 |
308 | **运行?**
309 |
310 | 就是 `./project` 就可以了。哦,别忘了设置环境变量:
311 |
312 | ```
313 | BAA_ENV=production
314 | ```
315 |
316 | **优雅重启?**
317 |
318 | Go1.8就要提供了,之前无论用什么方案都不可避免的要损失一些正在执行的连接。
319 |
320 | 我们目前采用的是多机部署,上线时,分批进行,保证服务有损但不下线。
321 |
322 | ### 依赖管理
323 |
324 | 依赖管理的工具有很多,我们目前使用的是 [godep](https://github.com/tools/godep),我们将产生的`Godeps`目录上传到了git中,确保构建时的环境一致。
325 |
326 |
327 |
--------------------------------------------------------------------------------
/zh-CN/context.md:
--------------------------------------------------------------------------------
1 | # Baa Context
2 |
3 | Context是HTTP上下文的意思,封装了`输入`、`输出`,提供请求处理,结果响应,模板渲染等相关操作。
4 |
5 | ## Request
6 |
7 | `c.Req`
8 |
9 | Request 中包含了所有的请求数据,是标准包中 `http.Request` 的封装,可以通过 `c.Req` 访问原生的请求结构。
10 |
11 | ### URL参数
12 |
13 | `func (c *Context) Posts() map[string]interface{}`
14 |
15 | 获取所有的POST 和 GET 数据,返回一个字典,字典的索引为表单字段的名称,值为字段的值,值如果只有一个则为 `string` 类型,值有多个则为 `[]string` 类型。
16 |
17 | `func (c *Context) Querys() map[string]interface{}`
18 |
19 | 获取所有的 GET 数据,返回一个字典,字典的索引为表单字段的名称,值为字段的值,值如果只有一个则为 `string` 类型,值有多个则为 `[]string` 类型。
20 |
21 | `func (c *Context) Query(name string) string`
22 |
23 | 根据 `name` 获取一个字段的值,返回 `string` 类型,包含 POST 和 GET 数据。
24 |
25 | `func (c *Context) QueryStrings(name string) []string`
26 |
27 | 根据 `name` 获取一个字段的多个值,返回 `[]string` 类型。
28 |
29 | `func (c *Context) QueryEscape(name string) string`
30 |
31 | 根据 `name` 获取一个字段的值,escapre编码后返回 `string` 类型。
32 |
33 | `func (c *Context) QueryTrim(name string) string`
34 |
35 | 根据 `name` 获取一个字段的值,去除两端空白后返回 `string` 类型。
36 |
37 | `func (c *Context) QueryBool(name string) bool`
38 |
39 | 根据 `name` 获取一个字段的值,并强制转化为 `bool` 类型 返回。
40 |
41 | `func (c *Context) QueryFloat(name string) float64`
42 |
43 | 根据 `name` 获取一个字段的值,并强制转化为 `float64` 类型 返回。
44 |
45 | `func (c *Context) QueryInt(name string) int`
46 |
47 | 根据 `name` 获取一个字段的值,并强制转化为 `int` 类型 返回。
48 |
49 | `func (c *Context) QueryInt32(name string) int32`
50 |
51 | 根据 `name` 获取一个字段的值,并强制转化为 `int32` 类型 返回。
52 |
53 | `func (c *Context) QueryInt64(name string) int64`
54 |
55 | 根据 `name` 获取一个字段的值,并强制转化为 `int64` 类型 返回。
56 |
57 | ### 路由参数
58 |
59 | `func (c *Context) Param(name string) string`
60 |
61 | 根据 `name` 获取一个路由参数的值,返回 `string` 类型。
62 |
63 | `func (c *Context) Params() map[string]string`
64 |
65 | 返回所有的路由参数组成的字典,字典的索引是参数名称。
66 |
67 | `func (c *Context) ParamBool(name string) bool`
68 |
69 | 根据 `name` 获取一个路由参数的值,并强制转化为 `bool` 类型 返回。
70 |
71 | `func (c *Context) ParamFloat(name string) float64`
72 |
73 | 根据 `name` 获取一个路由参数的值,并强制转化为 `float64` 类型 返回。
74 |
75 | `func (c *Context) ParamInt(name string) int`
76 |
77 | 根据 `name` 获取一个路由参数的值,并强制转化为 `int` 类型 返回。
78 |
79 | `func (c *Context) ParamInt32(name string) int32`
80 |
81 | 根据 `name` 获取一个路由参数的值,并强制转化为 `int32` 类型 返回。
82 |
83 | `func (c *Context) ParamInt64(name string) int64`
84 |
85 | 根据 `name` 获取一个路由参数的值,并强制转化为 `int64` 类型 返回。
86 |
87 | ### Cookie
88 |
89 | `func (c *Context) GetCookie(name string) string`
90 |
91 | 根据 `name` 获取一个Cookie的值,返回 `string` 类型。
92 |
93 | `func (c *Context) GetCookieBool(name string) bool`
94 |
95 | 根据 `name` 获取一个Cookie的值,并强制转化为 `bool` 类型 返回。
96 |
97 | `func (c *Context) GetCookieFloat64(name string) float64`
98 |
99 | 根据 `name` 获取一个Cookie的值,并强制转化为 `float64` 类型 返回。
100 |
101 | `func (c *Context) GetCookieInt(name string) int`
102 |
103 | 根据 `name` 获取一个Cookie的值,并强制转化为 `int` 类型 返回。
104 |
105 | `func (c *Context) GetCookieInt32(name string) int32`
106 |
107 | 根据 `name` 获取一个Cookie的值,并强制转化为 `int32` 类型 返回。
108 |
109 | `func (c *Context) GetCookieInt64(name string) int64`
110 |
111 | 根据 `name` 获取一个Cookie的值,并强制转化为 `int64` 类型 返回。
112 |
113 | `func (c *Context) SetCookie(name string, value string, others ...interface{})`
114 |
115 | 设置 名称为 `name` 值为 `value` 的Cookie。
116 |
117 | `setCookie` 还可以指定更多Cookie参数,通过可变长度的 `others` 参数可以依次指定:
118 |
119 | ```
120 | SetCookie(, , , , , , )
121 | ```
122 |
123 | 使用姿势:
124 |
125 | ```
126 | c.SetCookie("mykey", "myvalue")
127 | c.SetCookie("mykey", "myvalue", 3600)
128 | c.SetCookie("mykey", "myvalue", 3600, "/")
129 | c.SetCookie("mykey", "myvalue", 3600, "/", ".vodjk.com")
130 | c.SetCookie("mykey", "myvalue", 3600, "/", ".vodjk.com", true)
131 | c.SetCookie("mykey", "myvalue", 3600, "/", ".vodjk.com", true, true)
132 | ```
133 |
134 | > 可变参数需依次指定,不能跳过中间的参数
135 |
136 | ### 文件上传
137 |
138 | `func (c *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error)`
139 |
140 | 通过 `multipart/form-data` 表单上传的文件,可以通过 `c.GetFile` 指定文件字段获得到文件结构
141 | [multipart.File](https://godoc.org/mime/multipart#File) 和 [multipart.FileHeader](https://godoc.org/mime/multipart#FileHeader),
142 |
143 | 然后可以利用这些结构进行文件大小检测,文件类型检测,文件存储等。
144 |
145 | 举个栗子:
146 |
147 | ```
148 | func Upload(c *baa.Context) {
149 | file, header, err := c.GetFile("file1")
150 | if err != nil {
151 | c.Error(errors.New("没有文件被上传"))
152 | return
153 | }
154 | defer file.Close()
155 |
156 | savedTo := "savedFile.jpg"
157 | newFile, err := os.Create(savedTo)
158 | if err != nil {
159 | c.Error(errors.New("文件创建失败"))
160 | return
161 | }
162 | defer newFile.Close()
163 |
164 | size, err := io.Copy(newFile, file)
165 | msg := fmt.Sprintf("fileName: %s, savedTo: %s, size: %d, err: %v", header.Filename, savedTo, size, err)
166 | fmt.Println(msg)
167 |
168 | c.String(200, msg)
169 | }
170 |
171 | ```
172 |
173 | `func (c *Context) SaveToFile(name, savePath string) error`
174 |
175 | 快速保存指定的文件字段 `name` 到指定的路径 `savePath` 并返回 `nil` 或者 `error`
176 |
177 | 还是上面的例子,改一下:
178 |
179 | ```
180 | func Upload2(c *baa.Context) {
181 | savedTo := "savedFile2.jpg"
182 | err := c.SaveToFile("file1", savedTo)
183 | if err != nil {
184 | c.Error(err)
185 | return
186 | }
187 | c.String(200, savedTo)
188 | }
189 | ```
190 |
191 | ## Response
192 |
193 | `c.Resp`
194 |
195 | Response 中用于处理结果输出,是标准包中 `http.ResponseWriter` 的封装,可以通过 `c.Resp` 访问原生的接口。
196 |
197 | ### 数据存储
198 |
199 | `Context` 提供了临时存储可用于整个请求的生命周期中。
200 |
201 | `func (c *Context) Set(key string, v interface{})`
202 |
203 | 根据 `key` 设置一个值 `v` 到 `Context` 存储中。
204 |
205 | `func (c *Context) Get(key string) interface{}`
206 |
207 | 根据 `key` 从`Context`存储中获取一个值并返回。
208 |
209 | `func (c *Context) Gets() map[string]interface{}`
210 |
211 | 获取`Context`中存储的所有值,返回由这些值组成的字典。
212 |
213 | 举个例子:
214 |
215 | ```
216 | package main
217 |
218 | import (
219 | "github.com/go-baa/baa"
220 | )
221 |
222 | func main() {
223 | app := baa.New()
224 | app.Get("/", func(c *baa.Context) {
225 | c.Set("mykey", "myvalue")
226 | }, func(c *baa.Context) {
227 | val := c.Get("mykey")
228 | fmt.Println(val) // myvalue
229 |
230 | c.String(200, val.(string))
231 | })
232 |
233 | app.Run(":1323")
234 | }
235 | ```
236 |
237 | ### 内容输出
238 |
239 | baa 提供了多种形式的内容输出。
240 |
241 | `func (c *Context) String(code int, s string)`
242 |
243 | 设定输出的 http code 为 `code`,并输出一个字符串 `s`。
244 |
245 | `func (c *Context) Text(code int, s []byte)`
246 |
247 | 设定输出的 http code 为 `code`,并输出一个字节切片 `s`。
248 |
249 | `func (c *Context) JSON(code int, v interface{})`
250 |
251 | 设定输出的 http code 为 `code`,设定内容类型为 `application/json`, 把 结构 `v` 使用JSON编码后输出。
252 |
253 | `func (c *Context) JSONP(code int, callback string, v interface{})`
254 |
255 | 设定输出的 http code 为 `code`,设定内容类型为 `application/json`, 把 结构 `v` 使用JSON编码,并结合 `callback`参数输出。
256 |
257 | `func (c *Context) JSONString(v interface{}) (string, error)`
258 |
259 | 把 结构 `v` 使用JSON编码后返回。
260 |
261 | `func (c *Context) XML(code int, v interface{})`
262 |
263 | 设定输出的 http code 为 `code`,设定内容类型为 `application/json`, 把 结构 `v` 使用XML编码后输出。
264 |
265 | ## 有用的函数
266 |
267 | `func (c *Context) Baa() *Baa`
268 |
269 | `func (c *Context) Body() *RequestBody`
270 | `func (c *Context) Break()`
271 | `func (c *Context) Error(err error)`
272 |
273 | `func (c *Context) Next()`
274 | `func (c *Context) NotFound()`
275 | `func (c *Context) IsAJAX() bool`
276 | `func (c *Context) IsMobile() bool`
277 |
278 | `func (c *Context) Redirect(code int, url string) error`
279 | `func (c *Context) Referer() string`
280 | `func (c *Context) RemoteAddr() string`
281 | `func (c *Context) URL(hasQuery bool) string`
282 | `func (c *Context) UserAgent() string`
283 |
284 | ## 模板渲染
285 |
286 | baa 集成一个简单的模板渲染,使用Go标准库的 [template语法](https://godoc.org/html/template)。
287 |
288 | baa 的模板渲染使用 `Context`存储 中的数据作为模板变量。
289 |
290 | `func (c *Context) Fetch(tpl string) ([]byte, error)`
291 |
292 | 根据 `tpl` 模板文件路径,使用 `Context`存储中的数据,渲染模板并返回渲染后的内容。
293 |
294 | `func (c *Context) Render(code int, tpl string)`
295 |
296 | 设定输出的 http code 为 `code`,设定内容类型为 `text/html`, 渲染模板 `tpl` 并直接输出。
297 |
298 | > 内部就是调用的 `c.Fetch` 然后 把内容输出
299 |
300 | `func (c *Context) HTML(code int, tpl string)`
301 |
302 | `c.Render`的一个别名,用起来更顺手。
303 |
304 | 举个例子:
305 |
306 | ```
307 | package main
308 |
309 | import baa "github.com/go-baa/baa"
310 |
311 | func main() {
312 | app := baa.New()
313 | app.Get("/", func(c *baa.Context) {
314 | c.Set("title", "this is title")
315 | c.Set("content", "this is content")
316 | c.HTML(200, "template/index.html")
317 | })
318 | app.Run(":1323")
319 | }
320 |
321 | ```
322 |
323 | ```
324 |
325 |
326 |
327 |
328 |
329 | {{ .title }}
330 |
331 |
332 |
333 | {{ .content}}
334 |
335 |
336 |
337 | ```
338 |
339 | ### 模板语法
340 |
341 | 以下仅做简单介绍,完整文档请见官方 [html/template](https://godoc.org/html/template)。
342 |
343 | * 模板语法以一对 `双大括号` 包裹
344 | * 变量都是以 `.` 开始,`.` 代表所有数据组成的结构
345 | * 结构体中的字段用 `.` 表示子集
346 |
347 | #### 输出变量
348 |
349 | ```
350 | {{ .var }}
351 | {{ .user.id }}
352 | ```
353 |
354 | #### 条件语句
355 |
356 | ```
357 | {{ if .show }}
358 | i want show!
359 | {{ else }}
360 | i was hidden
361 | {{ end }}
362 | ```
363 |
364 | #### 循环语句
365 |
366 | ```
367 | {{ range .list }}
368 | {{ .id }}
369 | {{ .name }}
370 | {{ end }}
371 | ```
372 |
373 | 如果循环体不是结构体,比如就是一个字符串数组,直接用 `.` 即可输出:
374 |
375 | ```
376 | {{ range .strs }}
377 | {{ . }}
378 | {{ end }}
379 | ```
380 |
381 | ### 模板接口
382 |
383 | baa 中运行通过 `DI` 替换模板引擎,只要实现 `baa.Renderer` 接口即可。
384 |
385 | Renderer
386 |
387 | ```
388 | type Renderer interface {
389 | Render(w io.Writer, tpl string, data interface{}) error
390 | }
391 | ```
392 |
393 | 渲染接口只有一个方法 `Render`,该方法 接收三个参数:
394 |
395 | #### w `io.Writer`
396 |
397 | 一个可写入的类型,用于写入渲染后的数据,这里其实就是 `c.Resp` 。
398 |
399 | #### tpl `string`
400 |
401 | 模板文件路径
402 |
403 | #### data `interface{}`
404 |
405 | 向模板传递的数据(模板变量),这里其实传递过来的就是 `c.Gets` 的结果,是一个 `map[string]interface{}` 类型。
406 |
--------------------------------------------------------------------------------
/zh-CN/router.md:
--------------------------------------------------------------------------------
1 | # Baa 路由
2 |
3 | baa 基于 http resetfull 模式设计了路由管理器,提供了常规路由,参数路由,文件路由,静态文件路由,还有组路由。
4 |
5 | ## 常规路由
6 |
7 | ```
8 | func (b *Baa) Delete(pattern string, h ...HandlerFunc) RouteNode
9 | func (b *Baa) Get(pattern string, h ...HandlerFunc) RouteNode
10 | func (b *Baa) Head(pattern string, h ...HandlerFunc) RouteNode
11 | func (b *Baa) Options(pattern string, h ...HandlerFunc) RouteNode
12 | func (b *Baa) Patch(pattern string, h ...HandlerFunc) RouteNode
13 | func (b *Baa) Post(pattern string, h ...HandlerFunc) RouteNode
14 | func (b *Baa) Put(pattern string, h ...HandlerFunc) RouteNode
15 | ```
16 |
17 | 接受两个参数,一个是URI路径,另一个是 [HandlerFunc](https://godoc.org/github.com/go-baa/baa#HandlerFunc) 类型,设定匹配到该路径时执行的方法;允许多个,按照设定顺序进行链式处理。
18 |
19 | 返回一个 [RouteNode](https://godoc.org/github.com/go-baa/baa#RouteNode),该Node只有一个方法,`Name(name string)` 用于命名该条路由规则,以备后用。
20 |
21 | 除了以上几个标准方法,还支持多个method设定的路由姿势:
22 |
23 | ```
24 | func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) RouteNode
25 | func (b *Baa) Any(pattern string, h ...HandlerFunc) RouteNode
26 | ```
27 |
28 | ## 路由语法
29 |
30 | ### 静态路由
31 |
32 | 静态路由语法就是没有任何参数变量,pattern是一个固定的字符串。
33 |
34 | 使用示例:
35 |
36 | ```
37 | package main
38 |
39 | import (
40 | "github.com/go-baa/baa"
41 | )
42 |
43 | func main() {
44 | app := baa.New()
45 | app.Get("/foo", func(c *baa.Context) {
46 | c.String(200, c.URL(true))
47 | })
48 | app.Get("/bar", func(c *baa.Context) {
49 | c.String(200, c.URL(true))
50 | })
51 | app.Run("1323")
52 | }
53 | ```
54 |
55 | 测试:
56 |
57 | ```
58 | curl http://127.0.0.1:1323/foo
59 | curl http://127.0.0.1:1323/bar
60 | ```
61 |
62 | ### 参数路由
63 |
64 | 静态路由是最基础的,但显然满足不了需求的,我们在程序中通常相同的资源访问规则相同,不同的只是资源的编号,这时就该参数路由出场了。
65 |
66 | > 参数路由以 `/` 为拆分单位,故每两个斜线区间中只能有一个参数存在,更复杂的规则需要 正则路由。
67 |
68 | 参数路由以冒号 `:` 后面跟一个字符串作为参数名称,可以通过 `Context`的 `Param` 系列方法获取路由参数的值。
69 |
70 | 使用示例:
71 |
72 | ```
73 | package main
74 |
75 | import (
76 | "fmt"
77 | "github.com/go-baa/baa"
78 | )
79 |
80 | func main() {
81 | app := baa.New()
82 | app.Get("/user/:id", func(c *baa.Context) {
83 | c.String(200, "My user id is: " + c.Param("id"))
84 | })
85 | app.Get("/user/:id/project/:pid", func(c *baa.Context) {
86 | id := c.ParamInt("id")
87 | pid := c.ParamInt("pid")
88 | c.String(200, fmt.Sprintf("user id: %d, project id: %d", id, pid))
89 | })
90 | app.Run("1323")
91 | }
92 | ```
93 |
94 | 测试:
95 |
96 | ```
97 | curl http://127.0.0.1:1323/user/101
98 | curl http://127.0.0.1:1323/user/101/project/201
99 | ```
100 |
101 | ### 正则路由
102 |
103 | `正则路由,默认的baa中不支持正则表达式路由,需要一个增强组件来支持。`
104 |
105 | 语法和参数路由接近,并兼容参数路由,可以直接使用 正则路由替换默认路由。
106 |
107 | 参数路由以冒号 `:` 后面跟一个字符串作为参数名称,再加一对括号中间可以写正则;如果省略括号默认为 `.*` 的正则匹配。
108 |
109 | > 使用正则路由要先引入新的路由器,并通过DI替换掉内置路由。
110 |
111 | 使用示例:
112 |
113 | ```
114 | package main
115 |
116 | import (
117 | "fmt"
118 | "github.com/go-baa/baa"
119 | "github.com/go-baa/router/regtree"
120 | )
121 |
122 | func main() {
123 | app := baa.New()
124 | app.SetDI("router", regtree.New(app))
125 |
126 | app.Get("/user/:id", func(c *baa.Context) {
127 | c.String(200, "My user id is: " + c.Param("id"))
128 | })
129 | app.Get("/user/:id/project/:pid", func(c *baa.Context) {
130 | id := c.ParamInt("id")
131 | pid := c.ParamInt("pid")
132 | c.String(200, fmt.Sprintf("user id: %d, project id: %d", id, pid))
133 | })
134 |
135 | app.Get("/user-:id(\\d+)", func(c *baa.Context) {
136 | c.String(200, "My user id is: "+c.Param("id"))
137 | })
138 | app.Get("/user-:id(\\d+)-project-:pid(\\d+)", func(c *baa.Context) {
139 | id := c.ParamInt("id")
140 | pid := c.ParamInt("pid")
141 | c.String(200, fmt.Sprintf("user id: %d, project id: %d", id, pid))
142 | })
143 |
144 | app.Run("1323")
145 | }
146 | ```
147 |
148 | 测试:
149 |
150 | ```
151 | curl http://127.0.0.1:1323/user/101
152 | curl http://127.0.0.1:1323/user-101
153 | curl http://127.0.0.1:1323/user/101/project/201
154 | curl http://127.0.0.1:1323/user-101-project-201
155 | ```
156 |
157 | ## 路由选项
158 |
159 | ```
160 | func (b *Baa) SetAutoHead(v bool)
161 | ```
162 |
163 | 我记得搜索引擎很喜欢用HEAD方法来检查一个网页是否能正常访问。但我们一般又不会单独写一个HEAD的处理方法,一般行为是GET返回的数据不要内容。
164 |
165 | 使用 `app.SetAutoHead(true)` 将在设置 `GET` 方法时,自动添加 `HEAD` 路由,绑定和GET一样的处理。
166 |
167 | ```
168 | func (b *Baa) SetAutoTrailingSlash(v bool)
169 | ```
170 |
171 | 在URL访问中,一个目录要带不带最后的斜线也有很多争议,google站长工具明确表示,带不带斜线将表示不同的URL资源,但是浏览习惯问题,很多时候带不带都能访问到相同的资源目录。
172 |
173 | 使用 `app.SetAutoTrailingSlash(true)` 将处理最后的斜线,将带和不带都统一行为,自动补全最后一个斜线。
174 |
175 | ## 组路由
176 |
177 | ```
178 | func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc)
179 | ```
180 |
181 | 组路由,常常被同事问道,这个功能太好用了,你是怎么想到这样的设计,我说,我抄的,我抄的 [macaron](https://github.com/go-macaron/macaron),就是这么`直白`。
182 |
183 | 组路由,顾名思义,用来处理一组路由的需求,可以设定统一的前缀,统一的前置方法。
184 |
185 | 使用示例:
186 |
187 | ```
188 | package main
189 |
190 | import (
191 | "fmt"
192 | "github.com/go-baa/baa"
193 | )
194 |
195 | func main() {
196 | app := baa.New()
197 |
198 | app.Group("/group", func() {
199 | app.Get("/", func(c *baa.Context) {
200 | c.String(200, "我是组的首页")
201 | })
202 | app.Group("/user", func() {
203 | app.Get("/", func(c *baa.Context) {
204 | c.String(200, "我是组的用户")
205 | })
206 | app.Get("/:id", func(c *baa.Context) {
207 | c.String(200, "in group, user id: "+c.Param("id"))
208 | })
209 | })
210 | app.Get("/:gid", func(c *baa.Context) {
211 | c.String(200, "in group, group id: "+c.Param("gid"))
212 | })
213 | }, func(c *baa.Context) {
214 | // 我是组内的前置检测,过不了我这关休想访问组内的资源
215 | })
216 |
217 | app.Run("1323")
218 | }
219 | ```
220 |
221 | 测试:
222 |
223 | ```
224 | curl http://127.0.0.1:1323/group/
225 | curl http://127.0.0.1:1323/group/user/
226 | curl http://127.0.0.1:1323/group/user/101
227 | curl http://127.0.0.1:1323/group/111
228 | ```
229 |
230 | ### 链式处理
231 |
232 | 一个URL请求可以先处理A,根据A的结果再执行B。
233 |
234 | **举个例子:**
235 |
236 | 一个URL要先判断你登录过才可以访问,就可以设定两个Handler,第一个 判断是否登录,如果没登录就调到登录界面,否则继续执行第二个真正的内容。
237 |
238 | 使用示例:
239 |
240 | ```
241 | package main
242 |
243 | import (
244 | "github.com/go-baa/baa"
245 | )
246 |
247 | func main() {
248 | app := baa.Default()
249 | app.Get("/", func(c *baa.Context) {
250 | c.String(200, "Hello, 世界")
251 | })
252 | app.Post("/", func(c *baa.Context) {
253 | c.String(200, c.Req.Method)
254 | })
255 | app.Get("/admin", func(c *baa.Context) {
256 | if c.GetCookie("login_id") != "admin" {
257 | c.Redirect(302, "/login")
258 | c.Break()
259 | }
260 | }, func(c *baa.Context) {
261 | c.String(200, "恭喜你,看到后台了")
262 | })
263 | app.Get("/login", func(c *baa.Context) {
264 | c.Resp.Header().Set("Content-Type", "text/html; charset=utf-8")
265 | c.SetCookie("login_id", "admin", 3600, "/")
266 | c.Resp.Write([]byte("登录成功,点击进入后台"))
267 | })
268 | app.Run(":1323")
269 | }
270 | ```
271 |
272 | ## 命名路由
273 |
274 | ```
275 | func (n *Node) Name(name string)
276 | func (b *Baa) URLFor(name string, args ...interface{}) string
277 | ```
278 |
279 | 前面可以看到添加路由后,返回了一个 `RouteNode` 说可以做命名路由,有什么用呢?
280 |
281 | 就是给一个URL起个名字,然后在程序中可以通过 `URLFor`方法来生成这个符合这个路由的URL路径。
282 |
283 | 举个栗子:
284 |
285 | ```
286 | app := baa.New()
287 | app.Get("/user/:id/project", func(c *baa.Context) {
288 | c.String(200, c.Baa().URLFor("user_project", c.Param("id")))
289 | }).Name("user_project")
290 | ```
291 |
292 | 执行上面的方法,会输出你当前访问的URL,就是这个姿势。
293 |
294 | ## 文件路由
295 |
296 | ```
297 | func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc)
298 | func (b *Baa) StaticFile(pattern string, path string) RouteNode
299 | ```
300 |
301 | 在一个完整的应用中,我们除了业务逻辑,还有访问图片/CSS/JS等需求,通过文件路由,可以直接访问文件或文件夹。
302 |
303 | `app.StaticFile` 可以让你直接访问一个具体的文件,比如: robots.txt
304 |
305 | `app.Static` 可以访问一个目录下所有的资源,甚至列出目录结构,类似文件服务器。
306 |
307 | 举个例子:
308 |
309 | ```
310 | app := baa.New()
311 | app.Static("/assets", "/data/www/public/asssets", true, func(c *baa.Context) {
312 | // 你可以对输出的结果干点啥的
313 | })
314 | app.Static("/robots.txt", "/data/www/public/robots.txt")
315 | ```
316 |
317 | 就是酱样子,第一条路由就可以列出目录和访问下面的资源了。第二条路由可以直接返回一个静态文件。
318 |
319 | ## 自定义错误
320 |
321 | ### 500错误
322 |
323 | ```
324 | func (b *Baa) SetError(h ErrorHandleFunc)
325 | ```
326 |
327 | 要是运行过程中程序出错了,怎么办,会不会泄露你的隐私,能不能提供点错误日志?
328 |
329 | baa 默认在 `debug` 模式下向浏览器发送具体的错误信息,线上运行只显示 `Internal Server Error` 并返回 `500` 错误头。
330 |
331 | 可以通过 `app.SetError` 来设置错误处理方法,该方法接受一个 [ErrorHandleFunc](https://godoc.org/github.com/go-baa/baa#ErrorHandleFunc) 类型。
332 |
333 | ### 404错误
334 |
335 | ```
336 | func (b *Baa) SetNotFound(h HandlerFunc)
337 | ```
338 |
339 | baa默认返回 `Not Found` 和 `404` 错误头,你也可以通过 `app.SetNotFound`来自定义错误处理,该方法接受一个 [HandlerFunc](https://godoc.org/github.com/go-baa/baa#HandlerFunc) 类型。
340 |
341 |
342 | 举个栗子:
343 |
344 | ```
345 | app := baa.New()
346 | app.SetError(func(err error, c *baa.Context) {
347 | c.Baa().Logger().Println("记录日志", err)
348 | c.String(500, "出错了")
349 | })
350 | app.SetNotFound(func(c *baa.Context) {
351 | c.String(404, "页面放假了,请稍后再来。")
352 | })
353 | app.Run(":1323")
354 | ```
355 |
356 | ## Websocket
357 |
358 | ```
359 | func (b *Baa) Websocket(pattern string, h func(*websocket.Conn)) RouteNode
360 | ```
361 |
362 | Websocket 用于和浏览器进行保持通话。
363 |
364 | 在这里我们尝试了 官方的 `golang.org/x/net/websocket` 不好封装,放弃了。
365 |
366 | 官方推荐了 `github.com/gorilla/websocket` 我们试了下,不错哦,就用他了。
367 |
368 | baa 的websocket路由,用于快速开始一个 websocket 服务,混合现有应用编程。
369 |
370 | 该方法有两个参数,一个 `pattern` 路径,一个 [*websocket.Conn]() 类型的链接。
371 |
372 | 举个例子:
373 |
374 | ```
375 | package main
376 |
377 | import (
378 | "fmt"
379 | "time"
380 |
381 | "github.com/go-baa/baa"
382 | "github.com/gorilla/websocket"
383 | )
384 |
385 | func main() {
386 | app := baa.Default()
387 |
388 | app.Get("/", func(c *baa.Context) {
389 | c.String(200, "index")
390 | })
391 | app.Websocket("/socket", func(ws *websocket.Conn) {
392 | for {
393 | fmt.Println("websocket retry read...")
394 | messageType, data, err := ws.ReadMessage()
395 | if err != nil {
396 | if websocket.IsCloseError(err) {
397 | app.Logger().Println("websocket ReadMessage error: connection is closed")
398 | } else {
399 | app.Logger().Println("websocket ReadMessage error:", err)
400 | }
401 | ws.Close()
402 | return
403 | }
404 | fmt.Println("websocket receive: ", messageType, string(data))
405 | err = ws.WriteMessage(messageType, data)
406 | if err != nil {
407 | app.Logger().Println("websocket WriteMessage error:", err)
408 | ws.Close()
409 | return
410 | }
411 | }
412 | })
413 |
414 | app.Run(":1234")
415 |
416 | fmt.Println("end")
417 | }
418 | ```
419 |
420 | 含js和go代码的完整示例:[example/websocket](https://github.com/go-baa/example/tree/master/websocket)
421 |
422 | websocket的具体使用请参考 [gorilla/websocket](http://godoc.org/github.com/gorilla/websocket)
423 |
424 |
425 |
--------------------------------------------------------------------------------