利用 Amazon Web Services 集成企业应用程序--使用 Amazon SQS 发送 XML 消息(4)

 最后一个步骤是,当成功处理库存发货之后,将订单汇总队列项从消息队列中删除。清单 19 显示了如何使用 C# 从 Amazon SQS 队列删除消息。
  清单 19. DeleteMessage() 方法

				
public bool DeleteMessage(string queueName, string messageHandle) {
bool result = false;
try {
  String accessKeyId = 
           ConfigurationSettings.AppSettings["AmazonAccessKeyID"];
  String secretAccessKey = 
           ConfigurationSettings.AppSettings["AmazonSecretAccessKey"];
  AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
 
  // Create delete message request object
  DeleteMessageRequest request = new DeleteMessageRequest();
  
  // Set queue name containing item to be deleted
  request.QueueName = queueName;
  
  // Set handle of message to be deleted
  request.ReceiptHandle = messageHandle;
  
  // Delete message
  DeleteMessageResponse response = service.DeleteMessage(request);
  Debug.WriteLine("Service Response");                
 
  Debug.WriteLine("\tDelete Message Response");
  // If message response
  if (response.IsSetResponseMetadata())
  {
           Debug.WriteLine("\tResponse Metadata");
           ResponseMetadata responseMetadata = response.ResponseMetadata;
           if (responseMetadata.IsSetRequestId())
           {
                   Debug.WriteLine(String.Format("\tRequest Id: {0}", 
                            responseMetadata.RequestId));
           }
  }
}
catch (AmazonSQSException ex)
{
  Debug.WriteLine("Caught Exception: " + ex.Message);
  Debug.WriteLine("Response Status Code: " + ex.StatusCode);
  Debug.WriteLine("Error Code: " + ex.ErrorCode);
  Debug.WriteLine("Error Type: " + ex.ErrorType);
  Debug.WriteLine("Request ID: " + ex.RequestId);
  Debug.WriteLine("XML: " + ex.XML);
}
 
return result;
}

  制造商实现
  该解决方案的最后一个组件是制造商的 Order Processing Service,它是基于 Java 的服务,负责处理来自分销商的订单。Order Processing Service:
  轮询购买订单队列,该队列包含由分销商发送的购买订单。
  在收到购买订单之后,它创建一个订单汇总,并使用另一个 Amazon SQS 队列将其发送回给分销商。
  删除分销商发送来的购买订单。
  制造商应用程序包含 表 5 中的业务实体。
  表 5. 制造商应用程序中的业务实体

描述
AddresssEntity
包含一个客户或业务地址
CustomerOrderEntity
包含客户订单(购买订单)
CustomerOrderDetailEntity
包含每个客户订单(购买订单)的商品细节
MessageQueueEntity
包含消息队列项(即购买订单或订单汇总)
OrderSummaryEntity
包含订单发货汇总
OrderSummaryDetailEntity
包含订单发货汇总的商品细节

  这个解决方案对所有数据库操作使用 JdbcQuery 帮助类。此外,还使用另外两个帮助类:DateUtil 用于格式化数据;AppConfig 用于读取配置参数。SqsDataProvider 类同时也是提供 Amazon SQS 功能的实用程序类。
  制造商订单处理服务
  OrderProcessingService 类负责根据在 AppConfig.properties 文件中指定的轮询时间间隔处理购买订单。该服务获取尚未发货的购买订单列表,并处理这些订单。清单 20 中的 getMessageQueueItems 方法展示了如何使用 Java 代码从特定的 Amazon SQS 队列获取消息列表。
  清单 20. getMessageQueueItems() 方法

				
