72f5961d by astaxie

delete docs move to github.com/beego/beedoc

1 parent 9f6b803a
1 # Getting start with API application development
2 Go is very good for developing API applications which I think is the biggest strength compare to other dynamic languages. Beego provides powerful and quick setup tool for developing API applications, which gives you more focus on business logic.
3
4
5 ## Quick setup
6 bee can setup a API application very quick by executing commands under any `$GOPATH/src`.
7
8 `bee api beeapi`
9
10 ## Application directory structure
11
12 ```
13 ├── conf
14 │ └── app.conf
15 ├── controllers
16 │ └── default.go
17 ├── models
18 │ └── object.go
19 └── main.go
20 ```
21
22 ## Source code explanation
23
24 - app.conf has following configuration options for your API applications:
25
26 - autorender = false // Disable auto-render since API applications don't need.
27 - copyrequestbody = true // RESTFul applications sends raw body instead of form, so we need to read body specifically.
28
29 - main.go is for registering routers of RESTFul.
30
31 beego.RESTRouter("/object", &controllers.ObejctController{})
32
33 Match rules as follows:
34
35 <table>
36 <tr>
37 <th>URL</th> <th>HTTP Verb</th> <th>Functionality</th>
38 </tr>
39 <tr>
40 <td>/object</td> <td>POST</td> <td>Creating Objects</td>
41 </tr>
42 <tr>
43 <td>/object/objectId</td> <td>GET</td> <td>Retrieving Objects</td>
44 </tr>
45 <tr>
46 <td>/object/objectId</td> <td>PUT</td> <td>Updating Objects</td>
47 </tr>
48 <tr>
49 <td>/object</td> <td>GET</td> <td>Queries</td>
50 </tr>
51 <tr>
52 <td>/object/objectId</td> <td>DELETE</td> <td>Deleting Objects</td>
53 </tr>
54 </table>
55
56 - ObejctController implemented corresponding methods:
57
58 type ObejctController struct {
59 beego.Controller
60 }
61
62 func (this *ObejctController) Post(){
63
64 }
65
66 func (this *ObejctController) Get(){
67
68 }
69
70 func (this *ObejctController) Put(){
71
72 }
73
74 func (this *ObejctController) Delete(){
75
76 }
77
78 - models implemented corresponding object operation for adding, deleting, updating and getting.
79
80 ## Test
81
82 - Add a new object:
83
84 curl -X POST -d '{"Score":1337,"PlayerName":"Sean Plott"}' http://127.0.0.1:8080/object
85
86 Returns a corresponding objectID:astaxie1373349756660423900
87
88 - Query a object:
89
90 `curl -X GET http://127.0.0.1:8080/object/astaxie1373349756660423900`
91
92 - Query all objects:
93
94 `curl -X GET http://127.0.0.1:8080/object`
95
96 - Update a object:
97
98 `curl -X PUT -d '{"Score":10000}'http://127.0.0.1:8080/object/astaxie1373349756660423900`
99
100 - Delete a object:
101
102 `curl -X DELETE http://127.0.0.1:8080/object/astaxie1373349756660423900`
1 ## What is hot update?
2
3 If you have used nginx, you may know that nginx supports hot update, which means you can update your nginx without stopping and restarting it. It serves old connections with old version, and accepts new connections with new version. Notice that hot compiling is different from hot update, where hot compiling is monitoring your source files and recompile them when the content changes, it requires stop and restart your applications, `bee start` is a tool for hot compiling.
4
5
6 ## Is hot update necessary?
7
8 Some people says that hot update is not as useful as its cool name. In my opinion, this is absolutely necessary because zero-down server is our goal for our services. Even though sometimes some errors or hardware problems may occur, but it belongs to design of high availability, don't mix them up. Service update is a known issue, so we need to fix this problem.
9
10
11 ## How Beego support hot update?
12
13 The basic principle of hot update: main process fork a process, and child process execute corresponding programs. So what happens? We know that after forked a process, main process will have all handles, data and stack, etc, but all handles are saved in `CloseOnExec`, so all copied handles will be closed when you execute it unless you clarify this, and we need child process to reuse the handle of `net.Listener`. Once a process calls exec functions, it is "dead", system replaces it with new code. The only thing it left is the process ID, which is the same number but it is a new program after executed.
14
15 Therefore, the first thing we need to do is that let child process fork main process and through `os.StartProcess` to append files that contains handle that is going to be inherited.
16
17 The second step is that we hope child process can start listening from same handle, so we can use `net.FileListener` to achieve this goal. Here we also need FD of this file, so we need to add a environment variable to set this FD before we start child process.
18
19 The final step is that we want to serve old connections with old version of application, and serve new connections with new version. So how can we know if there is any old connections? To do this, we have to record all connections, then we are able to know. Another problem is that how to let new application to accept connection? Because two versions of applications are listening to same port, they get connection request randomly, so we just close old accept function, and it will get error in `l.Accept`.
20
21 Above are three problems that we need to solve, you can see my code logic for specific implementation.
22
23
24 ## Show time
25
26 1. Write code in your Get method:
27
28 func (this *MainController) Get() {
29 a, _ := this.GetInt("sleep")
30 time.Sleep(time.Duration(a) * time.Second)
31 this.Ctx.WriteString("ospid:" + strconv.Itoa(os.Getpid()))
32 }
33
34 2. Open two terminals:
35
36 One execute: ` ps -ef|grep <application name>`
37
38 Another one execute: `curl "http://127.0.0.1:8080/?sleep=20"`
39
40 3. Hot update
41
42 `kill -HUP <PID>`
43
44 4. Open a terminal to request connection: `curl "http://127.0.0.1:8080/?sleep=0"`
45
46 As you will see, the first request will wait for 20 seconds, but it's served by old process; after hot update, the first request will print old process ID, but the second request will print new process ID.
1 # Installation
2
3 Beego is a simple web framework, but it uses many third-party packages, so you have to install all dependency packages also.
4
5 - Before anything you do, you have to check that you installed Go in your computer, see more detail about Go installation in my book: [Chapter 1](https://github.com/Unknwon/build-web-application-with-golang_EN/blob/master/eBook/01.1.md)
6 - Use `go get ` to install Beego:
7
8 go get github.com/astaxie/beego
9
10 - Install bee tools for fast-develop Beego applications:
11
12 go get github.com/astaxie/bee
13
14 Good job, you're ready to Beego with powerful bee tools!
15
16 ![](images/bee.png)
17
18 Beego has following dependency packages:
19
20 - Session module: [github.com/astaxie/beego/session](https://github.com/astaxie/beego/session)
21 - To support redis engine: [github.com/garyburd/redigo/redis](https://github.com/garyburd/redigo/redis)
22 - To support mysql engine: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
23 - To support markdown as template function: [github.com/russross/blackfriday](https://github.com/russross/blackfriday)
24
25 - [Introduction](README.md)
26 - [Quick start](Quickstart.md)
1 # Quick start
2
3 Hey, you say you've never heard about Beego and don't know how to use it? Don't worry, after you read this section, you will know a lot about Beego. Before you start reading, make sure you installed Beego in your computer, if not, check this tutorial: [Installation](Install.md)
4
5 **Navigation**
6
7 - [Hello world](#hello-world)
8 - [New project](#new-project)
9 - [Development mode](#development-mode)
10 - [Router](#router)
11 - [Static files](#static-files)
12 - [Filter and middleware](#filter-and-middleware)
13 - [Controller](#controller)
14 - [Template](#template)
15 - [Handle request](#handle-request)
16 - [Redirect and error](#redirect-and-error)
17 - [Handle response](#handle-response)
18 - [Sessions](#sessions)
19 - [Cache](#cache)
20 - [Safe map](#safe-map)
21 - [Log](#log)
22 - [Configuration](#configuration)
23 - [Beego arguments](#beego-arguments)
24 - [Integrated third-party applications](#integrated-third-party-applications)
25 - [Deployment](#deployment)
26
27
28 ## Hello world
29
30 This is an example of "Hello world" in Beego:
31
32 package main
33
34 import (
35 "github.com/astaxie/beego"
36 )
37
38 type MainController struct {
39 beego.Controller
40 }
41
42 func (this *MainController) Get() {
43 this.Ctx.WriteString("hello world")
44 }
45
46 func main() {
47 beego.Router("/", &MainController{})
48 beego.Run()
49 }
50
51 Save file as "hello.go", build and run it:
52
53 $ go build main.go
54 $ ./hello
55
56 Open address [http://127.0.0.1:8080](http://127.0.0.1:8080) in your browser and you will see "hello world".
57
58 What happened in behind above example?
59
60 1. We import package `github.com/astaxie/beego`. As we know that Go initialize packages and runs init() function in every package ([more details](https://github.com/Unknwon/build-web-application-with-golang_EN/blob/master/eBook/02.3.md#main-function-and-init-function)), so Beego initializes the BeeApp application at this time.
61
62 2. Define controller. We define a struct called `MainController` with a anonymous field `beego.Controller`, so the `MainController` has all methods that `beego.Controller` has.
63
64 3. Define RESTful methods. Once we use anonymous combination, `MainController` has already had `Get`, `Post`, `Delete`, `Put` and other methods, these methods will be called when user sends corresponding request, like `Post` method for requests that are using POST method. Therefore, after we overloaded `Get` method in `MainController`, all GET requests will use `Get` method in `MainController` instead of in `beego.Controller`.
65
66 4. Define main function. All applications in Go use main function as entry point as C does.
67
68 5. Register routers, it tells Beego which controller is responsibility for specific requests. Here we register `/` for `MainController`, so all requests in `/` will be handed to `MainController`. Be aware that the first argument is the path and the second one is pointer of controller that you want to register.
69
70 6. Run application in port 8080 as default, press `Ctrl+c` to exit.
71
72
73 ## New project
74
75 Get into your $GOPATH, then use following command to setup Beego project:
76
77 bee new hello
78
79 It generates folders and files for your project, directory structure as follows:
80
81 .
82 ├── conf
83 │ └── app.conf
84 ├── controllers
85 │ └── default.go
86 ├── main.go
87 ├── models
88 ├── static
89 │ ├── css
90 │ ├── img
91 │ └── js
92 └── views
93 └── index.tpl
94
95
96 ## Development mode
97
98 Beego uses development mode as default, you can use following code to change mode in your application:
99
100 beego.RunMode = "prod"
101
102 Or use configuration file in `conf/app.conf`, and input following content:
103
104 runmode = prod
105
106 No differences between two ways.
107
108 In development mode, you have following effects:
109
110 - If you don't have directory `views`, it prints following error prompt:
111
112 2013/04/13 19:36:17 [W] [stat views: no such file or directory]
113
114 - It doesn't cache template and reload every time.
115 - If panic occurs in your server, it prints information like following screen shot:
116
117 ![](images/dev.png)
118
119
120 ## Router
121
122 The main function of router is to connect request URL and handler. Beego wrapped `Controller`, so it connects request URL and `ControllerInterface`. The `ControllerInterface` has following methods:
123
124 type ControllerInterface interface {
125 Init(ct *Context, cn string)
126 Prepare()
127 Get()
128 Post()
129 Delete()
130 Put()
131 Head()
132 Patch()
133 Options()
134 Finish()
135 Render() error
136 }
137
138 `beego.Controller` implemented all of them, so you just use this struct as anonymous field in your controller struct. Of course you have to overload corresponding methods for more specific usages.
139
140 Users can use following ways to register route rules:
141
142 beego.Router("/", &controllers.MainController{})
143 beego.Router("/admin", &admin.UserController{})
144 beego.Router("/admin/index", &admin.ArticleController{})
145 beego.Router("/admin/addpkg", &admin.AddController{})
146
147 For more convenient configure route rules, Beego references the idea from sinatra, so it supports more kinds of route rules as follows:
148
149 - beego.Router("/api/:id([0-9]+)", &controllers.RController{})
150
151 Customized regular expression match // match /api/123 :id= 123
152
153 - beego.Router("/news/:all", &controllers.RController{})
154
155 Match rest of all // match /news/path/to/123.html :all= path/to/123.html
156
157 - beego.Router("/user/:username([\w]+)", &controllers.RController{})
158
159 Regular expression // match /user/astaxie :username = astaxie
160
161 - beego.Router("/download/`*`.`*`", &controllers.RController{})
162
163 Wildcard character // match /download/file/api.xml :path= file/api :ext=xml
164
165 - beego.Router("/download/ceshi/`*`", &controllers.RController{})
166
167 wildcard character match rest of all // match /download/ceshi/file/api.json :splat=file/api.json
168
169 - beego.Router("/:id:int", &controllers.RController{})
170
171 Match type int // match :id is int type, Beego uses regular expression ([0-9]+) automatically
172
173 - beego.Router("/:hi:string", &controllers.RController{})
174
175 Match type string // match :hi is string type, Beego uses regular expression ([\w]+) automatically
176
177
178 ## Static files
179
180 Go provides `http.ServeFile` for static files, Beego wrapped this function and use following way to register static file folder:
181
182 beego.SetStaticPath("/static","public")
183
184 - The first argument is the path of your URL.
185 - The second argument is the directory in your application path.
186
187 Beego supports multiple static file directories as follows:
188
189 beego.SetStaticPath("/images","images")
190 beego.SetStaticPath("/css","css")
191 beego.SetStaticPath("/js","js")
192
193 After you setting static directory, when users visit `/images/login/login.png`,Beego accesses `images/login/login.png` in related to your application directory. One more example, if users visit `/static/img/logo.png`, Beego accesses file `public/img/logo.png`.
194
195
196 ## Filter and middleware
197
198 Beego supports customized filter and middleware, such as security verification, force redirect, etc.
199
200 Here is an example of verify user name of all requests, check if it's admin.
201
202 var FilterUser = func(w http.ResponseWriter, r *http.Request) {
203 if r.URL.User == nil || r.URL.User.Username() != "admin" {
204 http.Error(w, "", http.StatusUnauthorized)
205 }
206 }
207
208 beego.Filter(FilterUser)
209
210 You can also filter by arguments:
211
212 beego.Router("/:id([0-9]+)", &admin.EditController{})
213 beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) {
214 dosomething()
215 })
216
217 Filter by prefix is also available:
218
219 beego.FilterPrefixPath("/admin", func(rw http.ResponseWriter, r *http.Request) {
220 dosomething()
221 })
222
223
224 ## Controller
225
226 Use `beego.controller` as anonymous in your controller struct to implement the interface in Beego:
227
228 type xxxController struct {
229 beego.Controller
230 }
231
232 `beego.Controller` implemented`beego.ControllerInterface`, `beego.ControllerInterface` defined following methods:
233
234 - Init(ct `*`Context, cn string)
235
236 Initialize context, controller's name, template's name, and container of template arguments
237
238 - Prepare()
239
240 This is for expend usages, it executes before all the following methods. Users can overload this method for verification for example.
241
242 - Get()
243
244 This method executes when client sends request as GET method, 403 as default status code. Users overload this method for customized handle process of GET method.
245
246 - Post()
247
248 This method executes when client sends request as POST method, 403 as default status code. Users overload this method for customized handle process of POST method.
249
250 - Delete()
251
252 This method executes when client sends request as DELETE method, 403 as default status code. Users overload this method for customized handle process of DELETE method.
253
254 - Put()
255
256 This method executes when client sends request as PUT method, 403 as default status code. Users overload this method for customized handle process of PUT method.
257
258 - Head()
259
260 This method executes when client sends request as HEAD method, 403 as default status code. Users overload this method for customized handle process of HEAD method.
261
262 - Patch()
263
264 This method executes when client sends request as PATCH method, 403 as default status code. Users overload this method for customized handle process of PATCH method.
265
266 - Options()
267
268 This method executes when client sends request as OPTIONS method, 403 as default status code. Users overload this method for customized handle process of OPTIONS method.
269
270 - Finish()
271
272 This method executes after corresponding method finished, empty as default. User overload this method for more usages like close database, clean data, etc.
273
274 - Render() error
275
276 This method is for rendering template, it executes automatically when you set beego.AutoRender to true.
277
278 Overload all methods for all customized logic processes, let's see an example:
279
280 type AddController struct {
281 beego.Controller
282 }
283
284 func (this *AddController) Prepare() {
285
286 }
287
288 func (this *AddController) Get() {
289 this.Data["content"] = "value"
290 this.Layout = "admin/layout.html"
291 this.TplNames = "admin/add.tpl"
292 }
293
294 func (this *AddController) Post() {
295 pkgname := this.GetString("pkgname")
296 content := this.GetString("content")
297 pk := models.GetCruPkg(pkgname)
298 if pk.Id == 0 {
299 var pp models.PkgEntity
300 pp.Pid = 0
301 pp.Pathname = pkgname
302 pp.Intro = pkgname
303 models.InsertPkg(pp)
304 pk = models.GetCruPkg(pkgname)
305 }
306 var at models.Article
307 at.Pkgid = pk.Id
308 at.Content = content
309 models.InsertArticle(at)
310 this.Ctx.Redirect(302, "/admin/index")
311 }
312
313
314 ## Template
315
316
317 ### Template directory
318
319 Beego uses `views` as the default directory for template files, parses and caches them as needed(cache is not enable in develop mode), but you can **change**(because only one directory can be used for template files) its directory using following code:
320
321 beego.ViewsPath = "/myviewpath"
322
323
324 ### Auto-render
325
326 You don't need to call render function manually, Beego calls it automatically after corresponding methods executed. If your application is somehow doesn't need templates, you can disable this feature either in code of `main.go` or configuration file.
327
328 To disable auto-render in configuration file:
329
330 autorender = false
331
332 To disable auto-render in `main.go`(before you call `beego.Run()` to run the application):
333
334 beego.AutoRender = false
335
336
337 ### Template data
338
339 You can use `this.Data` in controller methods to access the data in templates. Suppose you want to get content of `{{.Content}}`, you can use following code to do this:
340
341 this.Data["Content"] = "value"
342
343
344 ### Template name
345
346 Beego uses built-in template engine of Go, so there is no different in syntax. As for how to write template file, please visit [Template tutorial](https://github.com/Unknwon/build-web-application-with-golang_EN/blob/master/eBook/07.4.md).
347
348 Beego parses template files in `viewpath` and render it after you set the name of the template file in controller methods. For example, Beego finds the file `add.tpl` in directory `admin` in following code:
349
350 this.TplNames = "admin/add.tpl"
351
352 Beego supports two kinds of extensions for template files, which are `tpl` and `html`, if you want to use other extensions, you have to use following code to let Beego know:
353
354 beego.AddTemplateExt("<your template file extension>")
355
356 If you enabled auto-render and you don't tell Beego which template file you are going to use in controller methods, Beego uses following format to find the template file if it exists:
357
358 c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt
359
360 Which is `<corresponding controller name>/<request method name>.<template extension>`. For example, your controller name is `AddController` and the request method is POST, and the default file extension is `tpl`, so Beego will try to find file `/<viewpath>/AddController/POST.tpl`.
361
362
363 ### Layout design
364
365 Beego supports layout design, which means if you are working on an administration application, and some part of its user interface is exactly same all the time, then you can make this part as a layout.
366
367 this.Layout = "admin/layout.html"
368 this.TplNames = "admin/add.tpl"
369
370 You have to set following variable in order to make Beego possible to insert your dynamic content:
371
372 {{.LayoutContent}}
373
374 Beego parses template file and assign content to `LayoutContent`, and render them together.
375
376 Right now, Beego caches all template files, so you can use following way to implement another kind of layout:
377
378 {{template "header.html"}}
379 Handle logic
380 {{template "footer.html"}}
381
382
383 ### Template function
384
385 Beego supports customized template functions that are registered before you call `beego.Run()`.
386
387 func hello(in string)(out string){
388 out = in + "world"
389 return
390 }
391
392 beego.AddFuncMap("hi",hello)
393
394 Then you can use this function in your template files:
395
396 {{.Content | hi}}
397
398 There are some built-in template functions:
399
400 * markdown
401
402 This function converts markdown content to HTML format, use {{markdown .Content}} in template files.
403
404 * dateformat
405
406 This function converts time to formatted string, use {{dateformat .Time "2006-01-02T15:04:05Z07:00"}} in template files.
407
408 * date
409
410 This function implements date function like in PHP, use formatted string to get corresponding time, use {{date .T "Y-m-d H:i:s"}} in template files.
411
412 * compare
413
414 This functions compares two objects, returns true if they are same, false otherwise, use {{compare .A .B}} in template files.
415
416 * substr
417
418 This function cuts out string from another string by index, it supports UTF-8 characters, use {{substr .Str 0 30}} in template files.
419
420 * html2str
421
422 This function escapes HTML to raw string, use {{html2str .Htmlinfo}} in template files.
423
424 * str2html
425
426 This function outputs string in HTML format without escaping, use {{str2html .Strhtml}} in template files.
427
428 * htmlquote
429
430 This functions implements basic HTML escape, use {{htmlquote .quote}} in template files.
431
432 * htmlunquote
433
434 This functions implements basic invert-escape of HTML, use {{htmlunquote .unquote}} in template files.
435
436
437 ## Handle request
438
439 We always need to get data from users, including methods like GET, POST, etc. Beego parses these data automatically, and you can access them by following code:
440
441 - GetString(key string) string
442 - GetInt(key string) (int64, error)
443 - GetBool(key string) (bool, error)
444
445 Usage example:
446
447 func (this *MainController) Post() {
448 jsoninfo := this.GetString("jsoninfo")
449 if jsoninfo == "" {
450 this.Ctx.WriteString("jsoninfo is empty")
451 return
452 }
453 }
454
455 If you need other types that are not included above, like you need int64 instead of int, then you need to do following way:
456
457 func (this *MainController) Post() {
458 id := this.Input().Get("id")
459 intid, err := strconv.Atoi(id)
460 }
461
462 To use `this.Ctx.Request` for more information about request, and object properties and method please read [Request](http://golang.org/pkg/net/http/#Request)
463
464
465 ### File upload
466
467 It's very easy to upload file through Beego, but don't forget to add `enctype="multipart/form-data"` in your form, otherwise the browser will not upload anything.
468
469 Files will be saved in memory, if the size is greater than cache memory, the rest part will be saved as temporary file. The default cache memory is 64 MB, and you can use following ways to change this size.
470
471 In code:
472
473 beego.MaxMemory = 1<<22
474
475 In configuration file:
476
477 maxmemory = 1<<22
478
479 Beego provides two convenient functions to upload files:
480
481 - GetFile(key string) (multipart.File, `*`multipart.FileHeader, error)
482
483 This function is mainly used to read file name element `the_file` in form and returns corresponding information. You can use this information either filter or save files.
484
485 - SaveToFile(fromfile, tofile string) error
486
487 This function a wrapper of GetFile and gives ability to save file.
488
489 This is an example to save file that is uploaded:
490
491 func (this *MainController) Post() {
492 this.SaveToFile("the_file","/var/www/uploads/uploaded_file.txt"")
493 }
494
495
496 ### Output Json and XML
497
498 Beego considered API function design at the beginning, and we often use Json or XML format data as output. Therefore, it's no reason that Beego doesn't support it:
499
500 Set `content-type` to `application/json` for output raw Json format data:
501
502 func (this *AddController) Get() {
503 mystruct := { ... }
504 this.Data["json"] = &mystruct
505 this.ServeJson()
506 }
507
508 Set `content-type` to `application/xml` for output raw XML format data:
509
510 func (this *AddController) Get() {
511 mystruct := { ... }
512 this.Data["xml"]=&mystruct
513 this.ServeXml()
514 }
515
516
517 ## Redirect and error
518
519 You can use following to redirect:
520
521 func (this *AddController) Get() {
522 this.Redirect("/", 302)
523 }
524
525 You can also throw an exception in your controller as follows:
526
527 func (this *MainController) Get() {
528 this.Abort("401")
529 v := this.GetSession("asta")
530 if v == nil {
531 this.SetSession("asta", int(1))
532 this.Data["Email"] = 0
533 } else {
534 this.SetSession("asta", v.(int)+1)
535 this.Data["Email"] = v.(int)
536 }
537 this.TplNames = "index.tpl"
538 }
539
540 Then Beego will not execute rest code of the function body when you call `this.Abort("401")`, and gives following default page view to users:
541
542 ![](images/401.png)
543
544 Beego supports following error code: 404, 401, 403, 500 and 503, you can customize your error handle, for example, use following code to replace 404 error handle process:
545
546 func page_not_found(rw http.ResponseWriter, r *http.Request) {
547 t, _ := template.New("beegoerrortemp").ParseFiles(beego.ViewsPath + "/404.html")
548 data := make(map[string]interface{})
549 data["content"] = "page not found"
550 t.Execute(rw, data)
551 }
552
553 func main() {
554 beego.Errorhandler("404", page_not_found)
555 beego.Router("/", &controllers.MainController{})
556 beego.Run()
557 }
558
559 You may be able to use your own `404.html` for your 404 error.
560
561 Beego also gives you ability to modify error message that shows on the error page, the following example shows how to set more meaningful error message when database has problems:
562
563 func dbError(rw http.ResponseWriter, r *http.Request) {
564 t, _ := template.New("beegoerrortemp").ParseFiles(beego.ViewsPath + "/dberror.html")
565 data := make(map[string]interface{})
566 data["content"] = "database is now down"
567 t.Execute(rw, data)
568 }
569
570 func main() {
571 beego.Errorhandler("dbError", dbError)
572 beego.Router("/", &controllers.MainController{})
573 beego.Run()
574 }
575
576 After you registered this customized error, you can use `this.Abort("dbError")` for any database error in your applications.
577
578
579 ## Handle response
580
581 There are some situations that you may have in response:
582
583 1. Output template
584
585 I've already talked about template above, Beego outputs template after corresponding method executed.
586
587 2. Redirect
588
589 You can use this.Redirect("/", 302) to redirect page.
590
591 3. Output string
592
593 Sometimes we just need to print string on the screen:
594
595 this.Ctx.WriteString("ok")
596
597
598 ## Sessions
599
600 Beego has a built-in session module and supports four engines, including memory, file, MySQL and redis. You can implement your own engine based on the interface.
601
602 It's easy to use session in Beego, use following code in your main() function:
603
604 beego.SessionOn = true
605
606 Or use configuration file:
607
608 sessionon = true
609
610 The following example shows you how to use session in Beego:
611
612 func (this *MainController) Get() {
613 v := this.GetSession("asta")
614 if v == nil {
615 this.SetSession("asta", int(1))
616 this.Data["num"] = 0
617 } else {
618 this.SetSession("asta", v.(int)+1)
619 this.Data["num"] = v.(int)
620 }
621 this.TplNames = "index.tpl"
622 }
623
624 We can see that there are few convenient methods:
625
626 - SetSession(name string, value interface{})
627 - GetSession(name string) interface{}
628 - DelSession(name string)
629
630 There are three kinds of operation for session: set, get, and delete.
631
632 Of course you can use following code to customized session logic:
633
634 sess:=this.StartSession()
635 defer sess.SessionRelease()
636
637 The sess object has following methods:
638
639 * sess.Set()
640 * sess.Get()
641 * sess.Delete()
642 * sess.SessionID()
643
644 However, I recommend you to use SetSession、GetSession、DelSession these three operations in order to prevent resource leak.
645
646 There are some arguments you can use in session module:
647
648 - SessionOn
649
650 Whether enable session or not, default is false, corresponding arguments in configuration file: sessionon.
651
652 - SessionProvider
653
654 Setting session engine, default is memory, other options are file, MySQL and redis, corresponding arguments in configuration file: sessionprovider.
655
656 - SessionName
657
658 Setting name of cookies, it saves in users' browser with name beegosessionID, corresponding arguments in configuration file: sessionname.
659
660 - SessionGCMaxLifetime
661
662 Setting session expired time, default is 3600 seconds, corresponding arguments in configuration: sessiongcmaxlifetime
663
664 - SessionSavePath
665
666 Setting save path or link address of corresponding file, MySQL and redis engines, default is empty, corresponding arguments in configuration file: sessionsavepath
667
668 When the SessionProvider is file, SessionSavePath saves file path:
669
670 beego.SessionProvider = "file"
671 beego.SessionSavePath = "./tmp"
672
673 When the SessionProvider is mysql, SessionSavePath is link address, it uses driver [go-sql-driver](https://github.com/go-sql-driver/mysql):
674
675 beego.SessionProvider = "mysql"
676 beego.SessionSavePath = "username:password@protocol(address)/dbname?param=value"
677
678 When the SessionProvider is redis, SessionSavePath is link address of redis, it uses driver [redigo](https://github.com/garyburd/redigo):
679
680 beego.SessionProvider = "redis"
681 beego.SessionSavePath = "127.0.0.1:6379"
682
683
684 ## Cache
685
686 Beego has a built-in cache module, it's like memcache, which caches data in memory. Here is an example of using cache module in Beego:
687
688 var (
689 urllist *beego.BeeCache
690 )
691
692 func init() {
693 urllist = beego.NewBeeCache()
694 urllist.Every = 0 // Not expired
695 urllist.Start()
696 }
697
698 func (this *ShortController) Post() {
699 var result ShortResult
700 longurl := this.Input().Get("longurl")
701 beego.Info(longurl)
702 result.UrlLong = longurl
703 urlmd5 := models.GetMD5(longurl)
704 beego.Info(urlmd5)
705 if urllist.IsExist(urlmd5) {
706 result.UrlShort = urllist.Get(urlmd5).(string)
707 } else {
708 result.UrlShort = models.Generate()
709 err := urllist.Put(urlmd5, result.UrlShort, 0)
710 if err != nil {
711 beego.Info(err)
712 }
713 err = urllist.Put(result.UrlShort, longurl, 0)
714 if err != nil {
715 beego.Info(err)
716 }
717 }
718 this.Data["json"] = result
719 this.ServeJson()
720 }
721
722 To use cache, you need to initialize a `beego.NewBeeCache` object and set expired time, and enable expired check. Then you can use following methods to achieve other operations:
723
724 - Get(name string) interface{}
725 - Put(name string, value interface{}, expired int) error
726 - Delete(name string) (ok bool, err error)
727 - IsExist(name string) bool
728
729
730 ## Safe map
731
732 We know that map is not thread safe in Go, if you don't know it, this article may be helpful for you: [atomic_maps](http://golang.org/doc/faq#atomic_maps). However, we need a kind of thread safe map in practice, especially when we are using goroutines. Therefore, Beego provides a simple built-in thread safe map implementation.
733
734 bm := NewBeeMap()
735 if !bm.Set("astaxie", 1) {
736 t.Error("set Error")
737 }
738 if !bm.Check("astaxie") {
739 t.Error("check err")
740 }
741
742 if v := bm.Get("astaxie"); v.(int) != 1 {
743 t.Error("get err")
744 }
745
746 bm.Delete("astaxie")
747 if bm.Check("astaxie") {
748 t.Error("delete err")
749 }
750
751 This map has following interfaces:
752
753 - Get(k interface{}) interface{}
754 - Set(k interface{}, v interface{}) bool
755 - Check(k interface{}) bool
756 - Delete(k interface{})
757
758
759 ## Log
760
761 Beego has a default BeeLogger object that outputs log into stdout, and you can use your own logger as well:
762
763 beego.SetLogger(*log.Logger)
764
765 Now Beego supports new way to record your log with automatically log rotate. Use following code in your main function:
766
767 filew := beego.NewFileWriter("tmp/log.log", true)
768 err := filew.StartLogger()
769 if err != nil {
770 beego.Critical("NewFileWriter err", err)
771 }
772
773 So Beego records your log into file `tmp/log.log`, the second argument indicates whether enable log rotate or not. The rules of rotate as follows:
774
775 1. segment log every 1,000,000 lines.
776 2. segment log every 256 MB file size.
777 3. segment log daily.
778 4. save log file up to 7 days as default.
779
780 You cannot segment log over 999 times everyday, the segmented file name with format `<defined file name>.<date>.<three digits>`.
781
782 You are able to modify rotate rules with following methods, be sure that you call them before `StartLogger()`.
783
784 - func (w *FileLogWriter) SetRotateDaily(daily bool) *FileLogWriter
785 - func (w *FileLogWriter) SetRotateLines(maxlines int) *FileLogWriter
786 - func (w *FileLogWriter) SetRotateMaxDays(maxdays int64) *FileLogWriter
787 - func (w *FileLogWriter) SetRotateSize(maxsize int) *FileLogWriter
788
789 ### Different levels of log
790
791 * Trace(v ...interface{})
792 * Debug(v ...interface{})
793 * Info(v ...interface{})
794 * Warn(v ...interface{})
795 * Error(v ...interface{})
796 * Critical(v ...interface{})
797
798 You can use following code to set log level:
799
800 beego.SetLevel(beego.LevelError)
801
802 Your project may have a lot of log outputs, but you don't want to output everything after your application is running on the internet, for example, you want to ignore Trace, Debug and Info level log outputs, you can use following setting:
803
804 beego.SetLevel(beego.LevelWarning)
805
806 Then Beego will not output log that has lower level of LevelWarning. Here is the list of all log levels, order from lower to higher:
807
808 LevelTrace, LevelDebug, LevelInfo, LevelWarning, LevelError, LevelCritical
809
810 You can use different log level to output different error messages, it's based on how critical the error you think it is:
811
812
813 ### Examples of log messages
814
815 - Trace
816
817 * "Entered parse function validation block"
818 * "Validation: entered second 'if'"
819 * "Dictionary 'Dict' is empty. Using default value"
820
821 - Debug
822
823 * "Web page requested: http://somesite.com Params='...'"
824 * "Response generated. Response size: 10000. Sending."
825 * "New file received. Type:PNG Size:20000"
826
827 - Info
828
829 * "Web server restarted"
830 * "Hourly statistics: Requested pages: 12345 Errors: 123 ..."
831 * "Service paused. Waiting for 'resume' call"
832
833 - Warn
834
835 * "Cache corrupted for file='test.file'. Reading from back-end"
836 * "Database 192.168.0.7/DB not responding. Using backup 192.168.0.8/DB"
837 * "No response from statistics server. Statistics not sent"
838
839 - Error
840
841 * "Internal error. Cannot process request #12345 Error:...."
842 * "Cannot perform login: credentials DB not responding"
843
844 - Critical
845
846 * "Critical panic received: .... Shutting down"
847 * "Fatal error: ... App is shutting down to prevent data corruption or loss"
848
849
850 ### Example
851
852 func internalCalculationFunc(x, y int) (result int, err error) {
853 beego.Debug("calculating z. x:",x," y:",y)
854 z := y
855 switch {
856 case x == 3 :
857 beego.Trace("x == 3")
858 panic("Failure.")
859 case y == 1 :
860 beego.Trace("y == 1")
861 return 0, errors.New("Error!")
862 case y == 2 :
863 beego.Trace("y == 2")
864 z = x
865 default :
866 beego.Trace("default")
867 z += x
868 }
869 retVal := z-3
870 beego.Debug("Returning ", retVal)
871
872 return retVal, nil
873 }
874
875 func processInput(input inputData) {
876 defer func() {
877 if r := recover(); r != nil {
878 beego.Error("Unexpected error occurred: ", r)
879 outputs <- outputData{result : 0, error : true}
880 }
881 }()
882 beego.Info("Received input signal. x:",input.x," y:", input.y)
883
884 res, err := internalCalculationFunc(input.x, input.y)
885 if err != nil {
886 beego.Warn("Error in calculation:", err.Error())
887 }
888
889 beego.Info("Returning result: ",res," error: ",err)
890 outputs <- outputData{result : res, error : err != nil}
891 }
892
893 func main() {
894 inputs = make(chan inputData)
895 outputs = make(chan outputData)
896 criticalChan = make(chan int)
897 beego.Info("App started.")
898
899 go consumeResults(outputs)
900 beego.Info("Started receiving results.")
901
902 go generateInputs(inputs)
903 beego.Info("Started sending signals.")
904
905 for {
906 select {
907 case input := <- inputs:
908 processInput(input)
909 case <- criticalChan:
910 beego.Critical("Caught value from criticalChan: Go shut down.")
911 panic("Shut down due to critical fault.")
912 }
913 }
914 }
915
916
917 ## Configuration
918
919 Beego supports to parse .ini file in path `conf/app.conf`, and you have following options:
920
921 appname = beepkg
922 httpaddr = "127.0.0.1"
923 httpport = 9090
924 runmode ="dev"
925 autorender = false
926 autorecover = false
927 viewspath = "myview"
928
929 If you set value in configuration file, Beego uses it to replace default value.
930
931 You can also have other values for your application, for example, database connection information:
932
933 mysqluser = "root"
934 mysqlpass = "rootpass"
935 mysqlurls = "127.0.0.1"
936 mysqldb = "beego"
937
938 Then use following code to load your settings:
939
940 beego.AppConfig.String("mysqluser")
941 beego.AppConfig.String("mysqlpass")
942 beego.AppConfig.String("mysqlurls")
943 beego.AppConfig.String("mysqldb")
944
945 AppConfig supports following methods:
946
947 - Bool(key string) (bool, error)
948 - Int(key string) (int, error)
949 - Int64(key string) (int64, error)
950 - Float(key string) (float64, error)
951 - String(key string) string
952
953
954 ## Beego arguments
955
956 Beego has many configurable arguments, let me introduce to you all of them, so you can use them for more usage in your application:
957
958 * BeeApp
959
960 Entry point of Beego, it initialized in init() function when you import Beego package.
961
962 * AppConfig
963
964 It stores values from file `conf/app.conf` and initialized in init() function.
965
966 * HttpAddr
967
968 Application listening address, default is empty for listening all IP.
969
970 * HttpPort
971
972 Application listening port, default is 8080.
973
974 * AppName
975
976 Application name, default is "beego".
977
978 * RunMode
979
980 Application mode, default is "dev" develop mode and gives friendly error messages.
981
982 * AutoRender
983
984 This value indicates whether auto-render or not, default is true, you should set to false for API usage applications.
985
986 * RecoverPanic
987
988 This value indicates whether recover from panic or not, default is true, and program will not exit when error occurs.
989
990 * PprofOn
991
992 This value indicates whether enable pprof or not, default is false, and you can use following address to see goroutine execution status once you enable this feature.
993
994 /debug/pprof
995 /debug/pprof/cmdline
996 /debug/pprof/profile
997 /debug/pprof/symbol
998
999 For more information about pprof, please read [pprof](http://golang.org/pkg/net/http/pprof/)
1000
1001 * ViewsPath
1002
1003 Template path, default is "views".
1004
1005 * SessionOn
1006
1007 This value indicate whether enable session or not, default is false.
1008
1009 * SessionProvider
1010
1011 Session engine, default is memory.
1012
1013 * SessionName
1014
1015 Name for cookie that save in client browser, default is "beegosessionID".
1016
1017 * SessionGCMaxLifetime
1018
1019 Session expired time, default is 3600 seconds.
1020
1021 * SessionSavePath
1022
1023 Save path of session, default is empty.
1024
1025 * UseFcgi
1026
1027 This value indicates whether enable fastcgi or not, default is false.
1028
1029 * MaxMemory
1030
1031 Maximum memory size for file upload, default is `1 << 26`(64M).
1032
1033 * EnableGzip
1034
1035 This value indicate whether enable gzip or not, default is false.
1036
1037
1038 ## Integrated third-party applications
1039
1040 Beego supports to integrate third-party application, you can customized `http.Handler` as follows:
1041
1042 beego.RouterHandler("/chat/:info(.*)", sockjshandler)
1043
1044 sockjshandler implemented interface `http.Handler`.
1045
1046 Beego has an example for supporting chat of sockjs, here is the code:
1047
1048 package main
1049
1050 import (
1051 "fmt"
1052 "github.com/astaxie/beego"
1053 "github.com/fzzy/sockjs-go/sockjs"
1054 "strings"
1055 )
1056
1057 var users *sockjs.SessionPool = sockjs.NewSessionPool()
1058
1059 func chatHandler(s sockjs.Session) {
1060 users.Add(s)
1061 defer users.Remove(s)
1062
1063 for {
1064 m := s.Receive()
1065 if m == nil {
1066 break
1067 }
1068 fullAddr := s.Info().RemoteAddr
1069 addr := fullAddr[:strings.LastIndex(fullAddr, ":")]
1070 m = []byte(fmt.Sprintf("%s: %s", addr, m))
1071 users.Broadcast(m)
1072 }
1073 }
1074
1075 type MainController struct {
1076 beego.Controller
1077 }
1078
1079 func (m *MainController) Get() {
1080 m.TplNames = "index.html"
1081 }
1082
1083 func main() {
1084 conf := sockjs.NewConfig()
1085 sockjshandler := sockjs.NewHandler("/chat", chatHandler, conf)
1086 beego.Router("/", &MainController{})
1087 beego.RouterHandler("/chat/:info(.*)", sockjshandler)
1088 beego.Run()
1089 }
1090
1091 The above example implemented a simple chat room for sockjs, and you can use `http.Handler` for more extensions.
1092
1093
1094 ## Deployment
1095
1096 Go compiles program to binary file, you only need to copy this binary to your server and run it. Because Beego uses MVC model, so you may have folders for static files, configuration files and template files, so you have to copy those files as well. Here is a real example for deployment.
1097
1098 $ mkdir /opt/app/beepkg
1099 $ cp beepkg /opt/app/beepkg
1100 $ cp -fr views /opt/app/beepkg
1101 $ cp -fr static /opt/app/beepkg
1102 $ cp -fr conf /opt/app/beepkg
1103
1104 Here is the directory structure pf `/opt/app/beepkg`.
1105
1106 .
1107 ├── conf
1108 │ ├── app.conf
1109 ├── static
1110 │ ├── css
1111 │ ├── img
1112 │ └── js
1113 └── views
1114 └── index.tpl
1115 ├── beepkg
1116
1117 Now you can run your application in server, here are two good ways to manage your applications, and I recommend the first one.
1118
1119 - Supervisord
1120
1121 More information: [Supervisord](Supervisord.md)
1122
1123 - nohup
1124
1125 nohup ./beepkg &
1126
1127 - [Introduction](README.md)
1128 - [Step by step](Tutorial.md)
1 # Beego
2
3 Beego is a lightweight, open source, non-blocking and scalable web framework for the Go programming language. It's like tornado in Python. This web framework has already been using for building web server and tools in SNDA's CDN system. Documentation and downloads available at [http://astaxie.github.com/beego](http://astaxie.github.com/beego)
4
5 It has following main features:
6
7 - Supports MVC model, you only need to focus on logic and implementation methods.
8 - Supports websocket, use customized handlers to integrate sockjs.
9 - Supports customized router rules, including regex and semanteme.
10 - Session integration, supports memory, file, redis, mysql, etc.
11 - Automated parsing user form, you can get data very easy.
12 - Log level system, easy to record debugging and deployment logs.
13 - Use configuration file (.ini) to customized your system.
14 - Use built-in templates in Go, and it provides much more useful functions which are commonly used in web development.
15
16 The working principles of Beego as follows:
17
18 ![](images/beego.png)
19
20 Beego is licensed under the Apache Licence, Version 2.0
21 (http://www.apache.org/licenses/LICENSE-2.0.html).
22
23
24 # Simple example
25
26 The following example prints string "Hello world" to your browser, it shows how easy to build a web application with Beego.
27
28 package main
29
30 import (
31 "github.com/astaxie/beego"
32 )
33
34 type MainController struct {
35 beego.Controller
36 }
37
38 func (this *MainController) Get() {
39 this.Ctx.WriteString("hello world")
40 }
41
42 func main() {
43 beego.Router("/", &MainController{})
44 beego.Run()
45 }
46
47
48 # Handbook
49
50 - [Purposes](Why.md)
51 - [Installation](Install.md)
52 - [Quick start](Quickstart.md)
53 - [Step by step](Tutorial.md)
54 - [Real world usage](Application.md)
55 - [Hot update](HotUpdate.md)
56
57
58 # Documentation
59
60 [Go Walker](http://gowalker.org/github.com/astaxie/beego)
1 ## Supervisord
2
3 [Supervisord](http://supervisord.org/) will make sure your web app is always up.
4
5 1. Installation
6
7 wget http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg
8
9 sh setuptools-0.6c11-py2.7.egg
10
11 easy_install supervisor
12
13 echo_supervisord_conf >/etc/supervisord.conf
14
15 mkdir /etc/supervisord.conf.d
16
17 2. Configure `/etc/supervisord.conf`
18
19 [include]
20 files = /etc/supervisord.conf.d/*.conf
21
22 3. Add new application
23
24 cd /etc/supervisord.conf.d
25 vim beepkg.conf
26
27 Configuration file:
28
29 [program:beepkg]
30 directory = /opt/app/beepkg
31 command = /opt/app/beepkg/beepkg
32 autostart = true
33 startsecs = 5
34 user = root
35 redirect_stderr = true
36 stdout_logfile = /var/log/supervisord/beepkg.log
1 # 一步一步跟我写博客
2
3
4 ## 创建项目
5
6
7 ## 数据库结构设计
8
9
10 ## 控制器设计
11
12
13 ## 模板设计
14
15
16 ## 用户登陆退出
17
18
19 ## 数据库操作
1 # Design purposes and ideas
2
3 People may ask me why I want to build a new web framework rather than use other good ones. I know there are many excellent web frameworks on the internet and almost all of them are open source, and I have my reasons to do this.
4
5 Remember when I was writing the book about how to build web applications with Go, I just wanted to tell people what were my valuable experiences with Go in web development, especially I have been working with PHP and Python for almost ten years. At first, I didn't realize that a small web framework can give great help to web developers when they are learning to build web applications in a new programming language, and it also helps people more by studying its source code. Finally, I decided to write a open source web framework called Beego as supporting materiel for my book.
6
7 I used to use CI in PHP and tornado in Python, there are both lightweight, so they has following advantages:
8
9 1. Save time for handling general problems, I only need to care about logic part.
10 2. Learn more about languages by studying their source code, it's not hard to read and understand them because they are both lightweight frameworks.
11 3. It's quite easy to make secondary development of these frameworks for specific purposes.
12
13 Those reasons are my original intention of implementing Beego, and used two chapters in my book to introduce and design this lightweight web framework in Go.
14
15 Then I started to design logic execution of Beego. Because Go and Python have somewhat similar, I referenced some ideas from tornado to design Beego. As you can see, there is no different between Beego and tornado in RESTful processing; they both use GET, POST or some other methods to implement RESTful. I took some ideas from [https://github.com/drone/routes](https://github.com/drone/routes) at the beginning of designing routes. It uses regular expression in route rules processing, which is an excellent idea that to make up for the default Mux router function in Go. However, I have to design my own interface in order to implement RESTful and use inherited ideas in Python.
16
17 The controller is the most important part of whole MVC model, and Beego uses the interface and ideas I said above for the controller. Although I haven't decided to have to design the model part, everyone is welcome to implement data management by referencing Beedb, my another open source project. I simply adopt Go built-in template engine for the view part, but add more commonly used functions as template functions. This is how a simple web framework looks like, but I'll keep working on form processing, session handling, log recording, configuration, automated operation, etc, to build a simple but complete web framework.
18
19 - [Introduction](README.md)
20 - [Installation](Install.md)
1 # API应用开发入门
2 Go是非常适合用来开发API应用的,而且我认为也是Go相对于其他动态语言的最大优势应用。beego在开发API应用方面提供了非常强大和快速的工具,方便用户快速的建立API应用原型,专心业务逻辑就行了。
3
4
5 ## 快速建立原型
6 bee快速开发工具提供了一个API应用建立的工具,在gopath/src下的任意目录执行如下命令就可以快速的建立一个API应用:
7
8 `bee api beeapi`
9
10 ## 应用的目录结构
11 应用的目录结构如下所示:
12
13 ```
14 ├── conf
15 │ └── app.conf
16 ├── controllers
17 │ └── default.go
18 ├── models
19 │ └── object.go
20 └── main.go
21 ```
22
23 ## 源码解析
24
25 - app.conf里面主要针对API的配置如下:
26
27 autorender = false //API应用不需要模板渲染,所以关闭自动渲染
28
29 copyrequestbody = true //RESTFul应用发送信息的时候是raw body,而不是普通的form表单,所以需要额外的读取body信息
30
31 - main.go文件主要针对RESTFul的路由注册
32
33 `beego.RESTRouter("/object", &controllers.ObejctController{})`
34
35 这个路由可以匹配如下的规则
36
37 <table>
38 <tr>
39 <th>URL</th> <th>HTTP Verb</th> <th>Functionality</th>
40 </tr>
41 <tr>
42 <td>/object</td> <td>POST</td> <td>Creating Objects</td>
43 </tr>
44 <tr>
45 <td>/object/objectId</td> <td>GET</td> <td>Retrieving Objects</td>
46 </tr>
47 <tr>
48 <td>/object/objectId</td> <td>PUT</td> <td>Updating Objects</td>
49 </tr>
50 <tr>
51 <td>/object</td> <td>GET</td> <td>Queries</td>
52 </tr>
53 <tr>
54 <td>/object/objectId</td> <td>DELETE</td> <td>Deleting Objects</td>
55 </tr>
56 </table>
57
58 - ObejctController实现了对应的方法:
59
60 ```
61 type ObejctController struct {
62 beego.Controller
63 }
64
65 func (this *ObejctController) Post(){
66
67 }
68
69 func (this *ObejctController) Get(){
70
71 }
72
73 func (this *ObejctController) Put(){
74
75 }
76
77 func (this *ObejctController) Delete(){
78
79 }
80 ```
81
82 - models里面实现了对应操作对象的增删改取等操作
83
84 ## 测试
85
86 - 添加一个对象:
87
88 `curl -X POST -d '{"Score":1337,"PlayerName":"Sean Plott"}' http://127.0.0.1:8080/object`
89
90 返回一个相应的objectID:astaxie1373349756660423900
91
92 - 查询一个对象
93
94 `curl -X GET http://127.0.0.1:8080/object/astaxie1373349756660423900`
95
96 - 查询全部的对象
97
98 `curl -X GET http://127.0.0.1:8080/object`
99
100 - 更新一个对象
101
102 `curl -X PUT -d '{"Score":10000}'http://127.0.0.1:8080/object/astaxie1373349756660423900`
103
104 - 删除一个对象
105
106 `curl -X DELETE http://127.0.0.1:8080/object/astaxie1373349756660423900`
1 # beego案例
2
3 - 短域名服务
4
5 使用beego开发了一个类似bitly的短域名服务,提供盛大内部项目使用,目前一台机器:32G内存、8核、centos64
6 redis数据库,数据量在1500w多点,从2012年8月份运行至今没有出现过问题
7 - 政府合作项目
8
9 使用beego提供系统级别服务,监控继承电路板信号,智能分析nginx配置,提供大数据量的下载调度
10
11 - 内部监控系统
12 目前这个项目还在开发中,主要是利用beego做两个服务,一个是服务器端,收集信息,一个是客户端,收集信息并上报给服务器端,如果和服务端断开,那么本地可以暂存数据,防止数据丢失,同时还支持类似pupput的功能,支持程序自动更新(重启功能,不支持热更新)
13
14 - 日志分析系统
15 以前采用hadoop来分析日志的来源和省份信息,发现hadoop分析这么大的数据,性能不是很好,延迟比较大,目前采用自己的一套架构,squid日志每小时分割上报,每小时对日志进行分割,然后进行UV、PV、省份、运营商、浏览器、数据量等的分析,同时把日志进行按域名分割,提供用户原始日志下载
16
17 - 下载分发系统
18 架构暂时不好公布,我们提供文件下载的智能分发,但是从文件上传到下发到每一台服务器,以前采用BT的方式,性能不是很好,目前采用新的架构,性能提升十几倍
19
20 - 基于微信的提醒助手
21 开源在github上
22
23 - 视频直播调度器
1 ## 热升级是什么?
2
3 热升级是什么呢?了解nginx的同学都知道,nginx是支持热升级的,可以用老进程服务先前链接的链接,使用新进程服务新的链接,即在不停止服务的情况下完成系统的升级与运行参数修改。那么热升级和热编译是不同的概念,热编译是通过监控文件的变化重新编译,然后重启进程,例如bee start就是这样的工具
4
5
6 ## 热升级有必要吗?
7
8 很多人认为HTTP的应用有必要支持热升级吗?那么我可以很负责的说非常有必要,不中断服务始终是我们所追求的目标,虽然很多人说可能服务器会坏掉等等,这个是属于高可用的设计范畴,不要搞混了,这个是可预知的问题,所以我们需要避免这样的升级带来的用户不可用。你还在为以前升级搞到凌晨升级而烦恼嘛?那么现在就赶紧拥抱热升级吧。
9
10
11 ## beego如何支持热升级
12 热升级的原理基本上就是:主进程fork一个进程,然后子进程exec相应的程序。那么这个过程中发生了什么呢?我们知道进程fork之后会把主进程的所有句柄、数据和堆栈继承过来、但是里面所有的句柄存在一个叫做CloseOnExec,也就是执行exec的时候,copy的所有的句柄都被关闭了,除非特别申明,而我们期望的是子进程能够复用主进程的net.Listener的句柄。一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。
13
14 那么我们要做的第一步就是让子进程继承主进程的这个句柄,我们可以通过os.StartProcess的参数来附加Files,把需要继承的句柄写在里面。
15
16 第二步就是我们希望子进程能够从这个句柄启动监听,还好Go里面支持net.FileListener,直接从句柄来监听,但是我们需要子进程知道这个FD,所以在启动子进程的时候我们设置了一个环境变量设置这个FD。
17
18 第三步就是我们期望老的链接继续服务完,而新的链接采用新的进程,这里面有两个细节,第一就是老的链接继续服务,那么我们怎么知道有老链接存在?所以我们必须每次接收一个链接记录一下,这样我们就知道还存在没有服务完的链接,第二就是怎么让老进程停止接收数据,让新进程接收数据呢?大家都监听在同一个端口,理论上是随机来接收的,所以这里我们只要关闭老的链接的接收就行,这样就会使得在l.Accept的时候报错。
19
20 上面是我们需要解决的三个方面的问题,具体的实现大家可以看我实现的代码逻辑。
21
22
23 ## 如何演示热升级
24
25 1. 编写代码,在beego应用的控制器中Get方法实现大概如下:
26
27 func (this *MainController) Get() {
28 a, _ := this.GetInt("sleep")
29 time.Sleep(time.Duration(a) * time.Second)
30 this.Ctx.WriteString("ospid:" + strconv.Itoa(os.Getpid()))
31 }
32
33 2. 打开两个终端
34
35 一个终端输入:` ps -ef|grep 应用名`
36
37 一个终端输入请求:`curl "http://127.0.0.1:8080/?sleep=20"`
38
39 3. 热升级
40
41 `kill -HUP 进程ID`
42
43 4. 打开一个终端输入请求:`curl "http://127.0.0.1:8080/?sleep=0"`
44
45 我们可以看到这样的结果,第一个请求等待20s,但是处理他的是老的进程,热升级之后,第一个请求还在执行,最后会输出老的进程ID,而第二次请求,输出的是新的进程ID
1 ## 方便的http客户端
2 我们经常会使用Go来请求其他API应用,例如你使用beego开发了一个RESTFul的API应用,那么如果来请求呢?当然可以使用`http.Client`来实现,但是需要自己来操作很多步骤,自己需要考虑很多东西,所以我就基于net下的一些包实现了这个简便的http客户端工具。
3
4 该工具的主要特点:
5
6 - 链式操作
7 - 超时控制
8 - 方便的解析
9 - 可控的debug
10
11 ## 例子
12 我们上次开发的RESTful应用,最后我写过如何通过curl来进行测试,那么下面一一对每个操作如何用httplib来操作进行展示
13
14 - 添加一个对象:
15
16 `curl -X POST -d '{"Score":1337,"PlayerName":"Sean Plott"}' http://127.0.0.1:8080/object`
17
18 返回一个相应的objectID:astaxie1373349756660423900
19
20 str,err:=beego.Post("http://127.0.0.1:8080/object").Body(`{"Score":1337,"PlayerName":"Sean Plott"}`).String()
21 if err != nil{
22 println(err)
23 }
24
25 - 查询一个对象
26
27 `curl -X GET http://127.0.0.1:8080/object/astaxie1373349756660423900`
28
29 var object Obeject
30 err:=beego.Get("http://127.0.0.1:8080/object/astaxie1373349756660423900").ToJson(&object)
31 if err != nil{
32 println(err)
33 }
34
35 - 查询全部的对象
36
37 `curl -X GET http://127.0.0.1:8080/object`
38
39 var objects []Object
40 err:=beego.Get("http://127.0.0.1:8080/object").ToJson(&objects)
41 if err != nil{
42 println(err)
43 }
44
45 - 更新一个对象
46
47 `curl -X PUT -d '{"Score":10000}'http://127.0.0.1:8080/object/astaxie1373349756660423900`
48
49 str,err:=beego.Put("http://127.0.0.1:8080/object/astaxie1373349756660423900").Body(`{"Score":10000}`).String()
50 if err != nil{
51 println(err)
52 }
53
54 - 删除一个对象
55
56 `curl -X DELETE http://127.0.0.1:8080/object/astaxie1373349756660423900`
57
58 str,er:=beego.Delete("http://127.0.0.1:8080/object/astaxie1373349756660423900").String()
59 if err != nil{
60 println(err)
61 }
62
63 ## 开启调试模式
64 用户可以开启调试打印request信息,默认是关闭模式
65
66 beego.Post(url).Debug(true)
67
68 ## ToFile、ToXML、ToJson
69 上面我演示了Json的解析,其实还有直接保存为文件的ToFile操作,解析XML的ToXML操作
70
71
72 ## 设置链接超时和读写超时
73 默认都设置为60秒,用户可以通过函数来设置相应的超时时间
74
75 beego.Get(url).SetTimeout(100*time.Second,100*time.Second)
76
77
78 更加详细的请参考[API接口](http://gowalker.org/github.com/astaxie/beego)
...\ No newline at end of file ...\ No newline at end of file
1 # 安装入门
2
3 beego虽然是一个简单的框架,但是其中用到了很多第三方的包,所以在你安装beego的过程中Go会自动安装其他关联的包。
4
5 - 当然第一步你需要安装Go,如何安装Go请参考我的书[第一章](https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/01.1.md)
6
7 - 安装beego
8
9 go get github.com/astaxie/beego
10
11 - 安装bee工具,这个工具可以用来快速的建立beego的应用
12
13 go get github.com/astaxie/bee
14
15 这样就完成了beego的安装,你就可以开始开发了,可以通过bee工具来创建beego项目
16
17 ![](images/bee.png)
18
19 >beego依赖的第三方包有如下:
20
21 > - session模块:github.com/astaxie/beego/session
22
23
24 > - session模块中支持redis引擎:github.com/garyburd/redigo/redis
25
26 > - session模块中支持mysql引擎:github.com/go-sql-driver/mysql
27
28
29
30 - [beego介绍](README.md)
31 - [快速入门](Quickstart.md)
1 # 快速入门
2
3 你对beego一无所知?没关系,这篇文档会很好的详细介绍beego的各个方面,看这个文档之前首先确认你已经安装了beego,如果你没有安装的话,请看这篇[安装指南](Install.md)
4
5 **导航**
6
7 - [最小应用](#%E6%9C%80%E5%B0%8F%E5%BA%94%E7%94%A8)
8 - [新建项目](#%E6%96%B0%E5%BB%BA%E9%A1%B9%E7%9B%AE)
9 - [开发模式](#%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F)
10 - [路由设置](#%E8%B7%AF%E7%94%B1%E8%AE%BE%E7%BD%AE)
11 - [静态文件](#%E9%9D%99%E6%80%81%E6%96%87%E4%BB%B6)
12 - [过滤和中间件](#%E8%BF%87%E6%BB%A4%E5%92%8C%E4%B8%AD%E9%97%B4%E4%BB%B6)
13 - [Controller设计](#%E6%8E%A7%E5%88%B6%E5%99%A8%E8%AE%BE%E8%AE%A1)
14 - [模板处理](#%E6%A8%A1%E6%9D%BF%E5%A4%84%E7%90%86)
15 - [request处理](#request%E5%A4%84%E7%90%86)
16 - [跳转和错误](#%E8%B7%B3%E8%BD%AC%E5%92%8C%E9%94%99%E8%AF%AF)
17 - [response处理](#response%E5%A4%84%E7%90%86)
18 - [Sessions/Flash](#sessionsflash)
19 - [Cache设置](#cache%E8%AE%BE%E7%BD%AE)
20 - [安全的Map](#%E5%AE%89%E5%85%A8%E7%9A%84map)
21 - [日志处理](#%E6%97%A5%E5%BF%97%E5%A4%84%E7%90%86)
22 - [配置管理](#%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86)
23 - [beego参数](#%E7%B3%BB%E7%BB%9F%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0)
24 - [第三方应用集成](#%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90)
25 - [部署编译应用](#%E9%83%A8%E7%BD%B2%E7%BC%96%E8%AF%91%E5%BA%94%E7%94%A8)
26
27
28 ## 最小应用
29
30 一个最小最简单的应用如下代码所示:
31
32 package main
33
34 import (
35 "github.com/astaxie/beego"
36 )
37
38 type MainController struct {
39 beego.Controller
40 }
41
42 func (this *MainController) Get() {
43 this.Ctx.WriteString("hello world")
44 }
45
46 func main() {
47 beego.Router("/", &MainController{})
48 beego.Run()
49 }
50
51 把上面的代码保存为hello.go,然后通过命令行进行编译并执行:
52
53 $ go build main.go
54 $ ./hello
55
56 这个时候你可以打开你的浏览器,通过这个地址浏览[http://127.0.0.1:8080](http://127.0.0.1:8080)返回“hello world”
57
58 那么上面的代码到底做了些什么呢?
59
60 1、首先我们引入了包`github.com/astaxie/beego`,我们知道Go语言里面引入包会深度优先的去执行引入包的初始化(变量和init函数,[更多](https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/02.3.md#maininit)),beego包中会初始化一个BeeAPP的应用,初始化一些参数。
61
62 2、定义Controller,这里我们定义了一个struct为`MainController`,充分利用了Go语言的组合的概念,匿名包含了`beego.Controller`,这样我们的`MainController`就拥有了`beego.Controller`的所有方法。
63
64 3、定义RESTFul方法,通过匿名组合之后,其实目前的`MainController`已经拥有了`Get``Post``Delete``Put`等方法,这些方法是分别用来对应用户请求的Method函数,如果用户发起的是`POST`请求,那么就执行`Post`函数。所以这里我们定义了`MainController``Get`方法用来重写继承的`Get`函数,这样当用户`GET`请求的时候就会执行该函数。
65
66 4、定义main函数,所有的Go应用程序和C语言一样都是Main函数作为入口,所以我们这里定义了我们应用的入口。
67
68 5、Router注册路由,路由就是告诉beego,当用户来请求的时候,该如何去调用相应的Controller,这里我们注册了请求`/`的时候,请求到`MainController`。这里我们需要知道,Router函数的两个参数函数,第一个是路径,第二个是Controller的指针。
69
70 6、Run应用,最后一步就是把在1中初始化的BeeApp开启起来,其实就是内部监听了8080端口:`Go默认情况会监听你本机所有的IP上面的8080端口`
71
72 停止服务的话,请按`ctrl+c`
73
74
75 ## 新建项目
76
77 通过如下命令创建beego项目,首先进入gopath目录
78
79 bee new hello
80
81 这样就建立了一个项目hello,目录结构如下所示
82
83 .
84 ├── conf
85 │ └── app.conf
86 ├── controllers
87 │ └── default.go
88 ├── main.go
89 ├── models
90 ├── static
91 │ ├── css
92 │ ├── img
93 │ └── js
94 └── views
95 └── index.tpl
96
97
98 ## 开发模式
99
100 通过bee创建的项目,beego默认情况下是开发模式。
101
102 我们可以通过如下的方式改变我们的模式:
103
104 beego.RunMode = "prod"
105
106 或者我们在conf/app.conf下面设置如下:
107
108 runmode = prod
109
110 以上两种效果一样。
111
112 开发模式中
113
114 - 开发模式下,如果你的目录不存在views目录,那么会出现类似下面的错误提示:
115
116 2013/04/13 19:36:17 [W] [stat views: no such file or directory]
117
118 - 模板每次使用都会重新加载,不进行缓存。
119 - 如果服务端出错,那么就会在浏览器端显示如下类似的截图:
120
121 ![](images/dev.png)
122
123
124 ## 路由设置
125
126 ### 默认路由RESTFul规则
127
128 路由的主要功能是实现从请求地址到实现方法,beego中封装了`Controller`,所以路由是从路径到`ControllerInterface`的过程,`ControllerInterface`的方法有如下:
129
130 type ControllerInterface interface {
131 Init(ct *Context, cn string)
132 Prepare()
133 Get()
134 Post()
135 Delete()
136 Put()
137 Head()
138 Patch()
139 Options()
140 Finish()
141 Render() error
142 }
143
144 这些方法`beego.Controller`都已经实现了,所以只要用户定义struct的时候匿名包含就可以了。当然更灵活的方法就是用户可以去自定义类似的方法,然后实现自己的逻辑。
145
146 用户可以通过如下的方式进行路由设置:
147
148 beego.Router("/", &controllers.MainController{})
149 beego.Router("/admin", &admin.UserController{})
150 beego.Router("/admin/index", &admin.ArticleController{})
151 beego.Router("/admin/addpkg", &admin.AddController{})
152
153 为了用户更加方便的路由设置,beego参考了sinatra的路由实现,支持多种方式的路由:
154
155 - beego.Router("/api/:id([0-9]+)", &controllers.RController{})
156 自定义正则匹配 //匹配 /api/123 :id= 123
157
158 - beego.Router("/news/:all", &controllers.RController{})
159 全匹配方式 //匹配 /news/path/to/123.html :all= path/to/123.html
160
161 - beego.Router(\`/user/:username([\w]+)\`, &controllers.RController{})
162 正则字符串匹配 //匹配 /user/astaxie :username = astaxie
163
164 - beego.Router("/download/*.*", &controllers.RController{})
165 *匹配方式 //匹配 /download/file/api.xml :path= file/api :ext=xml
166
167 - beego.Router("/download/ceshi/*", &controllers.RController{})
168 *全匹配方式 //匹配 /download/ceshi/file/api.json :splat=file/api.json
169
170 - beego.Router("/:id:int", &controllers.RController{})
171 int类型设置方式 //匹配 :id为int类型,框架帮你实现了正则([0-9]+)
172
173 - beego.Router("/:hi:string", &controllers.RController{})
174 string类型设置方式 //匹配 :hi为string类型。框架帮你实现了正则([\w]+)
175
176 如何在Controller中获取,上面的变量可以通过如下方式获取
177
178 this.Ctx.Params[":id"]
179 this.Ctx.Params[":username"]
180 this.Ctx.Params[":splat"]
181 this.Ctx.Params[":path"]
182 this.Ctx.Params[":ext"]
183
184 ### 自定义方法及RESTFul规则
185 上面列举的是默认的请求方法名(请求的method和函数名一致,例如GET请求执行Get函数,POST请求执行Post函数),如果用户期望自定义函数名,那么可以使用如下方式:
186
187 beego.Router("/",&IndexController{},"*:Index")
188
189 使用第三个参数,第三个参数就是用来设置对应method到函数名,定义如下
190
191 - *表示任意的method都执行该函数
192 - 使用`httpmethod:funcname`格式来展示
193 - 多个不同的格式使用`;`分割
194 - 多个method对应同一个funcname,method之间通过`,`来分割
195
196 以下是一个RESTful的设计如下
197
198 - beego.Router("/api/list",&RestController{},"*:ListFood")
199 - beego.Router("/api/create",&RestController{},"post:CreateFood")
200 - beego.Router("/api/update",&RestController{},"put:UpdateFood")
201 - beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
202
203 以下是多个http method指向同一个函数
204
205 beego.Router("/api",&RestController{},"get,post:ApiFunc")
206
207 一下是不同的method对应不同的函数,通过`;`进行分割
208
209 beego.Router("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
210
211 可用的http method
212 - * :包含一下所有的函数
213 - get :GET请求
214 - post :POST请求
215 - put :PUT请求
216 - delete :DELETE请求
217 - patch :PATCH请求
218 - options :OPTIONS请求
219 - head :HEAD请求
220
221 >>>如果同时存在*和对应的http method,那么优先执行http method的方法,例如同时注册了如下所示的路由:
222
223 >>> beego.Router("/simple",&SimpleController{},"*:AllFunc;post:PostFunc")
224
225 >>>那么执行POST请求的时候,执行PostFunc而不执行AllFunc
226
227 ### 自动化路由
228 用户首先需要把需要路由的控制器注册到自动路由中:
229
230 beego.AutoRouter(&controllers.ObjectController{})
231
232 那么beego就会通过反射获取该结构体中所有的实现方法,你就可以通过如下的方式访问到对应的方法中:
233
234 /object/login 调用ObjectController中的Login方法
235 /object/logout 调用ObjectController中的Logout方法
236
237 除了前缀两个/:controller/:method的匹配之外,剩下的url,beego会帮你自动化解析为参数,保存在`this.Ctx.Params`当中:
238
239 /object/blog/2013/09/12 调用ObjectController中的Blog方法,参数如下:map[0:2013 1:09 2:12]
240
241
242 >>> 方法名在内部是保存了用户设置的,例如Login,url匹配的时候都会转化为小写,所以,/object/LOGIN这样的url也一样可以路由到用户定义的Login方法中
243
244
245 ## 静态文件
246
247 Go语言内部其实已经提供了`http.ServeFile`,通过这个函数可以实现静态文件的服务。beego针对这个功能进行了一层封装,通过下面的方式进行静态文件注册:
248
249 beego.SetStaticPath("/static","public")
250
251 - 第一个参数是路径,url路径信息
252 - 第二个参数是静态文件目录(相对应用所在的目录)
253
254 beego支持多个目录的静态文件注册,用户可以注册如下的静态文件目录:
255
256 beego.SetStaticPath("/images","images")
257 beego.SetStaticPath("/css","css")
258 beego.SetStaticPath("/js","js")
259
260 设置了如上的静态目录之后,用户访问`/images/login/login.png`,那么就会访问应用对应的目录下面的`images/login/login.png`文件。如果是访问`/static/img/logo.png`,那么就访问`public/img/logo.png`文件。
261
262
263 ## 过滤和中间件
264
265 beego支持自定义过滤中间件,例如安全验证,强制跳转等
266
267 如下例子所示,验证用户名是否是admin,应用于全部的请求:
268
269 var FilterUser = func(w http.ResponseWriter, r *http.Request) {
270 if r.URL.User == nil || r.URL.User.Username() != "admin" {
271 http.Error(w, "", http.StatusUnauthorized)
272 }
273 }
274
275 beego.Filter(FilterUser)
276
277 还可以通过参数进行过滤,如果匹配参数就执行
278
279 beego.Router("/:id([0-9]+)", &admin.EditController{})
280 beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) {
281 dosomething()
282 })
283
284 当然你还可以通过前缀过滤
285
286 beego.FilterPrefixPath("/admin", func(rw http.ResponseWriter, r *http.Request) {
287 dosomething()
288 })
289
290
291 ## 控制器设计
292
293 基于beego的Controller设计,只需要匿名组合`beego.Controller`就可以了,如下所示:
294
295 type xxxController struct {
296 beego.Controller
297 }
298
299 `beego.Controller`实现了接口`beego.ControllerInterface``beego.ControllerInterface`定义了如下函数:
300
301 - Init(ct *Context, cn string)
302
303 这个函数主要初始化了Context、相应的Controller名称,模板名,初始化模板参数的容器Data
304
305 - Prepare()
306
307 这个函数主要是为了用户扩展用的,这个函数会在下面定义的这些Method方法之前执行,用户可以重写这个函数实现类似用户验证之类。
308
309 - Get()
310
311 如果用户请求的HTTP Method是GET, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Get请求.
312
313 - Post()
314
315 如果用户请求的HTTP Method是POST, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Post请求.
316
317 - Delete()
318
319 如果用户请求的HTTP Method是DELETE, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Delete请求.
320
321 - Put()
322
323 如果用户请求的HTTP Method是PUT, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Put请求.
324
325 - Head()
326
327 如果用户请求的HTTP Method是HEAD, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Head请求.
328
329 - Patch()
330
331 如果用户请求的HTTP Method是PATCH, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Patch请求.
332
333 - Options()
334
335 如果用户请求的HTTP Method是OPTIONS, 那么就执行该函数,默认是403,用户继承的子struct中可以实现了该方法以处理Options请求.
336
337 - Finish()
338
339 这个函数实在执行完相应的http Method方法之后执行的,默认是空,用户可以在子Strcut中重写这个函数,执行例如数据库关闭,清理数据之类的工作
340
341 - Render() error
342
343 这个函数主要用来实现渲染模板,如果beego.AutoRender为true的情况下才会执行。
344
345 所以通过子struct的方法重写,用户就可以实现自己的逻辑,接下来我们看一个实际的例子:
346
347 type AddController struct {
348 beego.Controller
349 }
350
351 func (this *AddController) Prepare() {
352
353 }
354
355 func (this *AddController) Get() {
356 this.Data["content"] = "value"
357 this.Layout = "admin/layout.html"
358 this.TplNames = "admin/add.tpl"
359 }
360
361 func (this *AddController) Post() {
362 pkgname := this.GetString("pkgname")
363 content := this.GetString("content")
364 pk := models.GetCruPkg(pkgname)
365 if pk.Id == 0 {
366 var pp models.PkgEntity
367 pp.Pid = 0
368 pp.Pathname = pkgname
369 pp.Intro = pkgname
370 models.InsertPkg(pp)
371 pk = models.GetCruPkg(pkgname)
372 }
373 var at models.Article
374 at.Pkgid = pk.Id
375 at.Content = content
376 models.InsertArticle(at)
377 this.Ctx.Redirect(302, "/admin/index")
378 }
379
380
381 ## 模板处理
382
383
384 ### 模板目录
385
386 beego中默认的模板目录是`views`,用户可以把你的模板文件放到该目录下,beego会自动在该目录下的所有模板文件进行解析并缓存,开发模式下会每次重新解析,不做缓存。当然用户可以通过如下的方式改变模板的目录:
387
388 beego.ViewsPath = "/myviewpath"
389
390
391 ### 自动渲染
392
393 beego中用户无需手动的调用渲染输出模板,beego会自动的在调用完相应的method方法之后调用Render函数,当然如果你的应用是不需要模板输出的,那么你可以在配置文件或者在main.go中设置关闭自动渲染。
394
395 配置文件配置如下:
396
397 autorender = false
398
399 main.go文件中设置如下:
400
401 beego.AutoRender = false
402
403
404 ### 模板数据
405
406 模板中的数据是通过在Controller中`this.Data`获取的,所以如果你想在模板中获取内容`{{.Content}}`,那么你需要在Controller中如下设置:
407
408 this.Data["Content"] = "value"
409
410
411 ### 模板名称
412
413 beego采用了Go语言内置的模板引擎,所有模板的语法和Go的一模一样,至于如何写模板文件,详细的请参考[模板教程](https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/07.4.md)
414
415 用户通过在Controller的对应方法中设置相应的模板名称,beego会自动的在viewpath目录下查询该文件并渲染,例如下面的设置,beego会在admin下面找add.tpl文件进行渲染:
416
417 this.TplNames = "admin/add.tpl"
418
419 我们看到上面的模板后缀名是tpl,beego默认情况下支持tpl和html后缀名的模板文件,如果你的后缀名不是这两种,请进行如下设置:
420
421 beego.AddTemplateExt("你文件的后缀名")
422
423 当你设置了自动渲染,然后在你的Controller中没有设置任何的TplNames,那么beego会自动设置你的模板文件如下:
424
425 c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt
426
427 也就是你对应的Controller名字+请求方法名.模板后缀,也就是如果你的Controller名是`AddController`,请求方法是`POST`,默认的文件后缀是`tpl`,那么就会默认请求`/viewpath/AddController/POST.tpl`文件。
428
429
430 ### layout设计
431
432 beego支持layout设计,例如你在管理系统中,其实整个的管理界面是固定的,只会变化中间的部分,那么你可以通过如下的设置:
433
434 this.Layout = "admin/layout.html"
435 this.TplNames = "admin/add.tpl"
436
437 在layout.html中你必须设置如下的变量:
438
439 {{.LayoutContent}}
440
441 beego就会首先解析TplNames指定的文件,获取内容赋值给LayoutContent,然后最后渲染layout.html文件。
442
443 目前采用首先把目录下所有的文件进行缓存,所以用户还可以通过类似这样的方式实现layout:
444
445 {{template "header.html"}}
446 处理逻辑
447 {{template "footer.html"}}
448
449
450 ### 模板函数
451
452 beego支持用户定义模板函数,但是必须在`beego.Run()`调用之前,设置如下:
453
454 func hello(in string)(out string){
455 out = in + "world"
456 return
457 }
458
459 beego.AddFuncMap("hi",hello)
460
461 定义之后你就可以在模板中这样使用了:
462
463 {{.Content | hi}}
464
465 目前beego内置的模板函数有如下:
466
467 * markdown
468
469 实现了把markdown文本转化为html信息,使用方法{{markdown .Content}}
470
471 * dateformat
472
473 实现了时间的格式化,返回字符串,使用方法{{dateformat .Time "2006-01-02T15:04:05Z07:00"}}
474
475 * date
476
477 实现了类似PHP的date函数,可以很方便的根据字符串返回时间,使用方法{{date .T "Y-m-d H:i:s"}}
478
479 * compare
480
481 实现了比较两个对象的比较,如果相同返回true,否者false,使用方法{{compare .A .B}}
482
483 * substr
484
485 实现了字符串的截取,支持中文截取的完美截取,使用方法{{substr .Str 0 30}}
486
487 * html2str
488
489 实现了把html转化为字符串,剔除一些script、css之类的元素,返回纯文本信息,使用方法{{html2str .Htmlinfo}}
490
491 * str2html
492
493 实现了把相应的字符串当作HTML来输出,不转义,使用方法{{str2html .Strhtml}}
494
495 * htmlquote
496
497 实现了基本的html字符转义,使用方法{{htmlquote .quote}}
498
499 * htmlunquote
500
501 实现了基本的反转移字符,使用方法{{htmlunquote .unquote}}
502
503
504 ## request处理
505
506 我们经常需要获取用户传递的数据,包括Get、POST等方式的请求,beego里面会自动解析这些数据,你可以通过如下方式获取数据
507
508 - GetString(key string) string
509 - GetInt(key string) (int64, error)
510 - GetBool(key string) (bool, error)
511
512 使用例子如下:
513
514 func (this *MainController) Post() {
515 jsoninfo := this.GetString("jsoninfo")
516 if jsoninfo == "" {
517 this.Ctx.WriteString("jsoninfo is empty")
518 return
519 }
520 }
521
522 如果你需要的数据可能是其他类型的,例如是int类型而不是int64,那么你需要这样处理:
523
524 func (this *MainController) Post() {
525 id := this.Input().Get("id")
526 intid, err := strconv.Atoi(id)
527 }
528
529 更多其他的request的信息,用户可以通过`this.Ctx.Request`获取信息,关于该对象的属性和方法参考手册[Request](http://golang.org/pkg/net/http/#Request)
530
531
532 ### 文件上传
533
534 在beego中你可以很容易的处理文件上传,就是别忘记在你的form表单中增加这个属性`enctype="multipart/form-data"`,否者你的浏览器不会传输你的上传文件。
535
536 文件上传之后一般是放在系统的内存里面,如果文件的size大于设置的缓存内存大小,那么就放在临时文件中,默认的缓存内存是64M,你可以通过如下来调整这个缓存内存大小:
537
538 beego.MaxMemory = 1<<22
539
540 或者在配置文件中通过如下设置
541
542 maxmemory = 1<<22
543
544 beego提供了两个很方便的方法来处理文件上传:
545
546 - GetFile(key string) (multipart.File, *multipart.FileHeader, error)
547
548 该方法主要用于用户读取表单中的文件名`the_file`,然后返回相应的信息,用户根据这些变量来处理文件上传:过滤、保存文件等。
549
550 - SaveToFile(fromfile, tofile string) error
551
552 该方法是在GetFile的基础上实现了快速保存的功能
553
554 保存的代码例子如下:
555
556 func (this *MainController) Post() {
557 this.SaveToFile("the_file","/var/www/uploads/uploaded_file.txt"")
558 }
559
560
561 ### JSON和XML输出
562
563 beego当初设计的时候就考虑了API功能的设计,而我们在设计API的时候经常是输出JSON或者XML数据,那么beego提供了这样的方式直接输出:
564
565 JSON数据直接输出,设置`content-type``application/json`
566
567 func (this *AddController) Get() {
568 mystruct := { ... }
569 this.Data["json"] = &mystruct
570 this.ServeJson()
571 }
572
573 XML数据直接输出,设置`content-type``application/xml`
574
575 func (this *AddController) Get() {
576 mystruct := { ... }
577 this.Data["xml"]=&mystruct
578 this.ServeXml()
579 }
580
581
582 ## 跳转和错误
583
584 我们在做Web开发的时候,经常会遇到页面调整和错误处理,beego这这方面也进行了考虑,通过`Redirect`方法来进行跳转:
585
586 func (this *AddController) Get() {
587 this.Redirect("/", 302)
588 }
589
590 如何中止此次请求并抛出异常,beego可以在控制器中这操作
591
592 func (this *MainController) Get() {
593 this.Abort("401")
594 v := this.GetSession("asta")
595 if v == nil {
596 this.SetSession("asta", int(1))
597 this.Data["Email"] = 0
598 } else {
599 this.SetSession("asta", v.(int)+1)
600 this.Data["Email"] = v.(int)
601 }
602 this.TplNames = "index.tpl"
603 }
604
605 这样`this.Abort("401")`之后的代码不会再执行,而且会默认显示给用户如下页面
606
607 ![](images/401.png)
608
609 beego框架默认支持404、401、403、500、503这几种错误的处理。用户可以自定义相应的错误处理,例如下面重新定义404页面:
610
611 func page_not_found(rw http.ResponseWriter, r *http.Request){
612 t,_:= template.New("beegoerrortemp").ParseFiles(beego.ViewsPath+"/404.html")
613 data :=make(map[string]interface{})
614 data["content"] = "page not found"
615 t.Execute(rw, data)
616 }
617
618 func main() {
619 beego.Errorhandler("404",page_not_found)
620 beego.Router("/", &controllers.MainController{})
621 beego.Run()
622 }
623
624 我们可以通过自定义错误页面`404.html`来处理404错误。
625
626 beego更加人性化的还有一个设计就是支持用户自定义字符串错误类型处理函数,例如下面的代码,用户注册了一个数据库出错的处理页面:
627
628 func dbError(rw http.ResponseWriter, r *http.Request){
629 t,_:= template.New("beegoerrortemp").ParseFiles(beego.ViewsPath+"/dberror.html")
630 data :=make(map[string]interface{})
631 data["content"] = "database is now down"
632 t.Execute(rw, data)
633 }
634
635 func main() {
636 beego.Errorhandler("dbError",dbError)
637 beego.Router("/", &controllers.MainController{})
638 beego.Run()
639 }
640
641 一旦在入口注册该错误处理代码,那么你可以在任何你的逻辑中遇到数据库错误调用`this.Abort("dbError")`来进行异常页面处理。
642
643
644 ## response处理
645
646 response可能会有几种情况:
647
648 1. 模板输出
649
650 上面模板介绍里面已经介绍,beego会在执行完相应的Controller里面的对应的Method之后输出到模板。
651
652 2. 跳转
653
654 上一节介绍的跳转就是我们经常用到的页面之间的跳转
655
656 3. 字符串输出
657
658 有些时候我们只是想输出相应的一个字符串,那么我们可以通过如下的代码实现
659
660 this.Ctx.WriteString("ok")
661
662
663 ## Sessions/Flash
664
665 beego内置了session模块,目前session模块支持的后端引擎包括memory、file、mysql、redis四中,用户也可以根据相应的interface实现自己的引擎。
666
667 beego中使用session相当方便,只要在main入口函数中设置如下:
668
669 beego.SessionOn = true
670
671 或者通过配置文件配置如下:
672
673 sessionon = true
674
675 通过这种方式就可以开启session,如何使用session,请看下面的例子:
676
677 func (this *MainController) Get() {
678 v := this.GetSession("asta")
679 if v == nil {
680 this.SetSession("asta", int(1))
681 this.Data["num"] = 0
682 } else {
683 this.SetSession("asta", v.(int)+1)
684 this.Data["num"] = v.(int)
685 }
686 this.TplNames = "index.tpl"
687 }
688
689 session有几个方便的方法:
690
691 - SetSession(name string, value interface{})
692 - GetSession(name string) interface{}
693 - DelSession(name string)
694
695 session操作主要有设置session、获取session、删除session
696
697 当然你要可以通过下面的方式自己控制相应的逻辑这些逻辑:
698
699 sess:=this.StartSession()
700 defer sess.SessionRelease()
701
702 sess对象具有如下方法:
703
704 * sess.Set()
705 * sess.Get()
706 * sess.Delete()
707 * sess.SessionID()
708
709 但是我还是建议大家采用SetSession、GetSession、DelSession三个方法来操作,避免自己在操作的过程中资源没释放的问题。
710
711 关于Session模块使用中的一些参数设置:
712
713 - SessionOn
714
715 设置是否开启Session,默认是false,配置文件对应的参数名:sessionon
716
717 - SessionProvider
718
719 设置Session的引擎,默认是memory,目前支持还有file、mysql、redis等,配置文件对应的参数名:sessionprovider
720
721 - SessionName
722
723 设置cookies的名字,Session默认是保存在用户的浏览器cookies里面的,默认名是beegosessionID,配置文件对应的参数名是:sessionname
724
725 - SessionGCMaxLifetime
726
727 设置Session过期的时间,默认值是3600秒,配置文件对应的参数:sessiongcmaxlifetime
728
729 - SessionSavePath
730
731 设置对应file、mysql、redis引擎的保存路径或者链接地址,默认值是空,配置文件对应的参数:sessionsavepath
732
733
734 当SessionProvider为file时,SessionSavePath是只保存文件的目录,如下所示:
735
736 beego.SessionProvider = "file"
737 beego.SessionSavePath = "./tmp"
738
739 当SessionProvider为mysql时,SessionSavePath是链接地址,采用[go-sql-driver](https://github.com/go-sql-driver/mysql),如下所示:
740
741 beego.SessionProvider = "mysql"
742 beego.SessionSavePath = "username:password@protocol(address)/dbname?param=value"
743
744 当SessionProvider为redis时,SessionSavePath是redis的链接地址,采用了[redigo](https://github.com/garyburd/redigo),如下所示:
745
746 beego.SessionProvider = "redis"
747 beego.SessionSavePath = "127.0.0.1:6379"
748
749 这个flash与Adobe/Macromedia Flash没有任何关系。它主要用于在两个逻辑间传递临时数据,flash中存放的所有数据会在紧接着的下一个逻辑中调用后清除。一般用于传递提示和错误消息。它适合[Post/Redirect/Get](http://en.wikipedia.org/wiki/Post/Redirect/Get)模式。下面看使用的例子
750
751 // 显示设置信息
752 func (c *MainController) Get() {
753 flash:=beego.ReadFromRequest(c)
754 if n,ok:=flash.Data["notice"];ok{
755 //显示设置成功
756 c.TplNames = "set_success.html"
757 }else if n,ok=flash.Data["error"];ok{
758 //显示错误
759 c.TplNames = "set_error.html"
760 }else{
761 // 不然默认显示设置页面
762 this.Data["list"]=GetInfo()
763 c.TplNames = "setting_list.html"
764 }
765 }
766
767 // 处理设置信息
768 func (c *MainController) Post() {
769 flash:=beego.NewFlash()
770 setting:=Settings{}
771 valid := Validation{}
772 c.ParseForm(&setting)
773 if b, err := valid.Valid(setting);err!=nil {
774 flash.Error("Settings invalid!")
775 flash.Store(c)
776 c.Redirect("/setting",302)
777 return
778 }else if b!=nil{
779 flash.Error("validation err!")
780 flash.Store(c)
781 c.Redirect("/setting",302)
782 return
783 }
784 saveSetting(setting)
785 flash.Notice("Settings saved!")
786 flash.Store(c)
787 c.Redirect("/setting",302)
788 }
789
790 上面的代码执行的大概逻辑是这样的:
791
792 1. Get方法执行,因为没有flash数据,所以显示设置页面
793 2. 用户设置信息之后点击递交,执行Post,然后初始化一个flash,通过验证,验证出错或者验证不通过设置flash的错误,如果通过了就保存设置,然后设置flash成功设置的信息。
794 3. 设置完成后跳转到Get请求
795 4. Get请求获取到了Flash信息,然后执行相应的逻辑,如果出错显示出错的页面,如果成功显示成功的页面。
796
797 默认情况下`ReadFromRequest`函数已经实现了读取的数据赋值给flash,所以在你的模板里面你可以这样读取数据
798
799 {{.flash.error}}
800 {{.flash.warning}}
801 {{.flash.notice}}
802
803 flash对象有三个级别的设置:
804 * Notice提示信息
805 * Warning警告信息
806 * Error错误信息
807
808 ## Cache设置
809
810 beego内置了一个cache模块,实现了类似memcache的功能,缓存数据在内存中,主要的使用方法如下:
811
812 var (
813 urllist *beego.BeeCache
814 )
815
816 func init() {
817 urllist = beego.NewBeeCache()
818 urllist.Every = 0 //不过期
819 urllist.Start()
820 }
821
822 func (this *ShortController) Post() {
823 var result ShortResult
824 longurl := this.Input().Get("longurl")
825 beego.Info(longurl)
826 result.UrlLong = longurl
827 urlmd5 := models.GetMD5(longurl)
828 beego.Info(urlmd5)
829 if urllist.IsExist(urlmd5) {
830 result.UrlShort = urllist.Get(urlmd5).(string)
831 } else {
832 result.UrlShort = models.Generate()
833 err := urllist.Put(urlmd5, result.UrlShort, 0)
834 if err != nil {
835 beego.Info(err)
836 }
837 err = urllist.Put(result.UrlShort, longurl, 0)
838 if err != nil {
839 beego.Info(err)
840 }
841 }
842 this.Data["json"] = result
843 this.ServeJson()
844 }
845
846 上面这个例子演示了如何使用beego的Cache模块,主要是通过`beego.NewBeeCache`初始化一个对象,然后设置过期时间,开启过期检测,在业务逻辑中就可以通过如下的接口进行增删改的操作:
847
848 - Get(name string) interface{}
849 - Put(name string, value interface{}, expired int) error
850 - Delete(name string) (ok bool, err error)
851 - IsExist(name string) bool
852
853
854 ## 安全的Map
855
856 我们知道在Go语言里面map是非线程安全的,详细的[atomic_maps](http://golang.org/doc/faq#atomic_maps)。但是我们在平常的业务中经常需要用到线程安全的map,特别是在goroutine的情况下,所以beego内置了一个简单的线程安全的map:
857
858 bm := NewBeeMap()
859 if !bm.Set("astaxie", 1) {
860 t.Error("set Error")
861 }
862 if !bm.Check("astaxie") {
863 t.Error("check err")
864 }
865
866 if v := bm.Get("astaxie"); v.(int) != 1 {
867 t.Error("get err")
868 }
869
870 bm.Delete("astaxie")
871 if bm.Check("astaxie") {
872 t.Error("delete err")
873 }
874
875 上面演示了如何使用线程安全的Map,主要的接口有:
876
877 - Get(k interface{}) interface{}
878 - Set(k interface{}, v interface{}) bool
879 - Check(k interface{}) bool
880 - Delete(k interface{})
881
882
883 ## 日志处理
884
885 beego默认有一个初始化的BeeLogger对象输出内容到stdout中,你可以通过如下的方式设置自己的输出:
886
887 beego.SetLogger(*log.Logger)
888
889 现在beego支持文件方式输出到,而且支持文件的自动化logrotate,在main函数入口处初始化如下:
890
891 filew := beego.NewFileWriter("tmp/log.log", true)
892 err := filew.StartLogger()
893 if err != nil {
894 beego.Critical("NewFileWriter err", err)
895 }
896
897 这样就默认开始在当前目录的tmp/log.log文件中开始记录日志,默认支持文件的logrotate,第二个参数为true表示开启,false表示关闭,开启的rotate的规则如下:
898
899 1. 1000000行日志就自动分割
900 2. 文件的大小为256M就自动分割
901 3. 每天进行分割
902 4. 日志默认保存7天
903
904 一天之中分割不能多余999个,每个分割的文件名是`定义的文件名.日期.三位数字`
905
906 用户可以通过如下函数修改相应的日志切割规则:
907
908 - func (w *FileLogWriter) SetRotateDaily(daily bool) *FileLogWriter
909 - func (w *FileLogWriter) SetRotateLines(maxlines int) *FileLogWriter
910 - func (w *FileLogWriter) SetRotateMaxDays(maxdays int64) *FileLogWriter
911 - func (w *FileLogWriter) SetRotateSize(maxsize int) *FileLogWriter
912
913 但是这些函数调用必须在调用`StartLogger`之前。
914
915 ### 不同级别的log日志函数
916
917 * Trace(v ...interface{})
918 * Debug(v ...interface{})
919 * Info(v ...interface{})
920 * Warn(v ...interface{})
921 * Error(v ...interface{})
922 * Critical(v ...interface{})
923
924 你可以通过下面的方式设置不同的日志分级:
925
926 beego.SetLevel(beego.LevelError)
927
928 当你代码中有很多日志输出之后,如果想上线,但是你不想输出Trace、Debug、Info等信息,那么你可以设置如下:
929
930 beego.SetLevel(beego.LevelWarning)
931
932 这样的话就不会输出小于这个level的日志,日志的排序如下:
933
934 LevelTrace、LevelDebug、LevelInfo、LevelWarning、LevelError、LevelCritical
935
936 用户可以根据不同的级别输出不同的错误信息,如下例子所示:
937
938
939 ### Examples of log messages
940
941 - Trace
942
943 * "Entered parse function validation block"
944 * "Validation: entered second 'if'"
945 * "Dictionary 'Dict' is empty. Using default value"
946
947 - Debug
948
949 * "Web page requested: http://somesite.com Params='...'"
950 * "Response generated. Response size: 10000. Sending."
951 * "New file received. Type:PNG Size:20000"
952
953 - Info
954
955 * "Web server restarted"
956 * "Hourly statistics: Requested pages: 12345 Errors: 123 ..."
957 * "Service paused. Waiting for 'resume' call"
958
959 - Warn
960
961 * "Cache corrupted for file='test.file'. Reading from back-end"
962 * "Database 192.168.0.7/DB not responding. Using backup 192.168.0.8/DB"
963 * "No response from statistics server. Statistics not sent"
964
965 - Error
966
967 * "Internal error. Cannot process request #12345 Error:...."
968 * "Cannot perform login: credentials DB not responding"
969
970 - Critical
971
972 * "Critical panic received: .... Shutting down"
973 * "Fatal error: ... App is shutting down to prevent data corruption or loss"
974
975
976 ### Example
977
978 func internalCalculationFunc(x, y int) (result int, err error) {
979 beego.Debug("calculating z. x:", x, " y:", y)
980 z := y
981 switch {
982 case x == 3:
983 beego.Trace("x == 3")
984 panic("Failure.")
985 case y == 1:
986 beego.Trace("y == 1")
987 return 0, errors.New("Error!")
988 case y == 2:
989 beego.Trace("y == 2")
990 z = x
991 default:
992 beego.Trace("default")
993 z += x
994 }
995 retVal := z - 3
996 beego.Debug("Returning ", retVal)
997
998 return retVal, nil
999 }
1000
1001 func processInput(input inputData) {
1002 defer func() {
1003 if r := recover(); r != nil {
1004 beego.Error("Unexpected error occurred: ", r)
1005 outputs <- outputData{result: 0, error: true}
1006 }
1007 }()
1008 beego.Info("Received input signal. x:", input.x, " y:", input.y)
1009
1010 res, err := internalCalculationFunc(input.x, input.y)
1011 if err != nil {
1012 beego.Warn("Error in calculation:", err.Error())
1013 }
1014
1015 beego.Info("Returning result: ", res, " error: ", err)
1016 outputs <- outputData{result: res, error: err != nil}
1017 }
1018
1019 func main() {
1020 inputs = make(chan inputData)
1021 outputs = make(chan outputData)
1022 criticalChan = make(chan int)
1023 beego.Info("App started.")
1024
1025 go consumeResults(outputs)
1026 beego.Info("Started receiving results.")
1027
1028 go generateInputs(inputs)
1029 beego.Info("Started sending signals.")
1030
1031 for {
1032 select {
1033 case input := <-inputs:
1034 processInput(input)
1035 case <-criticalChan:
1036 beego.Critical("Caught value from criticalChan: Go shut down.")
1037 panic("Shut down due to critical fault.")
1038 }
1039 }
1040 }
1041
1042
1043 ## 配置管理
1044
1045 beego支持解析ini文件, beego默认会解析当前应用下的`conf/app.conf`文件
1046
1047 通过这个文件你可以初始化很多beego的默认参数
1048
1049 appname = beepkg
1050 httpaddr = "127.0.0.1"
1051 httpport = 9090
1052 runmode ="dev"
1053 autorender = false
1054 autorecover = false
1055 viewspath = "myview"
1056
1057 上面这些参数会替换beego默认的一些参数。
1058
1059 你可以在配置文件中配置应用需要用的一些配置信息,例如下面所示的数据库信息:
1060
1061 mysqluser = "root"
1062 mysqlpass = "rootpass"
1063 mysqlurls = "127.0.0.1"
1064 mysqldb = "beego"
1065
1066 那么你就可以通过如下的方式获取设置的配置信息:
1067
1068 beego.AppConfig.String("mysqluser")
1069 beego.AppConfig.String("mysqlpass")
1070 beego.AppConfig.String("mysqlurls")
1071 beego.AppConfig.String("mysqldb")
1072
1073 AppConfig支持如下方法
1074
1075 - Bool(key string) (bool, error)
1076 - Int(key string) (int, error)
1077 - Int64(key string) (int64, error)
1078 - Float(key string) (float64, error)
1079 - String(key string) string
1080
1081
1082 ## 系统默认参数
1083
1084 beego中带有很多可配置的参数,我们来一一认识一下它们,这样有利于我们在接下来的beego开发中可以充分的发挥他们的作用:
1085
1086 * BeeApp
1087
1088 beego默认启动的一个应用器入口,在应用import beego的时候,在init中已经初始化的。
1089
1090 * AppConfig
1091
1092 beego的配置文件解析之后的对象,也是在init的时候初始化的,里面保存有解析`conf/app.conf`下面所有的参数数据
1093
1094 * AppConfigPath
1095
1096 配置文件所在的路径,默认是应用程序对应的目录下的`conf/app.conf`,用户可以修改该值配置自己的配置文件
1097
1098 * HttpAddr
1099
1100 应用监听地址,默认为空,监听所有的网卡IP
1101
1102 * HttpPort
1103
1104 应用监听端口,默认为8080
1105
1106 * AppName
1107
1108 应用名称,默认是beego
1109
1110 * RunMode
1111
1112 应用的模式,默认是dev,为开发模式,在开发模式下出错会提示友好的出错页面,如前面错误描述中所述。
1113
1114 * AutoRender
1115
1116 是否模板自动渲染,默认值为true,对于API类型的应用,应用需要把该选项设置为false,不需要渲染模板。
1117
1118 * RecoverPanic
1119
1120 是否异常恢复,默认值为true,即当应用出现异常的情况,通过recover恢复回来,而不会导致应用异常退出。
1121
1122 * PprofOn
1123
1124 是否启用pprof,默认是false,当开启之后,用户可以通过如下地址查看相应的goroutine执行情况
1125
1126 /debug/pprof
1127 /debug/pprof/cmdline
1128 /debug/pprof/profile
1129 /debug/pprof/symbol
1130 关于pprof的信息,请参考官方的描述[pprof](http://golang.org/pkg/net/http/pprof/)
1131
1132 * ViewsPath
1133
1134 模板路径,默认值是views
1135
1136 * SessionOn
1137
1138 session是否开启,默认是false
1139
1140 * SessionProvider
1141
1142 session的引擎,默认是memory
1143
1144 * SessionName
1145
1146 存在客户端的cookie名称,默认值是beegosessionID
1147
1148 * SessionGCMaxLifetime
1149
1150 session过期时间,默认值是3600秒
1151
1152 * SessionSavePath
1153
1154 session保存路径,默认是空
1155
1156 * UseFcgi
1157
1158 是否启用fastcgi,默认是false
1159
1160 * MaxMemory
1161
1162 文件上传默认内存缓存大小,默认值是`1 << 26`(64M)
1163
1164 * EnableGzip
1165
1166 是否开启gzip支持,默认为false不支持gzip,一旦开启了gzip,那么在模板输出的内容会进行gzip或者zlib压缩,根据用户的Accept-Encoding来判断。
1167
1168 * DirectoryIndex
1169
1170 是否开启静态目录的列表显示,默认不显示目录,返回403错误
1171
1172 ## 第三方应用集成
1173
1174 beego支持第三方应用的集成,用户可以自定义`http.Handler`,用户可以通过如下方式进行注册路由:
1175
1176 beego.RouterHandler("/chat/:info(.*)", sockjshandler)
1177
1178 sockjshandler实现了接口`http.Handler`
1179
1180 目前在beego的example中有支持sockjs的chat例子,示例代码如下:
1181
1182 package main
1183
1184 import (
1185 "fmt"
1186 "github.com/astaxie/beego"
1187 "github.com/fzzy/sockjs-go/sockjs"
1188 "strings"
1189 )
1190
1191 var users *sockjs.SessionPool = sockjs.NewSessionPool()
1192
1193 func chatHandler(s sockjs.Session) {
1194 users.Add(s)
1195 defer users.Remove(s)
1196
1197 for {
1198 m := s.Receive()
1199 if m == nil {
1200 break
1201 }
1202 fullAddr := s.Info().RemoteAddr
1203 addr := fullAddr[:strings.LastIndex(fullAddr, ":")]
1204 m = []byte(fmt.Sprintf("%s: %s", addr, m))
1205 users.Broadcast(m)
1206 }
1207 }
1208
1209 type MainController struct {
1210 beego.Controller
1211 }
1212
1213 func (m *MainController) Get() {
1214 m.TplNames = "index.html"
1215 }
1216
1217 func main() {
1218 conf := sockjs.NewConfig()
1219 sockjshandler := sockjs.NewHandler("/chat", chatHandler, conf)
1220 beego.Router("/", &MainController{})
1221 beego.RouterHandler("/chat/:info(.*)", sockjshandler)
1222 beego.Run()
1223 }
1224
1225 通过上面的代码很简单的实现了一个多人的聊天室。上面这个只是一个sockjs的例子,我想通过大家自定义`http.Handler`,可以有很多种方式来进行扩展beego应用。
1226
1227
1228 ## 部署编译应用
1229
1230 Go语言的应用最后编译之后是一个二进制文件,你只需要copy这个应用到服务器上,运行起来就行。beego由于带有几个静态文件、配置文件、模板文件三个目录,所以用户部署的时候需要同时copy这三个目录到相应的部署应用之下,下面以我实际的应用部署为例:
1231
1232 $ mkdir /opt/app/beepkg
1233 $ cp beepkg /opt/app/beepkg
1234 $ cp -fr views /opt/app/beepkg
1235 $ cp -fr static /opt/app/beepkg
1236 $ cp -fr conf /opt/app/beepkg
1237
1238 这样在`/opt/app/beepkg`目录下面就会显示如下的目录结构:
1239
1240 .
1241 ├── conf
1242 │ ├── app.conf
1243 ├── static
1244 │ ├── css
1245 │ ├── img
1246 │ └── js
1247 └── views
1248 └── index.tpl
1249 ├── beepkg
1250
1251 这样我们就已经把我们需要的应用搬到服务器了,那么接下来就可以开始部署了,我现在服务器端用两种方式来run,
1252
1253 - Supervisord
1254
1255 安装和配置见[Supervisord](Supervisord.md)
1256
1257 - nohup方式
1258
1259 nohup ./beepkg &
1260
1261 个人比较推荐第一种方式,可以很好的管理起来应用
1262
1263 - [beego介绍](README.md)
1264 - [一步一步开发应用](Tutorial.md)
1 # beego介绍
2 beego是一个类似tornado的Go应用框架,采用了RESTFul的方式来实现应用框架,是一个超轻量级的框架,主要有如下的特点:
3
4 - 支持MVC的方式,用户只需要关注逻辑,实现对应method的方法即可
5 - 支持websocket,通过自定义Handler实现集成sockjs等方式实现
6 - 支持自定义路由,支持各种方式的路由,正则、语意均支持,类似sinatra
7 - session集成,支持memory、file、redis、mysql等存储
8 - 表单处理自动化解析,用户可以很方便的获取数据
9 - 日志分级系统,用户可以很方便的调试和应用日志记录
10 - 自定义配置文件,支持ini格式的文本配置,可以方便的在系统中调参数
11 - 采用了Go内置的模板,集成实现了很多Web开发中常用的函数
12
13 执行过程如下所示:
14 ![](images/beego.png)
15
16 # beego简单例子
17
18 package main
19
20 import (
21 "github.com/astaxie/beego"
22 )
23
24 type MainController struct {
25 beego.Controller
26 }
27
28 func (this *MainController) Get() {
29 this.Ctx.WriteString("hello world")
30 }
31
32 func main() {
33 beego.Router("/", &MainController{})
34 beego.Run()
35 }
36
37
38 # beego 指南
39
40 * [为什么设计beego](Why.md)
41 * [安装入门](Install.md)
42 * [快速入门](Quickstart.md)
43 * [一步一步开发应用](Tutorial.md)
44 * [beego案例](Application.md)
45 * [热升级](HotUpdate.md)
46 * [API应用开发入门](API.md)
47 * [HTTPLIB客户端](HttpLib.md)
48
49
50 # API接口
51
52 API对于我们平时开发应用非常有用,用于查询一些开发的函数,godoc做的非常好了
53
54 [Go Walker](http://gowalker.org/github.com/astaxie/beego)
1 ## supervisord安装
2
3 1. setuptools安装
4
5 wget http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg
6
7 sh setuptools-0.6c11-py2.7.egg
8
9 easy_install supervisor
10
11 echo_supervisord_conf >/etc/supervisord.conf
12
13 mkdir /etc/supervisord.conf.d
14
15 2. 修改配置/etc/supervisord.conf
16
17 [include]
18 files = /etc/supervisord.conf.d/*.conf
19
20 3. 新建管理的应用
21
22 cd /etc/supervisord.conf.d
23 vim beepkg.conf
24
25 配置文件:
26
27 [program:beepkg]
28 directory = /opt/app/beepkg
29 command = /opt/app/beepkg/beepkg
30 autostart = true
31 startsecs = 5
32 user = root
33 redirect_stderr = true
34 stdout_logfile = /var/log/supervisord/beepkg.log
1 # 一步一步跟我写博客
2
3
4 ## 创建项目
5
6
7 ## 数据库结构设计
8
9
10 ## 控制器设计
11
12
13 ## 模板设计
14
15
16 ## 用户登陆退出
17
18
19 ## 数据库操作
1 # 为什么设计beego和设计的思路
2
3 很多人会问为什么有那么多框架了,还要去实现一个框架呢?是不是大家都有自己实现框架的情节,我可以肯定的说不是,我说一下为什么设计beego的初衷
4
5 还记得当初写书的时候,我纯粹只是想把自己在学习Go语言中的一些体会写出来,由于我以前主要从事PHP和python的Web开发,所以想写一本Go如何来做Web实战的经验,刚开始的时候书的目录里面根本就没有框架实现这些章节,是写到后来发现其实对于Web开发者来说,一个微型的框架是非常有利于大家学习一个语言和快速进行应用开发的。
6
7 我以前经常用PHP的CI框架和python的tornado框架,这些框架都是非常轻量级的,轻量级就有利于我们:
8
9 - 第一节约我开发中一些常见问题的处理,用户只需要关注逻辑层面的东西
10 - 第二轻量级以至于他们的代码也是非常清晰的,我们可以通过阅读他们的源码来学习和体会这门语言的一些细节
11 - 第三对于项目开发者来说可以基于这些框架进行改造以适应自己的项目,从而实现二次框架的创造
12
13 所以基于上面这些的考虑,我就想实现一个类似这些语言的轻量级框架,所以我就在书的最后设计了两个章节来介绍和实现beego框架,这就是当初写beego框架的初衷。
14
15 有了这个初衷之后我就开始设计beego的执行逻辑,由于Go语言和python的思路比较接近,所以我就参考了tornado的思路来设计beego,你可以看到beego的RESTful处理完全和tornado的处理是一模一样的,通过controller层的Get、Post等方法来实现RESTFul。刚开始的时候路由参考的是[https://github.com/drone/routes](https://github.com/drone/routes),这个的正则处理我觉得非常好,弥补了Go语言默认Mux中的路由功能,但是由于要采用RESTFul方式,所以我自己设计了一个接口,实现python中的继承思想。
16
17 整个的MVC逻辑中C是最重要的部分,这一块采用了我上面说的接口方式,M模块目前我还没想好怎么做,但是大家可以参考我的另一个开源项目beedb来实现数据的管理,V这一块目前采用了Go语言自带的模板引擎,但是实现了很多方便的模板函数。这样一个简易的框架就完成了,然后我就不断的完善周边的功能,包括表单处理、session处理、日志处理、配置处理、自动化运行等功能。
18
19 - [beego介绍](README.md)
20 - [安装入门](Install.md)
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!