Skip to content

Commit 70c8a55

Browse files
committed
Merge pull request astaxie#132 from chenwenli/master
review three file for 13 chapter ,updated some word
2 parents cb24e26 + c4983ed commit 70c8a55

File tree

4 files changed

+38
-34
lines changed

4 files changed

+38
-34
lines changed

13.1.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
# 13.1 项目规划
2-
做任何事情都需要做好规划,那么我们在开发博客系统之前,也需要多好项目的规划,如何设置目录结构,如何理解整个的流程图,当我们理解了应用的执行过程,那么接下来的设计编码就会变得相对容易了
2+
做任何事情都需要做好规划,那么我们在开发博客系统之前,同样需要做好项目的规划,如何设置目录结构,如何理解整个项目的流程图,当我们理解了应用的执行过程,那么接下来的设计编码就会变得相对容易了
33
## gopath以及项目设置
4-
gopath是一个文件系统的目录,我们可以随便设置一个目录为gopath,前面介绍过gopath可以是多个目录,在window系统设置环境变量在linux/MacOS系统只要`export gopath=/home/astaxie/gopath`但是必须保证gopath目录下面有三个目录pkg、bin、src目录。我们新建的项目放在src目录下面,我们暂定我们的博客目录叫做beeblog,下面是我在window下的环境变量和目录结构的截图
4+
假设指定gopath是文件系统的普通目录名,当然我们可以随便设置一个目录名,然后将其路径存入GOPATH。前面介绍过GOPATH可以是多个目录:在window系统设置环境变量在linux/MacOS系统只要输入终端命令`export gopath=/home/astaxie/gopath`但是必须保证gopath这个代码目录下面有三个目录pkg、bin、src。新建项目的源码放在src目录下面,现在暂定我们的博客目录叫做beeblog,下面是在window下的环境变量和目录结构的截图
55

66
![](images/13.1.gopath.png?raw=true)
77

88
![](images/13.1.gopath2.png?raw=true)
99

1010
## 应用程序流程图
11-
博客系统是基于模型-视图-控制器这一设计模式的。MVC是一种将应用程序的逻辑层和表现层进行分离的方法。在实践中,由于表现层从Go中分离了出来,所以它允许你的网页中只包含很少的脚本。
11+
博客系统是基于模型-视图-控制器这一设计模式的。MVC是一种将应用程序的逻辑层和表现层进行分离的结构方式。在实践中,由于表现层从Go中分离了出来,所以它允许你的网页中只包含很少的脚本。
1212

13-
- 模型 (Model) 代表你的数据结构。通常来说,你的模型类将包含取出、插入、更新你的数据库资料这些功能
14-
- 视图 (View) 是展示给用户的信息。一个视图通常是一个网页,但是在Go中,一个视图也可以是一个页面片段,如页头、页尾。它还可以是一个 RSS 页面,或任何其它类型的“页面”,Go实现的template包已经很好的体现了View这个概念
13+
- 模型 (Model) 代表数据结构。通常来说,模型类将包含取出、插入、更新数据库资料等这些功能
14+
- 视图 (View) 是展示给用户的信息的结构及样式。一个视图通常是一个网页,但是在Go中,一个视图也可以是一个页面片段,如页头、页尾。它还可以是一个 RSS 页面,或其它类型的“页面”,Go实现的template包已经很好的实现了View层中的部分功能
1515
- 控制器 (Controller) 是模型、视图以及其他任何处理HTTP请求所必须的资源之间的中介,并生成网页。
1616

17-
下图设计了我们接下来的博客系统数据流如何贯穿整个系统:
17+
下图显示了项目设计中博客系统的数据流是如何贯穿整个系统:
1818

1919
![](images/13.1.flow.png?raw=true)
2020

21-
1. main.go作为应用入口,初始化运行博客所需要的基本资源,配置信息,监听端口。
22-
2. 路由功能检查HTTP请求,根据URL以及method来确定谁来处理请求
23-
3. 如果缓存文件存在,它将绕过通常的系统执行顺序,被直接发送给浏览器。
24-
4. 安全检测:应用程序控制器调用之前,HTTP请求和任何用户提交的数据将被过滤
25-
5. 控制器装载模型、核心库、辅助函数,以及任何处理特定请求所需的其它资源,控制器主要处理业务逻辑
26-
6. 输出视图用来渲染需要发送到Web浏览器中的内容。如果开启缓存,视图首先被缓存,所以将可用于以后的请求
21+
1. main.go作为应用入口,初始化一些运行博客所需要的基本资源,配置信息,监听端口。
22+
2. 路由功能检查HTTP请求,根据URL以及method来确定谁(控制层)来处理请求的转发资源
23+
3. 如果缓存文件存在,它将绕过通常的流程执行,被直接发送给浏览器。
24+
4. 安全检测:应用程序控制器调用之前,HTTP请求和任一用户提交的数据将被过滤
25+
5. 控制器装载模型、核心库、辅助函数,以及任何处理特定请求所需的其它资源,控制器主要负责处理业务逻辑
26+
6. 输出视图层中渲染好的即将发送到Web浏览器中的内容。如果开启缓存,视图首先被缓存,将用于以后的常规请求
2727

