1. Play Framework 的请求处理流程
Play framework 是一个无状态的面向请求/回应的框架,所有的 HTTP 请求都遵循下面的处理流程:
- 框架接收到一个 HTTP Request
- Router 组件试图从 conf/routes 文件中找出对应的 Action 方法
- 执行应用代码
- 如果需要一个视图,则调用模板文件并执行该模板
- 写回最终处理结果
2. Play Framework 框架初学者入门
Play!是一个full-stack(全栈的)Java Web应用框架,包括一个简单的无状态MVC模型,具有Hibernate的对象持续,一个基于Groovy的模板引擎,以及建立一个现代Web应用所需 的所有东西。
Play!的关键特性:
1、一个非常简单的开发周期。此框架自动编译和重新装载源文件的任何改变。
2、智能捆绑HTTP参数到Java方法参数。
3、基于Apache Mina的快速HTTP服务器。
4、一个基于Groovy的强大的模板引擎,具有多层继承,定制用户标签的能力,等。
5、优秀的错误报告功能:当发生异常,此框架会直接显示出错代码,甚至是模板代码。
6、集成很多常用的组件包括 Hibernate、OpenID、Memcached 等一些热门框架
在本文中,我们将利用一个简单的 Hello world 应用来了解 Play 框架的基本开发。
安装 Play Framework
安装前确认 Java 的版本必须是 5.0 或者更新的版本,下载 Play 框架:http://download.playframework.org/releases/. 目前最新版是 1.0.3 ,下载完解压并设置以下环境变量:
在 Ubuntu 10.04, 我们可以通过以下命令进行设置
PLAY_HOME=/usr/share/apps/play/ PATH=$PATH:$PLAY_HOME chmod +x PLAY_HOME/play
这些配置值根据你解压的具体路径而定。
设置完毕后,正常的情况下,输入 play 命令可得到下面的输出:
oschina@Linux-Desktop:~$ play ~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! 1.0.3, http://www.playframework.org ~ ~ Usage: play cmd [app_path] [--options] ~ ~ with, new Create a new application ~ run Run the application in the current shell ~ help Show play help ~ oschina@Linux-Desktop:~$
接下来创建一个新的应用程序
Play 的做法很像 Rails,要创建一个新应用请使用下面命令:
play new app_name
这个命令必须在 play 的目录下执行,例如创建一个名为 hello 的应用如下:
oschina@Linux-Desktop:~/dev/play$ play new hello ~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! 1.0.3, http://www.playframework.org ~ ~ The new application will be created in /home/wichtounet/dev/play/hello ~ What is the application name? Hello World ~ ~ OK, the application is created. ~ Start it with : play run hello ~ Have fun! ~ oschina@Linux-Desktop:~/dev/play$
在创建过程中,Play 会询问应用名称,这里我们输入了Hello world 作为项目名,进入刚创建的 hello 目录,你可以看到如下的几个子目录:
- app : 存放应用本身,包括 java 文件和 html 文件
- conf : 存放配置文件
- lib : 包含一些java的jar包
- public : 存放一些静态文件,例如图片、js和css文件
- test : 存放测试文件 (JUnit or Selenium)
接下来我们就可以运行这个应用了,输入 play run hello ,运行结果如下所示:
oschina@Linux-Desktop:~/dev/play$ play run hello ~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! 1.0.3, http://www.playframework.org ~ ~ Ctrl+C to stop ~ Listening for transport dt_socket at address: 8000 17:49:56,395 INFO ~ Starting /home/wichtounet/dev/play/hello 17:49:56,889 WARN ~ You're running Play! in DEV mode 17:49:56,958 INFO ~ Listening for HTTP on port 9000 (Waiting a first request to start) ... 17:50:01,670 INFO ~ Application 'Hello World' is now started !
应用启动成功了,打开浏览器访问地址:http://localhost:9000/.
Play Framework 示例页面
来看看 Play 框架是怎么工作的 ?
打开 conf 目录下的 routes 文件,你可以看到这么一行:
GET / Application.index
该配置表示当请求 / 时,会调用 Application 类的 index 方法,接下来我们打开 app/controllers/Application.java ,就可以看到源码如下:
1 | package controllers; |
2 | import play.mvc.*; |
3 | |
4 | public class Application extends Controller { |
5 | public static void index() { |
6 | render(); |
7 | } |
8 | } |
这个代码中 index 方法输出了默认的模板,模板文件位于 app/views/Application/index.html ,与类名和方法名完全对应。模板文件如下所示:
1 | #{extends 'main.html' /} |
2 | #{set title:'Home' /} |
3 | |
4 | #{welcome /} |
该模板扩展了 main.html 模板,并设置了页面标题为 Home,然后输出欢迎信息。这些都是 Play 框架为我们提供的一些标签,我们可以稍加修改如下:
1 | #{extends 'main.html' /} |
2 | #{set title:'Hello World' /} |
3 | |
4 | < h3 >Hello the world !</ h3 > |
刷新页面就可以看到浏览器上输出了 Hello the world ! 的信息。接下来我们再在控制器 Application 的 index 方法中增加一些我们自己的代码,如下所示:
1 | public static void index() { |
2 | System.out.println( "render()" ); |
3 | render(); |
4 | } |
再次刷新页面的时候,我们可以在控制台中看到如下输出信息:
17:50:01,670 INFO ~ Application 'Hello World' is now started ! render() render() render() render() render()
增加一个新的页面
假设我们要新增一个页面 /bye ,我们首先要在 conf/routes 文件中增加如下一行:
GET /bye Application.bye
然后在 Application.java 中增加一个新的方法 bye,如下所示:
01 | package controllers; |
02 | |
03 | import play.mvc.*; |
04 | |
05 | public class Application extends Controller { |
06 | public static void index() { |
07 | render(); |
08 | } |
09 | |
10 | public static void bye() { |
11 | render(); |
12 | } |
13 | } |
最后就是新增模板文件 bye.html ,存放于 app/views/Application 目录下,模板内容如下:
1 | #{extends 'main.html' /} |
2 | #{set title:'Bye' /} |
3 | |
4 | < h3 >Bye bye !</ h3 > |
用浏览器访问 http://localhost:9000/bye 可看到如下输出:
Bye 页面的输出
3. Play 框架中五个很酷的做法
通过5个实例来体现Play框架背后的哲学
1.绑定HTTP参数到java方法参数
在Play框架中,获取http参数是非常容易的事情。只需要将方法参数名与HTTP参数名一致就行了。
比如下面的HTTP请求:
/articles/archive?date=08/01/08&page=2
只需要在java方法中定义两个名为date和page的参数就可以了
public static void archive(Date date, Integer page) {
List articles = Articles.fromArchive(date, page);
render(articles); }
Play会自动将HTTP参数转换为方法参数的类型
同样,还可以绑定到java对象类型,比如这样一个对象:
public class Person { public String name; public Integer age; }
一个保存人员的方法只需要这样写:
public static void add(Person p) {
p.save();
}
相应的HTML表单代码:
<form action="/Directory/add" method="POST">
Name: <input name="p.name" type="text" />
Age: <input name="p.age" type="text" />
</form>
2.通过调用相应的java方法实现操作跳转
在Play里面没有JavaServlet的forward方法,但跳转到其他的方法仍然是十分简单。只需要调用相应的java方法,Play会自动生成HTTP跳转的响应。
public static void show(Long id) {
Article article = Article.findById(id);
render(article);
}
public static void edit(Long id, String title) {
Article article = Article.findById(id);
article.title = title;
article.save();
show(id);
}
在edit方法的最后,调用了show方法,这会产生一个HTTP 302跳转,可有效的避免表单重复提交。
在任何模板文件中,可以使用相同的语法来生成这个链接:
<a href="@{Article.show(article.id)}">${article.title}</a>
生成的HTML代码如下:
<a href="/articles/15">My new article</a>
3.传递java对象到模板中
在大多数的Java框架中,需要类似下面方法来传递Java对象到模板中:
Article article = Article.findById(id);
User user = User.getConnected();
Map<String, Object> model = new HashMap<String,Object>();
model.put("article", article);
model.put("user", user);
render(model);
使用Play框架,你只需要这样写:
Article article = Article.findById(id);
User user = User.getConnected();
render(article, user);
模板中可以直接使用变量名称来获取对象值,减少大量无用的代码
4.增强的JPA支持
JPA可以说是Java里面最好的的对象-关系映射(ORM)API,Play更是将JPA的支持简化到了极致。不需要任何的配置,Play就会自动启动基于Hibernate的JPA实体管理器,而且在代码重载的时候自动神奇的同步。
如果你使用框架提供的play.db.jpa.Model基类,将会使代码更加简洁:
public void messages(int page) {
User connectedUser = User.find("byEmail", connected()).first();List<Message> messages = Message.find( "user = ? and read = false order by date desc", connectedUser ).from(page * 10).fetch(10);
render(connectedUser, messages);
}
4.文件上传
直接上代码吧!
表单:
#{form @uploadPhoto(), enctype:'multipart/form-data'}
<input type="text" name="title" />
<input type="file" id="photo" name="photo" />
<input type="submit" value="Send it..." /> #
{/}
Java代码
public static void uploadPhoto(String title, File photo) { ... }
还有比这更简单的吗?
4. 在 Eclipse 中开发基于 Play Framework...
在开始本文之前,请确保已经对 Play Framework 已经有所了解,请看 Play Framework 的入门教程。
Play 框架支持 Eclipse、NetBeans 和 IntelliJ IDEA 三个主流的 Java 开发环境,本文主要介绍 Eclipse 环境下如何开发 Play 框架的应用。
首先为 Eclipse 生成项目配置文件:
play eclipsify myApp
使用这个命令来创建 Play 项目的 Eclipse 环境所需的 .project 和 .classpath 文件,接着就可以通过 Eclipse 导入已有项目的功能,来导入 Play 框架中创建的应用项目所在的目录,导入后如下图所示:
如果你对应用做了很重要的改动,如修改了类路径,那你需要用 eclipsify 命令参数来重新创建配置文件。
另外 Play 框架也提供了一个 Eclipse 的插件,位于 support/eclipse 目录,只需要将该目录下的 jar 文件拷贝到 Eclipse 的 plugins 目录即可。
5. 使用 Play 框架开发的一些网站
Plan Cruncher creates a standard one-page summary of a business plan for a start-up company that is looking for external investment. You do this by choosing icons that represent some of the standard answers that a business plan must provide. Plancruncher was develop and put in production in less than a week thanks to the Play! framework.
6. Play Framework 的两种不同的部署模式
首先要意识到一点,Play Framework 开发过程中是无需编译的。
其次,Play Framework 有两种不同的工作模式:开发模式(dev)和产品模式(prod)。
具体的工作模式可在应用目录下的 conf/application.conf
application.mode=dev
两种模式的差别在于,dev模式不会预先编译java文件,只是有请求到才会编译,而且更改源文件后可立即生效;而 prod 模式下,一旦应用启动后就会自动编译所有 java 文件,而且不会重载修改的 java 文件,必须重启才能生效,包括模板文件和配置都是一样的, prod 是一种全优化的模式,所有的程序都会被缓存。
在错误发生时,dev 模式将会显示如下错误页面:
另外关于调试问题,dev模式会开启 8000 端口,用来连接 java 调试器。