Play 2(Scala版)中JavaScript路由

上一篇文章中 ,我介绍了在Play 2 Java应用程序中使用JavaScript路由。 这是Scala版本。 为了独立起见,它几乎是前一篇文章的副本。

Play 2中最好的功能之一是框架中可以生成JavaScript路由,以使基于AJAX的客户端代码更易于维护,但似乎并未广泛涉及。 在这里,我将介绍在基于Scala的Play 2应用程序中使用此功能。

总览

在JavaScript中看到发出AJAX请求的调用是很常见的。 通常,使用jQuery之类的库来提供支持。 例如,给定一条路线

GET    /foo    controllers.Application.getAll()

可以使用简写$ .get方法发出GET请求。

$.get("/foo", function( data ) {
  // do something with the response
});

在需要参数的情况下,变体需要更多的工作。

GET    /foo    controllers.Application.get(personId: Long, taskId: Long)

var personId = $('#person').val();
var taskId = $('#item').val();
$.get("/foo?person=" + personId + '&task=' + taskId, 
      function( data ) {
        // do something with the response
      });

所有这些似乎都与Play应用程序的简单风格相去甚远,后者的交互是惯用的且类型安全的。 幸运的是,Play提供了一项称为JavaScript路由的功能。 这使我们可以使用后端生成的JS对象,因此我们可以将上面的代码替换为

var personId = $('#person').val();
var taskId = $('#item').val();
appRoutes.controllers.Application.get(personId, taskId).ajax({
  success: function( data ) {
    // do something with the response
  }
})

这将导致以personId和taskId作为请求参数的GET请求到/ foo。

GET /foo?personId=personId&taskId=taskId

将路由文件更改为使用RESTful风格的URL / foo /:personId /:taskId将导致以下调用,而无需更改JS代码:

GET /foo/personId/taskId

让我们来看看实现这一目标需要做些什么。

基础

是时候创建我们的基本应用程序了。 使用命令行生成一个新的Play应用

play new jsRoutingScala

接受默认名称jsRoutingScala,然后为Scala应用程序选择选项。

_ __ | | __ _ _  _| |
| '_ \| |/ _' | || |_|
|  __/|_|\____|\__ (_)
|_|            |__/

play! 2.1.5 (using Java 1.7.0_17 and Scala 2.10.0), http://www.playframework.org

The new application will be created in /tmp/jsRoutingScala

What is the application name? [jsRoutingScala]
> 

Which template do you want to use for this new application? 

  1             - Create a simple Scala application
  2             - Create a simple Java application

> 1
OK, application jsRoutingScala is created.

Have fun!

这将为我们提供一个称为Application的基本控制器,并提供一些视图。 我们仍然需要创建一个模型类,所以现在就开始做。 在app目录中,创建一个名为models的包。 在模型包中,创建一个名为Person的类。 注意JSON读/写支持–这将允许控制器在Scala和JSON之间序列化和反序列化Person的实例。

package models

import anorm._
import anorm.SqlParser._
import play.api.Play.current
import play.api.db.DB
import play.api.libs.json._
import anorm.~

case class Person(id: Pk[Long] = NotAssigned, name: String)

object Person {

  val simple = {
    get[Pk[Long]]("person.id") ~
      get[String]("person.name") map {
      case id~name => Person(id, name)
    }
  }

  def insert(person: Person) = {
    DB.withConnection { implicit connection =>
      SQL(
        """
          insert into person values (
            (select next value for person_seq),
            {name}
          )
        """
      ).on(
        'name -> person.name
      ).executeInsert()
    } match {
      case Some(long) => long
      case None       => -1
    }
  }

