第六章SignalR的服务器广播

1.概述:

VS可以通过 Microsoft.AspNet.SignalR.Sample NuGet包来安装一个简单的模拟股票行情应用。在本教程的第一部分,您将从头开始创建一个应用程序的简化版本。在本教程的剩余部分,您将安装NuGet包,审阅Sample中的一些附加功能。

在本模拟股票行情应用代表了实时应用中的“推” ,或称之为广播,即我们将消息通知传播给所有已连接的客户端。

首先,您将要创建该应用程序的显示表格用于显示股票数据。

接下来,服务器会随机更新股票价格,并且将新数据推送至所有连接的客户端已更新表格。在浏览器中的表格上,价格以及百分比列中的数字都会随着服务器推送数据而自动更新。如果您打开更多的浏览器,它们都会显示相同的数据以及自动更新。

注意:如果您不想自动动手来构建这一应用程序,您可以再新建一个空的Asp.Net应程序项目中安装Simple包,通过阅读里面的步骤来获取代码解释。本例子的第一部分涵盖了Simple的子集,第二部分解释了包中的一些附加功能。

2.创建项目:

1)新建一个新的Asp.Net应用程序,命名为SignalR.StockTicker并创建

2)选择空项目并且确定。

3.创建Stock类:

首先:我们来创建一个Stock模型类,用来存储和传输股票信息。

1)新建一个类,命名为Stock.cs,然后输入一下代码:

using System;

namespace SignalR.StockTicker

{

public class Stock

{

private decimal _price;

public string Symbol { get; set; }

public decimal Price

{

get

{

return _price;

}

set

{

if (_price == value)

{

return;

}

_price = value;

if (DayOpen == 0)

{

DayOpen = _price;

}

}

}

public decimal DayOpen { get; private set; }

public decimal Change

{

get

{

return Price - DayOpen;

}

}

public double PercentChange

{

get

{

return (double)Math.Round(Change / Price, 4);

}

}

}

}

您设置了两个属性:股票代码和股票价格。其他的属性则依赖于您如何及何时设置股票价格。当您首次设置价格时,价格将被存储在DayOpen中。之后随着股票价格的改变,Change和PercentCHange会自动计算DayOpen及价格之间的的差额并输出结果。

4.创建StockTicker和StockTickerHub类:

您将使用SignalR集线器类的API来处理服务器到客户端的交互。StockTickerHub继续SinglaR集线器基类,用来处理接收客户端的连接和调用的方法。您还需要维护保存的数据,建立一个独立于客户端连接的Timer对象,来触发价格更新。您不能将这些功能放在集线器中,那是因为,每个针对集线器的操作,比如从客户端到服务器端的连接与调用都会建立一个新的集线器对象,每个集线器对象的生命周期是短暂的。因此,保存数据,价格,广播等更新机制需要放在另一个单独的类中。在此项目中,我们将其命名为StockTicker。

您只需要一个StockTicker类的实例。所以,你需要使用设计模式中的----单例模式,从每个StockTickerHub的类中添加对StockTicker单一实例的引用。由于StocckTicker类包含股票数据并触发更新,所以它必须能够广播到每个客户端。但StockTicker本身并不是一个集线器类,所以,StockTicker类必须得到一个SignalR集线器连接上下文对象的引用,后面,就可以使用这个上下文对象来将数据广播给客户端。

1)添加一个新的SignalR集线器类,命名为StockTickerHub并且使用以下的代码替换其内容

using System.Collections.Generic;

using Microsoft.AspNet.SignalR;

using Microsoft.AspNet.SignalR.Hubs;

namespace SignalR.StockTicker

{

[HubName("stockTickerMini")]

public class StockTickerHub : Hub

{

private readonly StockTicker _stockTicker;

public StockTickerHub() : this(StockTicker.Instance) { }

public StockTickerHub(StockTicker stockTicker)

{

_stockTicker = stockTicker;

}

public IEnumerable<Stock> GetAllStocks()

{

return _stockTicker.GetAllStocks();

}

}

}

此集线器类用来定义用于客户端调用的服务器方法。我们定义了一个GetAllStocks方法,当一个客户端首次连接至服务器时,它会调用此方法来获取所 有股票的清单及当期价格。该方法可以同步执行并返回IEnumerable<Sotck>,因为这些数据是从内存中返回的。如果该方法需要做 一些涉及等待的额外处理任务,比如数据库查询或调用Web服务来获取数据,您将指定 Task<IEnumerable<Stock>>作为返回值已启用异步处理。关于异步处理的更多信息,请参阅:ASP.NET SignalR Hubs API Guide - Server - When to execute asynchronously

