9.4 在web中使用ActiveMQ消息

博客搬家,更好阅读体验,猛戳http://www.jack-yin.com/english/translation/activemq-in-action/1604.html

9.4 Messaging on the web with ActiveMQ

9.4 在web中使用ActiveMQ消息

In the last few years we witnessed the rebirth of the web, usually called Web 2.0. The

transformation is taking place in two particular aspects of software development:

? Service-oriented architecture  . SOA and web services play an increasingly important

role for many software projects. Users demand that software functionality be

exposed through some kind of web service interface. One way to achieve this is

to introduce RESTful principles to your application architecture, which allows

you to expose your application resources over HTTP. ActiveMQ follows these

principles by exposing its resources through its REST API, as we’ll see in a

moment.

过去几年中,我们见证了web的重生,这里的web通常指Web2.0. 软件开发的在以下面向服务的架构

两个方面正在发生变化:

SOA和web service 在许多软件工程中扮演着越来越重要的角色.用户要求软件的功能需要

通过一种web service接口的方式暴露出来.实现这种暴露的一种方式是在软件架构中使用REST 原则,该原则

允许你通过HTTP协议暴露系统资源.ActiveMQ遵循了这些原则,可以通过提供的REST API来暴露资源,正如我们

接下来要看到的那样.

It’s easy to say that Asynchronous JavaScript and XML (Ajax) revolutionized web

development as we knew it. The possibility of achieving asynchronous communication

between the browser and the server (without page reloading) opened

many doors for web developers, and provided a way for web applications to

become much more interactive. Naturally, you can use ActiveMQ Ajax API to

communicate directly with the broker from your web browser, which adds even

more asynchronous communication possibilities between clients (JavaScript

browser code) and servers (back-end server applications).

我们知道,异步JavaScript和XML(Ajax)为web开发带来了革命性改变.浏览器和服务器之间的

异步通信(不需要刷新页面)机制为web开发者提供了更多的开发方法,同时也为用户和web程序

之间提供了更好的交互.当然,你可以使用ActiveMQ Ajax API通过浏览器与代理直接通信,这样

给客户端(浏览器里的JavaScript代码)和服务器(应用程序服务器后台)段提供了更多异步交互

的可能性.

So with REST and Ajax APIs in its toolbox, ActiveMQ is well suited to be a good player in

the web arena. Using asynchronous messaging with standard web tools provides whole

new programming concepts to web developers. In the rest of this section we’ll explore

REST and Ajax APIs. We’ll see how you can send and receive messages from the command

line by issuing GET and POST HTTP calls. We’ll also describe the Ajax stock portfolio consumer

that comes with the ActiveMQ distribution, which shows how asynchronous messaging

and Ajax can be used together to provide real-time updates in web pages.

ActiveMQ的工具箱中拥有REST 和 Ajax API之后,ActiveMQ将更加适合web领域的开发.ActiveMQ的异步消息系统

使用标准的web开发工具为web开发者提供了全新的编程理念.本节内容中,我们将探寻ActiveMQ的REST 和 Ajax API.

我们将看到如何在命令行中使用GET和POST这样的HTTP请求发送和接受消息.我们还会展示基于Ajax的stock portfolio

消息消费者,这也展示了如何整合异步消息和Ajax来实现web页面中实时的数据更新.

9.4.1 Using the ActiveMQ REST API

9.4.1 使用ActiveMQ REST API

As you probably know, the term REST first appeared in Roy T. Fielding’s PhD thesis

Architectural Styles and the Design of Network-based Software Architectures (http://mng.bz/

2Xa4). In this work, Fielding explains a collection of network architecture principles

that define how to address and manage resources (in general) over the network. In

simpler terms, if an application implements a RESTful architecture, it usually means

that it exposes its resources using HTTP protocol and in a similar philosophy to those

used on the World Wide Web.

你也许知道, 术语REST首次出现在Roy T. Fielding的博士论文<架构风格和基于网络的软件架构设计>