2828
## 目录结构
2929
根据上面的应用程序流程设计,博客的目录结构设计如下:
@@ -37,11 +37,11 @@ gopath是一个文件系统的目录,我们可以随便设置一个目录为go
3737
|——views 视图库
3838

3939
## 框架设计
40-
为了实现博客的快速搭建,打算基于上面的流程设计开发一个最小化的框架,框架包括路由功能、支持REST的控制器、自动化的模板渲染,日志系统、配置管理
40+
为了实现博客的快速搭建,打算基于上面的流程设计开发一个最小化的框架,框架包括路由功能、支持REST的控制器、自动化的模板渲染,日志系统、配置管理等
4141

4242
## 总结
43-
本小节介绍了博客系统从设置gopath到目录建立这样的基础信息,也介绍了将要采用的MVC模式,博客系统中数据流的执行流程,最后通过这些流程设计了博客系统的目录结构,至此我们完成了一个大框架的搭建,接下来的几个小节我们将会逐个实现。
43+
本小节介绍了博客系统从设置GOPATH到目录建立这样的基础信息,也简单介绍了框架结构采用的MVC模式,博客系统中数据流的执行流程,最后通过这些流程设计了博客系统的目录结构,至此,我们基本完成一个框架的搭建,接下来的几个小节我们将会逐个实现。
4444
## links
4545
* [目录](<preface.md>)
4646
* 上一章: [构建博客系统](<13.md>)
47-
* 下一节: [自定义路由器设计](<13.2.md>)
47+
* 下一节: [自定义路由器设计](<13.2.md>)

13.2.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
## HTTP路由
44
HTTP路由组件负责将HTTP请求交到对应的函数处理(或者是一个struct的方法),如前面小节所描述的结构图,路由在框架中相当于一个事件处理器,而这个事件包括:
55

6-
- 用户请求的路径(例如:/user/123,/article/123),当然还有查询串信息(例如?id=11)
7-
- HTTP的请求method(GET、POST、PUT、DELETE、PATCH等)
6+
- 用户请求的路径(path)(例如:/user/123,/article/123),当然还有查询串信息(例如?id=11)
7+
- HTTP的请求方法(method)(GET、POST、PUT、DELETE、PATCH等)
88

9-
路由器就是根据用户请求的这个信息定位到相应的处理函数
9+
路由器就是根据用户请求的事件信息转发到相应的处理函数(控制层)
1010
## 默认的路由实现
1111
在3.4小节有过介绍Go的http包的详解,里面介绍了Go的http包如何设计和实现路由,这里继续以一个例子来说明:
1212

