缓存
Web 服务的客户往往要比一般的客户端-服务器体系结构中的客户要多些;因此在 Web 服务体系结构中,客户端就要做更多的工作,比如缓存。Web 服务正确使用数据缓存就可以实现其最大的性能。当服务的请求信息主要是只读的时候或者当那些信息按照比所要求的速率变化得还要慢时,您就应该考虑要在 Web 服务中使用缓存了。
身份验证与授权使用
您可以在 WSManager 层中执行所有订购者的身份验证。所有想使用 Web 服务的客户都要经过这样的身份验证逻辑。您可以使用基本用户身份验证或者数字证书来实现此目的。
Struts 视图
您要通过使用 JSP 技术来构建基于 Struts 应用程序的视图部分。JSP 页包含有静态 HTML 加上 动态内容,这些内容是基于对特别行为标签说明(在页面要求时)的。JSP 环境包括一套标准的行为标签。另外,在自定义标签库中组织了一套标准的工具,开发者们可以使用这些工具来定义他们自己的标签。
Struts 框架包含有扩展的自定义标签库,这个库能帮助用户界面国际化更为全面并能非常适度地与 ActionForm 组件相互作用。视图层比较单薄,它不提供业务逻辑。Struts 视图是通过 ActionForm 与 Struts 控制器相互作用的。
Struts ActionForm
ActionForms 只是一些 Java 类而已,它继承了 Struts 所提供的 ActionForm 类,这些类中包含有 accessor 和 mutator 方法。 JSP 页或者 Action 类都会调用这些方法来检索或者从数据库刷新数据。
模型服务
模型服务是作为一组 Java 类来执行的。每个模型服务组件都会提供一套服务,而这些组件结合起来同样也提供一套普通服务。 ActionController 与 WSManager 类将数据当作预定义的数据访问对象来回传送。在处理过程中,ActionController 或者 WSManager 可以调用相关模型服务组件中所要求的方法。这些组件将所要求的数据以数据访问对象的形式传给模型服务,模型服务执行一切必须的商业逻辑处理然后从存储数据仓库中取出所需要的数据。模型服务组件聚集相关的预定义数据访问对象,然后将它传回给 ActionServlet 或者 WSManager 类。所有的错误或者确认信息都会通知给 ActionServlet 或 WSManager 层。
对于您的应用程序,您应该遵守以下的设计规则:
1. 模型服务不能含有任何与视图相关的代码(例如,会话处理)。
2. 所有的事务仅仅只能在 Action 或 WSManager 层中来提交。
3. 模型服务只能被同一模型服务组件中其他的模型服务或者高层 Action 类所调用。
数据存储层
数据存储层由所有的存储数据仓库组成。例如,它可能包含有关系数据库、平面文件或者甚至有 XML 文档。
示例
我已经附上了实现此处所讨论的体系结构的一个简单示例。所有的示例代码都包含在了 zip文件 中。这个例子举例说明了一个简单的新闻 Portal。新闻内容是从数据源(这里称为 DataSource )传送到 JSP 页,同时信息内容也要作为一个 Web 服务发布出来。这个 Portal 也可以从 StockQuote Web 服务中检索最新的股票报价并显示在同一个 JSP 页中。
这个 zip 文件包含了所有的源代码和 DataSource 的 SQL 脚本。它还包含有 Struts Action 和 ActionForm 类、模型服务类以及用来为发布者与订购者显示结果及其源代码的 JSP 页。它同时还包含有 WSDL 文件以及客户端源代码来访问已发布的 NewsContent Web 服务。
这里我不再阐述示例代码的详细信息了;您想要发现它的复杂性,最好的途径就是自己去试验。开始时,我会向您说明应用程序如何将信息内容(存储在 DataSource 中)和股票信息(从 Web 服务处获得)递交给 JSP 页的。
JSP 页被加载时,它就调用 Action 类,这个类在 MVC 设计模式中充当控制器角色。 Action 类通过传递预定义的数据访问对象来调用模型服务类中的 getNews() 方法。(清单 1 中所示的一小段 Action 类代码说明了如何从 Action 类中调用模型服务。)
getNews() 方法实现了所有必需的业务逻辑与数据检索逻辑。一旦从数据源取出了相关数据,模型服务就可以聚集数据访问对象并将它发送回给 Action 类。
清单 1. Action 类的部分代码
从模型服务处接收到数据访问对象后, Action 类通过传递转给模型服务的同一个数据访问对象来调用 WSManager 类中的 getStocks() 方法。 WSManager 类中的 getStocks() 方法执行 JAX-RPC 来订购股票 Web 服务。/* * Create a pre-defined Data Access Object */ newsSearchResultVOB = new NewsSearchResult(); /* * Call Business layer NewsMs's searchNews method passing the NewsCOD * and get back a Collection of News */ newsList = (Vector) newsMs.getNews(newsSearchResultVOB); /* * Put the NewsList in the request. * */ request.setAttribute(SystemConstants.NEWS_LIST, newsList); //Set the newslist in the form newsFrm.setNewsDetails(newsList); // Set the NewsForm in the request request.setAttribute(mapping.getAttribute(), newsFrm); //return actionForward; return mapping.findForward("success");
从股票 Web 服务获得的结果要转变成本地的 schema 并且聚集回到预定义数据访问对象中去。这个对象从它被调用的地方传回到 action 类。 清单 2 阐明了如何使用 WSManager 中的 JAX-RPC 来订购 Web 服务,以及如何将股票 Web 服务的结果转变成本地 schema 并聚集回到数据访问对象中去。
清单 2. 订购 Web 服务及传送响应
一旦 Action 类调用完模型服务和 WSManager, ActionForm 中的股票值及信息内容域就会被填充。控制就被返回到 JSP 页面,从 ActionForm 获取所有必需的值并打印 UI.public Vector getStocks() throws Exception { //Method level variables Vector stockValues = new Vector(); try { // create service factory javax.xml.rpc.ServiceFactory factory = javax.xml.rpc.ServiceFactory.newInstance(); // define targetNameSpace String targetNamespace = "http://www.themindelectric.com/" + "wsdl/net.xmethods.services.stockquote.StockQuote/"; // define qname QName serviceName = new QName(targetNamespace, "net.xmethods.services.stockquote.StockQuoteService"); // define portname QName portName = new QName(targetNamespace, "net.xmethods.services.stockquote.StockQuotePort"); // define operation name QName operationName = new QName("urn:xmethods-delayed-quotes", "getQuote"); //Specify wsdl location java.net.URL wsdlLocation = new java.net.URL("http://services.xmethods.net/soap/urn:xmethods- delayed-quotes.wsdl"); // create service javax.xml.rpc.Service service = factory.createService(wsdlLocation, serviceName); // create call javax.xml.rpc.Call call = service.createCall(portName, operationName); //Populate an array with list of stock names Vector populatedStockNames = this.getPopulatedList(); //Loop through the populated list, and for each stock get a result java.util.Iterator i = this.getPopulatedList().iterator(); String stockName = null; Float result; com.ddj.wsstruts.valueobject.StockValue stockValue = null; while(i.hasNext()) { stockName = (String) i.next(); // invoke the remote web service result = (Float) call.invoke(new Object[] {stockName}); if(category.isDebugEnabled()) { category.debug(" The quote for " + stockName + " is: " + result); } //Set stock name and stock values in stockValue bean stockValue = new com.ddj.wsstruts.valueobject.StockValue(); stockValue.setStockName(stockName); stockValue.setStockValue(result.toString()); //Add the stockValue bean to stockValues vector stockValues.add(stockValue); } }