Revel教程

手册简介:

Revel教程

手册说明:

Go语言Web框架Revel介绍

Revel是一个Go语言的web框架,其具有热编译,高性能,无状态,模块化等特性,非常适合做web开发。这个框架源于java的 Play! Framework.清晰的MVC结构,是现在go语言Web框架中优秀的框架。

Revel框架特性

热编译

编辑, 保存, 和 刷新时,Revel自动编译代码和模板,如果代码编译错误,会给出一个 错误提示,同时捕捉 运行期错误。

全栈功能

Revel 支持: 路由, 参数解析, 验证, session/flash, 模板, 缓存, 计划任务, 测试, 国际化 等功能。

高性能

Revel 基于 Go HTTP server 构建。 这是techempower发布的 最新评测结果 。在各种不同的场景下进行了多达三到十次的请求负载测试。

框架设计

同步

Go HTTP server 对于每个请求都运行在 goroutine上。Write simple callback-free code without guilt。

无状态

Revel 提供了保持Web层无状态的可预知的扩展。例如,会话数据被存储在用户的cookie中,缓存由memcached集群提供支持。

模块化

Revel框架由被称为 过滤器 的中间件组成,它实现了几乎所有的请求处理功能。 开发者可以自由地使用自定义的过滤器,比如如自定义的路由器,用以替换Revel默认的路由过滤器。

快速开始

1、安装revel之前,先安装go环境
2、安装还需要hg和git支持
3、设置GOPATH,然后把revel下载并安装到GOPATH内

mkdir ~/gocode
cd $GOPATH
go get github.com/robfig/revel

4.编译revel命令行工具,revel自己封装了go的命令行工具,创建revel项目、打包发布基本都用这个工具,执行下面的命令

go build -o bin/revel github.com/robfig/revel/cmd

5.可以将编译出来的revel命令行工具加到$PATH变量中方便调用

export PATH="$PATH:$GOPATH/bin"

6.最后验证revel是否可以工作了

$ revel help
~
~ revel! http://robfig.github.com/revel
~
usage: revel command [arguments]

The commands are:

    run         run a Revel application
    new         create a skeleton Revel application
    clean       clean a Revel application's temp files
    package     package a Revel application (e.g. for deployment)

Use "revel help [command]" for more information.

概要说明

本节简要介绍框架的几个主要组成部分:

路由
采用简单的声明性语法。反向路由类型安全。
控制器
组织端点到控制器。提供易用的数据绑定和表单验证。
模板
使用 Go 模板支持大规模应用.
拦截器
在一个函数运行之前或之后被调用. 控制器的方法都可以被注册拦截.
过滤器
通用的功能可以使用过滤器来实现.

Revel路由

路由采用声明性语法. 所有的路由都定义在一个routes文件中。 使用简单的语法匹配路由, 并从 URI 中提取参数到控制器中. 下面是带注释的示例:

# conf/routes
# 这个文件定义了所有的路由 (优先级按照先后顺序)
GET    /login                Application.Login       # 匹配一个简单的路由
GET    /hotels/              Hotels.Index            # 匹配一个带或者不带斜线的路由
GET    /hotels/:id           Hotels.Show             # 绑定到一个控制器参数
WS     /hotels/:id/feed      Hotels.Feed             # WebSockets
POST   /hotels/:id/:action   Hotels.:action          # 自由绑定到一个控制器的多个方法
GET    /public/*filepath     Static.Serve("public")  # 静态文件服务
*      /:controller/:action  :controller.:action     # 自动捕捉所有动作,自动生成路由

反向路由以类型安全的方式生成. 例如下面的Save程序:

// 展示信息.
func (c Hotels) Show(id int) revel.Result {
	hotel := HotelById(id)
	return c.Render(hotel)
}

// 保存信息,并重定向到Hotels.Show.
func (c Hotels) Save(hotel Hotel) revel.Result {
	// validate and save hotel
	return c.Redirect(routes.Hotels.Show(hotel.Id))
}

Revel控制器

所有请求的操作都基于控制器方法实现:

  • Data binding 从url或表单绑定数据并将他们传递到控制器的方法中。(也可以直接从控制器的一个参数字典中提取参数。)
  • Validation 用来处理服务端验证.
  • Flash flash 是一个请求中的 cookie (包括错误、消息等).
  • Session 会话是加密签名的cookie, 是一个字典 map[string]string.
  • Results 使用反向路由进行重定向。模板渲染,使您可以在模板中使用局部变量的名字!

下面是一个例子:

// app/controllers/app.go

type Application struct {
	*revel.Controller
}

func (c Application) Register() revel.Result {
	title := "Register"
	return c.Render(title)
}

func (c Application) SaveUser(user models.User, verifyPassword string) revel.Result {
	c.Validation.Required(verifyPassword)
	c.Validation.Required(verifyPassword == user.Password)
		Message("Password does not match")
	user.Validate(c.Validation)

	if c.Validation.HasErrors() {
		c.Validation.Keep()
		c.FlashParams()
		return c.Redirect(routes.Application.Register())
	}

	user.HashedPassword, _ = bcrypt.GenerateFromPassword(
		[]byte(user.Password), bcrypt.DefaultCost)
	err := c.Txn.Insert(&user)
	if err != nil {
		panic(err)
	}

	c.Session["user"] = user.Username
	c.Flash.Success("Welcome, " + user.Name)
	return c.Redirect(routes.Hotels.Index())
}
            

Revel模板

按照惯例, Revel 轻松整合了 Go 模板 到 rest web 应用。下面是一个渲染模板的例子(参考上面展示的控制器代码)。

注意:

  • Revel 自动使用控制器的方法名来查找模板。
  • field 用来返回校验错误和表单数据字典的辅助函数,你可以在应用中添加任何想要的模板函数。
  • title 是放到放在RenderArgs中、用于模板中的变量。(它用在header.html 示例中)
{{/* app/views/Application/Register.html */}}

