今天是最后一天,我决定学习一下 Play 框架。原本是想写关于Scala的,学习了几个小时之后发现在一天之内是不可能完成Scala的,所以今天会介绍一下Play框架的基本知识,然后学习如何用它开发应用。

什么是 Play 框架?

Play是一个开源的现代web框架,用于编写Java和Scala的可扩展Web应用程序。它通过自动重载变化来提高生产力,由于设计的就是一个无状态、无阻塞的架构,所以用Play框架来编写横向扩展Web应用程序是很容易的。

为什么要用它?

我的原因是:

  1. 开发人员生产力:我已经写了8年的Java,但在过去的几个月里我把更多的时间花在了Python和JavaScript (Node.js) 上。用动态语言工作时最让我吃惊的,就是用它编写程序的速度是如此之快。Java EE和Spring框架并不是快速原型和开发的理想选择,但在用Play框架时,你更改一处刷新一下页面,更新会立即出现,而且它支持热重载所有的Java代码、模板等,可以让你的迭代快很多。

  2. 天性使然:Play框架是建立在Netty之上的,所以它支持非阻塞I/O,这使得并行远程调用容易了很多,这一点对面向服务的架构中的高性能应用程序是很重要的。

  3. 支持Java和Scala:Play框架是一个真正的多语种Web框架,开发者可以在项目中同时使用Java和Scala。

  4. 一流的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.comThe new application will be created in /Users/shekhargulati/dev/challenges/30days30technologies/day30/blog/getbookmarksWhat is the application name? [getbookmarks]
> Which template do you want to use for this new application? 1             - Create a simple Scala application2             - Create a simple Java application> 2
OK, application getbookmarks is created.Have fun!

如上键入命令后,该框架会问几个问题。首先它要求有应用程序的名称,然后问是否要创建一个Scala或Java应用程序。默认情况下,它会使用文件夹名称作为应用程序的名称。

上面的命令将创建一个新的目录getbookmarks并生成以下文件和目录:

  1. app 目录包含如控制器 (controller) 、视图 (view) 和模型 (model) 的应用程序特定代码。控制器包中有响应URL路由的Java代码,视图目录包含服务器端模板,模型目录包含应用程序的域模型。在此应用中,域 (domain) 是一个Story类。
  2. conf 目录包含应用程序配置和路由定义文件。
  3. project 目录包含构建脚本,构建系统是基于SBT的。
  4. public 包含了如CSS、JavaScript和img目录等的公共资源。
  5. 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{@Idprivate 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)

上述代码表示:

  1. 当用户发出一个GET请求到应用程序的“/”URLindex.html将被渲染。
  2. 当用户发出一个GET请求到'/ api/v1/stories',将得到JSON格式的所有story。
  3. 当用户发出POST请求到'/ api/v1/stories',一个新的story将被创建。
  4. 当用户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;}}}

上述代码会操作:

  1. 它定义allStories()方法,该方法会找到数据库中所有的story。它是使用Model.Finder API来做到这一点的,然后把story列表转换成JSON格式并返回结果,返回HTTP状态代码200(即确定)。

  2. submitStory()方法首先会从JSON读取URL和全名的字段,然后发送GET请求到'http://gooseextractor-t20.rhcloud.com/api/v1/extract?url',这样就会找出标题、摘要以及已经给定url的主要image。创建一个使用所有信息的story并保存在数据库中,返回HTTP状态代码201(即创建)。

  3. getStory()方法为给定的storyId获取story,把这个story转换成JSON格式并返回响应。

可以从我的github仓库下载AngularJS前端,用其中一个库更换公共目录。

现在可以访问http://localhost:9000/看结果了。


30天系列的文章就此结束,非常感谢大家的持续关注,也希望你们能和SegmentFault一块成长。

So, see you next year. Oh~ Happy New Year to Y'all !


原文 Day 30: Play Framework--A Java Developer Dream Framework
翻译整理 SegmentFault