HubName特性定义了客户端的JS代码使用何种名称来调用集线器。如果你不使用这个特性,默认将通过采用使用Camel规范的类名来调用。在本例中,我们使用stockTickerHun。

稍后我们将创建StockTicker类,如您所见,我们在这里使用了单例模式。使用一个静态实例属性来创建这个类的单一实例。StockTicker的 单例将一直保留在内存中,不管有多少客户端连接或断开连接。并且使用该实例中包含的GetAllStocks方法返回股票信息。

2)添加一个新类,命名为StockTicker.cs,并使用以下代码替换内容:

a.Collections.Concurrent;

using System.Collections.Generic;

using System.Threading;

using Microsoft.AspNet.SignalR;

using Microsoft.AspNet.SignalR.Hubs;

namespace SignalR.StockTicker

{

public class StockTicker

{

// Singleton instance

private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();

private readonly object _updateStockPricesLock = new object();

//stock can go up or down by a percentage of this factor on each change

private readonly double _rangePercent = .002;

private readonly TimeSpan _updateInterval = TimeSpan.FromMilliseconds(250);

private readonly Random _updateOrNotRandom = new Random();

private readonly Timer _timer;

private volatile bool _updatingStockPrices = false;

private StockTicker(IHubConnectionContext clients)

{

Clients = clients;

_stocks.Clear();

var stocks = new List<Stock>

{

new Stock { Symbol = "MSFT", Price = 30.31m },

new Stock { Symbol = "APPL", Price = 578.18m },

new Stock { Symbol = "GOOG", Price = 570.30m }

};

stocks.ForEach(stock => _stocks.TryAdd(stock.Symbol, stock));

_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);

}

public static StockTicker Instance

{

get

{

return _instance.Value;

}

}

private IHubConnectionContext Clients

{

get;

set;

}

public IEnumerable<Stock> GetAllStocks()

{

return _stocks.Values;

}

private void UpdateStockPrices(object state)

{

lock (_updateStockPricesLock)

{

if (!_updatingStockPrices)

{

_updatingStockPrices = true;

foreach (var stock in _stocks.Values)

{

if (TryUpdateStockPrice(stock))

{

BroadcastStockPrice(stock);

}

}

_updatingStockPrices = false;

}

}

}

private bool TryUpdateStockPrice(Stock stock)

{

// Randomly choose whether to update this stock or not

var r = _updateOrNotRandom.NextDouble();

if (r > .1)

{

return false;

}

// Update the stock price by a random factor of the range percent

var random = new Random((int)Math.Floor(stock.Price));

var percentChange = random.NextDouble() * _rangePercent;

var pos = random.NextDouble() > .51;

var change = Math.Round(stock.Price * (decimal)percentChange, 2);

change = pos ? change : -change;

stock.Price += change;

return true;

}

private void BroadcastStockPrice(Stock stock)

{

Clients.All.updateStockPrice(stock);

}

}

}

注意:由于运行时会有多个线程对StockTicker的同一个实例进行操作,StockTicker类必须是线程安全的。

5.在静态字段中存储单例:

下面的代码用于在静态_instance字段中初始化一个StockTicker的实例。这是该类的唯一一个实例,因为构造函数已经被标记为私有的。_instance中的延迟初始化不是由于性能原因,而是要确保该线程的创建是线程安全的。

private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

public static StockTicker Instance

{

get

{

return _instance.Value;

}

}

每次客户端连接到服务器时,都会在单独的一个线程中创建StockTickerHub的新实例,之后从StockTicker.Instance静态属性中获取StockTicker的单例,如同你之前在StockTickerHub之前见到的那样。

6.在ConcurrentDictory中存放股票数据:

构造函数初始化了_stock集合并且初始化了一些样本数据并使用GetAllStocks返回股票数据。如前所述,客户端可以调用服务器端StockTickerHub集线器中的GetAllStocks方法用来返回股票数据集合到客户端。

private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();

private StockTicker(IHubConnectionContext clients)

{

Clients = clients;

_stocks.Clear();

var stocks = new List<Stock>

{

new Stock { Symbol = "MSFT", Price = 30.31m },

new Stock { Symbol = "APPL", Price = 578.18m },

new Stock { Symbol = "GOOG", Price = 570.30m }

};

stocks.ForEach(stock => _stocks.TryAdd(stock.Symbol, stock));

_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);

}