  def delete(id: Long) = {
    DB.withConnection { implicit connection =>
      SQL("delete from person where id = {id}").on('id -> id).executeUpdate()
    }
  }

  def getAll: Seq[Person] = {
    DB.withConnection { implicit connection =>
      SQL("select * from person").as(Person.simple *)
    }
  }

  implicit object PersonReads extends Reads[Person] {
    def reads(json: JsValue): JsResult[Person] =
      JsSuccess[Person](Person(NotAssigned, (json \ "name").as[String]), JsPath())
  }

  implicit object PersonWrites extends Writes[Person] {
    def writes(person: Person) = Json.obj(
      "id" -> Json.toJson(person.id.get),
      "name" -> Json.toJson(person.name)
    )
  }
}

我们将需要一个数据库,因此编辑conf / application.conf并取消注释以下几行:

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

因为此示例使用Anorm,所以我们需要自己配置数据库。 在conf文件夹中,创建一个名为Evolutions的文件夹,其中包含另一个文件夹default 。 在此处创建一个名为1.sql的文件,并将以下内容复制到其中:

# --- !Ups
create table person (
  id bigint not null,
  name varchar(255),
  constraint pk_person primary key (id))
;

create sequence person_seq;

# --- !Downs
SET REFERENTIAL_INTEGRITY FALSE;

drop table if exists person;

SET REFERENTIAL_INTEGRITY TRUE;

drop sequence if exists person_seq;

现在,我们准备构建控制器。

控制器

控制器包中,打开“应用程序”对象。 已经有一个索引方法,但是我们不需要更改它。

该应用程序将允许我们创建,删除和获取Person实例,因此我们需要支持这些操作的方法。

def getAll() = Action {
  Ok(Json.toJson(Person.getAll))
}

def delete(id: Long) = Action {
  Person.delete(id)
  Ok("Deleted " + id)
}

def create = Action { implicit request =>
  request.body.asJson match {
    case None => BadRequest
    case Some(json: JsValue) => {
      val person: Person = json.as[Person]
      val id = Person.insert(person)
      Ok(Json.obj(
        "id" -> id,
        "name" -> person.name
      ))
    }
  }
}

def jsRoutes = Action { implicit request =>
  Ok(Routes.javascriptRouter("appRoutes")(
    controllers.routes.javascript.Application.create,
    controllers.routes.javascript.Application.delete,
    controllers.routes.javascript.Application.getAll))
    .as("text/javascript")
}

这些方法涵盖了我们的业务逻辑,因此我们可以将它们添加到路由文件中

GET     /person       controllers.Application.getAll()
DELETE  /person/:id   controllers.Application.delete(id: Long)
POST    /person       controllers.Application.create()

添加JS路由支持

到目前为止,如此正常。 我们拥有可以通过HTTP调用访问的业务逻辑,但是没有专门的JS支持。 我们需要向控制器添加另一个方法,该方法指定我们希望在JS路由对象中可用的路由。

// jsRoutes

此方法将生成一个可以加载到客户端JavaScript文件。 进入视图后,我们将看到此内容。 因为这是从客户端调用的,所以我们需要向路由添加另一个条目。 注意路由的位置非常重要–它必须在现有的“ / assets / * file”条目之前,否则该路由将占用请求。

GET           /assets/js/routes             controllers.Application.jsRoutes()
GET           /assets/*file                 controllers.Assets.at(path="/public", file)

风景

现在我们要去哪里做。 第一步是使我们的视图了解JS路由代码,我们可以通过简单地将脚本标签添加到views / main.scala.html来做到这一点。

<script src="@controllers.routes.Application.jsRoutes()" type="text/javascript"></script>

我们终于准备好使用我们的JS路由对象。 以下代码是一个非常基本的单页应用程序,可连接到后端的获取,创建和删除功能。 将此代码复制并粘贴到现有的views / index.scala.html文件中,然后看一下它在做什么。 您可能会注意到此代码与Java示例中的代码相同。

@(message: String)

@main("Play 2 JavaScript Routing") {

    <fieldset>
        <form>
            <label for="personName">Name:
            <input type="text" name="personName" id="personName"/>
            <input type="button" value="Create" id="createPerson"/>
        </form>
    </fieldset>
    <ul id="peopleList">

    <script>
    var doc = $ (document);
    doc.ready (function() {
      // Delete a person
      doc.on ('click', '.deletePerson', function(e) {
        var target = $(e.target);
        var id = target.data('id');
        appRoutes.controllers.Application.delete(id).ajax( {
          success : function ( data ) {
            target.closest('li').remove();
          }
        });
      });

      // Create a new person
      $('#createPerson').click(function() {
        var personNameInput = $('#personName');
        var personName = personNameInput.val();
        if(personName && personName.length > 0) {
          var data = {
            'name' : personName
          };
          appRoutes.controllers.Application.create().ajax({
            data : JSON.stringify(data),
            contentType : 'application/json',
            success : function (person) {
              $('#peopleList').append('<li>' + person.name + ' <a href="#" data-id="' + person.id + '" class="deletePerson">Delete</a></li>');
                personNameInput.val('');
            }
          });
        }
      });

      // Load existing data from the server
      appRoutes.controllers.Application.getAll().ajax({
        success : function(data) {
          var peopleList = $('#peopleList');
          $(data).each(function(index, person) {
            peopleList.append('<li>' + person.name + ' <a href="#" data-id="' + person.id + '" class="deletePerson">Delete</a></li>');
          });
        }
      });
    }) ;
    </script>
}

这里有三行将生成对服务器的调用,即

  • appRoutes.controllers.Application.delete(id).ajax
  • appRoutes.controllers.Application.create()。ajax
  • appRoutes.controllers.Application.getAll()。ajax

让我们以delete为例,因为它带有一个参数。

  • appRoutes
    • 看一下您的Application类,您将看到名称appRoutes被赋予JS路由器。
  • 控制器应用
    • 这是目标控制器的标准名称。
  • 删除(ID)
    • 方法调用,包括参数。
  • 阿贾克斯
    • 此功能将调用服务器。

摘要

这似乎是很多工作,但其中大部分是在创建项目。 实际的JS路由只占很小的时间投资,却能获得不错的回报。 改型现有代码以使用此方法非常容易,一旦您从中受益,继续采用这种风格也非常简单。

应用范例

Java

本文从Scala的角度介绍了如何使用此功能。 在同级文章中,还演示了Java支持。 两者之间的差异很小,从客户端的角度来看不存在。 您可以在这里阅读本文。

参考:来自Objectify博客的JCG合作伙伴 Steve Chaloner的Play 2(Scala版)中JavaScript路由

翻译自: https://www.javacodegeeks.com/2014/01/javascript-routing-in-play-2-scala-edition.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值