2012 年最新整理的Play framework 框架学习文档
一、什么是Playframework
Play Framework 是一个功能完整的Java Web 开发框架。采用RESTful 架构设计,简便灵
活。Play Framework 使用MVC 模式作为Web 层,集成Hibernate管理持久层,Play Framework
还使用一个基于Groovy 的模板引擎。
Play Framework 让开发者无须重新编译打包发布应用,即可看到修改后的效果,方便
开发人员调试应用。
Play Framework 采用了无状态模型,是一个真正意义上的“无共享”系统,能够在多
个服务器上部署多个Play Framework 的实例,所有实例都不会互相干扰。
Play Framework 采用了Groovy 作为模板引擎,让表示层真正做到了开发高效简洁
Play Framework 拥有精确的错误定位机制,当错误发生的时候,可以精确的定位到错
误代码的位置。
Play Framework 的速度很快,启动快,运行的速度也十分快。
注:RESTful 架构:REST (REpresentation StateTransfer) 描述了一个架构样式的
网络系统,比如web 应用程序。它首次出现在2000 年Roy Fielding 的博士论文
中,他是HTTP 规范的主要编写者之一。
REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计
就是RESTful
Web 应用程序最重要的REST 原则是,客户端和服务器之间的交互在请求之间是
无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服
务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由
任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性
能。
另一个重要的REST 原则是分层系统,这表示组件无法了解它与之交互的中间层以外
的组件。通过将系统知识限制在单个层,可以限制整个系统的复杂性,促进了底层的
独立性。
当REST 架构的约束条件作为一个整体应用时,将生成一个可以扩展到大量客户
端的应用程序。它还降低了客户端和服务器之间的交互延迟。统一界面简化了整个系
统架构,改进了子系统之间交互的可见性。REST 简化了客户端和服务器的实现。
详细介绍:http://baike.baidu.com/view/5798116.htm
Groovy 模块引擎:Groovy 是一种新兴的Java 2 平台语言。Groovy 代码能够与Java 代码
很好地结合,也能用于扩展现有代码。目前的Groovy 版本是1.6.3,在Java1.4 和Java
5 平台上都能使用,也能在Java 6 上使用。
Groovy 是JVM 的一个替代语言— 替代是指可以用Groovy 在Java 平台上进行Java
编程,使用方式基本与使用Java 代码的方式相同。注意:不是指Groovy 替代java,而是
指Groovy 和java 很好的结合编程
● 是一个基于Java 虚拟机的敏捷动态语言。
● 构建在强大的Java 语言之上并添加了从Python,Ruby和Smalltalk 等语言中学
到的诸多特征。
● 为Java 开发者提供了现代最流行的编程语言特性,而且学习成本很低(几乎为零)。
● 支持DSL(Domain Specific Languages 领域定义语言)和其它简洁的语法,让你的
代码变得易于阅读和维护。
● Groovy 拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts
变的非常简单。
● 在开发Web,GUI,数据库或控制台程序时通过减少框架性代码大大提高了开发
者的效率。
● 支持单元测试和模拟(对象),可以简化测试。
● 无缝集成所有已经存在的Java 对象和类库。
● 直接编译成Java 字节码,这样可以在任何使用Java 的地方使用Groovy。
Groovy 的一个好处是,它的语法与Java 语言的语法很相似。虽然Groovy 的语法源
于Smalltalk 和Ruby 这类语言的理念,但是可以将它想像成Java 语言的一种更加简单、
表达能力更强的变体。(在这点上,Ruby 与Groovy 不同,因为它的语法与Java 语法差异
很大。)
许多Java 开发人员非常喜欢Groovy 代码和Java 代码的相似性。从学习的角度看,
如果知道如何编写Java 代码,那就已经了解Groovy 了。Groovy 和Java 语言的主要区
别是:完成同样的任务所需的Groovy 代码比Java 代码更少。(有时候会少很多!)
二、playframework 框架的优点
1) 修改代码及时生效!
编辑java 文件,保存,刷新浏览器,即可看到效果!无须编译,部署,重启服务
器。
2) 全栈式
集成Hibernate,OpenID,Memcached…还有强大的插件系统,提供了创建一个酷炫的
web 应用所需要的一切。
3) 无状态模式
4) Play 是一个真正的“Share nothing”的系统。适合REST,通过在多台服务器运行
同一个应用的多个实例,可以很容易地实现容量扩展。
5) 快速的解决错误
当发生错误时,Play 会向你准确展示源代码中产生问题的那一行代码,即使是发生
在模板中。
6) 高校的模块系统
一个简单的基于Groovy 作为表达式语言的模块系统。它提供了模块的继承,包含
和标签的功能。
7) 有趣&高校
帮助你节省等待java 应用重启的时间,提高生产效率,更快地完成工程。
8) 异步
基于非阻塞IO 模型,允许创建基于长轮询和WebSockets 的现代WebSockets 的现
代Web 应用。
9) 纯粹的Java
使用Java 进行编码,可以使用任何的Java 库,可以使用你喜欢的IDE,可以与
eclipse 或者netbeans 优雅地结合。
三、Play FrameWork 开发入门
1、准备工作
官方网站:www.playframework.org下载最新版本的play-1.2.3.zip 开发包。将下载的
包解压,解压后的路径最好不要包括空格、中文之类的,好像会有问题。
2、新建项目
将下载的play-1.2.3.zip 开发包解压并进行环境变量的配置(也可不需要配置环境变
量,但要在运行时要完整绝对路径)
打开cmd 命令窗口,键入cd play 压缩目录,接着输入play new 新建项目名称,
运行项目输入play run 项目名称。
如果没有报错证明项目可以运行,接着输入play eclipsify 项目名称,才可导入项目
到eclipsify,
打开eclipse,导入刚才新建的项目即可。
3、环境变量配置
Path: C:\Program Files\Java\jdk1.6.0_21\bin;
CLASSPATH: .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
JAVA_HOME: C:\JDK(jdk 安装路径)
4、MVC 模型
Play 应用遵循Web 架构使用的MVC 架构模式。
它将应用分离到不同的层中:表现层(Presentation)和模型层(Model)。表现层进一步分为视
图(View)和控制器(Controller)。
Model 是应用所处理信息的领域表述(Domain-SpecificRepresentation)。
绝大多数应用使用持久化机制如数据库存储数据。但是MVC 并没有特别提到数
据访问层,因为它属于下层,由模型封装。
View 将模型渲染成适合交互的表单,通常是用户界面。一个模型可有多个不同
目的视图。Web 应用中,View 通常以HTML,XML 或JSON 形式呈现,也可
能是二进制的Chart。
Controller 处理事件(通常是用户动作),并对模型做相应改变。Web 应用中,
事件通常是HTTP 请求:Controller 监听HTTP 请求,从其中提取数据,如查
询字符串参数,请求头,然后改变下层模型对象。
Play 将此三层分在app 目录下的不同package 中。
app/controllers
一个Controller 就是一个Java 类,它的静态公共方法则是动作(Action)。动作是接收HTTP
请求后的Java 处理入口点。Controller 类实际是面向过程的,非OO。Action 从HTTP 请求
中提取数据,读或更新Model 对象,然后返回一个包装成HTTP 响应(HTTP Response)的结
果。
app/models
Model 是一组具有所有OO 特性的Java 类。包含数据结构和应用可使用的操作。(译注:即充
血模型)。支持通过JPA 持久化。
app/views
应用的视图由Play 的模板系统生成。Controller 从Model 获取数据,然后使用模板呈现它。
此package 包含HTML,XML 等模板文件,用作动态生成模型的表述(Representation)。
5、应用程序布局
app 目录
包含所有可执行的工件:Java 源代码和视图模板。其下有三个标准package,每个代表MVC
的一层。你也能添加你自己的包,如示例的utils 包。
View pacakge 可以在分子packages:
tags 存储应用的ta。如可重用的模板片段。
一个Controller一个view 目录,按惯例,每个Controller 的相关模板存储
在自己的子目录中。
.class 文件在哪儿?
Play 在运行时编译Java 源代码,并将编译的类缓存在tmp\bytecode 目录下。Play 应用的
可执行工件时.java 源文件,不是已编译的.class(译注:包括jar 文件)。
public 目录
存储静态的、由Web 服务器直接处理的资源。分为三个子目录:images,stylesheets 和
javascripts,分别放图片,css 和js。
conf 目录
包含应用的所有配置文件。两个必须文件为:
application.conf: 应用主配置文件,包含所有标准的配置选项。
routes:url路由规则定义文件。
此目录包含在Java ClassPath 中。
lib 目录
存放应用依赖的标准Java 类库。此目录自动添加到Java classpath 中。
6、创建简单的helloworld 程序
打开CMD,执行:
play new helloworld
Play new 命令在当前路径下创建了一个helloworld 目录,其中包含一系列文件和目录,
重要的如下:
app/ 包含应用核心,分为models,controllers和views 目录。.java 生活的地方^_^
conf/包含应用的所有配置。application.conf 应用主配置.routes 定义url 路由规则,
messages 国际化用。
lib/ 包含应用依赖的标准.jar 文件。
public/包含所有外部可访问的资源:js,css 和image。
test/包含所有应用的测试程序。测试程序基于JUnit 或Selenium。
注:Play 要求所有文件必须是UTF-8 编码。
等等应用的.class 文件在哪儿。恩,Play 不使用class 文件而是直接读取Java 源文件,并
使用Eclipse compiler 编译他们。
这导致两件重要的事情。首先运行时Play 会检查你对源文件所作的变更并自动加载它们。
其次,当发生异常时,Play 将创建更好的错误报告并附加相关
运行应用
在cmd 中键入play run helloworld,play 启动Web Server 并监听9000 端口
打开浏览器键入http://localhost:9000/,应用显示了一个缺省的欢迎页
现在,看下此页是如何显示的。
应用的主入口点配置在conf/routes 文件中。它定义了应用所有可访问的URL。打开routes
文件,会看到第一个route:
GET /Application.index
它告诉Play,当/路径收到GET 请求后调用Application.indexJava方法。它是
controllers.Application.index的缩写,因为controllers 包是隐式的附加的。
创建标准Java 应用时,通常使用一个入口点即main 方法。Play 应用则有多个,一个URL
一个。这些方法称为action 方法。定义action 方法的类称为controller。
打开helloworld/app/controllers/Application.java:
package controllers;
import play.*;
import play.mvc.*;
import java.util.*;
import models.*;
public class Application extends Controller{
public static void index() {
render();
}
}
看到Application 扩展了play.mvcController 类。它提供了所有Controller 需要使用的方
法,如index 动作中使用的render 方法。
index 方法定义成public static void,因为Controller 永远无需实例化和返回值。(译注:
为了防止被使用者引入状态,并让Controller自然、干净而如此设计。但副作用是render
只能通过throw 扔出结果,用异常当GOTO,可谓兵行诡道)。
缺省的index 动作调用render 方法,通知Play 渲染一个模板。模板是app/views 目录下一
个简单的text 文件。此处使用Application/index.html
打开helloworld/app/views/Application/index.html文件:
#{extends 'main.html' /}
#{set title:'Home' /}
#{welcome /}
其中的内容是Play tag,类似JSP taglib.#{welcome/}tag 生成了之前看到的欢迎消息。
#{extends/}tags 告诉Play 此模板集成另一个main.html的模板.模板继承可用来创建复杂
的web 也并重用公共部分。
打开helloworld/app/views/main.html模板
<!DOCTYPEhtml>
<html>
<head>
<title>#{get 'title' /}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public
/stylesheets/main.css'}">
#{get 'moreStyles' /}
<link rel="shortcut icon" type="image/png" href="@{'/public/images/fav
icon.png'}">
<script src="@{'/public/javascripts/jquery-1.4.2.min.js'}"type="text/
javascript" charset="utf-8"></script>
#{get 'moreScripts' /}
</head>
<body>
#{doLayout /}
</body>
</html>
看到#{doLayout/}tag 吗?是Application/index.html 插入的位置。
创建FORM
编辑helloworld/app/views/Application/index.html模板
#{extends 'main.html' /}
#{set title:'Home' /}
<form action="@{Application.sayHello()}" method="GET">
<input type="text" name="myName" />
<input type="submit" value="Say hello!" />
</form>
我们使用@{…}符号请求Play 自动产生调用Application.sayHello动作的方法。刷新浏览
器。
Oops, 出错了。因为引用了一个不存在的动作。需要在
helloworld/app/controllers/Application.java中创建:
package controllers;
import play.mvc.*;
public class Application extends Controller{
public static void index() {
render();
}
public static void sayHello(String myName){
render(myName);
}
}
我们声明了myName 参数,它会自动映射到form 提交的HTTP 请求的myName参数。刷新浏览
器。
输入name 提交,出现另一个错误.
因为Play 渲染此动作的缺省模板时,没有找到它。我们创建文件
helloworld/app/views/Application/sayHello.html
#{extends 'main.html' /}
#{set title:'Home' /}
<h1>Hello ${myName ?: 'guest'}!</h1>
<a href="@{Application.index()}">Back to form</a>
然后刷新:
提供更好的URL
看下提交的url:
http://localhost:9000/application/sayhello?myName=chaos
它不够RESTful。因为Play 通过缺省规则捕获了此URL
* /{controller}/{action} {controller}.{action}
可以编辑helloworld/conf/routes文件在缺省规则前添加一条规则,提供更自然的hello
url
GET /hello Application.sayHello
自定义布局
可以修改模板更改布局。编辑helloworld/app/views/main.html文件:
添加验证
给form 添加一个验证,要求name 字段必填。我们通过Play validation 实现。编辑
helloworld/app/controllers/Application.java,在sayHello action 处:
public static void sayHello(@Required String myName) {
if (validation.hasErrors()){
flash.error("Oops, please enter your name!");
index();
}
render(myName);
}
并importplay.data.validation.*。@Required 告诉Play 自动检查myName 字段是否填写。
如果验证失败,我们加入一条消息到flashscope 中并重定向到index 动作。flashscope
允许在重定向时保持消息。
编辑helloworld/app/views/Application/index.html显示错误消息
#{extends 'main.html' /}
#{set title:'Home' /}
#{if flash.error}
<p style="color:#c00">
${flash.error}
</p>
#{/if}
<form action="@{Application.sayHello()}"method="GET">
<input type="text" name="myName" />
<input type="submit" value="Say hello!" />
</form>
输入空参数并提交,OK 起作用了。
自动化测试
Selenium Test
在测试模式下运行应用。在cmd 中输入play test helloworld。
打开浏览器,输入http://localhost:9000/@tests 启动测试器。
执行测试
Selenium 测试用例通常写成一个html 文件。Play 使用Play 模板引擎生成这些文件。
helloworld/test/Application.test.html文件:
*{ You can use plain selenium command using the selenium tag }*
#{selenium}
// Open the home page, and check that no error occured
open('/')
assertNotTitle('Application error')
#{/selenium}
此测试打开home 页,确认响应中没有“Application error”。
让我们来编写自己的测试。编辑测试内容:
*{ You can use plain selenium command using the selenium tag }*
#{selenium}
// Open the home page, and check that no error occurred
open('/')
assertNotTitle('Application error')
// Check that it is the form
assertTextPresent('The Hello world app.')
// Submit the form
clickAndWait('css=input[type=submit]')
// Check the error
assertTextPresent('Oops, please enter your name!')
// Type the name and submit
type('css=input[type=text]', 'bob')
clickAndWait('css=input[type=submit]')
// Check the result
assertTextPresent('Hello bob!')
assertTextPresent('The Hello world app.')
// Check the back link
clickAndWait('link=Back to form')
// Home page?
assertTextNotPresent('Hello bob!')
#{/selenium}
重新执行
详见:http://www.playframework.org/documentation/1.1.1/firstapp
注:app 里controllers 里的所有.java 文件里的所有方法名必须与View 文件里的所
有.html 文件名一样,不然就要指定html 文件名,如:render("User/userList.html",
pageObject);proObject 是对象名。__