public IEnumerable<Stock> GetAllStocks()

{

return _stocks.Values;

}

股票集合被定义为一个ConcurrentDictionary类以确保线程安全。作为替代,你可以使用Dictionary对象并在对其进行修改时显式的锁定它来确保线程安全。对于本示例,股票数据都存储在内存中,所以当应用程序重启时你会丢失所有的数据。在实际的应用中,你应该将数据安全的存放在后端(比如SQL数据库中)。

7.定期更新股票价格:

构造函数启动一个定时器来定期更新股票数据,股价以随机抽样的方式来随机变更。

_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);

private void UpdateStockPrices(object state)

{

lock (_updateStockPricesLock)

{

if (!_updatingStockPrices)

{

_updatingStockPrices = true;

foreach (var stock in _stocks.Values)

{

if (TryUpdateStockPrice(stock))

{

BroadcastStockPrice(stock);

}

}

_updatingStockPrices = false;

}

}

}

private bool TryUpdateStockPrice(Stock stock)

{

// Randomly choose whether to update this stock or not

var r = _updateOrNotRandom.NextDouble();

if (r > .1)

{

return false;

}

// Update the stock price by a random factor of the range percent

var random = new Random((int)Math.Floor(stock.Price));

var percentChange = random.NextDouble() * _rangePercent;

var pos = random.NextDouble() > .51;

var change = Math.Round(stock.Price * (decimal)percentChange, 2);

change = pos ? change : -change;

stock.Price += change;

return true;

}

定时器会定时调用UpdateStockPrices方法,在更新价格之前,_updateStockPricesLock对象被锁住。代码检查是否有另 一个线程在更新价格,然后调用TryUpdateStockPrice方法来对列表中的股票进行逐一更新。TryUpdateStockPrice方法将 判断是否需要更新股价以及更新多少。如果股票价格发生变化,BroadcastPrice方法将变动的数据广播到所有已连接的客户端上。

_updateStockPrices标识被标记为volatile以确保访问是线程安全的。

private volatile bool _updatingStockPrices = false;

在实际应用中,TryUpdateStockPrice方法可能会调用Web服务来查找股价;在本示例中,它使用一个随机数来模拟股价的变化。

8.获取SignalR上下文,以便StockTicker类对其调用来广播到客户端:

由于价格变动发生于StockTicker对象,该对象需要在所有已连接客户端上调用updateStockPrice方法。在集线器类中,你有现成的 API来调用客户端方法。但StockTicker类没有从集线器类派生,所以没有引用到集线器的基类对象。因此,为了对客户端广 播,StockTicker类需要获取SignalR上下文的实例并用它来调用客户端上的方法。

该代码会在创建单例的时候获取SignalR上下文的引用,将引用传递给构造函数,使构造函数能够将它放置在Clients属性中。

有两个原因使你只应该得到一次上下文:获取上下文是一个昂贵的操作,并且仅获得一次可以确保发送到客户端的消息顺序是有序的。

private readonly static Lazy<StockTicker> _instance =

new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

private StockTicker(IHubConnectionContext clients)

{

Clients = clients;

// Remainder of constructor ...

}

private IHubConnectionContext Clients

{

get;

set;

}

private void BroadcastStockPrice(Stock stock)

{

Clients.All.updateStockPrice(stock);

}

获取上下文中的Client属性,这样可以让你编写代码呼叫客户端方法,就如同你在集线器类中那样。例如,如果想广播到所有客户端,你可以写Clients.All.updateStockprice(stock)。

你在BroadcastStockPrice中调用的updateStockPrice客户端方法还不存在,稍后我们会在编写客户端代码时加上它。但现在 你就可以在这里引用updateStockPrice,这是因为Clients.All是动态的,这意味着该表达式将在运行时进行评估。当这个方法被执 行,SignalR将发送方法名和参数给客户端,如果客户端能够匹配到相同名称的方法,该方法会被调用,参数也将被传递给它。

Client.All意味着将把消息发送到全部客户端。SignalR也同样给你提供了其他选项来选择指定客户端或群组。请参阅HubConnectionContext

9.注册SignalR路由:

服务器需要知道那个URL用于拦截并指向SignalR,我们将添加OWIN启动类来实现。

1)添加一个OWIN启动类,并命名为Startup.cs。

2)使用下面的代码替换Startup.cs中的内容:

using System;

using System.Threading.Tasks;

using Microsoft.Owin;

using Owin;