Day 30: Play Framework —— Java开发者的梦想框架相关推荐

  1. 一文了解十大 Java 开发者必备测试框架!

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! 想要提升自己的自动化测试技能吗?本文将介绍10个优秀的 Java 测试框架和库,来提升你的自 ...

  2. java流行的测试框架调研+市面上书籍调研

    主要是根据51job的右侧来判断 java测试框架名称 51job职位数量 百度词条数量 JUnit 732 48,500,000 REST Assured 3 19,500,000 Selenium ...

  3. Java开发者薪资最低?程序员只能干到30岁?国外真的没有996?Intellij真的比Eclipse受欢迎?

    Stack Overflow作为全球最大的程序设计领域的问答网站,每年都会出据一份开发者调查报告.近日,Stack Overflow公布了其第9次年度开发者调查报告(https://insights. ...

  4. 距离 Java 开发者玩转 Serverless,到底还有多远?

    本文摘自 Spring Cloud Alibaba 开源项目创始团队成员方剑撰写的 <深入理解 Spring Cloud 与实战> 一书,主要讲述了 Java 微服务框架 Spring B ...

  5. 2021年,Java开发者值得学习的13项技能

    本文分享自百度开发者中心2021年,Java开发者值得学习的13项技能 作者 | Olivia Cuthbert 译者 | 王强 策划 | 刘燕 如果你想在这个竞争激烈的世界里,成为一名熟练开发 Ja ...

  6. 2021 年,Java 开发者值得学习的 13 项技能

    作者 | Olivia Cuthbert 译者 | 王强 策划 | 刘燕 如果你想在这个竞争激烈的世界里,成为一名熟练开发 Java 项目的开发人员,你应该学习很多东西才行.你需要掌握许多技能,具体应 ...

  7. 第七十期:2019年度Java开发者路线图

    本文将向大家展示了一张Java开发者路线图.该路线图在保持简单可行的基础上,介绍了各种具有业界标准.且方便多数人遵循的工具和程序库. 作者:陈峻 许多Java开发人员都希望通过某种Java成长路线图, ...

  8. Java 8 八年不倒、IntelliJ IDEA 力压 Eclipse,2022 年 Java 开发者都在用什么?

    整理 | 苏宓 出品 | CSDN(ID:CSDNnews) 技术更新迭代的速度,让很多开发者被动地开启了奋起直追的模式.但是在某些领域或技术层面,也永远不要小看技术人的「念旧」情结,譬如 2009 ...

  9. 2021 年 Java 开发者生产力报告

    责编 | 丁恩华 出品 | CSDN(ID:CSDNnews) 新的 2021 年,Perforce 公司依然没有 "爽约".前不久,这家公司发布了其第九份年度全球 Java 开发 ...

最新文章

  1. 百度Apollo首次披露纯视觉L4无人车方案:10摄像头,对标Mobileye
  2. SQL Injection(SQL注入)介绍及SQL Injection攻击检测工具
  3. Windows Communication Foundation(WCF) 一步一步从入门到精通
  4. 四、ajax请求超时与网络异常处理
  5. Arcpy报错及解决——持续补充中
  6. STM32通用定时器输出PWM
  7. mysql+imx6+移植_imx6ulevk---MfgTool的使用心得
  8. Android学习笔记---android平台中利用,SAX解析xml
  9. Go语言---字符串的基本操作
  10. a.使用new关键字产生对象会调用构造方法_七夕面向对象编程,你知道Java有哪些创建对象的方式吗?...
  11. 吴恩达机器学习视频教程(含课程作业源代码和学习笔记)
  12. 微信小程序--音乐播放器
  13. 算法设计与分析基础 课后习题答案(第一章)
  14. 防止 跨站请求伪造(CSRF)
  15. 企业办公3D指纹考勤系统解决方案
  16. 小胡时隔两年的第二篇Blog
  17. SEEDLab DNS_Remote Attack 实验报告
  18. iOS -- 第三方登录之微信登录 (Swift代码)
  19. unity3d 关于如何画扇形
  20. 苹果手机(ipone)点击元素,事件不执行

热门文章

  1. Spring Cloud Alibaba - 24 Gateway-路由、断言(Predicate)、过滤器(Filter)初体验
  2. java aop 切面判断对象是否是一个类的实例
  3. 传递list对象作为参数_24.scala的隐式参数
  4. mysql 分区表优化_Sql优化之Mysql表分区
  5. 常见JavaScript基础面试题上(附答案)
  6. leetcode 刷题 118. 杨辉三角解题思路
  7. android 地图相册,时光地图相册
  8. php 接收curl json数据格式,curl发送 JSON格式POST数据的接收,以及在yii2框架中的实现原理【精细剖析】...
  9. 自主云服务器处理器_云服务器哪家的CPU最便宜且好用
  10. C~K的班级_JAVA