(http://mng.bz/2Xa4).在这篇论文中,Fielding阐述了一系列的网络架构原则用来定义如何定位和管理

(通常指)网络上的资源.简单的说,如果一一个程序实现了RESTful结构,通常意味着这个程序暴露了其

系统资源,使用HTTP协议或类似方式可以通过互联网访问这些资源.

The web is designed as a system for accessing documents over the internet. Every

resource on the web (HTML page, image, video, and so forth) has a unique address

defined by its URL (uniform resource locator). Resources are mutually interlinked

and transferred between clients and servers using the HTTP protocol. The HTTP GET

method is used to obtain the representation of the resource, and shouldn’t be used to

make any modifications to it. The POST method, on the other hand, is used to send

data to be processed by the server. Apply these principles to your application’s

resources (destinations and messages in case of a JMS broker), and you’ve defined a

RESTful API. Now let’s see how ActiveMQ implements its REST API and how you can

use it to send and receive messages from the broker. Figure 9.2 shows how you can

connect a Java producer (sending messages using the OpenWire protocol) with

almost any consumer that can use standard HTTP connections.

web是一个被设计成在互联网上访问文档的系统.web中的每一个资源(HTML页面,图片,视频等)都有一个

唯一的通过其URL(统一资源定位器)定义的地址.每个资源通过HTTP协议实现在客户端和服务器之间的互

联和传输.HTTP协议中的GET方法用来获取资源,但不能对原始资源做任何修改.POST方法用于发送需要由数据

服务器处理的数据.一旦将这些方法应用到你程序中的资源(比如对于JMS来说是消息目的地和消息)上,你就已经

实现了RESTful API.现在,让我们看看ActiveMQ是如何实现REST API的,以及我们如何使用REST API以便

通过代理发送和接收消息.图9.2展示了任意的消息消费者如何使用标准的HTTP协议连接到Java 消息生产者

(使用OpenWire协议发送消息).

ActiveMQ comes with an embedded web server that starts at the same time your broker

starts. This web server is used to provide all necessary web infrastructure for the

ActiveMQ broker, including the REST API. By default, the demo application is started at

http://localhost:8161/demo and it’s also configured to expose the REST API at the 

following URL: http://localhost:8161/demo/message

ActiveMQ自带一个内嵌的web服务器,并且当启动ActiveMQ代理的时候这个web服务器也会一起启动.

这个web服务器用于为ActiveMQ提供所有必要的web功能,包括提了REST API的实现.默认情况下,代理

启动时一起启动的demo程序可以通过http://localhost:8161/demo访问,并且可以通过配置,将接收

REST API访问的URL设置为:http://localhost:8161/demo/message.

The API is implemented by the org.apache.activemq.web.MessageServlet servlet, and

if you wish to configure an arbitrary servlet container to expose the ActiveMQ REST

API, you have to define and map this servlet in an appropriate web.xml file (of course,

all necessary dependencies should be in your classpath). The following example

shows how to configure and map this servlet to the /message path as it is done in the

demo application:

ActiveMQ的REST API有org.apache.activemq.web.MessageServlet 这个servlet实现.如果你打算

在其他任意的servlet容器中配置以便暴露 ActiveMQ REST API的话,你需要在相应的web.xml中定义

servlet映射(当然,这个servlet的所有依赖都需要放到类路径(classpath)下).下面的配置例子来自demo

程序,展示了如何配置并映射这个servlet到/message路径下:

<servlet>

<servlet-name>MessageServlet</servlet-name>

<servlet-class>org.apache.activemq.web.MessageServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>MessageServlet</servlet-name>

<url-pattern>/message/*</url-pattern>

</servlet-mapping>

When configured like this, broker destinations are exposed as relative paths under the

defined URI. For example, the STOCKS.JAVA topic is mapped to the following URI:

http://localhost:8161/demo/message/STOCKS/JAVA?type=topic

通过这样的配置,代理的消息目的地就通过下面的RUI路径暴露出来.比如,STOCKS.JAVA消息主题就被映射到

下面的URI上:http://localhost:8161/demo/message/STOCKS/JAVA?type=topic

As you can see, a path translation is in place, so destination name path elements (separated

with .) are adjusted to the web URI philosophy where / is used as a separator.

Also, we used the type parameter to define whether we want to access a queue or a topic.

正如你看到的,路径的翻译需要根据相应规则来,因此消息目的地的名称中的的路径分割符(.)需要用URI中

的分隔符/来替代.

Now we can use GET and POST requests to receive and send messages to destinations

(retrospectively). We’ll run some simple examples to demonstrate how you can

use the REST API to communicate with your broker from the command line. For that

we’ll use two popular programs that can make HTTP GET and POST method requests

from the command line. First we’ll use GNU Wget (http://mng.bz/DMf6), a popular

tool for retrieving files using HTTP, to subscribe to the desired destination:

现在,我们可以使用GET和PSOT请求接收和发送消息到消息目的地了.我们将运行一些例子来说明如何

在命令里使用REST API来与代理进行通信.为此,我们将使用连个常用的程序,使用HTTP GET和POST方

法从命令行发送请求.首先,我们使用一个通过HTTP获取文件的流行工具GNU Wget(http://mng.bz/DMf6)

来订阅所需的消息目的地消息

$ wget -O message.txt \

--save-cookies cookies.txt --load-cookies cookies.txt \

--keep-session-cookies \

http://localhost:8161/demo/message/STOCKS/JAVA?type=topic

With this command, we instructed wget to receive the next available message from the

STOCKS.JAVA topic and to save it to the message.txt file. You may also notice that we

keep the HTTP sessions alive between wget calls by saving and sending cookies back to

the server. This is important because the actual consumer API used by the Message-

Servlet is stored in the session. So if you try to receive every message using a new session,

you’ll spawn a lot of consumers unnecessarily and your requests will probably be

left hanging. Also, if you plan to use multiple REST consumers, it’s advisable to set the

prefetch size to 1, just as we did with STOMP consumers. To do that, you have to set

the consumer.prefetchSize initialization parameter value of your message servlet.

The following example shows how to achieve that:

<servlet>

<servlet-name>MessageServlet</servlet-name>

<servlet-class>

org.apache.activemq.web.MessageServlet

</servlet-class>

<load-on-startup>1</load-on-startup>

<init-param>

<param-name>destinationOptions</param-name>

<param-value>consumer.prefetchSize=1</param-value>

</init-param>

</servlet>

Now, it’s time to send some messages to our topic. For that we’ll use cUrl (http://

curl.haxx.se/), a popular command-line tool for transferring files using the HTTP

POST method. Take a look at the following command:

$ curl -d "body=message" \

http://localhost:8161/demo/message/STOCKS/JAVA?type=topic

Here we’ve used the -d switch to specify that we want to POST data to the server. As

you can see, the actual content of the message is passed as the body parameter. The

sent message should be received by our previously run consumer.

This simple example shows how easy it is to use the REST API to do asynchronous

messaging even from the command line. But generally, you should give STOMP a try

(if it’s available for your platform) before falling back to the REST API, because it

allows you more flexibility and is much more messaging-oriented.

9.4.2 Using the ActiveMQ Ajax API

9.4.2 使用ActiveMQ Ajax API

As we said earlier, the option to communicate with the web server asynchronously

changed how developers thought about web applications. In this section we’ll see how

web developers can embrace asynchronous programming even further, by communicating

with message brokers directly from JavaScript.

前文已经说,与web服务器之间异步通信改变了开发者对于web程序的想法.本小节里,我们将看到web

开放人员如何通过使用JavaScript直接和消息代理通信来更好的拥抱异步程序程序开发.

First of all, we should configure our web server to support the ActiveMQ Ajax API.

Similar to the MessageServlet class used for implementing the REST API, ActiveMQ

provides an AjaxServlet that implements Ajax support. Figure 9.3 shows how the

AjaxServlet serves as a mediator between the web browser and the broker. So the

JavaScript clients communicate with the servlet, which connects to the broker as a

standard JMS client.

首先,我们需要配置web服务器支持ActiveMQ Ajax API.与MessageServlet实现了REST API

类似,ActiveMQ使用AjaxServlet试下了对Ajax的支持.图9.3中展示了AjaxServlet做为web浏览器

和代理之间的中介,因而JavaScript客户端可以想一个标准的JMS客户端一样连接到代理,从而实现

与servlet通信.

The following example shows how to configure it in your web application’s WEBINF/

 file:

下面的示例代码展示了如何在web程序的WEBINF/web.xml中进行配置.

<servlet>

<servlet-name>AjaxServlet</servlet-name>

<servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>AjaxServlet</servlet-name>

<url-pattern>/amq/*</url-pattern>

</servlet-mapping>

Of course, in order to make it work properly you have to put ActiveMQ in your web

application’s classpath. Now that we have a server side configured and a servlet listening

to the requests submitted to the URIs starting with /amq/, we can proceed to

implementing the client side of our Ajax application.

当然,为了是配置能正常工作,你需要将ActiveMQ放到web程序的类路径(classpath)下.现在,我们配置好了

服务器端并使用一个servlet来监听来自URI中包含/amq/路径的请求.接下来我们可以实现客户端的Ajax程

序了.

First of all, we have to include the amq.js script, which includes all necessary

JavaScript libraries for us. Also, we have to point the amq.uri variable to the URI our

Ajax servlet listens to. The following snippet shows how to achieve this:

首先,我们需要引入amq.js脚本文件,该文件包含全部所需的JavaScript库.其次,我们还需要设置

 amq.uri变量指向Ajax servlet监听的URI.下面的代码片段完成了这两步配置:

<script type="text/javascript" src="amq/amq.js"></script>

<script type="text/javascript">amq.uri='/amq';</script>

The amq.js script defines a JavaScript object named amq, which provides an API for us

to send messages and subscribe to ActiveMQ destinations. The following example

shows how to send a simple message from our Ajax application:

amq.sendMessage("topic://TEST", "message");

amq.js定义了一个名称为amq的JavaScript对象,该对象为我们提供了发送消息以及订阅ActiveMQ

消息目的地的API.下面的的示例代码展示了如何通过Ajax程序发送一个简单消息:

amq.sendMessage("topic://TEST", "message");

It can’t be much simpler than this: all you have to do is call a sendMessage() method

and provide a destination and the text of the message to be sent.

所有需要你做的就是调用sendMessage()方法并提供一个消息目的地和一个需要被发送的文本消息

,没有比这个更简单的了.

If you wish to subscribe to a certain destination (or multiple destinations), you

have to register a callback function that will be called every time a new message is

available. This is done with the addListener() method of the amq object, which in

addition to a callback function accepts a destination to subscribe to and ID that makes

further handling of this listener possible.

如果你打算订阅某个特定的消息目的地(或多个消息目的地),你需要注册一个回调函数,当接收到一个

新消息时,会调用这个函数.尅通过 amq对象的addListener() 注册回调函数,该函数除了接受一个 回

调函数作为参数外,同时还接受一个订阅的消息目的和一个ID作为参数,使用该ID参数使得进一步处

理这个监听器成为可能.

The ActiveMQ demo application comes with the stock portfolio example we’ve

used throughout the book, adopted to the web environment. The example contains a

servlet that publishes market data and a web page that uses the Ajax API to consume

that data. Using this example, we’ll show how to consume messages using the Ajax

API. Let’s take a look at the code shown in the following listing.

ActiveMQ demo程序是本书一直使用的stock portfolio示例程序为能在web环境中运行而修改后的版本.

这个例子包含一个用于发布市场数据的servlet和一个使用Ajax API处理市场数据的web页面.通过使用这个

例子,我们可以了解如何通过Ajax API处理消息.下面让我们看下下面的示例代码:

Listing 9.18 Consume messages from JavaScript using Ajax API

代码清单9.18 JavaScript 使用 Ajax API处理消息

var priceHandler =

{

_price: 

function(message)

{

if (message != null) 

{

var price = parseFloat(message.getAttribute('bid'))

var symbol = message.getAttribute('stock')

var movement = message.getAttribute('movement')

if (movement == null) 

{

movement = 'up'

}

var row = document.getElementById(symbol)

if (row)

{

// perform portfolio calculations

var value = asFloat(find(row, 'amount')) * price

var pl = value - asFloat(find(row, 'cost'))

// now let’s update the HTML DOM

find(row, 'price').innerHTML = fixedDigits(price, 2)

find(row, 'value').innerHTML = fixedDigits(value, 2)

find(row, 'pl').innerHTML = fixedDigits(pl, 2)

find(row, 'price').className = movement

find(row, 'pl').className = pl >= 0 ? 'up' : 'down'

}

}

}

};

function portfolioPoll(first)

{

if (first)

{

amq.addListener('stocks', 'topic://STOCKS.*', priceHandler._price);

}

}

amq.addPollHandler(portfolioPoll);

For starters, we’ve defined a JavaScript object named priceHandler with the _price()

function we’ll use to handle messages. This function finds an appropriate page element

and updates its value (or changes its class to show whether it’s a positive or negative

change). Now we have to register this function to listen to the stock topics. As you

can see, we’ve named our listener stocks, set it to listen to all topics in the STOCKS

name hierarchy, and defined _price() as a callback function. You can later remove

this subscription (if you wish) by calling the removeListener() function of the amq

object and providing the specified ID (stocks in this case).

首先,我们定义了一个名称为priceHandler的JavaScript对象,该对象含有一个_price()方法用于处理消息.

该方法会查找一个合适的页面元素并更新该页面元素的值(或者改变其class样式以展示变化正向还是负向的).

闲我们已经将这个函数注册为监听 stock提提了.正如你所看到的,我们将监听器命名为stocks,并将其设置为

监听所有以STOCKS开头的主题,同时定义_price()作为回调函数.你可以在稍后通过调用amq对象的

 removeListener()方法传递一个制定的ID(本例中使用的ID是stocks)来移除这个器.

Now we’re ready to run this example. First we’re going to start the portfolio publisher

servlet by entering the following URL in the browser:

http://localhost:8161/demo/portfolioPublish?count=1&refresh=2

&stocks=IBMW&stocks=BEAS&stocks=MSFT&stocks=SUNW

The Ajax consumer example is located at the following address:

http://localhost:8161/demo/portfolio/portfolio.html

现在我们可以预习这个例子了.首先在浏览器地址栏输入

http://localhost:8161/demo/portfolioPublish?count=1&refresh=2&stocks=IBMW&stocks=BEAS&stocks=MSFT&stocks=SUNW

以便启动portfolio的publisher.Ajax 消费者例子的位置为下面的地址:

http://localhost:8161/demo/portfolio/portfolio.html

After starting it, you can expect a page that looks similar to the one shown in figure 9.4.

The page will dynamically update as messages come to the broker. This simple

example shows how Ajax applications can benefit from asynchronous messaging, thus

taking dynamic web pages to a whole new level.

启动后,你将看到一个页面看起来类似于图9.4所示.该页面会根据来自代理的消息动态更新.

从这个简单的例子可以看出,得利于异步消息系统,Ajax 程序可以将动态页面技术提升至一个

新的高度.

猜你喜欢

转载自jackyin5918.iteye.com/blog/1978463
9.4