[assembly: OwinStartup(typeof(SignalR.StockTicker.Startup))]

namespace SignalR.StockTicker

{

public class Startup

{

public void Configuration(IAppBuilder app)

{

// Any connection or hub wire up and configuration should go here

app.MapSignalR();

}

}

}

现在你已经完成了全部的服务器端代码,接下来我们将配置客户端。

10.配置客户端代码:

1)新建一个Html文档,命名为StockTicker.html。

2)使用下面的代码替换StockTicker.html中的内容:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>ASP.NET SignalR Stock Ticker</title>

<style>

body {

font-family: 'Segoe UI', Arial, Helvetica, sans-serif;

font-size: 16px;

}

#stockTable table {

border-collapse: collapse;

}

#stockTable table th, #stockTable table td {

padding: 2px 6px;

}

#stockTable table td {

text-align: right;

}

#stockTable .loading td {

text-align: left;

}

</style>

</head>

<body>

<h1>ASP.NET SignalR Stock Ticker Sample</h1>

<h2>Live Stock Table</h2>

<div id="stockTable">

<table border="1">

<thead>

<tr><th>Symbol</th><th>Price</th><th>Open</th><th>Change</th><th>%</th></tr>

</thead>

<tbody>

<tr class="loading"><td colspan="5">loading...</td></tr>

</tbody>

</table>

</div>

<!--Script references. -->

<!--Reference the jQuery library. -->

<script src="/Scripts/jquery-1.10.2.min.js" ></script>

<!--Reference the SignalR library. -->

<script src="/Scripts/jquery.signalR-2.0.0.js"></script>

<!--Reference the autogenerated SignalR hub script. -->

<script src="/signalr/hubs"></script>

<!--Reference the StockTicker script. -->

<script src="StockTicker.js"></script>

</body>

</html>

我们在Html中创建了一个具有5列,一个标题和跨越所有5列的单个单元格的Table,数据行显示为“正在加载”,并且智慧在应用程序启动时一度显示。JS代码将会删除改行并在相同的卫士添加从服务器检索的股票数据。

script标签指定了jQuery脚本文件,SignalR核心脚本文件,SignalR代理脚本文件以及你即将创建的StockTicker脚本文 件。在SignalR代理脚本文件中,指定了"/signalr/hub"URL,这是动态生成的,是集线器方法中定义好的方法的代理方法。在本示例中为 StockTickerHub.GetAllStocks。如果你愿意,你可以手动生成该JS文件,通过使用SignalR 组件和在调用MapHubs 方法时禁用动态文件创建来实现相同的功能。

3)重要提示:请确保JS文件都得到了正确的引用,即检查script标签中引用的jQuery等文件路径和你项目中的JS脚本文件名称一致。

4)右击StockTicker.html,将其设置为起始页。

5)在项目文件夹中创建一个新的JS文件,命名为StockTicker.js并保存。

6)使用下面的代码替换掉StockTicker.js文件中的内容。

// A simple templating method for replacing placeholders enclosed in curly braces.

if (!String.prototype.supplant) {

String.prototype.supplant = function (o) {

return this.replace(/{([^{}]*)}/g,

function (a, b) {

var r = o[b];

return typeof r === 'string' || typeof r === 'number' ? r : a;

}

);

};

}

$(function () {

var ticker = $.connection.stockTickerMini, // the generated client-side hub proxy

up = '▲',

down = '▼',

$stockTable = $('#stockTable'),

$stockTableBody = $stockTable.find('tbody'),

rowTemplate = '<tr data-symbol="{Symbol}"><td>{Symbol}</td><td>{Price}</td><td>{DayOpen}</td><td>{Direction} {Change}</td><td>{PercentChange}</td></tr>';

function formatStock(stock) {

return $.extend(stock, {

Price: stock.Price.toFixed(2),

PercentChange: (stock.PercentChange * 100).toFixed(2) + '%',

Direction: stock.Change === 0 ? '' : stock.Change >= 0 ? up : down

});

}

function init() {

ticker.server.getAllStocks().done(function (stocks) {

$stockTableBody.empty();

$.each(stocks, function () {

var stock = formatStock(this);

$stockTableBody.append(rowTemplate.supplant(stock));

});

});

}

// Add a client-side hub method that the server will call

ticker.client.updateStockPrice = function (stock) {

var displayStock = formatStock(stock),

$row = $(rowTemplate.supplant(displayStock));

$stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')

.replaceWith($row);

}

// Start the connection

$.connection.hub.start().done(init);

});

