
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)
- }
- }
更多的内容,请按教程逐步进行深入学习
转载本站内容时,请务必注明来自W3xue。
部分原创内容未经授权禁止转载,违者必究。