覆盖Spring-WS2.x的所有关键特性一直是本书的主要目标。
然而,在最后两章中,详细介绍了使用REST风格和使用Spring远程调用功能进行基于契约的Web服务开发的不同方法。
第一章,构建SOAPWeb服务:本章涵盖了在HTTP、JMS、XMPP和电子邮件协议上设置SOAPWeb服务。它还涵盖了使用DOM、JDOM、XPath和Marshaller等技术来实现Web服务端点的不同实现。
第二章,为SOAPWeb服务构建客户端:本章涵盖了使用Spring-WS模板类在HTTP、JMS、XMPP和电子邮件协议上构建SOAPWeb服务客户端。
第三章,测试和监控Web服务:本章解释了如何使用Spring-WS的最新功能测试Web服务,并使用诸如soapUI和TCPMon之类的工具监控Web服务。
第四章,异常/SOAP故障处理:本章解释了在应用程序/系统故障的情况下的异常处理。
第五章,SOAP消息的日志记录和跟踪:在本章中,我们将看到如何记录重要事件并跟踪Web服务。
第六章,编组和对象-XML映射(OXM):我们将在本章中讨论编组/解组技术以及创建自定义编组器。
第九章,RESTfulWeb服务:本章解释了如何使用Spring中的RESTful支持开发RESTWeb服务。
第十章,Spring远程调用:我们将讨论使用Spring远程调用功能进行基于契约的Web服务开发,以将本地业务服务公开为使用Hessian/Burlap、JAX-WS、JMS的Web服务,并使用JAX-WSAPI通过ApacheCXF设置Web服务的方法。
Java知识以及基本的Maven知识是必备的。具有Web服务经验可以使您更容易地在开发环境中使用配方。本书中的基本配方帮助初学者快速学习Web服务主题。
这本书适用于那些具有Web服务经验或初学者的Java/J2EE开发人员。由于本书涵盖了Web服务开发的各种主题,因此那些已经熟悉Web服务的人可以将本书作为参考。初学者可以使用本书快速获得Web服务开发的实际经验。
在本书中,您会发现一些区分不同信息类型的文本样式。以下是一些这些样式的示例,以及它们的含义解释。
文本中的代码词显示如下:“MessageDispatcherServlet是Spring-WS的核心组件。”
代码块设置如下:
mvncleanpackagetomcat:run新术语和重要单词以粗体显示。例如,屏幕上看到的单词,菜单或对话框中的单词会以这种方式出现在文本中:“您可以单击JUnit标签,相邻于Console标签,以查看测试用例是否成功”。
警告或重要说明会显示在这样的框中。
提示和技巧会显示为这样。
在本章中,我们将涵盖:
SOAP(SimpleObjectAccessProtocol)旨在成为语言、传输和平台无关的,这是一种替代传统中间件技术(如CORBA和DCOM)的选择。SOAP也被设计为可扩展的。所谓的WS-*标准——WS-Addressing、WS-Policy、WS-Security等都是基于SOAP协议构建的。
使用SOAP的Web服务,以及WSDL和XML模式,已经成为交换基于XML的消息的标准。SpringWeb服务通过提供一套全面的API和配置,为灵活的Web服务的创建提供了便利。下图显示了Spring-WS在接收到传入消息时的工作方式(图表以抽象形式呈现):
MessageDispatcher是SpringWeb服务的中心点,将Web服务消息分派到注册的端点。在Spring-WS中,请求/响应消息被包装在MessageContext对象中,并且MessageContext将被传递给MessageDispatcher(在调用端点后,响应将被设置到MessageContext中)。当消息到达时,MessageDispatcher使用请求对象获取端点。(将请求映射到端点称为端点映射,可以通过使用应用程序上下文中的bean注册数据、扫描和自动检测注释来完成)。然后,MessageDispatcher通过使用端点,获取端点的拦截器(从零到多个),并在它们上调用handleRequest方法。
拦截器(这里是EndpointInterceptor)拦截请求/响应,在调用端点之前/之后执行一些操作。这个EndpointInterceptor在调用适当的端点之前/之后被调用,执行诸如日志记录、验证、安全等多个处理方面。接下来,MessageDispatcher获取适当的端点适配器,用于调用端点方法。每个适配器都专门用于调用具有特定方法参数和返回类型的方法。
最后,EndpointAdapter调用端点的方法,并将响应转换为所需的形式,并将其设置到MessageContext对象中。现在,最初传递给MessageDispatcher的消息上下文包含了响应对象,该对象将被转发给客户端(由MessageDispatcher的调用者)。
Spring-WS只支持基于契约的开发风格,其中创建契约(XSD或WSDL)是第一步。使用Spring-WS构建基于契约的Web服务的必要步骤如下:
有两种类型的端点,即有效载荷端点和消息端点。虽然消息端点可以访问整个XMLSOAP包络,有效载荷端点只能访问SOAP包络的有效载荷部分,也就是SOAP包络的主体。在本书中,重点是创建有效载荷端点。
为了说明Web服务的构建过程,本书使用了一个虚构的餐厅LiveRestaurant的简单业务场景,该餐厅需要接受来自客户的在线订单。LiveRestaurant决定将其OrderService组件发布为Web服务。为简单起见,OrderService(Java接口)只考虑了两个操作。
项目将遵循以下领域模型:
本书中的每个教程都将逐步构建项目的各个部分,使其成为完整的Web服务应用程序。Java项目名称为LiveRestaurant,每个教程将使用项目的略有不同的版本,带有扩展名_R-x.x。例如,本章的第一个教程将使用LiveRestaurant_R-1.1作为Web服务服务器,LiveRestaurant_R-1.1-Client作为客户端的项目名称。
本章的目标是设置Web服务,因此更多的重点是在服务器端代码和设置的解释上。本章中使用客户端代码来检查服务器的功能。有关客户端代码、设置和测试的更多内容将在接下来的章节中讨论。
基于企业级开源技术的最新现代软件开发需要一代新的构建和项目管理工具。这些工具可以为构建、管理和部署小规模到大规模应用程序提供标准的方式。
Maven是由Apache软件基金会托管的项目管理和自动化构建和部署工具。Maven建立在Ant的功能基础之上,并添加了诸如特性依赖和项目管理等功能。Maven最初用于Java编程,但也可以用于构建和管理其他编程语言编写的项目。近年来,Maven已被用于自动化构建、管理和测试主要开源项目的部署过程。
本教程详细介绍了设置Maven用于构建、测试和部署本书中使用的项目所需的步骤。
本教程需要安装以下软件或工具:
稍后,您可以向自定义存储库添加额外的存储库。您可以通过将activeByDefault设置为false来禁用此存储库(包含存储库的文件位于resources文件夹中):
转到项目的根目录(\chapterOne\LiveRestaurant_R-1.1)并执行:
mvneclipse:eclipse-Declipse.projectNameTemplate="LiveRestaurant_R-1.1"然后,您可以将Maven项目导入Eclipse项目。
如果Maven找不到一个JAR文件,可以使用以下命令使用自定义存储库:
mvn-Pmy-repositorycleanpackagetomcat:run工作原理...mvncleanpackage将所需的组件安装到本地存储库,并创建项目的WAR/JAR文件:
[INFO]Buildingwar:...LiveRestaurant.warmvntomcat:run在Tomcat插件上运行项目的WAR文件。mvnjetty:run在Jetty插件上运行项目的WAR文件:
为了能够设置SpringWeb服务,我们需要一个合同。有四种不同的方法可以为XML定义这样的合同:
DTDs对命名空间的支持有限,因此不适用于Web服务。RELAXNG和Schematron肯定比XMLSchema更容易。不幸的是,它们在各个平台上的支持并不如此广泛。Spring-WS使用XMLSchema。
数据合同是Spring-WS的中心,服务合同可以从数据合同中生成。创建XSD的最简单方法是从样本文档中推断出来。任何良好的XML编辑器或JavaIDE都提供了这种功能。基本上,这些工具使用一些样本XML文档,并从中生成一个模式,用于验证它们。在这个配方中,我们将讨论样本XML数据消息以及如何将它们转换为单个模式文件。生成的模式文件在本书中用作数据合同。
Spring-WS提供了在Java平台上开发Web服务的最简单机制之一。这个配方专注于使用Spring-WS提供的Spring-MVCDispatcherServlet和组件构建一个非常简单的Web服务。
在这个配方中,项目的名称是LiveRestaurant_R-1.2,具有以下Maven依赖项:
在web.xml中配置的DispatcherServlet负责接收所有具有URL映射[/Dispatcher/*]的请求。
DispatcherServlet在拦截HTTP请求并加载Springbean配置文件方面起着重要作用。默认情况下,它通过名称
SimpleUrlHandlerMapping用于使用URL模式将客户端请求重定向到适当的端点。在这里,以*.wsdl结尾的请求URL将被重定向到sampleServiceDefinition(即使用OrderService.wsdl生成响应的SimpleWsdl11Definition),如果请求URL包含/OrderService,它将被重定向到OrderSeviceMessageReceiverEndpoint。SOAPMessageDispatcher用于将SOAP消息分派到已注册的端点(OrderSeviceMessageReceiverEndpoint)。
privateStringxmlToString(Sourcesource){try{StringWriterstringWriter=newStringWriter();Resultresult=newStreamResult(stringWriter);TransformerFactoryfactory=TransformerFactory.newInstance();Transformertransformer=factory.newTransformer();transformer.transform(source,result);returnstringWriter.getBuffer().toString();}catch(TransformerConfigurationExceptione){e.printStackTrace();}catch(TransformerExceptione){e.printStackTrace();}returnnull;}}另请参阅本章中的使用MessageDispatcherServlet设置Web服务食谱。
MessageDispatcherServlet是Spring-WS的核心组件。通过简单的配置,可以在几分钟内设置Web服务。这个servlet作为配置Spring-MVCDispatcherServlet的替代方案而出现。与第二个食谱中使用DispatcherServlet设置Web服务一样,DispatcherServlet需要单独的WebServiceMessageReceiverHandlerAdapter,MessageDispatcher和WsdlDefinitionHandlerAdapter的实例。然而,MessageDispatcherServlet可以通过在应用程序上下文中设置来动态检测EndpointAdapters,EndpointMappings,EndpointExceptionResolvers和WsdlDefinition。
由于这是配置SpringWeb服务的默认方法,因此将在后续配方中使用。在此配方中,详细介绍了设置Spring-WS的基本实现。更高级的实现将在后面的配方设置基于契约的Web服务中解释。
在此配方中,项目名称为LiveRestaurant_R-1.3,具有以下Maven依赖项:
MessageDispatcherServlet是处理传入SOAP请求的中心元素,借助其他组件(EndpointAdapters,EndpointMappings,EndpointExceptionResolvers和WsdlDefinition)。它结合了DispatcherServlet和MessageDispatcher的属性,以将请求分派到适当的端点。这是建议使用Spring-WS构建Web服务的标准servlet。
由于MessageDispatcherServlet是从FrameworkServlet继承的,它会在类路径中查找名为-servlet.xml的配置文件(您可以使用web.xml中的context-param,contextConfigLocation设置更改配置文件名,如在配方*使用DispatcherServlet设置Web服务中所述)。在本例中,由于web.xml文件中的servlet名称设置为Spring-WS,因此文件spring-ws-servlet.xml是Web服务配置文件。
然后,MessageDispatcherServlet在配置文件中查找端点映射元素,以将客户端请求映射到端点。在这里, 在此方法中,参数源包括传入消息和从该参数中提取调用订单服务的输入参数,然后该方法调用orderService方法,并将传出消息包装在StringSource中,以发送回客户端: 在本章中讨论的配方使用DispatcherServlet设置Web服务,为Web服务设置简单的端点映射和设置基于契约的Web服务。 HTTP是最常见的Web服务协议。但是,Web服务目前是建立在多种传输上的,每种传输都有不同的场景。 JMS在1999年由SunMicrosystems包含在Java2、J2EE中。使用JMS,系统能够同步或异步通信,并基于点对点和发布-订阅模型。SOAPoverJMS继承了JSM的特性,并满足以下要求: SpringWeb服务提供了在JMS协议上设置Web服务的功能,该功能是建立在Spring框架中的JMS功能之上的。在这个配方中,介绍了如何在JMS上设置Spring-WS。 在这个配方中,项目的名称是LiveRestaurant_R-1.4,具有以下Maven依赖项: 在应用程序上下文中,WebServiceMessageListener是MessageListenerContainer中的监听器。消息容器使用connectionfactory连接到目的地(RequestQueue): 在第二章中讨论了在JMS传输上创建Web服务客户端配方,构建SOAPWeb服务的客户端和在第十章中讨论了使用JMS作为底层通信协议暴露Web服务的配方,Spring远程调用。 HTTP容易理解,因此通常被定义和实现,但在任何情况下都不是Web服务的最合适的传输方式。 电子邮件传输的Web服务可以利用存储转发消息传递来提供SOAP的异步传输。此外,电子邮件上没有防火墙问题,那些能够相互通信的应用程序无需设置Web服务器来建立Web服务。这允许在HTTP不适用的许多场景中使用SOAP通过邮件传输。 设置Web服务通过HTTP不适合的原因,以及电子邮件可能作为传输协议的解决方案如下所列: 在这个配方中,介绍了通过电子邮件传输设置Web服务。为了加载应用程序上下文并测试Web服务,使用了一个测试类。这个类还启动和关闭服务器。 在这个配方中,项目的名称是LiveRestaurant_R-1.5,具有以下Maven依赖项: mvncleanpackage........INFO[main]...-CreatingSAAJ1.3MessageFactorywithSOAP1.1Protocol..-Startingmailreceiver[imap://server@packtpubtest.com/INBOX]....Receivedresponse... 当加载应用程序上下文时,MailMessageReceiver启动邮件接收器及其收件箱文件夹(imap://server@packtpubtest.com/INBOX),即临时内存收件箱。加载应用程序上下文后,messageReceiverbean充当基于可插拔策略(monotoringStrategy)监视INBOX文件夹(imap://server@packtpubtest.com/INBOX)上的新消息的服务器监视器,轮询间隔为1000毫秒。storeUri是要监视传入消息的位置(imap://server@packtpubtest.com/INBOX),transportUri是用于发送响应的邮件服务器: MailTransportWebServiceIntegrationTest包含在项目中,用于加载应用程序上下文,设置邮件服务器并测试Web服务。 在第二章中讨论的在电子邮件传输上创建Web服务客户端配方,构建SOAPWeb服务的客户端。 外部HTTP服务器可能能够提供多种功能,但它们不够轻便,需要配置才能设置。 Spring-WS提供了一个功能,可以使用嵌入式Sun的JRE1.6HTTP服务器设置基于HTTP的Web服务。嵌入式HTTP服务器是一个轻量级的独立服务器,可以作为外部服务器的替代方案。在传统的外部服务器中,必须配置Web服务器的配置(web.xml),而嵌入式HTTP服务器不需要任何部署描述符来操作,它唯一的要求是通过应用程序上下文配置服务器的实例。 在这个配方中,介绍了在嵌入式HTTP服务器上设置SpringWeb服务。由于没有外部HTTP服务器,因此使用一个Java类来加载应用程序上下文并启动服务器。 在这个配方中,项目的名称是LiveRestaurant_R-1.6,具有以下Maven依赖项: mvncleanpackageexec:javamvncleanpackageexec:java 具有上下文属性的HTTP服务器使用服务类(orderServiceImpl)设置Web服务端点,并指定上下文内定义的URL(localhost:3478/OrderService)。此服务接口在上下文属性中注册。 然而,服务实现是使用component-scan自动检测的。HttpInvokerProxyFactoryBean为特定服务器URL创建客户端代理。 packagecom.packtpub.liverestaurant.server;publicclassServerStartUp{publicstaticvoidmain(String[]args)throwsIOException{ClassPathXmlApplicationContextappContext=newClassPathXmlApplicationContext("/applicationContext.xml");System.out.println(appContext);charc;//CreateaBufferedReaderusingSystem.inBufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));System.out.println("Enteranycharactertoquit.");c=(char)br.read();appContext.close();}在XMPP传输上设置Spring-WSHTTP通常用作Web服务传输协议。然而,它无法满足异步通信的要求。 XMPP传输上的Web服务能够进行异步通信,客户端无需等待服务端的响应;相反,服务在完成过程后将响应发送给客户端。Spring-WS2.0包括XMPP(Jabber)支持,其中Web服务可以通过XMPP协议进行通信。在这个配方中,介绍了在XMPP传输上设置Spring-WS的过程。由于没有外部HTTP服务器,因此使用一个测试类来加载应用程序上下文。 在这个配方中,项目的名称是LiveRestaurant_R-1.7,具有以下Maven依赖项: mvncleanpackage SamplePlayLoadEndPoint只接收请求并返回响应: publicclassSamplePlayLoadEndPointimplementsPayloadEndpoint{staticLoggerlogger=Logger.getLogger(SamplePlayLoadEndPoint.class);publicSourceinvoke(Sourcerequest)throwsException{returnrequest;}项目中包含一个测试类,用于加载应用程序上下文,设置XMPPWeb服务服务器,并测试Web服务。 在第二章中讨论的在XMPP传输上创建Web服务客户端教程,SOAPWeb服务的客户端。 从Java代码生成WSDL和XSD合同并设置Web服务称为合同后开发。这种方法的主要缺点是Web服务的合同(WSDL或XSD)最终可能会发生变化,如果Java类发生任何更改。通过这种方式,客户端必须更新客户端类,这并不总是令人满意。合同优先方法被引入作为解决合同后瓶颈的替代方法。在合同优先方法中,合同(WSDL或模式)是设置Web服务的主要工件。 合同优先方法相对于合同后方法的一些优点如下: 在本教程中,项目名称为LiveRestaurant_R-1.8,具有以下Maven依赖项: 此注释作为@Component的特化,允许通过类路径扫描自动检测实现类,这在服务器应用程序上下文文件(spring-ws-servlet.xml)中进行了配置: spring-ws-servlet.xml文件中的以下设置会导致应用程序从数据合同(orderService.xsd)自动生成WSDL文件。 因此,Spring-WS建议在开发时通过浏览器自动生成WSDL一次并保存,并使用静态WSDL来公开服务合同。 本章讨论的配方通过注释有效载荷根设置端点,简化使用MessageDispatcherServlet创建Web服务,以及第二章中讨论的为SOAPWeb服务构建客户端配方。 还可以查看第十章中讨论的配方Spring远程调用,了解如何设置基于契约的Web服务。 本配方演示了一个非常简单的端点映射,将Web服务请求映射到Java类方法。 在本配方中,项目名称为LiveRestaurant_R-1.9,具有以下Maven依赖项: 本配方的步骤与前一个配方设置基于契约的Web服务相同,只是端点的注册,即方法端点映射,并在spring-ws-servlet.xml中进行配置。 Spring-WS通过其注解功能进一步简化了复杂Web服务的创建,并减少了XML中的代码和配置。 在这个食谱中,项目的名称是LiveRestaurant_R-1.10,具有以下Maven依赖项: 这个食谱的步骤与设置一个基于契约的Web服务的步骤相同,这里我们想要描述在endpoint类中使用注解的端点映射。 返回类型注释@ResponsePayload指示MessageDispatcher,javax.xml.transform.Source的实例是ResponsePayload。聪明的Spring-WS框架在运行时检测这些对象的类型,并委托给适当的PayloadMethodProcessor。在这种情况下,它是SourcePayloadMethodProcessor,因为输入参数和返回值的类型都是javax.xml.transform.Source。 本章讨论的食谱设置一个与传输无关的WS-Addressing端点和为Web服务设置一个简单的端点映射。 在XML消息中使用HTTP传输信息来路由消息到端点,将数据和操作混合在一起,这些消息将被回复给请求的客户端。 在这个配方中,项目的名称是LiveRestaurant_R-1.11,具有以下Maven依赖项: 这个配方的步骤与通过注释负载根设置端点的步骤相同,只是端点类不同。因此,请按照上述配方的步骤,并使用WS-Addressing标准定义一个新的端点。 Spring-WS允许我们使用XPath表达式和注释从端点方法的签名中提取传递的参数。例如,在端点方法的handleOrderRequest(@RequestPayloadSourcesource)中,如果要查找源对象中任何元素的值,必须使用JavaAPI来提取该值。您可以通过在方法的签名中使用XPath来从传入的XML数据中提取数据来消除在处理程序方法中使用JavaAPI,如下所示:handleOrderRequest(@XPathParam("/OrderRequest/message")Stringmessage)。 这个配方演示了使用注释在端点映射中使用XPath表达式。 在这个配方中,项目的名称是LiveRestaurant_R-1.12,具有以下Maven依赖项: 这个配方的步骤与通过注释负载根设置端点的步骤相同,只是端点处理方法的实现不同。因此,请按照上述配方的步骤,并使用XPath表达式从传入消息中提取数据并创建响应。 注释XpathParam帮助MethodArgumentResolvers(XpathParamMethodArgumentResolver)从XML中提取信息并将节点值绑定到方法参数(使用//cause,整个消息被递归搜索,例如,//lName搜索整个placeRequestRequest消息)。相同的实现也用于方法cancelOrderRequest: 本章讨论了通过注释有效负载根来设置端点的方法。 端点的实现要求我们获取传入的XML消息并提取其数据。在Java中,有各种方法(W3CDOM、SAX、XPath、JAXB、Castor、XMLBeans、JiBX或XStream)用于从输入的XML消息中提取数据,但大多数方法都不是语言中立的。 DOM是为了语言中立而创建的,最初用于JavaScript操作HTML页面。在Java中,W3CDOM库用于与XML数据交互。来自W3CDOM库的类,例如org.w3c.dom.Document、org.w3c.dom.Element、org.w3c.dom.Node和org.w3c.dom.Text,用于从输入的XML消息中提取数据。 在这个配方中,W3CDOM用于从传入的消息中提取数据。 在这个配方中,项目的名称是LiveRestaurant_R-1.13,具有以下Maven依赖项: 这个配方的步骤与通过注释有效负载根设置端点的配方相同,只是端点处理方法的实现不同。因此,按照所述的配方的步骤,并使用DOM从传入的消息中提取数据并创建响应。 @PayloadRoot(namespace=NAMESPACE_URI,localPart="placeOrderRequest")@ResponsePayloadpublicElementhandlePlaceOrderRequest(@RequestPayloadElementplaceOrderRequest)throwsException{StringrefNumber=placeOrderRequest.getElementsByTagNameNS(NAMESPACE_URI,"refNumber").item(0).getTextContent();StringfName=placeOrderRequest.getElementsByTagNameNS(NAMESPACE_URI,"fName").item(0).getTextContent();StringlName=placeOrderRequest.getElementsByTagNameNS(NAMESPACE_URI,"lName").item(0).getTextContent();前面的代码从传入的XML消息(placeOrderRequest)中提取元素refNumber、fName和lName,通过方法getElementsByTagNameNS找到并返回refNumber、fName和lName元素中第一项的文本内容(通过item(0).getTextContent())。 代码的以下部分通过创建placeOrderResponse元素(使用document.createElementNS)来创建传出的XML消息)。然后,它创建子元素refNumber(使用document.createElementNS)并创建此元素的文本(使用createTextNode和appendChild)。然后,它将refNumber元素附加到响应元素placeOrderResponse(使用appendChild方法): Documentdocument=documentBuilder.newDocument();ElementresponseElement=document.createElementNS(NAMESPACE_URI,"placeOrderResponse");ElementcanElem=document.createElementNS(NAMESPACE_URI,"refNumber");TextresponseText=document.createTextNode(orderService.placeOrder(fName,lName,refNumber));canElem.appendChild(responseText);responseElement.appendChild(canElem);returnresponseElement;另请参阅在本章讨论的配方通过注释有效负载根设置端点和在第二章中讨论的配方在HTTP传输上创建Web服务客户端,构建SOAPWeb服务的客户端。 端点的实现要求我们获取传入的XML消息并提取其数据。DOM可以从XML文档中提取数据,但它速度慢,消耗内存,并且具有非常基本的功能。 JDOM文档不会构建到内存中;它是按需构建的(延迟初始化设计模式)。此外,JDOM通过提供标准的基于Java的集合接口,使得在文档树中导航或操作元素更容易。在这个配方中,JDOM用于从传入的消息中提取数据。 在这个配方中,项目的名称是LiveRestaurant_R-1.14,具有以下Maven依赖项: 这个配方的步骤与通过注释有效负载根设置端点配方的步骤相同,只是端点处理方法的实现不同。因此,请按照前述配方的步骤,使用JDOM从传入消息中提取数据,并创建响应。 代码的以下部分通过使用命名空间和XPath对象从传入的XML消息(placeOrderRequest)中提取值refNumber,fName和lName: NamespaceresNamespace=Namespace.getNamespace("tns",NAMESPACE_URI);Elementroot=newElement("placeOrderResponse",resNamespace);Elementmessage=newElement("refNumber",resNamespace);message.setText(orderService.placeOrder(fName,lName,refNumber));root.addContent(message);Documentdoc=newDocument(root);returndoc.getRootElement();另请参阅在本章讨论的配方通过注释有效负载根设置端点和使用DOM处理传入的XML消息。 在第二章中讨论的配方在HTTP传输上创建Web服务客户端,构建SOAPWeb服务的客户端。 JavaArchitectureforXMLBinding(JAXB)是用于对象-XML编组的Java标准。JAXB定义了一个用于从XML文档读取和写入Java对象的程序员API。对象-XML映射通常在类中进行注释。JAXB提供了一组有用的注释,其中大多数具有默认值,使得这种编组工作变得容易。 这个配方演示了如何以非常简单的方式使用JAXB处理Web服务中的传入XML消息。为了简单起见,并且延续之前的配方,相同的配方被重新使用,稍微改进了将XML模式转换为域类的方法,以演示JAXB的用法。 在这个配方中,项目的名称是LiveRestaurant_R-1.15,并且具有以下Maven依赖项: 这个食谱的步骤与食谱通过注释payload-root设置端点的步骤相同,只是端点处理方法的实现不同。因此,按照前述食谱的步骤,并使用JAXBMarshaller/Un-Mashaller将有效载荷转换为POJO。 publicclassOrderServiceImplimplementsOrderService{@ServicepublicclassOrderServiceImplimplementsOrderService{publicStringplaceOrder(StringfName,StringlName,StringrefNumber){return"order-"+fName+"_"+lName+"_"+refNumber;}publicbooleancancelOrder(StringrefNumber){returntrue;}这种方法允许开发人员使用简单的编组技术与Java对象而不是XML代码一起工作。 在本章中讨论的食谱通过注释payload-root设置端点。 在第六章中讨论的食谱使用JAXB2进行编组,编组和对象-XML映射(OXM)-使用编组器和解组器将POJO转换为XML消息/从XML消息转换为POJO。 数据合同是在设置Spring-WS时使用的基本概念。然而,在服务器端/客户端发送/回复SOAP消息之前,验证是一个基本要求。 Spring-WS支持服务器端和客户端消息的验证。在这个食谱中,应用了服务器端验证,当不正确的请求到达服务器或不正确的响应从服务器发送到客户端时,它会抛出异常。 在这个食谱中,项目的名称是LiveRestaurant_R-1.16,具有以下Maven依赖项: 这个食谱的步骤与使用DOM处理传入的XML消息的步骤相同,只是验证请求/响应消息的验证不同。 在第二章中讨论的食谱在HTTP传输上创建Web服务客户端。 使用JavaAPI,如SAAJ,可以生成客户端SOAP消息,并将其传输到/从Web服务。但是,这需要额外的编码和关于SOAP消息的知识。 org.springframework.ws.client.core包含了客户端API的核心功能,可以简化调用服务器端Web服务。 这个包中的API提供了像WebServiceTemplate这样的模板类,简化了Web服务的使用。使用这些模板,您将能够在各种传输协议(HTTP、JMS、电子邮件、XMPP等)上创建Web服务客户端,并发送/接收XML消息,以及在发送之前将对象编组为XML。Spring还提供了一些类,如StringSource和Result,简化了在使用WebServiceTemplate时传递和检索XML消息。 在本章中,前两个教程解释了如何在Eclipse和Maven中设置调用Web服务客户端的环境。 然后我们将讨论如何使用WebServiceTemplate在各种传输协议(HTTP、JMS、电子邮件、XMPP等)上创建Web服务客户端。除此之外,使用XPath表达式设置Web服务客户端这个教程解释了如何从XML消息中检索数据。最后,在最后一个教程使用XSLT转换Web服务消息中,介绍了如何在客户端和服务器之间将XML消息转换为不同格式。为了设置Web服务服务器,使用了第一章中的一些教程,构建SOAPWeb服务,并创建了一个单独的客户端项目,调用服务器端的Web服务。 最简单的Web服务客户端是调用服务器端Web服务的Java类。在这个教程中,介绍了设置调用服务器端Web服务的环境。在这里,客户端的Java类以两种形式调用服务器端的Web服务。第一种是在类的主方法中调用Web服务的Java类。第二种是使用JUnit测试类调用服务器端的Web服务。 这个教程类似于第一章中讨论的使用Maven构建和运行Spring-WS这个教程,构建SOAPWeb服务。 mvneclipse:eclipse-Declipse.projectNameTemplate="LiveRestaurant_R-2.1-Client"如何做...这个教程使用了第一章中讨论的使用JDOM处理传入的XML消息这个教程,构建SOAPWeb服务作为服务器端项目。 mvncleanpackagetomcat:run在客户端上运行Java类时的控制台输出如下: Receivedresponse.... Receivedresponse.. 然后,您将能够自定义传递的参数或设置并运行客户端。 当运行调用Web服务的Java类的主方法时,Eclipse通过以下Java类路径内部运行以下命令: java-classpathcom.packtpub.liverestaurant.client.OrderServiceClient当运行JUnit测试用例时,Eclipse通过内部调用以下命令来运行JUnit框架的测试用例: java-classpathcom.packtpub.liverestaurant.client.OrderServiceClientTest另请参阅在第一章中讨论的使用Maven构建和运行Spring-WS项目和使用JDOM处理传入的XML消息配方, 本章讨论的使用HTTP传输创建Web服务客户端配方。 Maven支持使用命令提示符运行类的主方法以及JUnit测试用例。 在这个配方中,解释了设置Maven环境以调用客户端Web服务。在这里,客户端Java代码以两种形式调用服务器上的Web服务。第一种是在类的主方法中调用Web服务的Java类。第二种使用JUnit调用服务器端Web服务。 在这个配方中,项目的名称是LiveRestaurant_R-2.2(用于服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-2.2-Client(客户端Web服务)的Maven依赖项: 这个配方使用了第一章中讨论的使用DOM处理传入的XML消息配方,构建SOAPWeb服务作为服务器端项目。 java-classpathcom.packtpub.liverestaurant.client.OrderServiceClient要在Maven中设置和运行JUnit测试用例,测试类OrderServiceClientTest应该包含在文件夹src/test/java中,并且测试类名称应该以Test结尾(OrderServiceClientTest)。命令mvncleanpackage运行src/test/java文件夹中的所有测试用例(内部Maven调用): java-classpath...;junit.jar..junit.textui.TestRunnercom.packtpub.liverestaurant.client.OrderServiceClientTest).另请参阅在第一章中讨论的使用Maven构建和运行Spring-WS项目和使用JDOM处理传入的XML消息的配方,构建SOAPWeb服务。 在本章中讨论的在HTTP传输上创建Web服务客户端的配方。 在这个配方中,WebServiceTemplate用于通过HTTP传输从客户端发送/接收简单的XML消息。 在这个配方中,项目的名称是LiveRestaurant_R-2.3(用于服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-2.3-Client(客户端Web服务)的Maven依赖项: 这个配方使用了在第一章中讨论的通过注释负载根来设置端点的配方,构建SOAPWeb服务,作为服务器端项目。以下是如何设置客户端: mvncleanpackagetomcat:runmvncleanpackageReceivedresponse.... 已配置的客户端WebServiceTemplate的applicationContext.xml文件(id="webServiceTemplate")用于发送和接收XML消息。可以从客户端程序中获取此bean的实例以发送和接收XML消息。 messageFactory是SaajSoapMessageFactory的一个实例,它被引用在WebServiceTemplate内。messageFactory用于从XML消息创建SOAP数据包。默认的服务URI是WebServiceTemplate默认使用的URI,用于发送/接收所有请求/响应: JMS(Java消息服务)于1999年由SunMicrosystems作为Java2、J2EE的一部分引入。使用JMS的系统可以同步或异步通信,并基于点对点和发布-订阅模型。SpringWeb服务提供了在Spring框架中基于JMS功能构建JMS协议的Web服务的功能。SpringWeb服务在JMS协议上提供以下通信功能: 在这个配方中,WebServiceTemplate用于在客户端上通过JMS传输发送/接收简单的XML消息。使用一个JUnit测试用例类在服务器端设置并使用WebServiceTemplate发送和接收消息。 在这个配方中,项目的名称是LiveRestaurant_R-2.4,具有以下Maven依赖项: 本配方使用在第一章中讨论的配方在JMS传输上设置Web服务,构建SOAPWeb服务作为服务器端项目。 Receivedresponse.. 已配置客户端WebServiceTemplate的applicationContext.xml文件(id="webServiceTemplate")用于发送和接收XML消息。可以从客户端程序中获取此bean的实例以发送和接收XML消息。messageFactory是SaajSoapMessageFactory的一个实例,被引用在WebServiceTemplate内。messageFactory用于从XML消息创建SOAP数据包。默认服务URI是WebServiceTemplate默认使用的JMSURI,用于发送/接收所有请求/响应。配置在WebServiceTemplate内的JmsMessageSender用于发送JMS消息。要使用JmsMessageSender,defaultUri或JMSURI应包含jms:前缀和目的地名称。一些JMSURI的例子是jms:SomeQueue,jms:SomeTopicpriority=3&deliveryMode=NON_PERSISTENT,jms:RequestQueuereplyToName=ResponseName等。默认情况下,JmsMessageSender发送JMSBytesMessage,但可以通过在JMSURI上使用messageType参数来覆盖使用TextMessages。例如,jms:QueuemessageType=TEXT_MESSAGE。 @TestpublicvoidtestSendReceive()throwsException{InputStreamis=newJmsTransportWebServiceIntegrationTest().getClass().getResourceAsStream("placeOrderRequest.xml");StreamSourcesource=newStreamSource(is);StringResultresult=newStringResult();webServiceTemplate.sendSourceAndReceiveToResult(source,result);XMLAssert.assertXMLEqual("Invalidcontentreceived",expectedResponseContent,result.toString());}另请参阅在第一章中讨论的配方在JMS传输上设置Web服务,构建SOAPWeb服务。 使用SpringJunit对Web服务进行单元测试 在这个示例中,WebServiceTemplate用于在客户端上通过电子邮件传输发送/接收简单的XML消息。使用第一章中讨论的在电子邮件传输上设置Web服务这个示例,构建SOAPWeb服务来设置Web服务。使用JUnit测试用例类来在服务器端设置Web服务,并使用WebServiceTemplate发送/接收消息。 在这个示例中,项目的名称是LiveRestaurant_R-2.5,具有以下Maven依赖项: 这个示例使用第一章中讨论的在电子邮件传输上设置Web服务这个示例,构建SOAPWeb服务作为服务器端项目。 Receivedresponse 配置的客户端WebServiceTemplate(id="webServiceTemplate")的applicationContext.xml文件用于发送和接收XML消息。可以从客户端程序中获取此bean的实例以发送和接收XML消息。messageFactory是SaajSoapMessageFactory的一个实例,被引用在WebServiceTemplate内。messageFactory用于从XML消息创建SOAP数据包。transportURI是一个由WebServiceTemplate使用的URI,指示用于发送请求的服务器。storeURI是一个URI,配置在WebServiceTemplate内,指示用于轮询响应的服务器(通常是POP3或IMAP服务器)。默认URI是WebServiceTemplate默认使用的电子邮件地址URI,用于发送/接收所有请求/响应: @TestpublicvoidtestWebServiceOnMailTransport()throwsException{InputStreamis=newMailTransportWebServiceIntegrationTest().getClass().getResourceAsStream("placeOrderRequest.xml");StreamSourcesource=newStreamSource(is);StringResultresult=newStringResult();webServiceTemplate.sendSourceAndReceiveToResult(source,result);applicationContext.close();XMLAssert.assertXMLEqual("Invalidcontentreceived",expectedResponseContent,result.toString());}另请参阅..在第一章中讨论的在电子邮件传输上设置Web服务这个示例,构建SOAPWeb服务。 XMPP(可扩展消息和出席协议)是一种开放和分散的XML路由技术,系统可以使用它向彼此发送XMPP消息。XMPP网络由XMPP服务器、客户端和服务组成。使用XMPP的每个系统都由唯一的ID(称为JabberID(JID))识别。XMPP服务器发布XMPP服务,以提供对客户端的远程服务连接。 在这个配方中,WebServiceTemplate用于通过XMPP传输在客户端发送/接收简单的XML消息。使用了第一章中的在XMPP传输上设置Web服务配方,构建SOAPWeb服务,来设置一个Web服务。使用了一个JUnit测试用例类来在服务器端设置Web服务,并使用WebServiceTemplate发送和接收消息。 在这个配方中,项目的名称是LiveRestaurant_R-2.6,具有以下Maven依赖项: Receivedresponse.. 已配置客户端WebServiceTemplate的applicationContext.xml文件(id="webServiceTemplate")用于发送和接收XML消息。可以从客户端程序中获取此bean的实例,以发送和接收XML消息。messageFactory是SaajSoapMessageFactory的一个实例,被引用在WebServiceTemplate内。messageFactory用于从XML消息创建SOAP数据包。WebServiceTemplate使用XmppMessageSender发送消息到服务器。默认URI是WebServiceTemplate默认使用的XMPP地址URI,用于发送/接收所有请求/响应: @AutowiredprivateGenericApplicationContextapplicationContext;@TestpublicvoidtestWebServiceOnXMPPTransport()throwsException{StringResultresult=newStringResult();StringSourcesc=newStringSource(requestContent);webServiceTemplate.sendSourceAndReceiveToResult(sc,result);XMLAssert.assertXMLEqual("Invalidcontentreceived",requestContent,result.toString());applicationContext.close();}另请参阅在第一章中讨论的在XMPP传输上设置Web服务配方,构建SOAPWeb服务。 使用SpringJUnit对Web服务进行单元测试 在Java编程中使用XPath是从XML消息中提取数据的标准方法之一。但是,它将XML节点/属性的XPath地址(最终可能非常长)与Java代码混合在一起。 Spring提供了一个功能,可以从Java中提取这些地址,并将它们转移到Spring配置文件中。在这个配方中,使用了第一章中的通过注释有效负载根设置端点配方,构建SOAPWeb服务,来设置一个Web服务服务器。 在这个配方中,项目的名称是LiveRestaurant_R-2.7(用于服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-2.7-Client(用于客户端Web服务)的Maven依赖项: 此食谱使用了在服务器端项目中讨论的通过注释负载根设置端点食谱。 @TestpublicfinalvoidtestPlaceOrderRequest(){DOMResultresult=invokeWS(isPlace);Stringmessage=xpathExpPlace.evaluateAsString(result.getNode());Assert.assertTrue(message.contains("Smith"));}@TestpublicfinalvoidtestCancelOrderRequest(){DOMResultresult=invokeWS(isCancel);Booleancancelled=xpathExpCancel.evaluateAsBoolean(result.getNode());Assert.assertTrue(cancelled);}另请参阅食谱使用XPath表达式设置端点在第一章构建SOAPWeb服务中讨论。 在本章中讨论的食谱在HTTP传输上创建Web服务客户端。 使用SpringJUnit对Web服务进行单元测试。 如食谱设置一个传输中立的WS-Addressing端点中所述,讨论在第一章构建SOAPWeb服务,WS-Addressing是一种替代的路由方式。WS-Addressing将路由数据与消息分开,并将其包含在SOAP头中,而不是在SOAP消息的主体中。以下是从客户端发送的WS-Addressing样式的SOAP消息示例: Spring-WS支持客户端和服务器端的WS-Addressing。要为客户端创建WS-Addressing头,可以使用org.springframework.ws.soap.addressing.client.ActionCallback。此回调将Action头保留为参数。它还使用WS-Addressing版本和To头。 在此食谱中,使用了在第一章构建SOAPWeb服务中讨论的设置一个传输中立的WS-Addressing端点食谱来设置WS-AddressingWeb服务。在这里使用客户端应用程序来调用服务器并返回响应对象。 在此食谱中,项目名称为LiveRestaurant_R-2.8(用于服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-2.8-Client(用于客户端Web服务)的Maven依赖项: 这个配方使用了第一章中讨论的为Web服务设置与传输无关的WS-Addressing端点配方,构建SOAPWeb服务,作为服务器端项目。创建WS-Addressing的客户端与在HTTP传输上创建Web服务客户端配方中描述的方式相同,不使用WebServiceTemplate。为了在客户端上添加WS-Addressing头,WebServiceTemplate的sendSourceAndReceiveToResult方法获得一个ActionCallBack实例。 已配置的客户端WebServiceTemplate的applicationContext.xml文件(id="webServiceTemplate")用于发送和接收XML消息,如*在HTTP传输上创建Web服务客户端*配方中描述的,除了使用WebServiceTemplate`的Java类的实现。 在第一章中讨论的为Web服务设置与传输无关的WS-Addressing端点配方,构建SOAPWeb服务。 在本章中讨论的在HTTP传输上创建Web服务客户端配方。 最终,Web服务的客户端可能使用不同版本的XML消息,要求在服务器端使用相同的Web服务。 SpringWeb服务提供PayloadTransformingInterceptor。这个端点拦截器使用XSLT样式表,在需要多个版本的Web服务时非常有用。使用这个拦截器,您可以将消息的旧格式转换为新格式。 在这个配方中,使用第一章中的为Web服务设置简单的端点映射配方,构建SOAPWeb服务,来设置一个Web服务,这里的客户端应用程序调用服务器并返回响应消息。 在这个配方中,项目的名称是LiveRestaurant_R-2.9(用于服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-2.9-Client(客户端Web服务)的Maven依赖项: 这个配方使用了第一章中讨论的为Web服务设置简单的端点映射配方,构建SOAPWeb服务,作为服务器端项目。客户端与在HTTP传输上创建Web服务客户端配方中讨论的相同,除了XSLT文件及其在服务器端应用程序上下文文件中的配置: mvncleanpackagetomcat:runmvncleanpackageReceivedresponse... 唯一的区别是服务器应用程序上下文文件。spring-servlet.xml中的transformingInterceptorbean使用oldRequests.xslt和oldResponse.xslt分别将旧的请求XML消息转换为服务器的更新版本,反之亦然: . 新的软件开发策略需要全面的测试,以实现软件开发过程中的质量。测试驱动设计(TDD)是开发过程的一种演进方法,它结合了测试优先的开发过程和重构。在测试优先的开发过程中,您在编写完整的生产代码之前编写测试以简化测试。这种测试包括单元测试和集成测试。 Spring提供了使用spring-test包的集成测试功能支持。这些功能包括依赖注入和在测试环境中加载应用程序上下文。 编写一个使用模拟框架(如EasyMock和JMock)测试Web服务的单元测试非常容易。但是,它不测试XML消息的内容,因此不模拟测试的真实生产环境。 SpringWeb-Services2.0提供了创建服务器端集成测试以及客户端集成测试的功能。使用这些集成测试功能,可以在不部署在服务器上时测试SOAP服务,当测试服务器端时,而在测试客户端时无需设置服务器。 在第一个配方中,我们将讨论如何使用Spring框架进行集成测试。在接下来的两个配方中,详细介绍了Spring-WS2.0的集成测试的新功能。在最后两个配方中,介绍了使用soapUI和TCPMon等工具监视和测试Web服务。 Spring支持使用org.springframework.test包中的类进行集成测试。这些功能使用生产应用程序上下文或任何用于测试目的的自定义应用程序上下文在测试用例中提供依赖注入。本教程介绍了如何使用具有功能的JUnit测试用例,spring-test.jar,JUnit4.7和XMLUnit1.1。 请注意,要运行集成测试,我们需要启动服务器。但是,在接下来的两个配方中,我们将使用Spring-WS2.0的集成测试的新功能,无需启动服务器。 在本配方中,项目名称为LiveRestaurant_R-3.1(服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-3.1-Client(客户端Web服务)的Maven依赖项: 本教程使用了在第一章中讨论的通过注释有效负载根设置端点配方中使用的项目,构建SOAPWeb服务,作为服务器端项目。以下是客户端设置: mvncleanpackagetomcat:runmvncleanpackage..................-------------------------------------------------------TESTS-------------------------------------------------------Runningcom.packtpub.liverestaurant.client.OrderServiceClientTest............................Testsrun:2,Failures:0,Errors:0,Skipped:0,Timeelapsed:1.633secResults:Testsrun:2,Failures:0,Errors:0,Skipped:0它是如何工作的...服务器端项目设置了一个Web服务服务器,客户端项目运行集成测试,并向服务器发送预定义的请求消息,并从服务器获取响应消息。然后将服务器响应与预期响应进行比较。Web服务的设置和Web服务的客户端已在前两章中详细介绍。这里只详细介绍测试框架。 在OrderServiceClientTest.java中,方法setUpBefore()将首先被调用以初始化数据(因为它被@before注释),然后将调用由@Test注释的测试方法(testCancelOrderRequest或testPalceOrderRequest),最后,方法setUpAfter()将被调用以释放资源(因为它被@after注释)。 当您运行mvncleanpackage时,Maven会构建并运行src/test/java文件夹中的任何测试类。因此,在OrderServiceClientTest.java中,首先将加载测试应用程序上下文。在应用程序上下文中,只需要WebServiceTemplate的配置: @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/applicationContext.xml")publicclassOrderServiceClientTest{@AutowiredprivateWebServiceTemplatewebServiceTemplate;........JUnit中的@Before告诉在运行测试用例之前运行标记的方法(setUpBefore)。JUnit@After导致在执行测试用例后调用标记的方法。JUnit中的@Test将标记的方法(testCancelOrderRequest和testPlaceOrderRequest)转换为JUnit测试方法: 在第一章中讨论的通过注释payload-root设置端点配方,构建SOAPWeb服务。 在第二章中讨论的在HTTP传输上创建Web服务客户端配方,构建SOAPWeb服务的客户端。 编写使用EasyMock和JMock等模拟框架测试Web服务的单元测试非常容易。但是,它不测试XML消息的内容,因此它不模拟测试的真实生产环境(因为这些模拟对象模拟软件的一部分,而这部分软件没有运行,这既不是单元测试也不是集成测试)。 SpringWeb-Services2.0提供了创建服务器端集成测试的功能。使用这个功能,可以非常简单地测试SOAP服务,而无需在服务器上部署,也无需在Spring配置文件中配置测试客户端。 服务器端集成测试的主要类是org.springframework.ws.test.server包中的MockWebServiceClient。这个类创建一个请求消息,将请求发送到服务,并获取响应消息。客户端将响应与预期消息进行比较。 在这个配方中,项目的名称是LiveRestaurant_R-3.2(作为包含使用MockWebServiceClient的测试用例的服务器端Web服务),并具有以下Maven依赖项: 这个配方使用了来自通过注释payload-root设置端点的项目,该项目在第一章中讨论,构建SOAPWeb服务,作为服务器端项目。以下是测试用例的设置: @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/WEB-INF/spring-ws-servlet.xml")publicclassOrderServiceServerSideIntegrationTest{.......................在@Before方法中,测试用例类初始化了客户端模拟对象和XML消息: @BeforepublicvoidcreateClient(){wsMockClient=MockWebServiceClient.createClient(applicationContext);placeOrderRequest=newOrderServiceServerSideIntegrationTest().getClass().getResourceAsStream("placeOrderRequest.xml");cancelOrderRequest=newOrderServiceServerSideIntegrationTest().getClass().getResourceAsStream("cancelOrderRequest.xml");placeOrderResponse=newOrderServiceServerSideIntegrationTest().getClass().getResourceAsStream("placeOrderResponse.xml");cancelOrderRsponse=newOrderServiceServerSideIntegrationTest().getClass().getResourceAsStream("cancelOrderResponse.xml");}然后,它发送一条消息并接收响应。然后比较预期的响应和实际的响应: 在本章中讨论的配方使用Spring-JUnit支持进行集成测试和使用MockWebServiceServer进行客户端集成测试。 在第一章中讨论的配方通过注释payload-root设置端点,构建SOAPWeb服务。 编写一个使用模拟框架测试Web服务客户端的客户端单元测试非常容易。但是,它不会测试通过线路发送的XML消息的内容,特别是当模拟整个客户端类时。 SpringWeb服务2.0提供了创建客户端集成测试的功能。使用这个功能,很容易测试SOAP服务的客户端而不需要设置服务器。 客户端集成测试的主要类是org.springframework.ws.test.server包中的MockWebServiceServer。这个类接受来自客户端的请求消息,对其进行验证,然后将响应消息返回给客户端。 由于这个项目是使用MockWebServiceServer进行客户端测试集成,它不需要任何外部服务器端Web服务。 在这个配方中,项目的名称是LiveRestaurant_R-3.3-Client(作为客户端项目,包括使用MockServiceServer作为服务器的测试用例),并且具有以下Maven依赖项: 这个配方使用了来自在HTTP传输上创建Web服务客户端的客户端项目,该项目在第二章中讨论,构建SOAPWeb服务的客户端。以下是测试用例的设置: mvncleanpackage**************************-------------------------------------------------------TESTS-------------------------------------------------------Runningcom.packtpub.liverestaurant.client.test.ClientSideIntegrationTest........Testsrun:3,Failures:0,Errors:0,Skipped:0,Timeelapsed:0.945secResults:Testsrun:3,Failures:0,Errors:0,Skipped:0它是如何工作的...测试用例类ClientSideIntegrationTest.java中的流程如下: publicclassOrderServiceClientextendsWebServiceGatewaySupport{publicResultgetStringResult(Sourcesource){StringResultresult=newStringResult();getWebServiceTemplate().sendSourceAndReceiveToResult(source,result);returnresult;}}在测试中,方法testExpectedRequestResponse,mockServer.expect设置了预期的请求和响应(webServiceTemplate在client-integration-test.xml中以“测试模式”配置。当调用sendSourceAndReceiveToResult方法时,模板会在没有任何真正的HTTP连接的情况下虚拟调用服务器)。然后client.getStringResult调用webserviceTemplate来调用服务器(MockWebServiceServer)。然后,mockServer.verify检查返回的响应是否与预期的响应匹配: @TestpublicvoidtestExpectedRequestResponse()throwsException{SourcerequestPayload=newStringSource(getStringFromInputStream(placeOrderRequest));SourceresponsePayload=newStringSource(getStringFromInputStream(placeOrderResponse));mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));Resultresult=client.getStringResult(requestPayload);XMLAssert.assertXMLEqual("Invalidcontentreceived",xmlToString(responsePayload),result.toString());mockServer.verify();}在测试方法testSchema中,使用了预期请求和响应的模式,而不是使用硬编码的请求/响应。此测试可以测试请求/响应的格式是否符合预期。如下所示: .@TestpublicvoidtestSchema()throwsException{Resourceschema=newFileSystemResource("orderService.xsd");mockServer.expect(validPayload(schema));client.getStringResult(newStreamSource(placeOrderRequest));mockServer.verify();}在测试方法testSchemaWithWrongRequest中,使用了预期请求和响应的模式。然而,客户端试图发送无效请求,这将导致失败: @Test(expected=AssertionError.class)publicvoidtestSchemaWithWrongRequest()throwsException{Resourceschema=newFileSystemResource("orderService.xsd");mockServer.expect(validPayload(schema));client.getStringResult(newStringSource(getStringFromInputStream(cancelOrderRequestWrong)));mockServer.verify();}另请参阅本章讨论了使用Spring-JUnit支持进行集成测试的配方。 TCPMon是一个带有SwingUI的Apache项目,它提供了监视客户端和服务器之间传输的基于TCP的消息的功能。还可以使用TCPMon向服务器发送SOAP消息。 本配方介绍了如何监视Web服务客户端和服务器之间传递的消息。此外,它还展示了如何使用TCPMon发送SOAP消息。该配方使用Spring-JUnit支持进行集成测试用于服务器端和客户端项目。 监视客户端和服务器之间的消息如下: 按以下方式向服务器发送SOAP请求: 转到Sender选项卡。输入SOAP服务地址和SOAP请求消息,然后单击Send按钮查看响应: 监视客户端和Web服务服务器之间传输的消息是TCPMon的最重要用途。此外,TCPMon还可以用作客户端向Web服务服务器发送消息。这是一个中间角色,显示了客户端和服务器之间传输的消息。客户端必须指向中间件而不是服务器服务。 第二个活动(向服务器发送SOAP请求)显示使用TCPMon向服务器发送消息,接收响应,并在TCPMon上显示所有这些。 本章讨论了使用Spring-JUnit支持进行集成测试的方法。 soapUI是用于测试Web服务的开源测试解决方案。使用用户友好的GUI,该工具提供了创建和执行自动功能和负载测试以及监控SOAP消息的功能。 本方法介绍了如何使用soapUI监控Web服务的SOAP消息以及功能和负载测试。为了设置Web服务,使用了Recipe3.1,使用Spring-JUnit支持进行集成测试。 通过执行以下步骤开始: mvncleanpackagetomcat:run如何操作...要运行功能测试并监控SOAP消息,请执行以下步骤: 进行负载测试如下: 功能测试和监控SOAP消息:soapUI提供三个级别的功能测试:测试套件、测试用例和测试步骤。 测试用例是从WSDL文件生成的单元测试,测试套件是这些单元测试的集合。测试步骤控制执行流程并验证要测试的服务的功能。例如,前面提到的cancelOrder测试套件中的一个测试用例可能首先测试数据库。如果有这样的订单可用,它会取消订单。 负载测试:soapUI提供了在测试用例上运行多个线程(取决于您的计算机硬件限制)的功能。运行负载测试时,底层测试用例将在每个线程内部克隆。延迟设置让每个线程在开始之前等待,并让Web服务为每个线程休息。 在处理Web服务时生成的服务器端异常被传输为SOAP故障。SOAP 以下代码表示SOAP消息中SOAP故障元素的一般结构: 本章从易于处理异常的机制开始,然后转向稍微复杂的情景。 org.springframework.ws.server.EndpointExceptionResolver是Spring-WS中服务器端异常处理的主要规范/合同。org.springframework.ws.soap.server.endpoint.SimpleSoapExceptionResolver是EndpointExceptionResolver的默认实现,可在Spring-WS框架中使用。如果开发人员没有明确处理,MessageDispatcher将使用SimpleSoapExceptionResolver处理服务器端异常。 本章中的示例演示了org.springframework.ws.server.EndpointExceptionResolver及其实现的不同用法,包括SimpleSoapExceptionResolver。 为了演示目的,构建Spring-WS的最简单的方法是使用MessageDispatcherServlet简化WebService的创建。 Spring-WS框架会自动将服务器端抛出的应用程序级别异常的描述转换为SOAP故障消息,并将其包含在响应消息中发送回客户端。本示例演示了捕获异常并设置有意义的消息以作为响应中的SOAP故障字符串发送。 在此示例中,项目的名称是LiveRestaurant_R-4.1(用于服务器端Web服务),并具有以下Maven依赖项: 以下是LiveRestaurant_R-4.1-Client(客户端Web服务)的Maven依赖项: 本示例使用了通过注释负载根设置端点中讨论的项目,该项目在第一章中讨论了构建SOAPWeb服务。以下步骤描述了如何修改端点: SimpleSoapExceptionResolver通过执行以下操作解决异常: 当我们在客户端检查响应消息时,可以看到在方法OrderServiceEndpoint.handlePlaceOrderRequest中设置的确切异常消息(未提供参考编号!)作为响应消息中的SOAP故障字符串返回。 有趣的是,开发人员不需要做任何处理或发送SOAP故障消息,除了抛出一个带有有意义的消息的异常。 在第一章中讨论的配方通过注释有效负载根设置端点,构建SOAPWeb服务。 Spring-WS框架允许在bean配置文件spring-ws-servlet.xml中轻松定制SOAP故障消息。它使用一个特殊的异常解析器SoapFaultMappingExceptionResolver来完成这项工作。我们可以将异常类映射到相应的SOAP故障,以便生成并返回给客户端。 在这个配方中,项目的名称是LiveRestaurant_R-4.2(用于服务器端Web服务),具有以下Maven依赖项: 以下是LiveRestaurant_R-4.2-Client(客户端Web服务)的Maven依赖项: 这个配方使用了通过注释有效负载根设置端点中的项目,在第一章中讨论,构建SOAPWeb服务。 这个强大的功能可以将异常与SOAP故障字符串进行映射,非常有用,可以将SOAP故障管理外部化,不需要修改代码并重新构建。此外,如果设计得当,spring-ws.xml文件中的配置(SOAP故障映射)可以作为所有可能的SOAP故障消息的单一参考点,可以轻松维护。 这是B2B应用的一个很好的解决方案。不适用于B2C,因为需要支持多种语言。一般来说,最好的方法是通过在数据库中配置消息。这样,我们可以在运行时更改和修复它们。在XML中配置的缺点是需要重新启动。在实时情况下,一个应用在30台服务器上运行。部署和重新启动是痛苦的过程。 在第一章中讨论的通过注释有效负载根设置端点的配方,构建SOAPWeb服务。 在第二章中讨论的在HTTP传输上创建Web服务客户端配方,构建SOAPWeb服务的客户端 在本章中讨论的通过将异常消息作为SOAP故障字符串返回来处理服务器端异常的配方。 Spring-WS框架允许将应用程序异常注释为SOAP故障消息,并在异常类本身中进行轻松定制。它使用一个特殊的异常解析器SoapFaultAnnotationExceptionResolver来完成这项工作。可以通过在类中进行注释来定制SOAP故障字符串和故障代码。 在这个配方中,项目的名称是LiveRestaurant_R-4.3(服务器端Web服务),并且具有以下Maven依赖项: 以下是LiveRestaurant_R-4.3-Client(客户端Web服务)的Maven依赖项: 这个配方使用了第一章中讨论的通过注释有效负载根设置端点的项目作为服务器端,以及第三章中讨论的如何使用Spring-Junit支持集成测试的配方作为客户端。 mvncleanpackagetomcat:run.mvncleanpackageDEBUG[main](WebServiceTemplate.java:632)-Receivedresponse..... @SoapFault(faultCode=FaultCode.SERVER,faultStringOrReason="Databaseserverundermaintenance,pleasetryaftersometime.")publicclassProcessingFailedExceptionextendsException{publicProcessingFailedException(Stringmessage){super(message);}}InvalidOrderRequestException代表客户端业务逻辑异常(faultCode=FaultCode.CLIENT): @SoapFault(faultCode=FaultCode.CLIENT,faultStringOrReason="InvalidOrderRequest:Requestmessageincomplete")publicclassInvalidOrderRequestExceptionextendsException{publicInvalidOrderRequestException(Stringmessage){super(message);}}您可以看到,带注释的faultStringOrReason被生成为SOAP故障,并传输回客户端。生成的SOAP故障消息在服务器端和客户端控制台屏幕上都被记录,显示了带注释的SOAP故障消息,而不是在Endpoint类中最初抛出的内容。 @SoapFault注释的faultCode属性具有以下可能的枚举值: 从枚举列表中选择一个指示调度程序应生成哪种SOAP故障以及其具体内容。根据前面的选择,依赖属性变得强制性。 例如,如果为faultCode选择了FaultCode.CUSTOM,则必须使用customFaultCode字符串属性,而不是faultStringOrReason,如本配方的代码片段中所示。用于customFaultCode的格式是QName.toString()的格式,即"{"+NamespaceURI+"}"+localpart,其中命名空间是可选的。请注意,自定义故障代码仅在SOAP1.1上受支持。 @SoaPFault注释还有一个属性,即locale,它决定了SOAP故障消息的语言。默认语言环境是英语。 在一般实践中,我们使用错误代码而不是错误消息。在客户端使用映射信息进行映射。这样可以避免对网络的任何负载,并且不会出现多语言支持的问题。 在第三章中讨论的如何使用Spring-JUnit支持集成测试的配方,测试和监控Web服务。 在本章中讨论的将异常类名映射到SOAP故障的配方。 Spring-WS框架提供了默认机制来处理异常,使用标准异常解析器,它允许开发人员通过构建自己的异常解析器来以自己的方式处理异常。SOAP故障可以定制以在其自己的格式中添加自定义细节,并传输回客户端。 本示例说明了一个自定义异常解析器,它将异常堆栈跟踪添加到SOAP响应的SOAP故障详细元素中,以便客户端获取服务器端异常的完整堆栈跟踪,对于某些情况非常有用。这个自定义异常解析器已经具有注释的功能,就像前面的示例一样。 在本配方中,项目的名称是LiveRestaurant_R-4.4(用于服务器端Web服务),具有以下Maven依赖项: LiveRestaurant_R-4.4-Client(用于客户端)具有以下Maven依赖项: 本配方使用了通过注释payload-root设置端点中讨论的项目,第一章,构建SOAPWeb服务。 有许多不同的创建自定义异常解析器的方法。不仅可以继承SoapFaultAnnotationExceptionResolver来实现这一目的。任何org.springframework.ws.server.EndpointExceptionResolver的实现都可以适当配置为用作异常解析器。开发人员可以从Spring-WSAPI中提供的一组非常方便的EndpointExceptionResolver实现中进行选择,利用这些实现的功能。 自定义这些类的位置是方法customizeFault。可以通过覆盖方法customizeFault来自定义SOAP故障。查看包org.springframework.ws.soap.server.endpoint,以获取适合您要求的现成异常解析器。 如果需要开发一个与当前可用实现不符的专门自定义异常解析器,则AbstractSoapFaultDefinitionExceptionResolver将是一个理想的起点,因为它已经实现了一些任何异常解析器都需要的非常常见和基本功能。开发人员只需实现抽象方法resolveExceptionInternal(),以满足特定需求。 需要注意的是,应该指示MessageDispatcherServlet考虑使用的解析器,可以通过在spring-ws-servlet.xml中注册或在异常类中进行注释(除了在spring-ws-servlet.xml中注册)。 本配方通过注释payload-root设置端点中讨论的项目,第一章,构建SOAPWeb服务。 本章讨论的配方使用@SOAPfault注释异常类。 日志记录和跟踪是指捕获和记录有关软件程序执行的事件和数据结构,以提供审计跟踪。它有助于开发人员和支持团队收集有关软件程序执行的运行时信息。对于任何严肃的软件开发团队,实现系统日志记录非常重要。 对于Web服务开发,能够看到在客户端和服务器之间传输的SOAP消息非常有用。SpringWeb服务在SOAP消息到达时或发送前提供日志记录和跟踪。在Spring-WS中,日志记录由标准的CommonsLogging接口管理。 通常,在Spring项目中,log4j被用作具体的日志记录库(因为Spring日志功能是建立在log4j之上的)。本章介绍了记录SOAP消息的几种简单方法。 这里所示的配方可以应用于本书中任何配方的项目源。为了演示目的,使用了配方通过注释负载根设置端点的现有项目源,因为这可以应用于本书中使用的任何项目。 消息有效载荷是SOAP消息元素SOAP-ENV:Body的内容。这是整个SOAP信封的确切消息部分,用于请求和响应。 这个配方演示了从代码内部手动记录消息有效载荷。 在这个配方中,项目的名称是LiveRestaurant_R-5.1(用于服务器端Web服务),具有以下Maven依赖项: LiveRestaurant_R-5.1-Client(用于客户端),具有以下Maven依赖项: 这个配方使用了第一章中使用的通过注释负载根设置端点的配方中使用的项目,构建SOAPWeb服务。 log4j.rootLogger=INFO,stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout#Patterntooutputthecaller'sfilenameandlinenumber.log4j.appender.stdout.layout.ConversionPattern=%5p[%t](%F:%L)-%m%n方法xmlToString(...)将XML源/元素对象转换为String,使用StringWriter: If(logger.isDebugEnabled())logger.debug(message);在运行时,我们可以根据需求启用和禁用日志。 本配方中给出的示例使用SimpleMethodEndpointMapping,它以XMLSource(javax.xml.transform.Source)或Element(org.w3c.dom.Element)对象的形式接收消息负载作为方法参数,并使用RequestPayload注解,而在其他情况下,传入消息将以不同的形式出现。例如,在编组端点中,输入已经是编组对象。在这些情况下,您需要采用适当的机制来转换传入的参数。之后的配方将为您提供有关日志记录和跟踪的其他方法的见解。 Spring-WS框架允许开发人员使用简单的日志记录器配置记录整个SOAP消息。本配方通过log4j日志记录框架配置框架的SOAP消息内部日志记录。 在这个配方中,项目的名称是LiveRestaurant_R-5.2(用于服务器端Web服务),具有以下Maven依赖项: 它还有LiveRestaurant_R-5.2-Client(用于客户端)并具有以下Maven依赖项: 本配方使用了配方通过注释payload-root设置端点中使用的项目: 以下是服务器端控制台的输出(请注意Web服务响应中生成的SOAP-Env:Envelope元素): 在receive()方法中,它检查命名日志实例的日志设置,org.springframework.ws.server.MessageTracing.received检查记录SOAP请求,org.springframework.ws.server.MessageTracing.sent检查SOAP响应。如果这些设置的值为TRACE或DEBUG,它将打印相应请求或响应的整个SOAP信封: log4j.rootLogger=INFO,stdout,Rlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout#Patterntooutputthecaller'sfilenameandlinenumber.log4j.appender.stdout.layout.ConversionPattern=%5p[%t](%F:%L)-%m%n#RollingFileAppenderlog4j.appender.R=org.apache.log4j.RollingFileAppenderlog4j.appender.R.File=LiveRestaurant.loglog4j.appender.R.MaxFileSize=100KB#Keeponebackupfilelog4j.appender.R.MaxBackupIndex=1log4j.appender.R.layout=org.apache.log4j.PatternLayoutlog4j.appender.R.layout.ConversionPattern=%p%t%c-%m%nlog4j.logger.org.springframework.ws.server.MessageTracing.received=TRACElog4j.logger.org.springframework.ws.server.MessageTracing.sent=TRACE跟踪或调试的最简单设置是在log4j.properties中,如前所述。 以前,出于安全目的,消息是加密的,因此启用日志记录并不总是有用的。最好在输入方法内完成解密后记录消息。 Spring-WS提供了记录传入/传出消息的功能。这些功能是通过使用PayloadLoggingInterceptor和SoapEnvelopeLoggingInterceptor类来实现的,这些类使用CommonsLoggingLog进行记录。虽然PayloadLoggingInterceptor仅记录消息的有效负载,但SoapEnvelopeLoggingInterceptor记录整个SOAP信封,包括标头。要使用这两个拦截器激活日志记录功能,log4j属性文件中的日志属性应设置为拦截器包的调试。 在这个配方中,解释了使用PayloadLoggingInterceptor和SoapEnvelopeLoggingInterceptor记录Web服务消息。 在本教程中,项目的名称是LiveRestaurant_R-5.3(用于服务器端Web服务),并具有以下Maven依赖项: 以及LiveRestaurant_R-5.3-Client(用于客户端)和以下Maven依赖项: 本教程使用了教程通过注释payload-root设置端点中使用的项目: 以下是服务器端控制台的输出: 仅在spring-ws-servlet.xml中注册PayloadLoggingInterceptor会记录消息的有效负载: ........log4j.appender.R.layout=org.apache.log4j.PatternLayoutlog4j.appender.R.layout.ConversionPattern=%p%t%c-%m%nlog4j.logger.org.springframework.ws.soap.server.endpoint.interceptor=debuglog4j.logger.org.springframework.ws.server.endpoint.interceptor=debug还有更多...将PayloadLoggingInterceptor的logRequest和logResponse属性设置为true/false,启用/禁用请求/响应消息的记录。 Eclipse可以配置为在嵌入式和远程服务器中进行Web/app服务器调试。本教程解释了如何在Eclipse内部以Web应用程序的形式调试Spring-WS项目,使用外部远程Tomcat实例。 要开始: 在本教程中,项目的名称是LiveRestaurant_R-5.4(用于服务器端WebService),并具有以下Maven依赖项: 它还有LiveRestaurant_R-5.4-Client(用于客户端)和以下Maven依赖项: 安装Tomcat后:在Linux上>编辑.profile>,添加以下内容以用于Tomcat: exportTOMCAT_HOME=/opt2/apache-tomcat-6.0.14exportPATH=$TOMCAT_HOME:$PATH setJPDA_TRANSPORT=dt_socketsetJPDA_ADDRESS=8000call"%EXECUTABLE%"jpdastart%CMD_LINE_ARGS%exportJPDA_ADDRESS=8000exportJPDA_TRANSPORT=dt_socketexec"$PRGDIR"/"$EXECUTABLE"jpdastart"$@" 此处使用JavaDebugger(JDB)工具来帮助在本地和服务器上找到并修复Java语言程序中的错误。JDB是JavaPlatformDebuggingArchitecture(JPDA)的一部分,为您构建Java平台的最终用户调试器应用程序提供了所需的基础设施。 要在JavaEE应用程序服务器或Servlet容器(如Tomcat)中使用JDB,必须首先启用调试并通过JPDA端口(默认端口为1044)将其附加到调试器。在第4步,JPDA端口设置为8000。此处使用debug.bat/debug.sh启动服务器,而不是run.bat/run.sh,这意味着服务器以调试模式启动。 JDB参数指定调试器的操作方式。例如,JPDA_TRANSPORT=dt_socket指示JVM调试器连接将通过套接字进行,而JPDA_ADDRESS=8000参数通知端口号将为8000。 然后EclipseIDE将连接到接受调试连接的JVM。该项目被设置为Eclipse内的远程Java应用程序,监听相同的端口,即8000,以进行任何调试活动。接下来,将在服务类中设置断点,该断点将在运行时由JDB管理和重定向到IDE。 当LiveRestaurant_R-5.4-Client项目作为服务的客户端程序执行时,服务类OrderServiceEndpoint被调用,并在处于调试模式的JVM中命中断点。它通知前端JDI的实现位置以及在这种情况下的IDE。 类似于Tomcat服务器,您可以将任何应用程序服务器附加到Eclipse、NetBeans或JDeveloper等IDE。概念是相同的。但是,每个应用程序服务器和IDE的步骤可能会有所不同。 在本章中,我们将涵盖以下主题: 在对象/XML映射(OXM)术语中,编组(序列化)将数据的对象表示转换为XML格式,而解组将XML转换为相应的对象。 Spring的OXM通过使用Spring框架的丰富特性简化了OXM操作。例如,可以使用依赖注入功能将不同的OXM技术实例化为对象以使用它们,Spring可以使用注解将类或类的字段映射到XML。 Spring-WS受益于Spring的OXM,可以将有效负载消息转换为对象,反之亦然。例如,可以在应用程序上下文中使用以下配置将JAXB设置为OXM框架: 有许多可用的编组框架的实现。JAXB(JavaArchitectureforXMLBinding)、JiBX、XMLBeans、Castor等都是例子。对于一些OXM框架,提供了工具来将模式转换为POJO类,并在这些类中生成映射数据,或者在单独的外部配置文件中生成映射数据。 本章提供了示例来说明不同框架用于对象/XML映射的用法。 为了简化,本章中大多数示例使用了“使用Spring-JUnit支持进行集成测试”一章中讨论的项目,该项目在“测试和监视Web服务”一章中讨论,用于设置服务器并通过客户端发送和接收消息。然而,在“使用XStream进行编组”一章中的示例中,使用了“为WS-Addressing端点创建Web服务客户端”一章中讨论的项目,该项目在“构建SOAPWeb服务的客户端”一章中讨论,用于服务器和客户端。 JAXB提供了许多扩展和工具,使得对象/XML绑定变得简单。其注解支持允许开发人员在现有类中标记O/X绑定,以便在运行时生成XML。其Maven工具插件(maven-jaxb2-plugin)可以从给定的XMLSchema文件生成Java类。 这个示例说明了如何设置编组端点并使用JAXB2作为编组库构建客户端程序。 这个示例包含一个服务器(LiveRestaurant_R-6.1)和一个客户端(LiveRestaurant_R-6.1-Client)项目。 LiveRestaurant_R-6.1具有以下Maven依赖项: LiveRestaurant_R-6.1-Client具有以下Maven依赖项: 这个示例使用maven-jaxb2-plugin从模式生成类。 以下是客户端输出: -Receivedresponse.... POM文件中的以下部分从文件夹src\main\webapp\WEB-INF(由schemaDirectory设置)中的模式(OrderService.xsd)生成JAXB类。 GeneratePackage设置包括生成类的包,generateDirectory设置了托管生成包的文件夹: @PayloadRoot(localPart="placeOrderRequest",namespace=SERVICE_NS)publicPlaceOrderResponsegetOrder(PlaceOrderRequestplaceOrderRequest){PlaceOrderResponseresponse=JAXB_OBJECT_FACTORY.createPlaceOrderResponse();response.setRefNumber(orderService.placeOrder(placeOrderRequest.getOrder()));returnresponse;}@PayloadRoot(localPart="cancelOrderRequest",namespace=SERVICE_NS)publicCancelOrderResponsecancelOrder(CancelOrderRequestcancelOrderRequest){CancelOrderResponseresponse=JAXB_OBJECT_FACTORY.createCancelOrderResponse();response.setCancelled(orderService.cancelOrder(cancelOrderRequest.getRefNumber()));returnresponse;}在服务器的spring-ws-servlet.xml中的以下部分将编组器设置为端点(OrderServiceEndpoint)为Jaxb2Marshaller。在marshallerbean中的contextPath设置注册了包com.packtpub.liverestaurant.domain中的所有bean,以便由Jaxb2Marshaller进行编组/解组: 使XMLBeans与其他XML-Java绑定选项不同的两个主要特点是: 此配方包含服务器(LiveRestaurant_R-6.2)和客户端(LiveRestaurant_R-6.2-Client)项目。 LiveRestaurant_R-6.2具有以下Maven依赖项: LiveRestaurant_R-6.2-Client具有以下Maven依赖项: 此配方使用xmlbeans-maven-plugin从模式生成类并绑定文件。 [INFO][INFO]--......[INFO][INFO]---xmlbeans-maven-plugin:2.3.2:xmlbeans....[INFO][INFO].....Receivedresponse... 很容易注意到,代码中的两个主要区别在于OrderServiceEndPoint和spring-ws-servlet.xml。与上一个示例不同,getOrder方法返回OrderResponseDocument的实例,并接受OrderRequestDocument作为输入参数。cancelOrderDoc方法也是如此。 与上一个示例一样,POM文件中的插件从文件夹src\main\webapp\WEB-INF(由schemaDirectory设置)中的模式(OrderService.xsd)生成XMLBean类: XMLBeans配备了一套内置的强大工具,可以为XML和Java之间的编组添加更多功能。本示例仅使用了其中一个工具,即scomp,即模式编译器,它可以从XML模式(.xsd)文件生成Java类/压缩的JAR文件。其他一些有用的工具包括: xmlbeanAnttask是自动化生成Java类的一种不错的方式,可以与构建脚本集成。 从1.2版本开始,JiBX已解决了这些瓶颈,现在它具有易于使用的编组工具和框架。使用JiBX工具,用户可以从现有Java代码生成模式,或者从现有模式生成Java代码和绑定文件。JiBX库在运行时将Java类绑定到XML数据,反之亦然。 在本示例中,使用JiBX工具(jibx-maven-plugin)生成POJO类,并从现有模式绑定定义文件,然后将基于JiBX库构建Web服务客户端和服务器。 这个示例包含一个服务器(LiveRestaurant_R-6.3)和一个客户端(LiveRestaurant_R-6.3-Client)项目。 LiveRestaurant_R-6.3具有以下Maven依赖项: LiveRestaurant_R-6.3-Client具有以下Maven依赖项: 以下是客户端的输出: ................[INFO]---jibx-maven-plugin:1.2.3:bind(compile-binding)@LiveRestaurant_Client---[INFO]RunningJiBXbindingcompiler(single-modulemode)on1bindingfile(s)[INFO][INFO]....Receivedresponse... ...... @PayloadRoot(localPart="cancelOrderRequest",namespace=SERVICE_NS)publicCancelOrderResponsehandleCancelOrderRequest(CancelOrderRequestcancelOrderRequest)throwsException{CancelOrderResponsecancelOrderResponse=newCancelOrderResponse();cancelOrderResponse.setCancelled(orderService.cancelOrder(cancelOrderRequest.getRefNumber()));returncancelOrderResponse;}@PayloadRoot(localPart="placeOrderRequest",namespace=SERVICE_NS)publicPlaceOrderResponsehandleCancelOrderRequest(PlaceOrderRequestplaceOrderRequest)throwsException{PlaceOrderResponseorderResponse=newPlaceOrderResponse();orderResponse.setRefNumber(orderService.placeOrder(placeOrderRequest.getOrder()));returnorderResponse;}......还有更多...JiBX通过让用户创建自己的自定义编组器来提供更大的灵活性。这意味着可以使用自定义绑定文件和自定义编组器类来对任何类型的数据结构进行编组到XML文档中。 在这个配方中,创建了一个使用XStream库作为编组器的Web服务客户端和服务器。由于XStream在XML数据(有效负载)中不使用任何命名空间,因此设置了一种Web服务的网址样式。 此配方包含一个服务器(LiveRestaurant_R-6.4)和一个客户端(LiveRestaurant_R-6.4-Client)项目。 LiveRestaurant_R-6.4具有以下Maven依赖项: LiveRestaurant_R-6.4-Client具有以下Maven依赖项: importcom.thoughtworks.xstream.annotations.XStreamAlias;@XStreamAlias("name")publicclassName{privateStringFName;privateStringMName;privateStringLName;被注释为@Endpoint的OrderServiceEndPoint与JiBX配方相同,即端点方法的输入和返回参数是POJO(PlaceOrderResponse,PlaceOrderRequest等),它们被映射到模式。唯一的区别是端点使用Web寻址进行方法映射: 在这个配方中,Moose用于在Web服务客户端和服务器通信中将对象编组/解组为XML数据。 这个配方包含一个服务器(LiveRestaurant_R-6.5)和一个客户端(LiveRestaurant_R-6.5-Client)项目。 LiveRestaurant_R-6.5具有以下Maven依赖项: LiveRestaurant_R-6.5-Client具有以下Maven依赖项: Receivedresponse... @XML(name="cancelOrderRequest")publicclassCancelOrderRequest{@XMLField(name="refNumber")privateStringrefNumber;/***Getthe'refNumber'elementvalue.**@returnvalue*/publicStringgetRefNumber(){returnrefNumber;}/***Setthe'refNumber'elementvalue.**@paramrefNumber*/publicvoidsetRefNumber(StringrefNumber){this.refNumber=refNumber;}}被注释为@Endpoint的OrderServiceEndPoint与JiBX配方相同,传递和返回参数是映射到模式的POJO(PlaceOrderResponse,PlaceOrderRequest等)。 @PayloadRoot(localPart="cancelOrderRequest",namespace=SERVICE_NS)publicCancelOrderResponsehandleCancelOrderRequest(CancelOrderRequestcancelOrderRequest)throwsException{CancelOrderResponsecancelOrderResponse=newCancelOrderResponse();cancelOrderResponse.setCancelled(orderService.cancelOrder(cancelOrderRequest.getRefNumber()));returncancelOrderResponse;}@PayloadRoot(localPart="placeOrderRequest",namespace=SERVICE_NS)publicPlaceOrderResponsehandleCancelOrderRequest(PlaceOrderRequestplaceOrderRequest)throwsException{PlaceOrderResponseorderResponse=newPlaceOrderResponse();orderResponse.setRefNumber(orderService.placeOrder(placeOrderRequest.getOrder()));returnorderResponse;}使用XPath创建自定义的marshaller进行条件XML解析。始终使用现有的编组器框架(JAXB、JiBX等)是处理编组任务的最简单方法。但是,最终您可能需要编写自定义的编组器。例如,您可能会收到一个XML输入数据,它的格式与通常由已识别的编组器使用的格式不同。 Spring允许您定义自定义编组器并将其注入到端点编组器中,就像现有的编组器框架一样。在这个示例中,客户端以以下格式向服务器发送/接收数据: 这个示例包含一个服务器(LiveRestaurant_R-6.6)和一个客户端(LiveRestaurant_R-6.6-Client)项目。 LiveRestaurant_R-6.6具有以下Maven依赖项: LiveRestaurant_R-6.6-Client具有以下Maven依赖项: 以下是服务器端输出: Receivedrequest..... 当Web服务调用端点方法(handleOrderRequest)构建传递参数(PlaceOrderRequest)时,将调用方法unmarshal。在unmarshal方法中,使用DOM4j和XPath从传入的XML数据中提取值。这些值将填充POJO类并将其返回给端点。当端点方法(handleOrderRequest)返回响应(PlaceOrderResponse)时,将调用方法marshal。在marshal方法内部,使用XMLStreamWriter将所需格式的XML数据返回给客户端: WS-Security(WSS)由OASIS发布,是SOAP的扩展,提供Web服务的安全标准功能。XML和Web服务安全(XWSS)是SUN对WSS的实现,包含在JavaWeb服务开发人员包(WSDP)中。 EndpointInterceptor,顾名思义,拦截请求并在调用端点之前执行某些操作。在之前的章节中,已经解释了SoapEnvelopeLoggingInterceptor,PayloadLoggingInterceptor和PayloadValidatingInterceptor用于记录和验证目的。 在本章和下一章中,将解释SecurityInterceptors。 Spring-WSXwsSecurityInterceptor是用于在调用端点之前对请求消息执行安全操作的EndpointInterceptor。这个基于XWSS的拦截器需要一个策略配置文件来运行。这是一个可以包含多个安全要求的策略配置文件的示例: 此外,此拦截器需要一个或多个callBackHandlers用于安全操作,如身份验证,签署传出消息,验证传入消息的签名,解密和加密。这些callBackHandlers需要在应用程序上下文文件中注册: 为简化起见,本章中的大多数示例使用了在第三章中讨论的使用Spring-JUnit支持进行集成测试示例中使用的项目,用于设置服务器并由客户端发送和接收消息。但是,在最后一个示例中,使用了来自为WS-Addressing端点创建Web服务客户端示例中讨论的第二章中的项目,用于服务器和客户端。 身份验证简单地意味着检查服务的调用者是否是他们声称的人。检查调用者的身份验证的一种方式是检查密码。 XWSS提供API来从传入的SOAP消息中获取用户名和密码,并将它们与配置文件中定义的内容进行比较。通过为消息的发送方和接收方定义策略文件来实现此目标,发送方在传出消息中包含用户名令牌,而接收方在接收消息时期望收到此用户名令牌以进行身份验证。 传输明文密码会使SOAP消息不安全。XWSS提供了在策略文件中配置设置以在发送方消息中包含密码的摘要(由特定算法生成的密码文本的哈希)的配置。在服务器端,服务器将传入消息中包含的摘要密码与从配置文件中设置的摘要密码进行比较(请参见spring-ws-servlet.xml中callbackHandlerbean内的属性用户)使用发送方端上的相同算法。本教程展示了如何使用用户名令牌和明文/摘要密码对Web服务调用进行身份验证。本教程包含两种情况。在第一种情况下,密码将以明文格式传输。但是,在第二种情况下,通过更改策略文件配置,密码将以摘要格式传输。 在本教程中,项目名称为LiveRestaurant_R-7.1(用于服务器端Web服务),具有以下Maven依赖项: LiveRestaurant_R-7.1-Client(用于客户端Web服务)具有以下Maven依赖项: 以下步骤实现使用用户名令牌和明文密码进行身份验证: mvncleanpackagetomcat:runmvncleanpackageINFO:====SendingMessageStart==== 在服务器端,XwsSecurityInterceptor强制服务器对所有传入消息应用securityPolicy.xml中的策略,并使用SimplePasswordValidationCallbackHandler来比较传入消息的用户名/密码与服务器配置文件中包含的用户名/密码(请参阅callbackHandlerbean中的属性users): 在使用带有明文密码的用户名令牌进行身份验证的情况下,由于在客户端和服务器端策略文件中都有digestPassword="false",因此在输出结果中可以看到客户端发送的消息中包含用户名和明文密码: 本章讨论的配方使用Spring安全验证Web服务调用以验证带有明文/摘要密码的用户名令牌,使用JAAS服务验证用户名令牌的Web服务调用和使用X509证书验证Web服务调用。 与本章的第一个配方相同,这个配方也包含两种情况。在第一种情况下,密码将以明文格式传输。在第二种情况下,通过更改策略文件的配置,密码将以摘要格式传输。 在这个配方中,项目的名称是LiveRestaurant_R-7.2(用于服务器端Web服务),具有以下Maven依赖项: LiveRestaurant_R-7.2-Client(用于客户端Web服务)具有以下Maven依赖项: 在这个配方中,所有步骤与前一个配方使用用户名令牌对Web服务调用进行身份验证中的步骤相同,只是服务器端应用程序上下文文件(spring-ws.servlet.xml)回调处理程序更改并使用DAO层来获取数据: 以下步骤实现了使用SpringSecurity对带有明文密码的用户名令牌进行身份验证的Web服务调用的身份验证: 在第一种情况下,CallbackHandlerSpringPlainTextPasswordValidationCallbackHandler比较了传入SOAP消息中包含的明文密码和从DAO层获取的明文密码。 publicclassMyUserDetailServiceimplementsUserDetailsService{@OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{returngetUserDataFromDao(username);}privateMyUserDetailgetUserDataFromDao(Stringusername){/***Realscenario:finduserdatafromaDAOlayerbyuserName,*ifthisusernamefound,populateMyUserDetailwithitsdata(username,password,Role,....).*/MyUserDetailmydetail=newMyUserDetail(username,"pass",true,true,true,true);mydetail.getAuthorities().add(newGrantedAuthorityImpl("ROLE_GENERAL_OPERATOR"));returnmydetail;}该服务最终返回了在MyUserDetails.java中填充的数据,该类应该实现Spring的UserDetails。 publicclassMyUserDetailimplementsUserDetails{privateStringpassword;privateStringuserName;privatebooleanisAccountNonExpired;privatebooleanisAccountNonLocked;privatebooleanisCredentialsNonExpired;privatebooleanisEnabled;publicstaticCollection 与7.1项目一样,在服务器端/客户端的securityPolicy.xml中将digestPassword设置为true/false会导致密码以明文或摘要格式传输。 在实时环境中,我们从不配置明文密码选项。这是一个让黑客启用和禁用的好选项。我们在实时环境中从不需要这样的选项。无论任何类型的系统或应用程序配置,密码始终以加密格式传输。 在本章中讨论的示例使用Spring安全性对用户名令牌进行身份验证,使用JAAS服务对用户名令牌进行身份验证和使用X509证书对Web服务调用进行身份验证。 xwss包中的JaasPlainTextPasswordValidationCallbackHandler是调用在JAAS配置文件中配置的Login模块的API。 在这个示例中,项目的名称是LiveRestaurant_R-7.3(用于服务器端Web服务),具有以下Maven依赖项: LiveRestaurant_R-7.3-Client(用于客户端Web服务)具有以下Maven依赖项: 客户端发送包含明文用户名令牌的请求SOAP消息。服务器接收此消息并使用JAAS框架将传入消息的用户名/密码与JAAS从DAO层获取的内容进行比较。如果匹配,则返回正常响应;否则返回失败消息。 RdbmsPlainText{com.packtpub.liverestaurant.service.security.RdbmsPlainTextLoginModuleRequired;};将从RdbmsPlainTextLoginModule.java的login方法中调用以从DAO层获取用户密码和凭据。如果获取的密码与传入消息的密码匹配,则设置凭据并返回true;否则,抛出异常,导致服务器向客户端发送故障消息: 在本章中讨论了使用用户名令牌和明文/摘要密码进行Web服务调用身份验证、使用SpringSecurity对用户名令牌进行身份验证以及使用X509证书进行身份验证的配方。 为了为Web服务调用添加更多安全措施,我们需要一些额外的操作,如对Web服务消息进行签名和验证签名、加密/解密以及使用证书进行身份验证。XWSS使用密钥库提供这些操作。java.security.KeyStore类为加密密钥和证书提供了内存容器。此类可以包括三种类型的条目: 密钥库可以包含一个到多个条目。密钥库中的别名用于区分条目。私钥和证书由一个别名引用,而任何其他受信任的证书或秘密密钥条目则由密钥库中的不同个别别名引用。 在本章的前面,介绍了使用用户名令牌对Web服务调用进行身份验证。可以使用证书对Web服务调用进行身份验证。在本章的后面,将介绍使用证书进行身份验证。此外,这些证书可以用于证书验证、签名验证和加密。 Javakeytool是一个生成和存储密钥和证书在密钥库文件中的工具。这个密钥库由一个密钥库密码保护。此外,还有一个密码保护私钥。 在本配方中,使用keytool生成具有对称密钥条目、私钥条目(私钥和公钥证书对)和受信任证书条目的密钥库。这些密钥稍后将在本章和第八章以及SecuringSOAPWeb-ServicesusingWSS4JLibrary中用于签名和验证Web服务消息的签名、加密/解密和使用证书进行身份验证。 按照第一个配方中描述的安装Java。 要生成一个具有别名symmetric的秘密密钥条目的密钥库,请运行以下命令(此密钥库稍后用于对称加密/解密): keytool-genseckey-alias'symmetric'-keyalg'DESede'-keystoresymmetricStore.jks-storepass'symmetricPassword'-keypass'keyPassword'-storetype"JCEKS"要生成一个具有私钥条目或密钥对(包含私钥和公钥证书对)的密钥库,请按照以下步骤进行: keytool-genseckey-alias'symmetric'-keyalg'DESede'-keystoresymmetricStore.jks-storepass'symmetricPassword'-keypass'keyPassword'-storetype"JCEKS"要生成一个具有私钥条目和受信任证书条目的密钥库,首先应该为客户端和服务器端生成一个密钥对(私钥和公钥证书)密钥库。 然后应该从客户端/服务器密钥库中导出公钥证书。最后,应该将客户端证书导入服务器密钥库,并将服务器证书导入客户端密钥库(此导入的证书将被称为受信任证书)。 keytool-genkey-aliasaliasName-keyalgRSA-keystorekeyStoreFileName.jks-validity3653上述命令生成一个具有私钥条目的密钥库,其中aliasName是密钥库的标识符。有效期是此密钥有效的天数。 keytool-export-fileclientStore.cert-keystoreclientStore.jks-storepassclientPassword-aliasclient上述命令导出嵌入在密钥库中私钥条目内的公钥证书。 keytool-import-fileclientStore.cert-keystoreserverStore.jks-storepassserverPassword-aliasclient上述命令将从客户端密钥库中导入生成的公钥证书到服务器密钥库中(此导入的证书将被称为受信任证书)。 有关加密和密钥库的更多信息可以在以下网址找到: 本章讨论了使用数字签名保护SOAP消息,使用X509证书对Web服务调用进行身份验证以及加密/解密SOAP消息的方法。 数字签名的目的是验证接收到的消息是否被篡改,以证明发送者是他/她声称的身份(身份验证),并证明来自特定发送者的操作。对消息进行数字签名意味着添加哈希数据,即将一段信息(令牌)添加到SOAP信封中。接收者需要从传入的消息中重新生成自己的哈希并将其与发送者的哈希进行比较。如果接收者的哈希与发送者的哈希匹配,则实现了数据完整性,接收者将继续进行;否则,它将向发送者返回一个SOAP故障消息。 为了验证发送者,发送者应使用自己的私钥加密签名令牌。接收者应在接收者密钥库中拥有发送者的公钥证书(该证书称为受信任证书,并位于受信任证书条目下)以解密发送者的签名令牌,并重复已解释的步骤以检查消息完整性。现在,如果消息完整性得到保证,则证明了发送者的身份验证(因为只有嵌入在接收者密钥库中的发送者证书才能解密发送者的加密签名)。此外,还证明了发送者发送消息的行为(因为在接收者端成功解密签名表明发送者已经使用自己的私钥对其进行了加密)。 在本章中,发送方(客户端)对消息进行签名,并使用其自己的私钥(在客户端密钥库中)对签名进行加密。在接收方(服务器)端,服务器密钥库中的客户端公钥证书(该证书称为受信任证书,并位于密钥库中的受信任证书条目下)将用于解密令牌的签名;然后服务器验证签名令牌。 在本章中,项目名称为LiveRestaurant_R-7.4(用于服务器端Web服务),具有以下Maven依赖项: LiveRestaurant_R-7.4-Client(用于客户端Web服务)具有以下Maven依赖项: 在策略文件中的以下服务器端安全配置会导致服务器期望从传入消息中获得安全令牌(用于验证传入消息): 在这个示例中,项目的名称是LiveRestaurant_R-7.5(用于服务器端Web服务),它具有以下Maven依赖项: LiveRestaurant_R-7.5-Client(用于客户端Web服务)具有以下Maven依赖项: 在这个配方中,所有步骤与前一个配方使用数字签名保护SOAP消息中的步骤相同,除了修改客户端的策略文件,将客户端证书包含在传出消息中以及服务器端应用程序上下文文件(spring-ws.servlet.xml)的更改,并且使用DAO层来获取数据: 以下是客户端输出(请注意下划线文本中的X509客户端认证): INFO:====SendingMessageStart==== 一旦客户端证书被提取(即嵌入在传入消息中),就可以通过检索用户名或其他信息进行身份验证。 在客户端策略文件中包含以下部分会导致客户端在传出消息中包含自己的公钥证书: publicclassMyUserDetailServiceimplementsUserDetailsService{@OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{returnfindUserDetailFromDAO(username);}privateUserDetailsfindUserDetailFromDAO(StringuserName)throwsUsernameNotFoundException{MyUserDetailmydetail=null;/***Realscenario:Finduser-namefromDAOlayer,ifuserfound,getdatafromtheDAOandsetMyUserDetailotherwisethrowUsernameNotFoundException.*/if(!userName.equals("MyFirstNameMyLastName")){thrownewUsernameNotFoundException("Usernamenotfound");}mydetail=newMyUserDetail(userName,"fetchedPassword",true,true,true,true,newGrantedAuthorityImpl("ROLE_GENERAL_OPERATOR"));returnmydetail;}}参见...本章讨论的使用数字签名保护SOAP消息和准备对和对称密钥库的配方。 加密是将可读或明文数据格式转换为不可读的加密格式或密文的过程,使用特定算法。这些算法称为加密算法,需要加密密钥。解密只是加密的反向操作;它使用解密密钥将密文转换回可读或明文数据格式。加密和解密密钥可以相同也可以不同。如果加密和解密密钥相同,并且发送方和接收方共享密钥,则该密钥称为对称或秘密密钥。加密和解密密钥可以不同,在这种情况下,该密钥称为非对称或公钥。 以下图表展示了对称密钥用于加密/解密的用法。发送方和接收方可以共享相同的密钥,这被称为对称密钥。拥有此密钥的人可以解密/加密消息。例如,发送方使用对称密钥进行加密,接收方使用对称密钥进行解密: 以下图表展示了公钥/私钥用于加密/解密的用法。作为发送方的Bob获取Alice的公钥,加密一条消息并发送给Alice。因为只有她拥有自己的私钥,她可以解密消息: 在这个配方中,发送方(客户端)以三种不同的情况对消息进行加密并将其发送给接收方(服务器)。在第一种情况下,对称密钥(在具有客户端和服务器相同的秘密密钥条目的存储中)用于在客户端进行加密和在服务器端进行解密。然后,在第二种情况下,接收方(服务器)在发送方(客户端)的密钥库中使用的接收方(服务器)的公钥证书(在接收方受信任的证书条目内)用于数据加密,并且接收方(服务器)的私钥在服务器端密钥库上用于解密。 有关端点映射的更多信息,请参阅第一章中讨论的配方通过注释有效负载根设置端点和设置传输中立WS-Addressing端点,构建SOAPWeb服务。 在前两种情况下,整个有效负载用于加密/解密。XWSS策略配置文件使得可能对有效负载部分进行加密/解密。在第三种情况下,只有有效负载的一部分被设置为加密/解密的目标。 在这个配方中,项目的名称是LiveRestaurant_R-7.6(用于服务器端Web服务),并具有以下Maven依赖项: LiveRestaurant_R-7.6-Client(用于客户端Web服务)具有以下Maven依赖项: 以下步骤使用共享对称密钥(symmetricStore.jks)实现加密/解密: mvncleanpackagetomcat:runmvncleanpackageINFO:====ReceivedMessageStart====.... mvncleanpackagetomcat:runmvncleanpackageINFO:====SendingMessageStart====... ---serverconfiguration ---clientconfiguration 本章讨论了《使用数字签名保护SOAP消息》和《准备成对和对称密钥库》的配方。 本书讨论了《创建用于WS-Addressing端点的Web服务客户端》一章中的配方,该章节可在《第二章构建SOAPWeb服务的客户端》中找到。 在上一章中,解释了在Spring-WS中使用SUN的实现(XWSS):OASISWeb-ServicesSecurity(WS-Security或WSS)规范(使用XwsSecurityInterceptor执行安全操作)。在本章中,将解释Spring-WS对Apache的实现(WSS4J)OASISWS-Security规范的支持。尽管这两种WS-Security的实现都能够执行所需的安全操作(身份验证、签名消息和加密/解密),但WSS4J的执行速度比XWSS快。 Spring-WS支持使用Wss4jSecurityInterceptor来支持WSS4J,这是一个在调用Endpoint之前对请求消息执行安全操作的EndpointInterceptor。 虽然XWSS使用外部配置策略文件,但WSS4J(以及相应的Wss4jSecurityInterceptor)不需要外部配置文件,并且完全可以通过属性进行配置。该拦截器应用的验证(接收方)和保护(发送方)操作通过validationActions和securementActions属性指定。可以将多个操作设置为由空格分隔的字符串。以下是本章中接收方(服务器端)的示例配置: securementActions是由空格分隔的操作列表。当发送者向接收者发送消息时,将执行这些操作。 操作的顺序很重要,并由Wss4jSecurityInterceptor应用。如果传入的SOAP消息securementActions(在发送方)与validationActions(在接收方)配置的方式不同,该拦截器将返回故障消息。 对于加密/解密或签名等操作,WSS4J需要从密钥库(store.jks)中读取数据: 为简化起见,在本章的大多数示例中,使用如何使用Spring-JUnit支持集成测试项目,第三章,测试和监控Web服务,来设置服务器并通过客户端发送和接收消息。然而,在最后一个示例中,使用了来自第二章的项目,为WS-Addressing端点创建Web服务客户端,用于服务器和客户端。 身份验证简单地意味着检查服务的调用者是否是其所声称的。检查调用者的身份验证的一种方式是检查其密码(如果我们将用户名视为一个人,密码类似于该人的签名)。Spring-WS使用Wss4jSecurityInterceptor来发送/接收带有密码的用户名令牌以及SOAP消息,并在接收方进行比较,比较其与属性格式中预定义的用户名/密码。拦截器的此属性设置强制告诉消息发送方,发送消息中应包含带有密码的用户名令牌,并且在接收方,接收方期望接收此用户名令牌以进行身份验证。 传输明文密码会使SOAP消息不安全。Wss4jSecurityInterceptor提供了配置属性(以属性格式)来将密码的摘要与发送方消息一起包括。在接收方,将与属性格式中设置的摘要密码进行比较,该摘要密码包含在传入消息中。 本示例介绍了如何使用用户名令牌对Web服务调用进行身份验证。在这里,客户端充当发送方,服务器充当接收方。本示例包含两种情况。在第一种情况下,密码将以明文格式传输。在第二种情况下,通过更改属性,密码将以摘要格式传输。 在本示例中,我们有以下两个项目: 按照以下步骤使用带有明文密码的普通用户名令牌进行身份验证: mvncleanpackagetomcat:runmvncleanpackageSentrequest.....[ mvncleanpackagetomcat:runmvncleanpackageSentrequest.....[ Liverestaurant_R-8.1-Client项目是一个客户端测试项目,用于向服务器发送包含用户名令牌和密码的SOAP信封。 在服务器端,Wss4jSecurityInterceptor强制服务器对所有传入消息进行用户名令牌验证: 在这一章中: 就像本章的第一个示例一样,这个示例也包含两种情况。在第一种情况下,密码将以纯文本格式传输。在第二种情况下,通过更改配置,密码将以摘要格式传输。 在这个示例中,我们有以下两个项目: 按照以下步骤实现Web服务调用的身份验证,使用Spring安全性对具有纯文本密码的用户名令牌进行身份验证: mvncleanpackagetomcat:runmvncleanpackageSentrequest..... 在第一种情况下,CallbackHandlerSpringPlainTextPasswordValidationCallbackHandler使用authenticationManager,该管理器使用DaoAuthenticationProvider。 publicclassMyUserDetailServiceimplementsUserDetailsService{@OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{returngetUserDataFromDao(username);}privateMyUserDetailgetUserDataFromDao(Stringusername){/***Realscenario:finduserdatafromaDAOlayerbyuserName,*ifthisusernamefound,populateMyUserDetailwithitsdata(username,password,Role,....).*/MyUserDetailmydetail=newMyUserDetail(username,"pass",true,true,true,true);mydetail.getAuthorities().add(newGrantedAuthorityImpl("ROLE_GENERAL_OPERATOR"));returnmydetail;}然而,在第二种情况下,CallbackHandler是SpringDigestPasswordValidationCallbackHandler,它将SOAP传入消息中包含的摘要密码与从DAO层获取的摘要密码进行比较(请注意,DAO层可以从不同的数据源获取数据,如数据库、LDAP、XML文件等): 在本章中: 在安全术语中,签名的目的是验证接收到的消息是否被篡改。签名在WS-Security中扮演着两个主要任务,即对消息进行签名和验证签名。消息签名涉及的所有概念都在上一章的使用数字签名保护SOAP消息中详细介绍。在这个配方中,使用WSS4J进行签名和验证签名。 Spring-WS的Wss4jSecurityInterceptor能够根据WS-Security标准进行签名和验证签名。 将此拦截器的securementActions属性设置为Signature会导致发送方对传出消息进行签名。要加密签名令牌,需要发送方的私钥。需要在应用程序上下文文件中配置密钥库的属性。securementUsername和securementPassword属性指定了用于使用的密钥库中的私钥的别名和密码。securementSignatureCrypto应指定包含私钥的密钥库。 将validationActions设置为value="Signature"会导致消息的接收方期望并验证传入消息的签名(如开头所述)。validationSignatureCryptobean应指定包含发送方公钥证书(受信任证书)的密钥库。 来自wss4j包的org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean可以提取密钥库数据(例如证书和其他密钥库信息),并且这些数据可以用于身份验证。 在本教程中,客户端存储的私钥用于加密消息的客户端签名。在服务器端,包含在服务器密钥库中的客户端公钥证书(在受信任证书条目中)将用于解密消息签名令牌。然后服务器对签名进行验证(如开头所述)。在[第七章中使用的密钥库,在准备配对和对称密钥库中使用。 在本教程中,我们有以下两个项目: 在服务器端将validationActions设置为Signature会导致它期望来自客户端配置的签名,并且设置密钥库会导致服务器端密钥库中的客户端公钥证书(受信任证书)用于解密签名。然后服务器对签名进行验证: 第七章,使用XWSS库保护SOAPWeb服务: 在本章的前面部分,介绍了如何使用用户名令牌对传入消息进行身份验证。随传入消息一起传来的客户端证书可以用作替代用户名令牌进行身份验证。 为了确保所有传入的SOAP消息携带客户端的证书,发送方的配置文件应该签名,接收方应该要求所有消息都有签名。换句话说,客户端应该对消息进行签名,并在传出消息中包含X509证书,服务器首先将传入的证书与信任的证书进行比较,该证书嵌入在服务器密钥库中,然后进行验证传入消息的签名。 在此配方中,我们有以下两个项目: 以下是客户端的输出(请注意突出显示的文本): Sentrequest.... SOAP消息的加密和解密概念与第七章中描述的加密/解密SOAP消息相同。Spring-WS的Wss4jSecurityInterceptor通过在接收方(这里是服务器端)设置属性validationActions为Encrypt来提供对传入SOAP消息的解密。在发送方(这里是客户端)设置属性securementActions会导致发送方对传出消息进行加密。 Wss4jSecurityInterceptor需要访问密钥库进行加密/解密。在使用对称密钥的情况下,KeystoreCallbackHandler负责访问(通过设置location和password属性)并从对称密钥库中读取,并将其传递给拦截器。然而,在使用私钥/公钥对存储的情况下,CryptoFactoryBean将执行相同的工作。 在这个示例中,在第一种情况下,客户端和服务器共享的对称密钥用于客户端的加密和服务器端的解密。然后,在第二种情况下,客户端密钥库中的服务器公钥证书(受信任的证书)用于数据加密,服务器端密钥库中的服务器私钥用于解密。 在前两种情况下,整个有效载荷用于加密/解密。通过设置一个属性,可以对有效载荷的一部分进行加密/解密。在第三种情况下,只有有效载荷的一部分被设置为加密/解密的目标。 按照以下步骤使用对称密钥实施加密/解密: mvncleanpackagetomcat:runmvncleanpackageSentrequest... 以下是服务器端的输出(请注意突出显示的文本): mvncleanpackagetomcat:runmvncleanpackage.......... 然而,在第二和第三种情况下,客户端存储中嵌入的服务器证书用于加密有效负载,在服务器端,服务器存储的私钥将用于解密。第二种和第三种情况之间的区别在于第二种情况加密/解密整个有效负载,但在第三种情况下,只有部分有效负载将成为加密/解密的目标。 在第一种情况下,在服务器端将validationActions设置为Encrypt会导致服务器使用对称密钥解密传入消息。拦截器使用ValidationCallbackHandler进行解密,使用在location属性中设置的对称密钥存储。type属性设置密钥的存储类型,password设置对称密钥的密钥存储密码: 默认情况下,SOAP标头中的ds:KeyName元素采用securementEncryptionUser属性的值。securementEncryptionEmbeddedKeyName可用于指示不同的值。securementEncryptionKeyTransportAlgorithm属性定义要使用的算法来加密生成的对称密钥。securementCallbackHandler提供了KeystoreCallbackHandler,指向适当的密钥存储,即服务器端配置中描述的对称密钥存储: 第二章,为SOAPWeb服务构建客户端 第七章,使用XWSS库保护SOAPWeb服务 简单对象访问协议(SOAP)允许应用程序使用XML作为通信格式进行通信(SOAP很容易理解),但由于它是基于XML的,即使对于非常简单的Web服务场景,它也往往冗长。 表述性状态转移(REST),由RoyFielding于2000年发表的博士论文,旨在简化Web服务的使用。 以下是REST的一些缺点:REST仅适用于HTTP;调用RESTfulWeb服务受到HTTP动词的限制:GET、POST、PUT和DELETE。 RESTful是建立在REST原则之上的,其中使用HTTP的方法基于其概念。例如,HTTP的GET、POST、PUT和DELETE都在RESTful架构中使用,与HTTP的含义相匹配。 RESTfulWeb服务公开其资源的状态。在本章中,例如,RESTful服务公开了获取在线餐厅中可用订单项目列表和订单对象的服务。要获取可用订单项目列表,使用GET方法,而要下订单,则使用POST方法。PUT方法可用于添加/更新条目,DELETE方法可用于删除条目。 以下是用于进行RESTfulWeb服务调用并获取可用订单项目列表的示例URL: 以下是返回响应(响应格式不一定是XML格式;它可以是JSON、纯文本或任何格式): Spring作为JavaEE广泛使用的框架,在3.0版本中引入了对RESTfulWeb服务的支持。RESTful已经集成到Spring的MVC层中,允许应用程序使用RESTful功能构建Spring。其中最重要的功能包括: Spring3.0支持基于SpringMVC的RESTfulWeb服务。Spring使用注解来设置RESTfulWeb服务,并需要在Spring应用程序上下文文件中进行配置以扫描注解。需要一个SpringMVC控制器来设置RESTfulWeb服务。@Controller注解标记一个类为MVC控制器。@RequestMapping注解将传入的请求映射到控制器类中的适当Java方法。使用这个注解,你可以定义URI和HTTP方法,这些方法映射到Java类方法。例如,在下面的例子中,如果请求URI后跟着/orderItems,那么方法loadOrderItems将被调用,@PathVariable用于将请求参数({cayegoryId})的值注入到方法参数中(StringcayegoryId): @RequestMapping(value="/orderItem/{cayegoryId}",method=RequestMethod.GET)publicModelAndViewloadOrderItems(@PathVariableStringcayegoryId){...}在这个示例中,介绍了使用Spring3MVC实现RESTfulWeb服务。这个Web服务的客户端项目在这里实现了,但将在本章的最后一个示例中详细介绍:使用Spring模板类为SpringRESTfulWeb服务创建WS客户端。 在这个示例中,项目的名称是LiveRestaurant_R-9.1(LiveRestaurant_R-9.1-Client项目包含在代码中用于测试目的),具有以下Maven依赖项: spring-oxm是Spring对对象/XML映射的支持,spring-web和spring-webmvc是对Seb和MVC支持的支持,xstream是用于对象/XML映射框架的支持。 所有请求将到达DispatcherServlet,它将被转发到控制器OrderController,根据请求URI,将调用适当的方法返回响应给调用者。web.xml中的以下配置将所有请求转发到DispatcherServlet: @RequestMapping(value="/order/{orderId}",method=RequestMethod.POST)publicModelAndViewplaceOrder(@PathVariableStringorderId){..}@PathVariable导致从URI中注入并传递给placeOrder方法的orderId参数。 方法的主体placeOrder调用OrderService接口的方法并返回Order对象: Orderorder=orderService.placeOrder(orderId);ModelAndViewmav=newModelAndView("orderXmlView",BindingResult.MODEL_KEY_PREFIX+"order",order);returnmav;然后,它基于将Order对象编组成XML格式来构建视图,使用Marshallingviewbean(MVC中的视图使用XStreamMarshaller将模型对象编组成XML格式),并将其返回给服务的调用者。 @RequestMapping(value="/orderItems",method=RequestMethod.GET)publicModelAndViewloadOrderItems(){List 在本书中: 第六章,编组和对象-XML映射(OXM): 使用XStream进行编组 RESTClient是一个用于调用和测试RESTfulWeb-Services的应用程序。RESTClient作为Firefox/Flock附加组件提供。FirefoxRESTClient支持所有HTTP方法,RFC2616(HTTP/1.1)和RFC2518(WebDAV)。使用此附加组件,您可以构建自己定制的URI,添加标头,将其发送到RESTfulWeb-Services,并获取响应。 在本教程中,我们将学习如何使用FirefoxRESTClient测试RESTfulWeb-Service的呈现方式。本教程使用本章的第一个教程,使用SpringMVC中的RESTful功能设置SpringRESTfulWeb-Service,作为RESTfulWeb-Services。 下载并安装Firefox的以下附加组件: 这是结果: 使用SpringMVC中的RESTful功能设置SpringRESTfulWeb-Service HTTP协议上的客户端和服务器使用文本格式交换数据。最终,需要接受不同的请求格式,并将文本格式转换为有意义的格式,例如对象或JSON格式。Spring提供了提供从相同文本格式到多个请求/演示的功能。 Spring3引入了ContentNegotiatingViewResolver,它可以从相同的URI选择各种视图,并提供多个演示。 执行相同任务的另一种方法是使用HttpMessageConverter接口和@ResponseBody注解。Spring中HttpMessageConverter接口的实现将HTTP消息转换为多种格式。其广泛使用的实现包括: 在本示例中,使用MarshallingHttpMessageConverter,MappingJacksonHttpMessageConverter和AtomFeedHttpMessageConverter进行消息转换。由于此项目类似于本章的第一个示例,使用SpringMVC中的RESTful功能设置SpringRESTfulWeb服务,因此它被重用作项目的模板。本示例的区别在于控制器实现和应用程序上下文配置。 这个Web服务的客户端项目在这里实现,但将在本章的最后一个示例中详细介绍,使用Spring模板类为SpringRESTfulWeb服务创建WS客户端。 在本示例中,项目名称为LiveRestaurant_R-9.2(LiveRestaurant_R-9.2-Client在本示例中包含在代码中以进行测试。但是,它将在最后一个示例中解释),并且具有以下Maven依赖项: jackson-core和jackson-mapper支持JSON格式,其他支持ATOM格式。 这个示例与本章的第一个示例几乎相同,只是它使用了消息转换器和@ResponseBody来提供多个表示。 在第一个示例中,MarshallingView负责将响应转换为所选视图的XML类型(使用XstreamMarshaller)。然而,在这里,消息转换器负责将数据模型呈现为所选格式,MarshallingHttpMessageConverter负责将List @RequestMapping(method=RequestMethod.POST,value="/orderJson/{orderId}",headers="Accept=application/json")public@ResponseBodyOrderplaceOrderJson(@PathVariableStringorderId){Orderorder=orderService.placeOrder(orderId);returnorder;}并以JSON格式返回Order对象(使用@ResponseBody和MappingJacksonHttpMessageConverter在order-context.xml中配置): {"message":"OrderPizzahasbeenplaced","ref":"Ref:1","orderItemId":"1"}以下代码导致控制器方法接受请求URI方法的GET格式-atom: @RequestMapping(method=RequestMethod.GET,value="/orderItemsFeed",headers="Accept=application/atom+xml")public@ResponseBodyFeedloadOrderItemsAtom(){Feedfeed=null;try{feed=getOrderItemsFeed(orderService.listOrderItems());}catch(Exceptione){thrownewRuntimeException(e);}returnfeed;}它还以Atom格式返回List 使用SpringMVC中的RESTful功能设置SpringRESTfulWeb服务 Spring提供了各种模板类,使用不同的技术简化了许多复杂性。例如,WebServiceTemplate用于调用基于SOAP的Web服务,JmsTemplate用于发送/接收JMS消息。Spring还有RestTemplate来简化与RESTfulWeb服务的交互。 使用RestTemplate: 在这个示例中,我们将学习如何使用RestTemplate消耗RESTfulWeb服务。这个示例使用了本章的第三个示例,使用HTTP消息转换设置SpringRESTfulWeb服务,作为RESTfulWeb服务。 在这个示例中,项目的名称是LiveRestaurant_R-9.2-Client(LiveRestaurant_R-9.2包含在这个示例中,用于设置RESTful服务器,如前面的示例使用HTTP消息转换设置SpringRESTfulWeb服务中所解释的),具有以下Maven依赖项: 在套件类测试方法中,响应将与期望的值进行比较。 applicationContext.xml定义了restTemplatebean并设置了一系列消息转换器: OrderClient.java是一个辅助类,用于调用RESTfulWeb服务,使用RestTemplate: Spring-WS项目是一种基于契约的方法来构建Web服务。这种方法已经在前八章中详细介绍过。然而,有时的要求是将现有的业务Springbean暴露为Web服务,这被称为契约后方法,用于设置Web服务。 Spring的远程支持与多种远程技术的通信。Spring远程允许在服务器端暴露现有的Springbean作为Web服务。在客户端,Spring远程允许客户端应用程序通过本地接口调用远程Springbean(该bean作为Web服务暴露)。在本章中,详细介绍了Spring的以下远程技术的功能: 由于JAX-WS是JAX-RPC的后继者,因此本章不包括JAX-RPC。相反,本章将详细介绍ApacheCXF,因为它可以使用JAX-WS来设置Web服务,即使它不是Spring的远程的一部分。 为简化起见,在本章中,将暴露以下本地业务服务作为Web服务(领域模型在第一章的介绍部分中已经描述,构建SOAPWeb服务)。 publicinterfaceOrderService{placeOrderResponseplaceOrder(PlaceOrderRequestplaceOrderRequest);}这是接口实现: publicclassOrderServiceImplimplementsOrderService{publicPlaceOrderResponseplaceOrder(PlaceOrderRequestplaceOrderRequest){PlaceOrderResponseresponse=newPlaceOrderResponse();response.setRefNumber(getRandomOrderRefNo());returnresponse;}...使用RMI设置Web服务RMI是J2SE的一部分,允许在不同的Java虚拟机(JVM)上调用方法。RMI的目标是在单独的JVM中公开对象,就像它们是本地对象一样。通过RMI调用远程对象的客户端不知道对象是远程还是本地,并且在远程对象上调用方法与在本地对象上调用方法具有相同的语法。 Spring的远程提供了基于RMI技术的暴露/访问Web服务的功能。在服务器端,Spring的RmiServiceExporterbean将服务器端Spring业务bean暴露为Web服务。在客户端,Spring的RmiProxyFactoryBean将Web服务的方法呈现为本地接口。 在这个示例中,我们将学习使用RMI设置Web服务,并了解通过RMI呼叫Web服务的呈现方式。 mvncleanpackageexec:javamvncleanpackage.........-LocatedRMIstubwithURL[rmi://localhost:1199/OrderService]....-RMIstub[rmi://localhost:1199/OrderService]isanRMIinvoker......Testsrun:1,Failures:0,Errors:0,Skipped:0,Timeelapsed:0.78sec...Testsrun:1,Failures:0,Errors:0,Skipped:0......[INFO]BUILDSUCCESS工作原理...OrderServiceSetUp是加载服务器端应用程序上下文并设置服务器以将服务器端业务服务暴露为Web服务的类。OrderServiceClientTest是客户端测试类,加载客户端应用程序上下文并通过代表远程业务服务的客户端本地接口调用Web服务方法。 OrderServiceImpl是要通过Web服务公开的服务。在服务器端的应用程序上下文中,在org.springframework.remoting.rmi.RmiServiceExporterBean中,OrderService是将在RMI注册表中注册的服务的名称。服务属性用于传递RmiServiceExporter和bean实例。serviceInterface是表示本地业务服务的接口。只有在此接口中定义的方法才能远程调用: Spring的远程提供了基于这些技术的Web服务的暴露/访问功能。在服务器端,Spring的ServiceExporterbean将服务器端Spring业务bean(OrderServiceImpl)暴露为Web服务: 按照以下步骤设置基于servlet的Web服务,使用Hessian服务: mvncleanpackagetomcat:runmvncleanpackagetext.annotation.internalCommonAnnotationProcessor];rootoffactoryhierarchyTestsrun:1,Failures:0,Errors:0,Skipped:0,Timeelapsed:0.71secResults:Testsrun:1,Failures:0,Errors:0,Skipped:0[INFO]按照以下步骤使用Burlap服务设置基于servlet的Web服务: mvncleanpackagetomcat:runmvncleanpackagetext.annotation.internalCommonAnnotationProcessor];rootoffactoryhierarchyTestsrun:1,Failures:0,Errors:0,Skipped:0,Timeelapsed:0.849secResults:Testsrun:1,Failures:0,Errors:0,Skipped:0[INFO][INFO]---maven-jar-plugin:2.3.1:jar..[INFO]Buildingjar:...[INFO]------------------------------------------------------------------------[INFO]BUILDSUCCESS它是如何工作的...Liverestaurant_R-10.2项目是一个服务器端Web服务,使用Spring远程的burlap/hessian出口商设置基于servlet的Web服务。 Liverestaurant_R-10.2-Client项目是一个客户端测试项目,调用了Spring远程的burlap/hessianWeb服务,使用了burlap/hessian客户端代理。 使用RMI设置Web服务 JAX-RPC是JavaEE1.4中附带的一个标准,用于开发Web服务,在近年来变得越来越不受欢迎。JAX-WS2.0是在JavaEE5中引入的,比JAX-RPC更灵活,基于注解的绑定概念。以下是JAX-WS相对于JAX-RPC的一些优势: Spring远程提供了设置使用Java1.5+功能的JAX-WSWeb服务的功能。例如,在这里,注解@WebService会导致Spring检测并将此服务公开为Web服务,@WebMethod会导致以下方法:publicOrderResponseplaceOrder(..),被调用为Web服务方法(placeOrder): @Service("OrderServiceImpl")@WebService(serviceName="OrderService",endpointInterface="com.packtpub.liverestaurant.service.OrderService")publicclassOrderServiceImplimplementsOrderService{@WebMethod(operationName="placeOrder")publicPlaceOrderResponseplaceOrder(PlaceOrderRequestplaceOrderRequest){在这个食谱中,使用JDK内置的HTTP服务器来设置Web服务(自从Sun的JDK1.6.0_04以来,JAX-WS可以与JDK内置的HTTP服务器集成)。 安装Java和Maven(SE运行时环境(构建jdk1.6.0_29))。 在这个食谱中,我们有以下两个项目: mvncleanpackageexec:javamvncleanpackage.....DynamicallycreatingrequestwrapperClasscom.packtpub.liverestaurant.service.jaxws.PlaceOrderNov14,201111:34:13PMcom.sun.xml.internal.ws.model.RuntimeModelergetResponseWrapperClassINFO:DynamicallycreatingresponsewrapperbeanClasscom.packtpub.liverestaurant.service.jaxws.PlaceOrderResponse......Results:Testsrun:1,Failures:0,Errors:0,Skipped:0它是如何工作的...Liverestaurant_R-10.3项目是一个服务器端Web服务(通过Spring远程的出口器bean),它使用DK内置的HTTP服务器设置了一个JAX-WS。 Liverestaurant_R-10.3-Client项目是一个客户端测试项目,它使用Spring远程的客户端代理调用JAX-WSWeb服务。 在服务器端,applicationContext.xml扫描并检测OrderServiceImpl中的注释标签。然后,SimpleJaxWsServiceExporter将此业务服务公开为Web服务: @Service("orderServiceImpl")@WebService(serviceName="OrderService")publicclassOrderServiceImplimplementsOrderService{@WebMethod(operationName="placeOrder")publicPlaceOrderResponseplaceOrder(PlaceOrderRequestplaceOrderRequest){PlaceOrderResponseresponse=newPlaceOrderResponse();response.setRefNumber(getRandomOrderRefNo());returnresponse;}.......}在客户端,JaxWsPortProxyFactoryBean负责将远程方法暴露给客户端,使用本地客户端接口。WsdlDocumentUrl是Web服务WSDL地址,portName是WSDL中的portName值,namespaceUri是WSDL中的targetNameSpace,serviceInterface是本地客户端服务接口: 第二章,构建SOAPWeb服务的客户端 在HTTP传输上创建Web服务客户端 ApacheCXF起源于以下项目的组合:Celtix(IONATechnologies)和XFire(Codehaus),它们被整合到Apache软件基金会中。CXF的名称意味着它起源于Celtix和XFire项目名称。 ApacheCXF提供了构建和部署Web服务的功能。ApacheCXF推荐的Web服务配置方法(前端或API)是JAX-WS2.x。ApacheCXF并不是Spring的远程的一部分,但是,由于它可以使用JAX-WS作为其前端,因此将在本配方中进行解释。 安装Java和Maven(SERuntimeEnvironment(构建jdk1.6.0_29))。 在这个配方中,我们有以下两个项目: Liverestaurant_R-10.4项目是一个服务器端Web服务,它使用JAX-WSAPI设置了一个CXF。 Liverestaurant_R-10.4-Client项目是一个客户端测试项目,它使用Spring的远程调用从JAX-WSWeb服务调用客户端代理。 在服务器端,applicationContext.xml中的配置检测OrderServiceImpl中的注释标签。然后jaxws:endpoint将此业务服务公开为Web服务: 在客户端,JaxWsProxyFactoryBean负责使用本地客户端接口向客户端公开远程方法。address是Web服务的地址,serviceInterface是本地客户端服务接口: Java消息服务(JMS)由Java2和J2EE引入,由SunMicrosystems于1999年成立。使用JMS的系统能够以同步或异步模式进行通信,并且基于点对点和发布-订阅模型。 Spring远程提供了使用JMS作为底层通信协议公开Web服务的功能。Spring的JMS远程在单线程和非事务会话中在同一线程上发送和接收消息。 但是,对于JMS上的Web服务的多线程和事务支持,您可以使用基于Spring的JMS协议的Spring-WS,该协议基于Spring的基于JMS的消息传递。 在这个示例中,使用apache-activemq-5.4.2来设置一个JMS服务器,并且默认对象,由这个JMS服务器创建的(队列,代理),被项目使用。 安装apache-activemq-5.4.2。 在服务器端应用程序上下文文件中注册业务服务到JmsInvokerServiceExporterbean,并使用activemq默认对象(代理,destination)注册SimpleMessageListenerContainer。 mvncleanpackageexec:javamvncleanpackageTESTS-------------------------------------------------------Runningcom.packtpub.liverestaurant.service.client.OrderServiceClientTestlog4j:WARNNoappenderscouldbefoundforlogger(org.springframework.test.context.junit4.SpringJUnit4ClassRunner).log4j:WARNPleaseinitializethelog4jsystemproperly.Testsrun:1,Failures:0,Errors:0,Skipped:0,Timeelapsed:1.138secResults:Testsrun:1,Failures:0,Errors:0,Skipped:0工作原理...Liverestaurant_R-10.5项目是一个服务器端Web服务,它通过监听JMS队列设置了一个Web服务。 Liverestaurant_R-10.5-Client项目是一个客户端测试项目,它向JMS队列发送JMS消息。 在服务器端,OrderServiceSetUp类加载applicationContext.xml并在容器中创建一个messageListener(使用SimpleMessageListenerContainer),等待在特定目的地(requestQueue)监听消息。一旦消息到达,它通过Spring的远程调用类(JmsInvokerServiceExporter)调用业务类(OrderServiceImpl)的方法。
另请参阅在第一章中讨论的设置简单的端点映射用于Web服务的配方,构建SOAPWeb服务。
OrderEndPoint被注释为@Endpoint,与JiBX示例相同,端点方法的输入和返回参数是映射到模式的POJO(PlaceOrderResponse、PlaceOrderRequest等)。
RESTfulWeb服务有几种实现,例如Restlet、RestEasy和Jersey。其中,Jersey是这一组中最重要的实现,是JAX-RS(JSR311)的实现。