$.connection引用SignalR代理,来获取引用到代理类的StockTickerHub类,并放置在ticker变量中。代理名称是由HubName特性所指定的。

Var ticker = $.connection.stockTickerMini

[HubName("stockTickerMini")]
public class StockTickerHub : Hub

当所有变量及函数都定义完成之后,代码文件中的最后一行通过调用SignalR start函数来初始化SignalR连接。start函数将异步执行并返回一个jQuery的递延对象,这意味着你可以在异步操作后调用函数来完成指定的功能。

$.connection.hub.start().done(init);

init函数调用服务器上的getAllStocks方法,并使用服务器返回的数据来更新股票表格中的信息。请注意,在默认情况下你必须在客户端上使用 camel命名规范来调用服务器端的Pascal命名规范的方法。另外camel命名规范仅适用于方法而不是对象。例如要使用stock.Symbol跟 stock.Price,而不是stock.symbol跟stock.price。

function init() {

ticker.server.getAllStocks().done(function (stocks) {

$stockTableBody.empty();

$.each(stocks, function () {

var stock = formatStock(this);

$stockTableBody.append(rowTemplate.supplant(stock));

});

});

}

public IEnumerable<Stock> GetAllStocks()
{
    return _stockTicker.GetAllStocks();
}

如果你想在客户端上使用Pascal命名规范,或者你想使用一个完全不同的方法名,你可以使用HubMethodName特性来修饰集线器方法, 如同使用HubName来修饰集线器类一样。

在init方法中,接收到从服务器传来股票信息后,会清除table row的html,然后通过ormatStock来格式化股票对象,之后将其附加到表格中。

在执行异步启动函数后 ,作为回调函数,调用init方法。如果你将init作为单独的JS对象在start函数中调用,函数将会失败,因为它会立即执行而不会等待启动功能来完成连接。在本例中,init函数会在服务器连接建立后再去调用getAllStocks函数。

当服务器改变了股票的价格,它调用已连接客户端的updateStockPrice。该函数被添加到stockTicker代理的客户端属性中,使其可以从服务器端调用。

ticker.client.updateStockPrice = function (stock) {

var displayStock = formatStock(stock),

$row = $(rowTemplate.supplant(displayStock));

$stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')

.replaceWith($row);

}

如同inti函数一样,updateStockPrice函数格式化从服务器接收到的股票对象并插入表格中。而不是附加到表格的行后面,它会发现当前表格中的股票行并使用新的数据替换掉。

11.测试应用程序:

1)按下F5启动应用程序。

表格最初显示“正在加载”,在初始化股票数据后,显示最初的股票价格,之后便会随着股价变动而开始改变。

2)复制多个浏览器窗口,你会看到同第一步一样的情况,之后所有浏览器会同时根绝股价发生变化。

3)关闭所有浏览器,再打开一个新的,打开相同的URL你会看到股票价格仍在改变(你看不到初始化时显示初始股价的数字及信息),这是由于stockTicker单例继续在服务器上运行。

4)关闭浏览器。

12.启用日志记录:

SignalR有个一内置的日志功能,您可以启动它来进行Bug排查,本节我们将展示这一功能。关于SignalR针对IIS以及浏览器所不同的传输方式,请参见前几章教程。

1)打开stockTicker.js并添加一行代码来启动日志。

// Start the connection
$.connection.hub.logging = true;
$.connection.hub.start().done(init);

2)按下F5开始运行项目。

3)打开浏览器中的开发者工具,可能需要刷新页面建立一个新连接才能看到SignalR的传输方式。

