日期:2014-05-20  浏览次数:20896 次

Play Framework 简单实例分析以及基础知识整合

前言

通过分析官方使用Play创建的一个例子:To-Do List 来说明使用play创建web项目的一个基本结构和流程

首先要说明的是,整个demo是基于Play 2.1.0的,其他版本的play可能会有错误,所以在跟着官方demo走的时候,请保证版本一致性,我一开始是在2.0.4的play下创建整个项目的,在中间就有一些方法是不兼容的,需要2.1.0的play才可以使用,所以只能下最新的play并且重新新建项目。

新建项目、绑定IDE、运行Play 这几个步骤,我在这里就不重复了,可以看博客:Play Framework配置

在eclipse中打开项目,可以看到项目的基本组成如下图所示


在这里要说的是,在使用eclipse或者是Intelij或者其他IDE进行编辑过程中,可能会提示有错误,如果不是拼写错误,那么可以先忽略,因为在运行的时候,play会帮你编译,有错误的话,可以直接在浏览器中看到。而且IDE中指出的错误,很多时候都是错的,因为IDE中并没有play的全部资料,所以很多提示都是基于IDE现在拥有的sdk进行判断的。所以项目中是否存在错误,由编译时,play帮你查实最准的(个人觉得是这样)。

上面看到的是整个项目的结构,现在对我来说最重要的就是app和conf这两个文件夹。app文件夹是放java代码的地方,基于MVC规则。conf是配置项目的地方,路由以及数据库连接的配置等,后面会一一说到。

概述

程序的主要入口是conf/routes文件,这个文件定义了程序中所有可访问的URL。打开文件,可以看到play为我们生成了这样一个路由映射关系
# Home page
GET     /                           controllers.Application.index()
这个语句告诉play,当服务器收到一个对根目录的GET请求时,必须调用controllers.Application.index()方法。
打开app/controllers/Application.java文件,可以看到如下:

其中Application继承于controller,在Application中有一个共有的静态方法index(),这个方法返回的是一个Result类型的对象。

这里要理清 controller、Action、Result这几个概念和这几个概念之间的关系。详细的说明可以看文档:Actions,Controllers and Results

简单来说,当Play程序接收到一个请求时,一般都是交由Action进行处理,Action就是一个java的方法,处理来自客户端的请求并返回结果给客户端。

可以看到返回的是Result值,Result代表的是回送给客户端的HTTP响应,就像上面的index()方法 返回的是ok,里面包含的是一个200 OK状态码和一个带有文本的响应主体。

而controller就是包含多个Action的类。

要注意的是重定向也是Result的一种哦,因为重定向也是由服务器发送给客户端的一种响应报文,在主体中包含了新的URL,客户端使用新的URL去发请求。

看回上面的代码,这个Action返回的是一个200 OK响应和一个HTML文档响应主体。HTML的内容是由模板提供的,Play模板会编译成标准的java方法,使用的就是这个方法

views.html.index.render(String message). 而模板的定义 是定义在app/views/index.scala.html中,下面是预先生成的模板


第一行声明了进入函数时候的参数,这里声明的是String类型的参数,所以在前面的index.render方法中,传的就是一个String。

模板的内容是由HTML和Scala语句混合的,Scala语句是由@符号开始的。

—————————————————————————————————————————————————————————————————————————————

下面开始就是To-Do List的开发啦

Preparing the application

在这个程序中,外面需要几个Action和相对应的URL,所以先从定义路由映射开始
打开conf/routes文件,添加以下的代码

可以看到,请求都是在tasks的目录下进行的,最后一个删除请求是带有一个参数的。有关routing的相关知识,可以看文档:HTTP Routing
如果我们在这个时候就访问9000端口,那么肯定是报错,因为我们并没有定义Appication里面的task等几个方法

所以,接下来我们就要在Application.java中添加这三个新的Action

我们在三个Action中都返回了一个TODO,这是Play定义的一个Result,返回501 Not Implemented.
现在我们在浏览器运行 http://localhost:9000/tasks的话 就可以看到下面这样啦

为了让程序一运行就访问tasks目录,我们在index方法中返回一个重定向

Task Model

在实现上面定义的三个Action之前,我们需要先定义好一个Task是怎么样的,也就是定义我们的Model啦
在app目录下,新建一个Model包,在Model包内新建一个Task类


在定义Model的同时,我们还定义了三个关于Task的静态方法,用于对Task的操作,在后面会进行实现。

Application template

这个程序是一个single web page的程序,所有操作都在一个页面进行,下面是修改index.scala.html模板

我们修改了模板为带两个参数的
一个是要展示的task链表,一个task表单
在模板中import了Helper._ 这个是form creation helper。关于Template和form Helper的相关内容,可以先看文档,后面我会再写博客分析
The Template engine and Form tempate helpers

The tsak form

一个Form对象是内嵌在HTML form 标签内,并包含有相应的一些限制。
下面是为Task 类创建一个form,在Application中添加下面的代码

创建了一个基于Task的Form对象 taskForm 为了使用Form和Task类,我们需要import play.data.*和models.*
现在,我们可以在Task类中添加一些约束,例如,我们规定label是必须的


要添加限制 需要import play.data.validation.Constraints.*
更多有关Form的内容,请看文档:Handing form submission

Rendering the first page

现在,我们已经把所有需要展示的元素都搞定了,可以实现tasks action了

我们在render方法中传入的两个参数,正是定义template时指定的两个参数,此时访问9000端口,可以看到

handing the form submission

接下来就是要实现create task 了,下面是newTask的实现

至于为什么在我们按下create按钮的时候,会调用这个action呢,看回前面的template的定义就知道了
我们使用bindingFromRequest方法新建了一个from,这个form中包含了请求数据,也就是用户输入的task
因为网络的原因,可能会出现错误,所以我们需要进行判断,如果没有错误的话,我们就创建新的task并刷新页面。

Persist the tasks in a database

为了可以在页面上显示出用户已经创建的task,我们需要将用户已创建的task保存在服务器的数据库中
首先,我们要在程序中激活数据库,在conf/application.conf文件中添加下面的代码
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
我们就可以使用 in memory database H2.我们将使用EBean(Play的默认ORM)去访问数据库,
所以我们必须在这个文件中激活ebean,通过添加以下代码激活
ebean.default="models.*"
通过这个,我们创建了一个Ebean server 连接到了默认的数据源,管理models包中所有的entity
接下来,我们需要将我们的Task类转换为相应的EBean entity,将原来Task类的代码中除了三个静态方法外的修改为如下图所示

首先import进两个ebean相关操作的包,然后是让Task继承于play.db.ebean.Model,这样Task才可以访问Play内嵌的Ebean helper。
我们添加了persistence annotation,并创建了一个find helper去初始化查询。
接下来就要实现剩下的三个CRUD(增删查更)操作了。

现在,我们再刷新一个浏览器,就可以看到我们添加的Task了

有关Ebean的更多知识,可以看以下两篇文章,后面我也会写关于Ebean的博客:Using the Ebean ORM and Play Framework 2 Tutorial: Ebean ORM

Delete tasks

上面只实现了创建,删除的操作还没做呢,因为我们的deleteTask action还没实现

这样就可以啦~

暂时先写到这里,博主也是最近刚开始学play 觉得这是一个挺不错的框架,有兴趣的朋友也可以关注下 Play Home