[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫

时间:2022-12-29 22:44:28

前言

30天挑战的最后一天,我决定学习 Play Framework .我本来想写Sacla,但是研究几个小时后,我发现没法在一天内公正评价Scala,下个月花些时间来了解并分享经验。本文我们先来看看Play框架基础,再开发个程序。

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫

什么是Play框架?

Play 是一个开源的现代web框架,用Java和Scala写可扩展的web程序。它能自动加载更新使得极大提高生产率。Play设计了无状态,非阻塞的架构,这使得用Play框架开发水平扩展web程序很容易。

我为什么关注Play?

我学习Play的原因:

  1. 高效: 我用Java已经8年了,但是几个月前我更多关注到Python和JavaScript(Node.js).最令我吃惊的是,使用动态语言开发程序是那么快。Java      EE和Spring框架都不是快速原型开发的理想选择,但是用Play框架,有更新时,刷新页面,瞧!直接可以看到更新了。它支持所有Java代码,模板等的热加载,让你快速继续。
  1. 自然反应:Play框架基于 Netty 构建,所以它支持非阻塞I/O, 能简单经济的水平远程调用,这对于以服务为导向的架构高效工作很重要。
  1. 同时支持Java和Scala: Play框架是真正的通晓多语言的web框架,开发者在他们的项目中可以同时使用Java和Scala.
  1. 首个支持REST JSON类:Play让写RESTful程序变得很简单,很好的支持HTTP路由,HTTP路由将HTTP请求转换成具体动作,JSON      marshalling/unmarshalling API在核心API中,所以不需要添加库来完成。

程序用例

本文,我们来开发一个网摘程序,允许用户发布和分享链接,你可以在OpenShift上看 在线 程序。这和我们之前第22天开发的程序一样,你可以参考之前的用例来更好了解。

安装Play

请参考 文档 了解怎样安装Play框架。

开发Play程序

介绍完基础,我们来开始写程序。

在你机器上运行以下命令。

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫
$ 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!

如上,输入命令后,Play框架会问几个问题。首先是程序的名字,然后是我们是否想创建一个Scala程序或者Java程序。默认使用文件夹名作为程序名,我们选择第二个选项来创建Java程序。

以上命令新建了一个目录getbookmarks,生成一下文件和目录。

  1. app目录包含了程序特定代码如控制器,视图和模块。控制器包包含Java代码,用于响应url路由。views目录包含了服务端的模板,models目录包含程序域模块,在这个程序里,域是一个Story类。
  1. conf目录包含程序配置和路由定义文件。
  2. project目录包含构建脚本,这个构建系统基于 sbt .
  3. public包含公共资源,如css,      JavaScript和图像目录。
  4. test包含程序测试。

现在我们可以运行Play创建的默认程序,打开play控制台,运行play命令,然后用run命令。

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫
$ 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 .

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫

创建Story域类

这个程序,我们只有一个域类, Story. 新建一个包模块然后新建Java类。

[译] 第三十天:Play Framework - 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用它自己的ORM层Ebean, 每个实体类都扩展基础模块类。

Ebean默认是没激活的,要激活它,打开程序conf,  取消下面这行的注释。

ebean.default="models.*"

激活数据库

现在来激活程序的数据库,Play框架提供了内置支持的H2数据库,要激活它,打开程序conf文件,取消以下两行的注释。

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"

现在刷新浏览器可以看到如下异常。

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫

点击Apply this script now使SQL更新生效。

定义程序路由

本文,我们开发了和第22天相同的程序,这个程序有AngularJS后端和REST后端,我们用Play框架写REST后端,重新用AngularJS后端,在conf/routes文件里,复制粘贴一下代码。

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫
# 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请求到'/' url, index.html会被加载。
  2. 当用户发出GET请求到'/api/v1/stories', 会得到所有JSON格式的文章。
  3. 当用户发出POST请求到'/api/v1/stories', 一个新的文章会被创建。
  4. 当用户发出GET请求到'/api/v1/stories/123', id是123的文章会被加载。

创建StoryController

现在在控制器包里新建Java类,复制粘贴以下代码到StoryController.java 文件。

[译] 第三十天:Play Framework - 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()方法,用于在数据库中查找文章,它用Model.Finder      API完成,然后我们转换这个列表成JSON格式,返回结果。返回HTTP状态代码200代表OK.
  1. submitStory()方法先从JSON读取url和全名,然后发出GET请求到'http://gooseextractor-t20.rhcloud.com/api/v1/extract?url',      从给定url查找标题,摘要和主要图像。用这些所有信息新建文章保存到数据库,返回HTTP状态代码201代表已创建。
  1. getStory()方法从给定的文章id获取文章,我们转换文章称JSON格式然后在响应里返回。

AngularJS前端

我决定重新用第22天写的AngularJS前端,第22天展示了我们怎样用AngularJS和Java Spring框架,最好的部分是用JavaScript MV*框架,如果你的程序还是用REST接口客户端需求,你可以再用前端代码。详情参考第22天文章。

现在刷新浏览器访问程序 http://localhost:9000/

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫

这就是今天的内容,希望你喜欢这个系列。

原文: https://www.openshift.com/blogs/day-30-play-framework-a-java-developer-dream-framework

[译] 第三十天:Play Framework - Java开发者梦寐以求的框架 - 百花宫的更多相关文章

  1. Java进阶&lpar;三十六&rpar;深入理解Java的接口和抽象类

    Java进阶(三十六)深入理解Java的接口和抽象类 前言 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太 ...

  2. 第三百三十三节,web爬虫讲解2—Scrapy框架爬虫—Scrapy模拟浏览器登录—获取Scrapy框架Cookies

    第三百三十三节,web爬虫讲解2—Scrapy框架爬虫—Scrapy模拟浏览器登录 模拟浏览器登录 start_requests()方法,可以返回一个请求给爬虫的起始网站,这个返回的请求相当于star ...

  3. 聊聊高并发(三十八)解析java&period;util&period;concurrent各个组件(十四) 理解Executor接口的设计

    JUC包中除了一系列的同步类之外,就是Executor运行框架相关的类.对于一个运行框架来说,能够分为两部分 1. 任务的提交 2. 任务的运行. 这是一个生产者消费者模式,提交任务的操作是生产者,运 ...

  4. 聊聊高并发(三十九)解析java&period;util&period;concurrent各个组件(十五) 理解ExecutorService接口的设计

    上一篇讲了Executor接口的设计,目的是将任务的运行和任务的提交解耦.能够隐藏任务的运行策略.这篇说说ExecutorService接口.它扩展了Executor接口,对Executor的生命周期 ...

  5. 第三十篇:SOUI模块结构图及SOUI框架图

    模块结构图: SOUI框架图:

  6. 三十二、Java图形化界面设计——布局管理器之CardLayout(卡片布局)

    摘自 http://blog.csdn.net/liujun13579/article/details/7773945 三十二.Java图形化界面设计--布局管理器之CardLayout(卡片布局) ...

  7. JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

    JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了 ...

  8. JAVA之旅(三十四)——自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫

    JAVA之旅(三十四)--自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫 我们接着来说网络编程,TCP 一.自定义服务端 我们直接写一个服务端,让本机去连接 ...

  9. JAVA之旅(三十二)——JAVA网络请求,IP地址&comma;TCP&sol;UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用

    JAVA之旅(三十二)--JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用 GUI写到一半电脑系统挂了,也就算了,最多GUI还有一个提示框和实例, ...

随机推荐

  1. Java提高篇——静态代码块、构造代码块、构造函数以及Java类初始化顺序

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次构造代码块:类中直接用{}定义,每一次创建对象时执行.执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public H ...

  2. 用Python操纵MySQL

    本例用Python操纵MySQL,从指定文件读取数据,并对数据进行处理,处理之后批量插入MySQL. 贴上代码: # -*- coding: gbk -*- import re import MySQ ...

  3. perl 正则详解

    用/s 来匹配任意字符 默认情况下,点号(.)无法匹配换行符,这对大多数单行匹配的情况是合适的. . 圆点用于匹配除换行符外的任何单个字符 + 意味着一个或多个相同的字符 .+ 匹配任意单个字符至少一 ...

  4. (36)JS运动之使物体向右运动

    基本思路:样式要是绝对定位,不然的话根本走不起来.当开启一个定时器的时候.必须先清除定时器.这是为了防止鼠标连续点击button而开启多个定时器,导致物体的速度加快等原因,其次要控制好物体的运动和停止 ...

  5. Entity Framewor中的 Migration

    http://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx = Code bas ...

  6. lxml&period;etree&period;HTML&lpar;text&rpar; 解析HTML文档

    0.参考 http://lxml.de/tutorial.html#the-xml-function There is also a corresponding function HTML() for ...

  7. Edge Deletion CodeForces - 1076D(水最短路)

    题意: 设从1到每个点的最短距离为d,求删除几条边后仍然使1到每个点的距离为d,使得剩下的边最多为k 解析: 先求来一遍spfa,然后bfs遍历每条路,如果d[v] == d[u] + Node[i] ...

  8. Dos命令讲解

    目录 一.什么是DOS 二.启动DOS的多种方法 三.DOS的内部命令与外部命令 四.系统环境变量讲解 增加Path环境变量路径 常见的系统环境变量 五.常用的运行命令 六.DOS使用技巧 设置CMD ...

  9. &lt&semi;spark入门&gt&semi;&lt&semi;Intellj环境配置&gt&semi;&lt&semi;scala&gt&semi;rk入门&gt&semi;&lt&semi;Intellj环境配置&gt&semi;&lt&semi;scala&gt&semi;

    # 写在前面: 准备开始学spark,于是准备在IDE配一个spark的开发环境. 嫌这篇格式不好的看这里链接 用markdown写的,懒得调格式了,么么哒 # 相关配置: ## 关于系统 * mac ...

  10. web 架构 &sol;http协议,状态码,django中常用命令

    什么是web应用? web应用 架构 :B/S架构 | C/S架构 网站:BS架构其实就是应用程序: B是浏览器 S是sever(实现了wsgi协议,实现了socket的服务端) + applicat ...