protected ArrayList<HashMap<String, String>> getMessageQueueItems(String queueName) {
ArrayList<HashMap<String, String>> results = new ArrayList<HashMap<String, String>>();
 
try {
  String accessKeyId = AppConfig.getProperty("AmazonAccessKeyID");
  String secretAccessKey =  AppConfig.getProperty("AmazonSecretAccessKey");
 
  AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
  
  // get messages from queue
  ReceiveMessageRequest request = new ReceiveMessageRequest();
  request.setQueueName(queueName);
  request.setVisibilityTimeout(1);
  
  ReceiveMessageResponse response = service.receiveMessage(request);
  
  // if received response
  if (response.isSetReceiveMessageResult()) {
           System.out.println("\tReceive Message Result");
           ReceiveMessageResult receiveMessageResult = 
                   response.getReceiveMessageResult();
           
           // get all messages and iterate through them
           List<Message> messageList = receiveMessageResult.getMessage();
           for (Message message : messageList) {
                   // build hashmap containing each message
                   HashMap<String, String> row = new HashMap<String, String>();
                   
                   if (message.isSetMessageId()) {
                            row.put(COLUMN_ID, message.getMessageId());
                            System.out.println("\t\tMessageId: " + 
                                     message.getMessageId());
                   }
                   if (message.isSetReceiptHandle()) {
                            row.put(COLUMN_HANDLE, message.getReceiptHandle());
                   }
                   if (message.isSetBody()) {                                   
                            row.put(COLUMN_MESSAGE, message.getBody());
                   }
                   
                   // add row
                   results.add(row);
           }
  }        
} catch (AmazonSQSException ex) {
  System.out.println("Caught Exception: " + ex.getMessage());
  System.out.println("Response Status Code: " + ex.getStatusCode());
  System.out.println("Error Code: " + ex.getErrorCode());
  System.out.println("Error Type: " + ex.getErrorType());
  System.out.println("Request ID: " + ex.getRequestId());
  System.out.println("XML: " + ex.getXML());
}
 
return results;
}
Java 技术不像 .NET 框架那样具有内置的 XML 系列化功能,因此使用 JDOM API 来生成 XML 文档。JDOM 类似于 DOM,但它提供一个简单的 Java API 来解析、操作和输出 XML。参见 参考资料 了解关于如何使用 JDOM 的信息。

  PurchaseOrderSerializer 类负责将消息中的 XML 内容反序列化到 Java 类。您将使用 JDOM 来解析 XML 内容,如 清单 21 所示。(对于理解这段代码,参考 清单 7 中的购买订单模式会有帮助)。
  清单 21. PurchaseOrderSerializer 类

				
public class PurchaseOrderSerializer {

public CustomerOrderEntity deserializePO(MessageQueueEntity message) {
  CustomerOrderEntity order = null;
  
  String xml = message.getMessageBody();
  System.out.println("Purchase Order:\n" + xml);
  
  try {
           // Create input source from string containing XML
           InputSource xmlIS = new InputSource();
           xmlIS.setCharacterStream(new StringReader(xml));
           
           // Initialize SAX Builder object
           SAXBuilder builder = new SAXBuilder();
 
           // Build JDOM Document object from input source
           Document doc = builder.build(xmlIS);
           Element rootElem = doc.getRootElement();
           
           // get order id
           String id = rootElem .getChildText("Id");        
           
           // create customer order 
           order = new CustomerOrderEntity(id);
           
           // set order date
           String dateStr = rootElem.getChildText("OrderDate");
           order.setOrderDate(DateUtil.getDate(dateStr));
            
           // get company (customer) address element node and parse it
           Element addrElem = rootElem.getChild("Company");
           this.setCompanyAddress(order, addrElem);

           // get vendor address element node and parse it
           addrElem = rootElem.getChild("Vendor");
           this.setVendorAddress(order, addrElem);

           // get order items list and parse it
           Element itemsElem = rootElem.getChild("Items");
           this.setOrderItems(order, itemsElem);
           
           System.out.println(order.toString());
  } catch (IOException e) {
           e.printStackTrace();
  } catch (NullPointerException e) {
           e.printStackTrace();
  } catch (JDOMException e) {
           e.printStackTrace();
  }
  return order;
}
 
private void setVendorAddress(CustomerOrderEntity order, Element addrElem) {
  // get data from xml
  String coName = addrElem.getChildText("CompanyName");
  String streetAddress = addrElem.getChildText("StreetAddress");
  String city = addrElem.getChildText("City");
  String state = addrElem.getChildText("State");
  String zipCode = addrElem.getChildText("ZipCode");
  
  AddressEntity coAddress = order.getVendorAddress();
   
  // build address entity object using data read from xml
  AddressEntity coAddress = order.getCompanyAddress();
  coAddress.setCity(city);
  coAddress.setCompanyName(coName);
  coAddress.setStreetAddress(streetAddress);
  coAddress.setState(state);
  coAddress.setZipCode(zipCode);
}
  
private void setCompanyAddress(CustomerOrderEntity order, Element addrElem) {
  // get data from xml
  String coName = addrElem.getChildText("CompanyName");
  String streetAddress = addrElem.getChildText("StreetAddress");
  String city = addrElem.getChildText("City");
  String state = addrElem.getChildText("State");
  String zipCode = addrElem.getChildText("ZipCode");
  
  // build address entity object using data read from xml
  AddressEntity coAddress = order.getCompanyAddress();
  coAddress.setCity(city);
  coAddress.setCompanyName(coName);
  coAddress.setStreetAddress(streetAddress);
  coAddress.setState(state);
  coAddress.setZipCode(zipCode);
}
 
private void setOrderItems(CustomerOrderEntity order, Element itemsElem) {
  List itemList = itemsElem.getChildren();
  if (itemList == null) return;
  
  // iterate through all items in collection
  for (int index = 0; index < itemList.size(); index++) {
           // get current element
           Element curElem = (Element) itemList.get(index);
           
           // get item values
           String itemId = curElem.getAttributeValue("Id");
           String itemName = curElem.getAttributeValue("Name");
           String quantity = curElem.getAttributeValue("Quantity");
           
           // create order item
           CustomerOrderDetailEntity detail = new CustomerOrderDetailEntity();
           detail.setItemId(itemId);
           detail.setItemName(itemName);
           detail.setQuantity(Integer.parseInt(quantity));
  
           // add order item to order summary
           order.addItem(detail);
  }
}
}

  接下来,为购买订单构建订单汇总。清单 22 显示了所需的代码。
  清单 22. getOrderSummaryForCustomerOrder() 方法

				