@@ -22,14 +22,14 @@ HTTP路由组件负责将HTTP请求交到对应的函数处理(或者是一个st
2222

2323
log.Fatal(http.ListenAndServe(":8080", nil))
2424

25-
上面的例子调用了http默认的DefaultServeMux来添加路由,两个参数,第一个参数是前面所讲的用户请求的路径(Go中保存在r.URL.Path),第二参数是定位要执行的函数,路由的思路主要集中在两点:
25+
上面的例子调用了http默认的DefaultServeMux来添加路由,需要提供两个参数,第一个参数是希望用户访问此资源的URL路径(保存在r.URL.Path),第二参数是即将要执行的函数,以提供用户访问的资源。路由的思路主要集中在两点:
2626

2727
- 添加路由信息
2828
- 根据用户请求转发到要执行的函数
2929

30-
Go默认的包添加是通过函数`http.Handle``http.HandleFunc`等来添加,底层都是调用了`DefaultServeMux.Handle(pattern string, handler Handler)`,这个函数会把路由信息存储在一个map信息中`map[string]muxEntry`,这就解决了上面说的第一点。
30+
Go默认的路由添加是通过函数`http.Handle``http.HandleFunc`等来添加,底层都是调用了`DefaultServeMux.Handle(pattern string, handler Handler)`,这个函数会把路由信息存储在一个map信息中`map[string]muxEntry`,这就解决了上面说的第一点。
3131

32-
Go的监听端口,然后接收到tcp连接会扔给Handler来处理,上面的例子默认nil即为`http.DefaultServeMux`,通过`DefaultServeMux.ServeHTTP`函数来进行调度,循环上面存储的map信息,和访问url进行比对查询注册的处理函数,这样就实现了上面所说的第二点。
32+
Go监听端口,然后接收到tcp连接会扔给Handler来处理,上面的例子默认nil即为`http.DefaultServeMux`,通过`DefaultServeMux.ServeHTTP`函数来进行调度,遍历之前存储的map路由信息,和用户访问的URL进行匹配,以查询对应注册的处理函数,这样就实现了上面所说的第二点。
3333

3434
for k, v := range mux.m {
3535
if !pathMatch(k, path) {
@@ -43,13 +43,13 @@ Go的监听端口,然后接收到tcp连接会扔给Handler来处理,上面
4343

4444

4545
## beego框架路由实现
46-
目前几乎所有的Web应用路由实现都是基于http默认的路由器,但是默认的路由器有几个限制点
46+
目前几乎所有的Web应用路由实现都是基于http默认的路由器,但是Go自带的路由器有几个限制
4747

4848
- 不支持参数设定,例如/user/:uid 这种泛类型匹配
4949
- 无法很好的支持REST模式,无法限制访问的方法,例如上面的例子中,用户访问/foo,可以用GET、POST、DELETE、HEAD等方式访问
50-
- 默认的路由规则太多了,我前面自己开发了一个API的应用,路由规则有三十几条,这种路由多了之后其实可以进一步简化,通过struct的方法进行一种简化
50+
- 一般网站的路由规则太多了,编写繁琐。我前面自己开发了一个API应用,路由规则有三十几条,这种路由多了之后其实可以进一步简化,通过struct的方法进行一种简化
5151

52-
beego框架的路由器基于上面的几点限制考虑设计了一种REST方式的路由实现,路由设计也是基于上面的默认设计的两点来考虑:存储路由和转发路由
52+
beego框架的路由器基于上面的几点限制考虑设计了一种REST方式的路由实现,路由设计也是基于上面Go默认设计的两点来考虑:存储路由和转发路由
5353

5454
### 存储路由
5555
针对前面所说的限制点,我们首先要解决参数支持就需要用到正则,第二和第三点我们通过一种变通的方法来解决,REST的方法对应到struct的方法中去,然后路由到struct而不是函数,这样在转发路由的时候就可以根据method来执行不同的方法。
@@ -74,16 +74,18 @@ ControllerRegistor对外的接口函数有
7474

7575
详细的实现如下所示:
7676

77-
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) {
77+
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface) {
7878
parts := strings.Split(pattern, "/")
7979

8080
j := 0
8181
params := make(map[int]string)
8282
for i, part := range parts {
8383
if strings.HasPrefix(part, ":") {
8484
expr := "([^/]+)"
85+
8586
//a user may choose to override the defult expression
86-
// similar to expressjs: ‘/user/:id([0-9]+)’
87+
// similar to expressjs: ‘/user/:id([0-9]+)’
88+
8789
if index := strings.Index(part, "("); index != -1 {
8890
expr = part[index:]
8991
part = part[:index]
@@ -96,9 +98,11 @@ ControllerRegistor对外的接口函数有
9698

9799
//recreate the url pattern, with parameters replaced
98100
//by regular expressions. then compile the regex
101+
99102
pattern = strings.Join(parts, "/")
100103
regex, regexErr := regexp.Compile(pattern)
101104
if regexErr != nil {
105+
102106
//TODO add error handling here to avoid panic
103107
panic(regexErr)
104108
return
@@ -116,7 +120,7 @@ ControllerRegistor对外的接口函数有
116120
}
117121

118122
### 静态路由实现
119-
上面我们实现的动态路由的实现,Go的http包默认支持静态文件处理FileServer,由于我们实现了自定义的路由器,那么静态文件也需要自己设定,beego的静态文件夹保存在全局变量StaticDir中,StaticDir是一个map类型,实现如下:
123+
上面我们实现的动态路由的实现,Go的http包默认支持静态文件处理FileServer,由于我们实现了自定义的路由器,那么静态文件也需要自己设定,beego的静态文件夹路径保存在全局变量StaticDir中,StaticDir是一个map类型,实现如下:
120124

121125
func (app *App) SetStaticPath(url string, path string) *App {
122126
StaticDir[url] = path
@@ -129,7 +133,7 @@ ControllerRegistor对外的接口函数有
129133

130134

131135
### 转发路由
132-
转发路由是基于ControllerRegistor的路由信息来进行转发的,详细的实现如下代码所示:
136+
转发路由是基于ControllerRegistor里的路由信息来进行转发的,详细的实现如下代码所示:
133137

134138
// AutoRoute
135139
func (p *ControllerRegistor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -257,4 +261,4 @@ ControllerRegistor对外的接口函数有
257261
## links
258262
* [目录](<preface.md>)
259263
* 上一章: [数据库设计](<13.2.md>)
260-
* 下一节: [controller设计](<13.4.md>)
264+
* 下一节: [controller设计](<13.4.md>)

13.3.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# 13.3 controller设计
22

3-
传统的MVC框架大多数是基于Action设计的后缀式映射,然而目前流行的Web趋势是REST风格的架构。尽管使用Filter或者rewrite能够通过URL重写实现REST风格的URL,但是为什么不直接设计一个全新的REST风格的 MVC框架呢?本小节就是基于这种思路来讲述如何从头设计一个基于REST风格的MVC框架中的controller,最大限度地简化Web应用的开发,您甚至编写一行代码就可以实现“Hello, world”。
3+
传统的MVC框架大多数是基于Action设计的后缀式映射,然而,现在Web流行REST风格的架构。尽管使用Filter或者rewrite能够通过URL重写实现REST风格的URL,但是为什么不直接设计一个全新的REST风格的 MVC框架呢?本小节就是基于这种思路来讲述如何从头设计一个基于REST风格的MVC框架中的controller,最大限度地简化Web应用的开发,甚至编写一行代码就可以实现“Hello, world”。
44

55
## controller作用
6-
MVC设计模式是目前Web应用开发中最常见的一种架构模式,通过分离 Model(模型)、View(视图)和 Controller(控制器),可以更容易实现易于扩展的UI。Model指后台返回的数据;View指需要渲染的页面,通常是模板页面,渲染后的结果通常是HTML;Controller指Web开发人员编写的处理不同URL的控制器,如前面小节讲述的路由就是转发到控制器的过程,controller在整个的MVC框架中起到了一个核心的作用,处理业务逻辑,因此控制器是整个框架中必不可少的一部分,Model和View会根据不同的业务可以不写,例如没有数据处理的逻辑处理,没有页面输出的302调整之类的就不需要Model和View,但是controller是必不可少的
6+
MVC设计模式是目前Web应用开发中最常见的架构模式,通过分离 Model(模型)、View(视图)和 Controller(控制器),可以更容易实现易于扩展的用户界面(UI)。Model指后台返回的数据;View指需要渲染的页面,通常是模板页面,渲染后的内容通常是HTML;Controller指Web开发人员编写的处理不同URL的控制器,如前面小节讲述的路由就是URL请求转发到控制器的过程,controller在整个的MVC框架中起到了一个核心的作用,负责处理业务逻辑,因此控制器是整个框架中必不可少的一部分,Model和View对于有些业务需求是可以不写的,例如没有数据处理的逻辑处理,没有页面输出的302调整之类的就不需要Model和View,但是controller这一环节是必不可少的
77

88
## beego的REST设计
99
前面小节介绍了路由实现了注册struct的功能,而struct中实现了REST方式,因此我们需要设计一个用于逻辑处理controller的基类,这里主要设计了两个类型,一个struct、一个interface
@@ -32,7 +32,7 @@ MVC设计模式是目前Web应用开发中最常见的一种架构模式,通
3232
Render() error //执行完method对应的方法之后渲染页面
3333
}
3434

35-
那么前面介绍的路由add的时候是定义了ControllerInterface类型,因此,只要我们实现这个接口就可以,所以我们的基类Controller实现如下的方法:
35+
那么前面介绍的路由add函数的时候是定义了ControllerInterface类型,因此,只要我们实现这个接口就可以,所以我们的基类Controller实现如下的方法:
3636

3737
func (c *Controller) Init(ct *Context, cn string) {
3838
c.Data = make(map[interface{}]interface{})
@@ -113,7 +113,7 @@ MVC设计模式是目前Web应用开发中最常见的一种架构模式,通
113113
c.Ct.Redirect(code, url)
114114
}
115115

116-
上面的controller基类完成了接口定义的函数,通过路由根据url执行相应的controller的原则,会依次执行如下的函数
116+
上面的controller基类已经实现了接口定义的函数,通过路由根据url执行相应的controller的原则,会依次执行如下
117117

118118
Init() 初始化
119119
Prepare() 执行之前的初始化,每个继承的子类可以来实现该函数
@@ -160,4 +160,4 @@ index.tpl的代码如下所示,我们可以看到数据的设置和显示都
160160
## links
161161
* [目录](<preface.md>)
162162
* 上一章: [自定义路由器设计](<13.2.md>)
163-
* 下一节: [日志和配置设计](<13.4.md>)
163+
* 下一节: [日志和配置设计](<13.4.md>)

genepub.sh

100755100644
File mode changed.

0 commit comments

Comments
 (0)