第六章SignalR的服务器广播的更多相关文章

  1. [渣译文] SignalR 2.0 系列:SignalR的服务器广播

    英文渣水平,大伙凑合着看吧…… 这是微软官方SignalR 2.0教程Getting Started with ASP.NET SignalR 2.0系列的翻译,这里是第八篇:SignalR的服务器广 ...

  2. SignalR 2.0 系列:SignalR的服务器广播

    英文渣水平,大伙凑合着看吧…… 这是微软官方SignalR 2.0教程Getting Started with ASP.NET SignalR 2.0系列的翻译,这里是第八篇:SignalR的服务器广 ...

  3. SignalR的服务器广播

    可以试试 https://github.com/angular-ui/bootstrap 这个框架啊 [渣译文] SignalR 2.0 系列:SignalR的服务器广播 2014-03-13 09: ...

  4. 【linux高级程序设计】(第十六章)网络服务器应用设计

    xinetd服务介绍 xinetd是Linux下的一个网络守候进程,用来统一管理网络负载不大的一组小型网路服务. 一些小型的网络服务,比如时间,telnet服务,不以守候进程出现,而是让xinetd服 ...

  5. SignalR系列教程:服务器广播与主动数据推送

    本篇是本系列入门篇的最后一遍,由于工作关系,接触SignalR的时间不是很多.等下次有空的话我会写一个利用“SignalR”开发一个在线聊天室的系列博文.近期的话我更偏向于更新框架设计相关的文章,到时 ...

  6. 使用SignalR 2进行服务器广播

    概述 在本教程中,您将创建一个股票代码应用程序,该应用程序代表您希望定期“推送”或广播从服务器到所有连接客户端的通知的实时应用程序.在本教程的第一部分中,您将从头开始创建该应用程序的简化版本.在本教程 ...

  7. 与http协作的web服务器、http首部(第五章、第六章)

    第五章 与http协作的web服务器 1.用单台虚拟主机实现多个域名 通过域名访问主机,经过DNS解析成ip地址,反向代理,可以代理多台服务器,正向代理则相反,代理客户端 2.通信数据转化程序:代理. ...

  8. SignalR入门二、使用 SignalR 2 实现服务器广播

    一.概述 这篇教程通过实现一个股票报价的小程序来讲解如何使用SignalR进行服务器端的推送,服务器会模拟股票价格的波动,并把最新的股票价格推送给所有连接的客户端,最终的运行效果如下图所示. 教程:使 ...

  9. 第五章SignalR的实时高频通讯

    第五章SignalR的实时高频通讯 概述:本例子演示了如果创建一个对象与其他浏览器共享实时状态的应用程序.我们要创建的应用程序为“MoveShape”,该MoveShape页面会显示一个Html Di ...

随机推荐

  1. hdu 1690 The Balance_母函数

    题意:给你n个数,这些数可以互相加或者减,输出在范围[1,sum]里不能通过运算得出的数 思路:套母函数模版 #include <iostream> #include<cstdio& ...

  2. Ext 怎么发ajax请求

    Ext3.3完整包 Ext3.3中文文档 数据表的结构是:数据表table  > 记录record > 字段 store的结构是:  Ext.data.Store > Ext.dat ...

  3. Apple Mach-O Linker Warning 警告解决的方法

    此警告解决的方法: 项目名字 -> targets -> Build Settings -> search path 把里面无用的东西 点 减号 删掉 即可了. $(function ...

  4. Elasticsearch的javaAPI之percolator

    Elasticsearch的javaAPI之percolator percolator同意一个在index中注冊queries,然后发送包括doc的请求,返回得到在index中注冊过的而且匹配doc的 ...

  5. 对于deferred的一点点理解

    deferred对象,是一个异步队列.能够实现异步代码调用,从而解决代码执行顺序的问题. 它提供了一下主要方法: jQuery.Deferred() 一个构造函数,返回一个链式实用对象方法来注册多个回 ...

  6. Android开发 学习笔记——HelloWorld

    Day01 1.java开发过程———————————————不建议先用ECLIPSE写代码,因为它的函数式自动生成的,不利于找寻编程手感打开记事本写完程序后,修改扩展名为.java然后在DOS控制台 ...

  7. JSP简介

    论坛 博客 微论 问答 游戏厅 天涯客 读书 更多 手机 服务 登录 注册   聚焦 民生 文学 旅游 财经 汽车 IT数码 时尚 情感 娱乐 视频 更多 北京 上海 广东 更多 天涯部落> J ...

  8. zoj1074 To the Max

    题目很简单,求一个连续的最大子矩阵的值. zoj上的数据非常弱. 首先爆搜是O(N^4),10^8的复杂度略高,那么我们可以处理一下其中一维的前缀和,降一阶,然后按照连续最大子序列来处理,因为可能为负 ...

  9. GetRect:通过提供点和宽度返回对应矩形RECT

    RECT GetRect(int x,int y,int width,int height); 描述:通过提供点和宽度返回对应矩形RECT 返回:矩形结构RECT 参数: x:X轴坐标 y:Y轴坐标 ...

  10. 多主一从mysql replication同步表的大胆尝试.

    能否将不同机器上的不同库中的表同步到同一个机器的同一个库中?表是不同的.而且对于slave这台机子来说,这些表只用来读.   同步不同库的表很简单了,用 replicate-do-table=db_n ...