public OrderSummaryEntity getOrderSummaryForCustomerOrder(
	CustomerOrderEntity customerOrder) {
	
	if (customerOrder == null) return null;
	
	// create order
	OrderSummaryEntity orderSummary = new OrderSummaryEntity();
	orderSummary.setOrderDate(new Date());
	orderSummary.setReferenceId(customerOrder.getId());
	
	// set addresses
	orderSummary.setCompanyAddress(customerOrder.getVendorAddress());
	orderSummary.setCustomerAddress(customerOrder.getCompanyAddress());
	
	// add items
	Iterator<CustomerOrderDetailEntity> itemIter = customerOrder.getItems();
	while(itemIter.hasNext()) {
		CustomerOrderDetailEntity item = itemIter.next();
		
		OrderSummaryDetailEntity detail = new OrderSummaryDetailEntity();
		detail.setItemId(item.getItemId());
		detail.setItemName(item.getItemName());
		detail.setQuantity(item.getQuantity());
		
		orderSummary.addItem(detail);
	}
	
	return orderSummary;
}			

  然后,您必须将 OrderSummaryEntity 系列化到 XML。您需要使用 JDOM 系列化该消息,如 清单 23 所示。(参考 清单 8中的订单汇总模式会有帮助)。
  清单 23. OrderSummarySerializer 类

				
public class OrderSummarySerializer {
	public String serializeOrder(OrderSummaryEntity order) {
		Document doc = new Document();
		
		Element rootElem = new Element("OrderSummary");
		doc.addContent(rootElem);
		
		// add id
		Element idElem = new Element("OrderId");
		idElem.setText(order.getOrderId());
		rootElem.addContent(idElem);
		
		// add reference id
		Element referenceIdElem = new Element("ReferenceId");
		referenceIdElem.setText(order.getReferenceId());
		rootElem.addContent(referenceIdElem);
		
		// add order date
		Element dateElem = new Element("OrderDate");
		String dateStr = DateUtil.getDateString(new Date());
		dateElem.setText(dateStr);		
		rootElem.addContent(dateElem);
		
		// set company address
		Element addrElem = this.getElementForAddress("CompanyAddress", 
			order.getCompanyAddress());
		rootElem.addContent(addrElem);
		
		// set customer address
		addrElem = this.getElementForAddress("CustomerAddress", 
			order.getCustomerAddress());
		rootElem.addContent(addrElem);
		
		// iterate through all items and add each item to order
		Element itemsElem = new Element("Items");
		Iterator<OrderSummaryDetailEntity> itemIter = order.getItems();
		while(itemIter.hasNext()) {
			OrderSummaryDetailEntity item = itemIter.next();
			
			Element itemElem = new Element("Item");
			itemElem.setAttribute("ItemId", item.getItemId());
			itemElem.setAttribute("ItemName", item.getItemName());
			String quantityStr = String.valueOf(item.getQuantity());
			itemElem.setAttribute("Quantity", quantityStr);
			
			itemsElem.addContent(itemElem);
		}
		rootElem.addContent(itemsElem);
		
		// convert xml document to string
		XMLOutputter outp = new XMLOutputter();
		StringWriter strWriter = new StringWriter();        
		try {
			outp.output(doc, strWriter);
		} catch (IOException e) {
			e.printStackTrace();
		}		
		return strWriter.toString();
	}

