ch10.md 5.8 KB
Newer Older
W
ch10  
wizardforcel 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# 在 Nashron 中使用 Backbone.js

> 原文:[Using Backbone.js with Nashorn](http://winterbe.com/posts/2014/04/07/using-backbonejs-with-nashorn/) 

> 译者:[飞龙](https://github.com/wizardforcel)  

> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)

这个例子展示了如何在Java8的Nashron JavaScript引擎中使用Backbone.js模型。Nashron在2014年三月首次作为Java SE 8 的一部分发布,并通过以原生方式在JVM上运行脚本扩展了Java的功能。对于Java Web开发者,Nashron尤其实用,因为它可以在Java服务器上复用现有的客户端代码。传统的[Node.js](http://nodejs.org/)具有明显优势,但是Nashorn也能够缩短JVM的差距。

当你在HTML5前端使用现代的JavaScript MVC框架,例如[Backbone.js](http://backbonejs.org/)时,越来越多的代码从服务器后端移动到Web前端。这个方法可以极大提升用户体验,因为在使用视图的业务逻辑时节省了服务器的很多往返通信。

Backbone允许你定义模型类,它们可以用于绑定视图(例如HTML表单)。当用户和UI交互时Backbone会跟踪模型的升级,反之亦然。它也能通过和服务器同步模型来帮助你,例如调用服务端REST处理器的适当方法。所以你最终会在前端实现业务逻辑,将你的服务器模型用于处理持久化数据。

W
typo  
wizardforcel 已提交
15
在服务端复用Backbone模型十分易于用Nashron完成,就像下面的例子所展示的那样。在我们开始之前,确保你通过阅读我的[Nashorn教程](ch3.md)熟悉了在Nashron引擎中编写JavaScript。
W
ch10  
wizardforcel 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

## Java 模型

首先,我们在Java中定义实体类`Product`。这个类可用于数据库的CURD操作(增删改查)。要记住这个类是个纯粹的Java Bean,不实现任何业务逻辑,因为我们想让前端正确执行UI的业务逻辑。

```java
class Product {
    String name;
    double price;
    int stock;
    double valueOfGoods;
}
```

## Backbone 模型

现在我们定义Backbone模型,作为Java Bean的对应。Backbone模型`Product`使用和Java Bean相同的数据结构,因为它是我们希望在Java服务器上持久存储的数据。

W
typo  
wizardforcel 已提交
34
Backbone模型也实现了业务逻辑:`getValueOfGoods`方法通过将`stock``price`相乘计算所有产品的总值。每次`stock``price`的变动都会使`valueOfGoods`重新计算。
W
ch10  
wizardforcel 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

```js
var Product = Backbone.Model.extend({
    defaults: {
        name: '',
        stock: 0,
        price: 0.0,
        valueOfGoods: 0.0
    },

    initialize: function() {
        this.on('change:stock change:price', function() {
            var stock = this.get('stock');
            var price = this.get('price');
            var valueOfGoods = this.getValueOfGoods(stock, price);
            this.set('valueOfGoods', valueOfGoods);
        });
    },

    getValueOfGoods: function(stock, price) {
        return stock * price;
    }
});
```

由于Backbone模型不使用任何Nashron语言扩展,我们可以在客户端(浏览器)和服务端(Java)安全地使用同一份代码。

要记住我特意选择了十分简单的函数来演示我的意图。真实的业务逻辑应该会更复杂。

## 将二者放在一起

下一个目标是在Nashron中,例如在Java服务器上复用Backbone模型。我们希望完成下面的行为:把所有属性从Java Bean上绑定到Backbone模型上,计算`valueOfGoods`属性,最后将结果传回Java。

首先,我们创建一个新的脚本,它仅仅由Nashron执行,所以我们这里可以安全地使用Nashron的扩展。

```js
load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js');
load('http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js');
load('product-backbone-model.js');

var calculate = function(javaProduct) {
    var model = new Product();
    model.set('name', javaProduct.name);
    model.set('price', javaProduct.price);
    model.set('stock', javaProduct.stock);
    return model.attributes;
};
```

这个脚本首先加载了相关的外部脚本[Underscore](http://underscorejs.org/)[Backbone](http://backbonejs.org/)(Underscore是Backbone的必备条件),以及我们前面的`Product`Backbone模型。

函数`calcute`接受`Product`Java Bean,将其所有属性绑定到新创建的Backbone`Product`上,之后返回模型的所有属性给调用者。通过在Backbone模型上设置`stock``price`属性,`ValueOfGoods`属性由于注册在模型`initialize`构造函数中的事件处理器,会自动计算出来。

最后,我们在Java中调用`calculate`函数。

```java
Product product = new Product();
product.setName("Rubber");
product.setPrice(1.99);
product.setStock(1337);

ScriptObjectMirror result = (ScriptObjectMirror)
    invocable.invokeFunction("calculate", product);

System.out.println(result.get("name") + ": " + result.get("valueOfGoods"));
// Rubber: 2660.63
```

我们创建了新的`Product`Java Bean,并且将它传递到JavaScript函数中。结果触发了`getValueOfGoods`方法,所以我们可以从返回的对象中读取`valueOfGoods`属性的值。

## 总结

在Nashron中复用现存的JavaScript库十分简单。Backbone适用于构建复杂的HTML5前端。在我看来,Nashron和JVM现在是Node.js的优秀备选方案,因为你可以在Nashron的代码库中充分利用Java的整个生态系统,例如JDK的全部API,以及所有可用的库和工具。要记住你在使用Nashron时并不限制于Java -- 想想 Scala、Groovy、Clojure和`jjs`上的纯JavaScript。

这篇文章中可运行的代码托管在[Github](https://github.com/winterbe/java8-tutorial)上(请见[这个文件](https://github.com/winterbe/java8-tutorial/blob/master/res/nashorn6.js))。请随意[fork我的仓库](https://github.com/winterbe/java8-tutorial/fork),或者在[Twitter](https://twitter.com/winterbe_)上向我反馈。