Merging other languages

This commit is contained in:
James Miranda
2016-09-23 18:01:10 -03:00
parent 380a8ee74c
commit de3c5bdaa4
490 changed files with 24539 additions and 24588 deletions

View File

@@ -1,163 +1,168 @@
# 13.3 controller设计
传统的MVC框架大多数是基于Action设计的后缀式映射然而现在Web流行REST风格的架构。尽管使用Filter或者rewrite能够通过URL重写实现REST风格的URL但是为什么不直接设计一个全新的REST风格的 MVC框架呢本小节就是基于这种思路来讲述如何从头设计一个基于REST风格的MVC框架中的controller最大限度地简化Web应用的开发甚至编写一行代码就可以实现“Hello, world”。
## controller作用
MVC设计模式是目前Web应用开发中最常见的架构模式通过分离 Model模型、View视图和 Controller控制器可以更容易实现易于扩展的用户界面(UI)。Model指后台返回的数据View指需要渲染的页面通常是模板页面渲染后的内容通常是HTMLController指Web开发人员编写的处理不同URL的控制器如前面小节讲述的路由就是URL请求转发到控制器的过程controller在整个的MVC框架中起到了一个核心的作用负责处理业务逻辑因此控制器是整个框架中必不可少的一部分Model和View对于有些业务需求是可以不写的例如没有数据处理的逻辑处理没有页面输出的302调整之类的就不需要Model和View但是controller这一环节是必不可少的。
## beego的REST设计
前面小节介绍了路由实现了注册struct的功能而struct中实现了REST方式因此我们需要设计一个用于逻辑处理controller的基类这里主要设计了两个类型一个struct、一个interface
type Controller struct {
Ct *Context
Tpl *template.Template
Data map[interface{}]interface{}
ChildName string
TplNames string
Layout []string
TplExt string
}
type ControllerInterface interface {
Init(ct *Context, cn string) //初始化上下文和子类名称
Prepare() //开始执行之前的一些处理
Get() //method=GET的处理
Post() //method=POST的处理
Delete() //method=DELETE的处理
Put() //method=PUT的处理
Head() //method=HEAD的处理
Patch() //method=PATCH的处理
Options() //method=OPTIONS的处理
Finish() //执行完成之后的处理
Render() error //执行完method对应的方法之后渲染页面
}
那么前面介绍的路由add函数的时候是定义了ControllerInterface类型因此只要我们实现这个接口就可以所以我们的基类Controller实现如下的方法
func (c *Controller) Init(ct *Context, cn string) {
c.Data = make(map[interface{}]interface{})
c.Layout = make([]string, 0)
c.TplNames = ""
c.ChildName = cn
c.Ct = ct
c.TplExt = "tpl"
}
func (c *Controller) Prepare() {
}
func (c *Controller) Finish() {
}
func (c *Controller) Get() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Post() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Delete() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Put() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Head() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Patch() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Options() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Render() error {
if len(c.Layout) > 0 {
var filenames []string
for _, file := range c.Layout {
filenames = append(filenames, path.Join(ViewsPath, file))
}
t, err := template.ParseFiles(filenames...)
if err != nil {
Trace("template ParseFiles err:", err)
}
err = t.ExecuteTemplate(c.Ct.ResponseWriter, c.TplNames, c.Data)
if err != nil {
Trace("template Execute err:", err)
}
} else {
if c.TplNames == "" {
c.TplNames = c.ChildName + "/" + c.Ct.Request.Method + "." + c.TplExt
}
t, err := template.ParseFiles(path.Join(ViewsPath, c.TplNames))
if err != nil {
Trace("template ParseFiles err:", err)
}
err = t.Execute(c.Ct.ResponseWriter, c.Data)
if err != nil {
Trace("template Execute err:", err)
}
}
return nil
}
func (c *Controller) Redirect(url string, code int) {
c.Ct.Redirect(code, url)
}
上面的controller基类已经实现了接口定义的函数通过路由根据url执行相应的controller的原则会依次执行如下
Init() 初始化
Prepare() 执行之前的初始化,每个继承的子类可以来实现该函数
method() 根据不同的method执行不同的函数GET、POST、PUT、HEAD等子类来实现这些函数如果没实现那么默认都是403
Render() 可选根据全局变量AutoRender来判断是否执行
Finish() 执行完之后执行的操作,每个继承的子类可以来实现该函数
## 应用指南
上面beego框架中完成了controller基类的设计那么我们在我们的应用中可以这样来设计我们的方法
package controllers
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
this.Data["Username"] = "astaxie"
this.Data["Email"] = "astaxie@gmail.com"
this.TplNames = "index.tpl"
}
上面的方式我们实现了子类MainController实现了Get方法那么如果用户通过其他的方式(POST/HEAD等)来访问该资源都将返回403而如果是Get来访问因为我们设置了AutoRender=true那么在执行完Get方法之后会自动执行Render函数就会显示如下界面
![](images/13.4.beego.png?raw=true)
index.tpl的代码如下所示我们可以看到数据的设置和显示都是相当的简单方便
<!DOCTYPE html>
<html>
<head>
<title>beego welcome template</title>
</head>
<body>
<h1>Hello, world!{{.Username}},{{.Email}}</h1>
</body>
</html>
## links
* [目录](<preface.md>)
* 上一章: [自定义路由器设计](<13.2.md>)
* 下一节: [日志和配置设计](<13.4.md>)
# 13.3 Design controllers
Most of the traditional MVC framework is based on the design of postfix Action mapping, however, is now popular REST-style Web architecture. Although the use of Filter or rewrite URL rewriting can be achieved through a REST-style URL, but why not just design a new REST-style MVC framework it ? This section is based on this idea on how to start from scratch to design a REST-style MVC framework based on the controller, to maximize simplify Web application development, or even write a single line of code to achieve the "Hello, world".
## Controller role
MVC design pattern is the most common Web application development framework model, by separating Model( model ), View( view ) and the Controller( controller ) can be more easily achieved easily extensible user interface(UI). Model refers to the background data returned ; View refers to the need to render the page, usually a template page, the content is usually rendered HTML; Controller refers to Web developers to write controllers handle different URL, such as the route described in the previous section is a URL request forwarded to the process controller, controller in the whole MVC framework plays a central role, responsible for handling business logic, so the controller is an essential part of the whole framework, Model and View for some business needs can not write, for example, no data processing logic processing, no page output 302 and the like do not need to adjust the Model and View, but the controller of this part is essential.
## Beego the REST design
Previous section describes the routing function to achieve a registered struct, and the struct implements REST approach, so we need to design a controller for logic processing base class, where the main design of the two types, a struct, an interface
type Controller struct {
Ct *Context
Tpl *template.Template
Data map[interface{}]interface{}
ChildName string
TplNames string
Layout []string
TplExt string
}
type ControllerInterface interface {
Init(ct *Context, cn string) //Initialize the context and subclass name
Prepare() //some processing before execution begins
Get() //method = GET processing
Post() //method = POST processing
Delete() //method = DELETE processing
Put() //method = PUT handling
Head() //method = HEAD processing
Patch() //method = PATCH treatment
Options() //method = OPTIONS processing
Finish() //executed after completion of treatment
Render() error //method executed after the corresponding method to render the page
}
Then add function described earlier, when a route is defined ControllerInterface type, so long as we can implement this interface, so our base class Controller to achieve the following methods:
func (c *Controller) Init(ct *Context, cn string) {
c.Data = make(map[interface{}]interface{})
c.Layout = make([]string, 0)
c.TplNames = ""
c.ChildName = cn
c.Ct = ct
c.TplExt = "tpl"
}
func (c *Controller) Prepare() {
}
func (c *Controller) Finish() {
}
func (c *Controller) Get() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Post() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Delete() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Put() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Head() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Patch() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Options() {
http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405)
}
func (c *Controller) Render() error {
if len(c.Layout) > 0 {
var filenames []string
for _, file := range c.Layout {
filenames = append(filenames, path.Join(ViewsPath, file))
}
t, err := template.ParseFiles(filenames...)
if err != nil {
Trace("template ParseFiles err:", err)
}
err = t.ExecuteTemplate(c.Ct.ResponseWriter, c.TplNames, c.Data)
if err != nil {
Trace("template Execute err:", err)
}
} else {
if c.TplNames == "" {
c.TplNames = c.ChildName + "/" + c.Ct.Request.Method + "." + c.TplExt
}
t, err := template.ParseFiles(path.Join(ViewsPath, c.TplNames))
if err != nil {
Trace("template ParseFiles err:", err)
}
err = t.Execute(c.Ct.ResponseWriter, c.Data)
if err != nil {
Trace("template Execute err:", err)
}
}
return nil
}
func (c *Controller) Redirect(url string, code int) {
c.Ct.Redirect(code, url)
}
At the controller base class already implements the interface defined functions performed by routing the appropriate controller according url principles will be followed by implementation of the following:
Init() initializes
Prepare() before the execution of the initialization, each subclass can inherit to implement the function
method() depending on the method to perform different functions: GET, POST, PUT, HEAD, etc. sub-classes to implement these functions, if not achieved, then the default is 403
Render() optional, according to a global variable to determine whether to execute AutoRender
Finish() after the implementation of the action, each subclass inherits the function can be achieved
## Application guide
Above beego Framework base class to complete the design of the controller, then we in our application can be to design our approach:
package controllers
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
this.Data["Username"] = "astaxie"
this.Data["Email"] = "astaxie@gmail.com"
this.TplNames = "index.tpl"
}
The way we achieved above subclass MainController, implements Get method, so if the user through other means(POST/HEAD, etc. ) to access the resource will return 403, and if it is Get access, because we set the AutoRender = true, then play in the implementation of the Get method is performed automatically after the Render function, it will display the following interface:
![](images/13.4.beego.png?raw=true)
index.tpl code is shown below, we can see the data set and display are quite simple:
<!DOCTYPE html>
<html>
<head>
<title>beego welcome template</title>
</head>
<body>
<h1>Hello, world!{{.Username}},{{.Email}}</h1>
</body>
</html>
## Links
- [Directory](preface.md)
- Previous section: [Customized routers](13.2.md)
- Next section: [Logs and configurations](13.4.md)