	private Element getElementForAddress(String elemName, AddressEntity address) {
		Element addrElem = new Element(elemName);
		
		String coName = address.getCompanyName();
		String streetAddress = address.getStreetAddress();
		String cityName = address.getCity();
		String stateName= address.getState();
		String zipCode = address.getZipCode();
		
		Element coElem = new Element("CompanyName");
		coElem.setText(coName);
		addrElem.addContent(coElem);
		
		Element streetElem = new Element("StreetAddress");
		streetElem.setText(streetAddress);
		addrElem.addContent(streetElem);
		
		Element cityElem = new Element("City");
		cityElem.setText(cityName);
		addrElem.addContent(cityElem);
		
		Element stateElem = new Element("State");
		stateElem.setText(stateName);
		addrElem.addContent(stateElem);
		
		Element zipCodeElem = new Element("ZipCode");
		zipCodeElem.setText(zipCode);
		addrElem.addContent(zipCodeElem);
		
		return addrElem;
	}
}			

  使用 Amazon Java API 将 XML 消息发送到 Amazon SQS 队列。清单 24 显示了如何发送消息。
  清单 24. sendMessage() 方法

				
protected boolean sendMessage(String queueName, String messageBody) {
boolean result = false;
try {
	String accessKeyId = AppConfig.getProperty("AmazonAccessKeyID");
	String secretAccessKey =  AppConfig.getProperty("AmazonSecretAccessKey");

	AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
	
	SendMessageRequest request = new SendMessageRequest();
	request.setQueueName(queueName);
	request.setMessageBody(messageBody);
	
	SendMessageResponse response = service.sendMessage(request);
	// Send Message Response
	if (response.isSetSendMessageResult()) {
		System.out.println("\tSend Message Result");
		SendMessageResult sendMessageResult = response.getSendMessageResult();
		if (sendMessageResult.isSetMessageId()) {
			System.out.println("\t\tMessageId: " + 
				sendMessageResult.getMessageId());
			result = true;
		}
	} 		
} catch (AmazonSQSException ex) {
	System.out.println("Caught Exception: " + ex.getMessage());
	System.out.println("Response Status Code: " + ex.getStatusCode());
	System.out.println("Error Code: " + ex.getErrorCode());
	System.out.println("Error Type: " + ex.getErrorType());
	System.out.println("Request ID: " + ex.getRequestId());
	System.out.println("XML: " + ex.getXML());
}

return result;
}

  最后,您必须从 Amazon SQS 队列删除购买订单队列项。清单 25 显示了如何删除消息。
  清单 25. deleteMessage() 方法

				
protected boolean deleteMessage(String queueName, String handle) {
boolean result = false;

try {
	String accessKeyId = AppConfig.getProperty("AmazonAccessKeyID");
	String secretAccessKey =  AppConfig.getProperty("AmazonSecretAccessKey");

	AmazonSQS service = new AmazonSQSClient(accessKeyId, secretAccessKey);
	DeleteMessageRequest request = new DeleteMessageRequest();
	request.setQueueName(queueName);
	request.setReceiptHandle(handle);
	
	DeleteMessageResponse response = service.deleteMessage(request);

	// Delete Message Response
	if (response.isSetResponseMetadata()) {
		// Response Metadata
		ResponseMetadata  responseMetadata = response.getResponseMetadata();
		if (responseMetadata.isSetRequestId()) {
			System.out.print("RequestId: " + 
				responseMetadata.getRequestId());
			result = true;
		}
	} 
} catch (AmazonSQSException ex) {
	System.out.println("Caught Exception: " + ex.getMessage());
	System.out.println("Response Status Code: " + ex.getStatusCode());
	System.out.println("Error Code: " + ex.getErrorCode());
	System.out.println("Error Type: " + ex.getErrorType());
	System.out.println("Request ID: " + ex.getRequestId());
	System.out.println("XML: " + ex.getXML());
}

return result;
}

  测试解决方案
  现在,您可以测试这个解决方案了。为此,为库存不足的商品提交一个订单。然后,您可以跟踪整个过程:
  提交订单
  分销商推迟订单并创建一个购买订单
  制造商接收订单并向分销商发送订单汇总
  分销商收到订单汇总并处理推迟的订单
  图 6 中的分销商客户端在添加新订单之前显示库存余量。
  图 6. 浏览库存
列出库存商品及其数量的库存管理窗口的屏幕截图
  图 7 显示了订单提交窗口。
  图 7. 提交订单
