zoukankan      html  css  js  c++  java
  • [译] 第三十天:Play Framework

    前言

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

     

    什么是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 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!
    View Code

    如上,输入命令后,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命令。

    $ 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...)
    View Code

     现在可以看到程序  http://localhost:9000.

     

    创建Story域类

    这个程序,我们只有一个域类, 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
    }
    View Code

     以上代码定义了一个简单的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"

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

     

    点击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)
    View Code

    以上代码:

    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 文件。

    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;
            } 
        } 
    }
    View Code

    以上代码:

    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/

     

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

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

  • 相关阅读:
    Log4NET初接触
    wwwww
    关于ASP.NET 的进程帐户对 IIS 元数据库读访问权问题
    CentOS8 .NET Core项目部署
    CentOS7.6中安装Apache及Apache常见操作和配置说明
    .net core 命令行下启动指定端口
    Centos7安装mongodb
    centos8+oracle19开机自启动
    计算机网络常用端口
    Centos7安装mongodb
  • 原文地址:https://www.cnblogs.com/endless-on/p/3529081.html
Copyright © 2011-2022 走看看