Day 30: Play Framework —— Java开发者的梦想框架

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



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

image.png

什么是 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.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并生成以下文件和目录:

  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 里运行该应用了。

image.png

创建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

publicclassStory extends Model{

   @Id

   privateString id;

   privateString url;

   privateString fullname;

   private Date submittedOn = newDate();

   privateString title;

   privateString text;

   privateString image;

   publicStory() {

   }

   publicStory(String url, String fullname) {

       this.url = url;

       this.fullname = fullname;

   }

   publicStory(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"

刷新浏览器会看到:

image.png

点击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 = newStory(url,fullname);

       }else{

           String image = response.findPath("image").textValue();

           String text = response.findPath("text").textValue();

           String title = response.findPath("title").textValue();

           story = newStory(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格式并返回响应。

相关文章
|
4天前
|
存储 安全 Java
Java 集合框架中的老炮与新秀:HashTable 和 HashMap 谁更胜一筹?
嗨,大家好,我是技术伙伴小米。今天通过讲故事的方式,详细介绍 Java 中 HashMap 和 HashTable 的区别。从版本、线程安全、null 值支持、性能及迭代器行为等方面对比,帮助你轻松应对面试中的经典问题。HashMap 更高效灵活,适合单线程或需手动处理线程安全的场景;HashTable 较古老,线程安全但性能不佳。现代项目推荐使用 ConcurrentHashMap。关注我的公众号“软件求生”,获取更多技术干货!
23 3
|
2月前
|
Java 数据库
在Java中使用Seata框架实现分布式事务的详细步骤
通过以上步骤,利用 Seata 框架可以实现较为简单的分布式事务处理。在实际应用中,还需要根据具体业务需求进行更详细的配置和处理。同时,要注意处理各种异常情况,以确保分布式事务的正确执行。
|
2月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
2月前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
168 3
|
13天前
|
Java 开发者
Java 开发者注意!限时招募产品体验官,100% 获得好礼
🚀【开发者福音】SoFlu-JavaAI 开发助手来袭!💻 摆脱熬夜赶需求的压力,SoFlu-JavaAI 助你轻松应对:理清需求、设计架构、编写逻辑与代码、一键构建工程。立即体验高效开发![了解更多](https://mp.weixin.qq.com/s/h9lwDGbwhYodoNjOxsaxIQ) # 产品体验官限时招募中!
Java 开发者注意!限时招募产品体验官,100% 获得好礼
|
2月前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
43 4
|
2月前
|
开发框架 Java 关系型数据库
Java哪个框架适合开发API接口?
在快速发展的软件开发领域,API接口连接了不同的系统和服务。Java作为成熟的编程语言,其生态系统中出现了许多API开发框架。Magic-API因其独特优势和强大功能,成为Java开发者优选的API开发框架。本文将从核心优势、实际应用价值及未来展望等方面,深入探讨Magic-API为何值得选择。
66 2
|
2月前
|
前端开发 Java 数据库连接
你不可不知道的JAVA EE 框架有哪些?
本文介绍了框架的基本概念及其在编程领域的应用,强调了软件框架作为通用、可复用的软件环境的重要性。文章分析了早期Java EE开发中使用JSP+Servlet技术的弊端,包括可维护性差和代码重用性低等问题,并阐述了使用框架的优势,如提高开发效率、增强代码规范性和可维护性及提升软件性能。最后,文中详细描述了几种主流的Java EE框架,包括Spring、Spring MVC、MyBatis、Hibernate和Struts 2,这些框架通过提供强大的功能和支持,显著提升了Java EE应用的开发效率和稳定性。
107 1
|
2月前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
52 0
|
2月前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
36 0