Customer Order 窗口屏幕截图,订单请求的商品数量大于库存列出的数量
  图 8 显示了 Browse Orders 窗口。
  图 8. 浏览订单
列出已处理和未处理订单的 Browse Orders 窗口屏幕截图,还列出了 ID、客户名、订单日期、发货日期和订单是否被推迟
  在添加了新的订单之后,图 9中的窗口显示了当该订单被推迟时的订单完成服务的输出。
  图 9. 分销商订单完成和库存管理服务
分销商订单完成和库存管理服务的输出消息的屏幕截图
  在添加了新的订单之后,图 10 中的窗口显示了 POQueue 消息队列的内容。
  图 10. 查看消息队列
带有消息的 View Queues 窗口的屏幕截图
  制造商接收来自消息队列的购买订单并处理它。图 11 显示了制造商的订单处理系统的输出。
  图 11. 制造商的订单管理服务
制造商的订单管理服务发出的消息的屏幕截图
  结束语
  本文演示了如何利用 XML 和 Amazon SQS Web 服务集成企业业务应用程序。通过将 XML 的扩展性和 Amazon SQS 结合起来可以提供灵活的、伸缩性强的应用程序。这个解决方案的主要益处是伸缩性、扩展性和集成的便捷性。该集成不需要考虑任何防火墙或安全问题。这个解决方案的最后一个好处是 —— 同时也是 Web 服务的关键驱动力 —— 它是跨平台的,并且不受所采用技术的技术的影响。制造商和分销商在集成业务流程以促进运营效率和提高投资收益时,仍然可以保留现有的技术平台。
  这个解决方案也存在一些局限性。首先,Amazon SQS 的消息体的最大尺寸为 8KB。您可以通过其他可行的办法绕过这一限制:
  使用 Amazon Simple Storage Service (Amazon S3) 存储大型 XML 文档,并为 Amazon SQS 消息中的 Amazon S3 项添加一个句柄。
  使用 Amazon SimpleDB 存储结构化数据,并为 Amazon SQS 消息中的项添加句柄。
  第二个限制是 Amazon 应用于队列的最终一致性方法。这有好的一面也有坏的一面,但 Amazon 肯定认为其好处是多于坏处的。该解决方案的最后一个限制就是没有优先级或 FIFO 方法。再次强调一下,Amazon 是有意这样设计的,因为它能提供伸缩性更强、可用性更高以及更可靠的解决方案。
  如果您在消息体中使用 XML 进行数据交换,最佳实践建议您执行 XML Schema (XSD) 验证,以确保发送器和接收器使用相同的语言。就像在其他 XML 集成项目中一样,发送器和接收器需要使用通用的模式。
  分销商应用程序 C# 项目,NETSolution.zip:temp_10022811053568.zip
  制造商应用程序 Java 项目,JavaSolution.zip:temp_10022811077169.zip
  配置脚本,DbScripts.zip:temp_10022811085897.zip

(责任编辑:)

分享到:

更多
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
  • 微笑/wx
  • 撇嘴/pz
  • 抓狂/zk
  • 流汗/lh
  • 大兵/db
  • 奋斗/fd
  • 疑问/yw
  • 晕/y
  • 偷笑/wx
  • 可爱/ka
  • 傲慢/am
  • 惊恐/jk
用户名: 验证码:点击我更换图片
资料下载专区
图文资讯

如何运维网站能让其稳定高效之稳定篇

如何运维网站能让其稳定高效之稳定篇

作为一名运维工程师,工作中最大的希望就是自己运维的网站能够稳定高效运行,但理想很...[详细]

黑客、Geek等高手们都是这样上网的

黑客、Geek等高手们都是这样上网的

电脑高手们都会尽可能地寻找各种快捷高效的操作方式,譬如很多快速启动类的工具(如Exe...[详细]

如何选择最佳的数据中心闪存?

如何选择最佳的数据中心闪存?

全闪存数据中心是个未来概念,同样还有不少方法实现数据中心内服务器或基于阵列的闪存...[详细]

手机解锁:图案、数字谁更强?

手机解锁:图案、数字谁更强?

手机九宫格解锁到底安全不?九宫格能画出多少图案啊?我自己设置的九宫格总是被同学分...[详细]

黑客声称一款流行的加密App竟然只用了异或

黑客声称一款流行的加密App竟然只用了异或加密!

一名黑客生成加密程序的作者竟然没有实现其核心的功能:加密! 这位ID为NinjaDoge24(...[详细]

返回首页 返回顶部