{{template "header.html" .}}

<h1>Register:</h1>
<form action="/register" method="POST">
  {{with $field := field "user.Username" .}}
    <p class="{{$field.ErrorClass}}">
      <strong>Username:</strong>
      <input type="text" name="{{$field.Name}}" size="16" value="{{$field.Flash}}"> *
      <span class="error">{{$field.Error}}</span>
    </p>
  {{end}}

  {{/* other fields */}}

  <p class="buttons">
    <input type="submit" value="Register"> <a href="/">Cancel</a>
  </p>
</form>

{{template "footer.html" .}}

Revel拦截器

拦截器是请求被执行之前或之后,或响应恐慌的控制器方法。 通过嵌入一个控制器,可以共享跨越多个控制器的拦截和字段信息。

举个栗子, db 模块在初始化时打开一个数据库连接,放到一个全局变量,db.Transactional 类型添加了一个 sql.Txn 字段, 以便拦截事务的开始与提交 (或者在出错时提供回滚)。

下面是如何使用拦截的列子 (忽略了错误处理):

// github.com/revel/revel/modules/db/app/db.go

var Db *sql.DB

func Init() {
	// 读取数据库配置.
	Driver, _ = revel.Config.String("db.driver")
	Spec, _ = revel.Config.String("db.spec")

	// 连接到数据库.
	Db, _ = sql.Open(Driver, Spec)
}

// 为控制器添加事务管理.
type Transactional struct {
	*revel.Controller
	Txn *sql.Tx
}

func (c *Transactional) Begin() revel.Result {
	c.Txn, _ = Db.Begin()
	return nil
}

func (c *Transactional) Commit() revel.Result {
	_ = c.Txn.Commit()
	c.Txn = nil
	return nil
}

func (c *Transactional) Rollback() revel.Result {
	_ = c.Txn.Rollback()
	c.Txn = nil
	return nil
}

func init() {
	revel.InterceptMethod((*Transactional).Begin, revel.BEFORE)
	revel.InterceptMethod((*Transactional).Commit, revel.AFTER)
	revel.InterceptMethod((*Transactional).Rollback, revel.PANIC)
}

下面是如何在应用控制器中使用事务管理功能:

type Bookings struct {
	*revel.Controller
	db.Transactional  // Adds .Txn
	user.Login        // Adds .User
}

func (c Bookings) ShowFirstBooking() revel.Result {
	row := c.Txn.QueryRow(`
select id, hotel_id, user_id, price, nights
  from Booking
 where UserId = ?
 limit 1`, c.User.Id)
	...
	return c.Render(booking)
}

Revel过滤器

过滤器是Revel程序的中间件,是具有特定签名的函数:

type Filter func(c *Controller, filterChain []Filter)

像拦截器框架等一些内建的功能就是被作为过滤器来实现:

// github.com/revel/revel/intercept.go

var InterceptorFilter = func(c *Controller, fc []Filter) {
	defer invokeInterceptors(FINALLY, c)
	defer func() {
		if err := recover(); err != nil {
			invokeInterceptors(PANIC, c)
			panic(err)
		}
	}()

	// Invoke the BEFORE interceptors and return early, if we get a result.
	invokeInterceptors(BEFORE, c)
	if c.Result != nil {
		return
	}

	fc[0](c, fc[1:])
	invokeInterceptors(AFTER, c)
}

Revel提供了开发者可以重写过滤器的默认的栈。 这很容易让开发者来选择想要使用的框架组件。

// github.com/revel/revel/filter.go

// Filters 是默认的全局过滤器
// 可以在初始化应用程序时进行设置
var Filters = []Filter{
	PanicFilter,             // 从恐慌中恢复,并显示一个错误页面。
	RouterFilter,            // 使用路由表来选择合适的动作
	FilterConfiguringFilter, // 用于添加或删除每个动作的过滤器的钩子.
	ParamsFilter,            // 解析参数到 Controller.Params 中.
	SessionFilter,           // 恢复和写入会话 cookie.
	FlashFilter,             // 恢复和写入 flash cookie.
	ValidationFilter,        // 还原保存验证错误并保存到新的Cookie中
	I18nFilter,              // 解析请求的语言
	InterceptorFilter,       // 执行拦截.
	ActionInvoker,           // 执行一个动作.
}
						

Revel 框架几乎所有的功能都是在过滤器中实现的, 而过滤器栈是作为配置的一部分直接暴露出来, 这使得Revel容易理解和模块化。

作为模块化的证明, 看看在 main server handler 中使用它是多简单啊:

// github.com/revel/revel/server.go

func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) {
	var (
		req  = NewRequest(r)
		resp = NewResponse(w)
		c    = NewController(req, resp)
	)
	req.Websocket = ws

	Filters[0](c, Filters[1:])
	if c.Result != nil {
		c.Result.Apply(req, resp)
	}
}

更多的内容,请按教程逐步进行深入学习


更新记录:

二维码
建议反馈
二维码