- Day 1: Bower - 管理你的客户端依赖关系
- Day 2: AngularJS - 对 AngularJS 的初步认识
- Day 3: Flask - 使用 Python 和 OpenShift 进行即时 Web 开发
- Day 4:PredictionIO - 如何创建一个博客推荐器
- Day 5: GruntJS - 重复乏味的工作总会有人做(反正我不做)
- Day 6:在 Java 虚拟机上使用 Grails 进行快速 Web 开发
- Day 7: GruntJS 在线重载 提升生产率至新境界
- Day 8: Harp.JS - 现代静态 web 服务器
- Day 9: TextBlob - 对文本进行情感分析
- Day 10: PhoneGap - 开发手机应用如此简单
- Day 11: AeroGear 推送服务器:使应用的通知推送变得简单
- Day 12: OpenCV - Java 开发者的人脸检测
- Day 13: Dropwizard - 非常棒的 Java REST 服务器栈
- Day14:使用斯坦福 NER 软件包实现你自己的命名实体识别器(Named Entity Recognition,NER)
- Day 15:Meteor - 从零开始创建一个 Web 应用
- Day 16: Goose Extractor - 好用的文章提取工具
- Day 17: 使用 JBoss Forge 和 OpenShift 构建部署 JAVA EE 6 应用
- Day 18: BoilerPipe - Java 开发者的文章提取工具
- Day 19: EmberJS 入门指南
- Day 20: 斯坦福 CoreNLP - 用 Java 给 Twitter 进行情感分析
- Day 21:Docker 入门教程
- Day 22: 使用 Spring、MongoDB 和 AngularJS 开发单页面应用
- Day 23:使用 TimelineJS 构建精美的时间轴
- Day 24: 使用 Yeoman 自动构建 Ember 项目
- Day 25: 联合 Tornado、MongoDB 和 AngularJS 进行应用开发
- Day 26: TogetherJS - 让我们一起来编程!
- Day 27: Restify - 在 Node.js 中构建正确的 REST Web 服务
- Day 28: OpenShift 的 Eclipse 集成
- Day 29:编写你的第一个 Google Chrome 扩展程序
- Day 30: Play Framework - Java 开发者的梦想框架
Day 30: Play Framework - Java 开发者的梦想框架
今天是最后一天,我决定学习一下 Play 框架 。原本是想写关于 Scala 的,学习了几个小时之后发现在一天之内是不可能完成 Scala 的,所以今天会介绍一下 Play 框架的基本知识,然后学习如何用它开发应用。
什么是 Play 框架?
Play 是一个开源的现代 web 框架,用于编写 Java 和 Scala 的可扩展 Web 应用程序。它通过自动重载变化来提高生产力,由于设计的就是一个无状态、无阻塞的架构,所以用 Play 框架来编写横向扩展 Web 应用程序是很容易的。
为什么要用它?
我的原因是:
- 开发人员生产力:我已经写了 8 年的 Java,但在过去的几个月里我把更多的时间花在了 Python 和 JavaScript (Node.js) 上。用动态语言工作时最让我吃惊的,就是用它编写程序的速度是如此之快。Java EE 和 Spring 框架并不是快速原型和开发的理想选择,但在用 Play 框架时,你更改一处刷新一下页面,更新会立即出现,而且它支持热重载所有的 Java 代码、模板等,可以让你的迭代快很多。
- 天性使然:Play 框架是建立在 Netty 之上的,所以它支持非阻塞 I/O,这使得并行远程调用容易了很多,这一点对面向服务的架构中的高性能应用程序是很重要的。
- 支持 Java 和 Scala:Play 框架是一个真正的多语种 Web 框架,开发者可以在项目中同时使用 Java 和 Scala。
- 一流的 REST JSON 支持:它很容易编写基于 REST 的应用。对 HTTP 路由有很好的支持,HTTP 路由会将 HTTP 请求转化为具体动作;JSON 编组/解组 API 是目前的核心 API,所以没有必要加一个库来做到这一点。
应用类型案例
今天的介绍中,将开发一个社交书签应用程序,它允许用户发布和共享链接。你可以在 这里 查看正在运行的该程序,因为这个和 第 22 天 的应用是一样的,所以请参阅之以便更好地了解这个案例。
开发 Play 应用
请 参阅文档 以了解如何安装 Play 框架,开始应用程序的开发吧。
$ play new getbookmarks
_
_ __ | | __ _ _ _
| '_ \| |/ _' | || |
| __/|_|\____|\__ /
|_| |__/
play 2.2.1 built with Scala 2.10.2 (running Java 1.7.0_25), http://www.playframework.com
The new application will be created in /Users/shekhargulati/dev/challenges/30days30technologies/day30/blog/getbookmarks
What is the application name? [getbookmarks]
>
Which template do you want to use for this new application?
1 - Create a simple Scala application
2 - Create a simple Java application
> 2
OK, application getbookmarks is created.
Have fun!
如上键入命令后,该框架会问几个问题。首先它要求有应用程序的名称,然后问是否要创建一个 Scala 或 Java 应用程序。默认情况下,它会使用 文件夹名称
作为应用程序的名称。
上面的命令将创建一个新的目录 getbookmarks
并生成以下文件和目录:
- app 目录包含如控制器 (controller) 、视图 (view) 和模型 (model) 的应用程序特定代码。控制器包中有响应 URL 路由的 Java 代码,视图目录包含服务器端模板,模型目录包含应用程序的域模型。在此应用中,域 (domain) 是一个 Story 类。
- conf 目录包含应用程序配置和路由定义文件。
- project 目录包含构建脚本,构建系统是基于 SBT 的。
- public 包含了如 CSS、JavaScript 和 img 目录等的公共资源。
- test 目录包含应用测试。
通过如下命令发布 play 控制台,运行 Play 编写的默认程序。
$ cd getbookmarks
$ play
[info] Loading project definition from /Users/shekhargulati/dev/challenges/30days30technologies/day30/blog/getbookmarks/project
[info] Set current project to getbookmarks (in build file:/Users/shekhargulati/dev/challenges/30days30technologies/day30/blog/getbookmarks/)
_
_ __ | | __ _ _ _
| '_ \| |/ _' | || |
| __/|_|\____|\__ /
|_| |__/
play 2.2.1 built with Scala 2.10.2 (running Java 1.7.0_25), http://www.playframework.com
> Type "help play" or "license" for more information.
> Type "exit" or use Ctrl+D to leave this console.
[getbookmarks] $ run
[info] Updating {file:/Users/shekhargulati/dev/challenges/30days30technologies/day30/blog/getbookmarks/}getbookmarks...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
--- (Running the application from SBT, auto-reloading is enabled) ---
[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
(Server started, use Ctrl+D to stop and go back to the console...)
现在可以在 http://localhost:9000
里运行该应用了。
创建 Story 域类
该应用程序只有一个域类 (domain class),叫做 story,创建一个新的包模型和 Java 类。
package models;
import play.db.ebean.Model;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
@Entity
public class Story extends Model{
@Id
private String id;
private String url;
private String fullname;
private Date submittedOn = new Date();
private String title;
private String text;
private String image;
public Story() {
}
public Story(String url, String fullname) {
this.url = url;
this.fullname = fullname;
}
public Story(String url, String fullname, String image, String text, String title) {
this.url = url;
this.fullname = fullname;
this.title = title;
this.text = text;
this.image = image;
}
// Getter and Setter removed for brevity
}
上述代码定义了一个简单的 JPA 实体,并使用 @Entity
和 @Id
JPA 注解,Play 用它自己的一个被称作 Ebean 的 ORM 层,而且每一个实体类必须扩展基本模型类。
Ebean 默认禁用,启用它需要打开 application.conf
并取消注释以下行。
ebean.default="models.*"
启用数据库
启动应用程序的数据库,Play 框架提供了内置的 H2 数据库的支持。要启用它,打开 application.conf
文件,并取消如下两行的注释。
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
刷新浏览器会看到:
点击 Apply this script now
将 SQL 的更改部署上去。
定义应用程序的路由
今天讲的应用程序和第 22 天是一样的,都有 AngularJS 后台和 REST 后端,所以可以使用 Play 框架重写 REST 后台和 AngularJS 后端,在 conf/routes
文件,复制并粘贴如下代码。
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / controllers.Assets.at(path="/public", file="/index.html")
GET /api/v1/stories controllers.StoryController.allStories()
POST /api/v1/stories controllers.StoryController.submitStory()
GET /api/v1/stories/:storyId controllers.StoryController.getStory(storyId)
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
上述代码表示:
- 当用户发出一个 GET 请求到应用程序的
“/”URL
,index.html
将被渲染。 - 当用户发出一个 GET 请求到
'/ api/v1/stories'
,将得到 JSON 格式的所有 story。 - 当用户发出 POST 请求到
'/ api/v1/stories'
,一个新的 story 将被创建。 - 当用户 GET 请求
'/ api/v1/stories/123'
,id 为 123 的 story 会被渲染。
创建 Story 控制器
在控制器包里创建一个 Java 类,将如下代码粘贴进 StoryController.java
文件里。
package controllers;
import com.fasterxml.jackson.databind.JsonNode;
import models.Story;
import play.api.libs.ws.Response;
import play.api.libs.ws.WS;
import play.db.ebean.Model;
import play.libs.Json;
import play.mvc.BodyParser;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Results;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class StoryController {
public static Result allStories(){
List<Story> stories = new Model.Finder<String , Story>(String.class, Story.class).all();
return Results.ok(Json.toJson(stories));
}
@BodyParser.Of(BodyParser.Json.class)
public static Result submitStory(){
JsonNode jsonNode = Controller.request().body().asJson();
String url = jsonNode.findPath("url").asText();
String fullname = jsonNode.findPath("fullname").asText();
JsonNode response = fetchInformation(url);
Story story = null;
if(response == null){
story = new Story(url,fullname);
}else{
String image = response.findPath("image").textValue();
String text = response.findPath("text").textValue();
String title = response.findPath("title").textValue();
story = new Story(url,fullname, image , text , title);
}
story.save();
return Results.created();
}
public static Result getStory(String storyId){
Story story = new Model.Finder<String, Story>(String.class, Story.class).byId(storyId);
if(story == null){
return Results.notFound("No story found with storyId " + storyId);
}
return Results.ok(Json.toJson(story));
}
private static JsonNode fetchInformation(String url){
String restServiceUrl = "http://gooseextractor-t20.rhcloud.com/api/v1/extract?url="+url;
Future<Response> future = WS.url(restServiceUrl).get();
try {
Response result = Await.result(future, Duration.apply(30, TimeUnit.SECONDS));
JsonNode jsonNode = Json.parse(result.json().toString());
return jsonNode;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
上述代码会操作:
- 它定义
allStories()
方法,该方法会找到数据库中所有的 story。它是使用 Model.Finder API 来做到这一点的,然后把 story 列表转换成 JSON 格式并返回结果,返回 HTTP 状态代码 200(即确定)。 submitStory()
方法首先会从 JSON 读取 URL 和全名的字段,然后发送 GET 请求到'http://gooseextractor-t20.rhcloud.com/api/v1/extract?url'
,这样就会找出标题、摘要以及已经给定 url 的主要 image。创建一个使用所有信息的 story 并保存在数据库中,返回 HTTP 状态代码 201(即创建)。getStory()
方法为给定的 storyId 获取 story,把这个 story 转换成 JSON 格式并返回响应。
可以从我的 github 仓库 下载 AngularJS 前端,用其中一个库更换公共目录。
现在可以访问 http://localhost:9000/
看结果了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论