订房示例程序演示下面几个内容:

  • 通过配置 Revel DB模块使用SQL数据库。.
  • 使用 GORP 操作数据库
  • 使用拦截器检查用户是否登录。
  • 使用验证显示错误

程序结构如下:

booking/app/
	models		   # 结构体验证.
		booking.go
		hotel.go
		user.go

	controllers
		init.go    # 注册拦截器.
		gorp.go    # 配置 Gorp, 创建表, 管理实务.
		app.go     # 用户注册、登录
		hotels.go  # 酒店查询和预定

	views
		...

浏览 Github 上的代码

安装

示例程序使用了 go-sqlite3, 他封装了 C 库.

Mac 平台 (OSX):

  1. 安装 Homebrew ( http://mxcl.github.com/homebrew/ ):

ruby <(curl -fsSkL raw.github.com/mxcl/homebrew/go)

  1. 安装 pkg-config 和 sqlite3:

brew install pkgconfig sqlite3

Linux (Ubuntu):

  `sudo apt-get install sqlite3 libsqlite3-dev`

安装完 SQLite 后, 就可以运行程序了:

$ revel run github.com/revel/revel/samples/booking

数据库 / Gorp 插件

app/controllers/gorp.go 定义了 GorpPlugin, 主要处理了:

  • 程序启动时: 使用DB模块打开SQLite内存数据库,创建用户,预订和酒店三张表,并插入一些测试记录
  • 请求开始之前: 开始一个事务,并存储在控制器
  • 请求完成之后: 提交事务,如果提交出错,将抛出一个panic。
  • 出现异常: 出错后回滚事务。

浏览代码

拦截器

app/controllers/init.go 注册拦截器:

func init() {
	revel.OnAppStart(Init)
	revel.InterceptMethod((*GorpController).Begin, revel.BEFORE)
	revel.InterceptMethod(Application.AddUser, revel.BEFORE)
	revel.InterceptMethod(Hotels.checkUser, revel.BEFORE)
	revel.InterceptMethod((*GorpController).Commit, revel.AFTER)
	revel.InterceptMethod((*GorpController).Rollback, revel.FINALLY)
}

举个栗子, checkUser 从会话中查找用户名,如果没有查到,会重定向到登录页面。

func (c Hotels) checkUser() revel.Result {
	if user := c.connected(); user == nil {
		c.Flash.Error("Please log in first")
		return c.Redirect(Application.Index)
	}
	return nil
}

浏览代码

验证

示例程序包含了多个验证:

func (booking Booking) Validate(v *revel.Validation) {
	v.Required(booking.User)
	v.Required(booking.Hotel)
	v.Required(booking.CheckInDate)
	v.Required(booking.CheckOutDate)

	v.Match(b.CardNumber, regexp.MustCompile(`\d{16}`)).
		Message("Credit card number must be numeric and 16 digits")

	v.Check(booking.NameOnCard,
		revel.Required{},
		revel.MinSize{3},
		revel.MaxSize{70},
	)
}

浏览代码

Revel 使用验证变量的名字去验证、存储错误(除非被重写),例如, booking.CheckInDate 是必填字段; 如果值为空, Revel 会在上下文在保存一个名为 “booking.CheckInDate”、 类型为ValidationError 的错误信息。

然后, 就可以在Hotels/Book.html 模板中使用 field 标签进行访问:

  {{with $field := field "booking.CheckInDate" .}}
    <p class="{{$field.ErrorClass}}">
      <strong>Check In Date:</strong>
      <input type="text" size="10" name="{{$field.Name}}" class="datepicker" value="{{$field.Flash}}">
      * <span class="error">{{$field.Error}}</span>
    </p>
  {{end}}

field 模板标签会在验证上下文中查找名为 “booking.CheckInDate” 错误。