1、服务注册:(目录)UDDI允许用户查找服务的基石
2、服务需求者:(传输)SOAP是连接应用和数据的机制
3、服务提供商:(接口)用WSDL定义如何应用服务
服务提供商-发布-服务注册
服务需求者-发现-服务注册
服务提供者-绑定-服务提供商
Writing Contract-First Web Services
1. Introduction
This tutorial shows you how to write contract-first Web services , that is, developing web services that start with the XML Schema/WSDL contract first followed by the Java code second. Spring-WS focuses on this development style, and this tutorial will help you get started. Note that the first part of this tutorial contains almost no Spring-WS specific information: it is mostly about XML, XSD, and WSDL. The second part focusses on implementing this contract using Spring-WS .
The most important thing when doing contract-first Web service development is to try and think in terms of XML. This means that Java-language concepts are of lesser importance. It is the XML that is sent across the wire, and you should focus on that. The fact that Java is used to implement the Web service is an implementation detail. An important detail, but a detail nonetheless.
In this tutorial, we will define a Web service that is created by a Human Resources department. Clients can send holiday request forms to this service to book a holiday.
2. Messages
In this section, we will focus on the actual XML messages that are sent to and from the Web service. We will start out by determining what these messages look like.
2.1. Holiday
In the scenario, we have to deal with holiday requests, so it makes sense to determine what a holiday looks like in XML:
<Holiday xmlns="http://mycompany.com/hr/schemas"> <StartDate>2006-07-03</StartDate> <EndDate>2006-07-07</EndDate> </Holiday>
A holiday consists of a start date and an end date. We have also decided to use the standard ISO 8601 date format for the dates, because that will save a lot of parsing hassle. We have also added a namespace to the element, to make sure our elements can used within other XML documents.
There is also the notion of an employee in the scenario. Here is what it looks like in XML:
<Employee xmlns="http://mycompany.com/hr/schemas"> <Number>42</Number> <FirstName>Arjen</FirstName> <LastName>Poutsma</LastName> </Employee>
We have used the same namespace as before. If this
<Employee/>
element could be used in other
scenarios, it might make sense to use a different namespace, such as
http://mycompany.com/employees/schemas
.
2.3. HolidayRequest
Both the holiday and employee element can be put in a
<HolidayRequest/>
:
<HolidayRequest xmlns="http://mycompany.com/hr/schemas"> <Holiday> <StartDate>2006-07-03</StartDate> <EndDate>2006-07-07</EndDate> </Holiday> <Employee> <Number>42</Number> <FirstName>Arjen</FirstName> <LastName>Poutsma</LastName> </Employee> </HolidayRequest>
The order of the two elements does not matter: <Employee/>
could have been the first element just as well. What is important is
that all of the data is there. In fact, the data is the only thing
that is important: we are taking a data-driven
approach.
3. Data Contract
Now that we have seen some examples of the XML data that we will use, it makes sense to formalize this into a schema. This data contract defines the message format we accept. There are four different ways of defining such a contract for XML:
DTDs have limited namespace support, so they are not suitable for Web services. Relax NG and Schematron certainly are easier than XML Schema. Unfortunately, they are not so widely supported across platforms. We will use XML Schema.
By far the easiest way to create an XSD is to infer it from sample documents. Any good XML editor or Java IDE offers this functionality. Basically, these tools use some sample XML documents, and generate a schema from it that validates them all. The end result certainly needs to be polished up, but it's a great starting point.
Using the sample described above, we end up with the following generated schema:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://mycompany.com/hr/schemas" xmlns:hr="http://mycompany.com/hr/schemas"> <xs:element name="HolidayRequest"> <xs:complexType> <xs:sequence> <xs:element ref="hr:Holiday"/> <xs:element ref="hr:Employee"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Holiday"> <xs:complexType> <xs:sequence> <xs:element ref="hr:StartDate"/> <xs:element ref="hr:EndDate"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="StartDate" type="xs:NMTOKEN"/> <xs:element name="EndDate" type="xs:NMTOKEN"/> <xs:element name="Employee"> <xs:complexType> <xs:sequence> <xs:element ref="hr:Number"/> <xs:element ref="hr:FirstName"/> <xs:element ref="hr:LastName"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Number" type="xs:integer"/> <xs:element name="FirstName" type="xs:NCName"/> <xs:element name="LastName" type="xs:NCName"/> </xs:schema>
This generated schema obviously can be improved. The first thing
to notice is that every type has a root-level element declaration.
This means that the Web service should be able to accept all of
these elements as data. This is not desirable: we only want to
accept a <HolidayRequest/>
. By removing
the wrapping element tags (thus keeping the types), and inlining
the results, we can accomplish this.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:hr="http://mycompany.com/hr/schemas" elementFormDefault="qualified" targetNamespace="http://mycompany.com/hr/schemas"> <xs:element name="HolidayRequest"> <xs:complexType> <xs:sequence> <xs:element name="Holiday" type="hr:HolidayType"/> <xs:element name="Employee" type="hr:EmployeeType"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="HolidayType"> <xs:sequence> <xs:element name="StartDate" type="xs:NMTOKEN"/> <xs:element name="EndDate" type="xs:NMTOKEN"/> </xs:sequence> </xs:complexType> <xs:complexType name="EmployeeType"> <xs:sequence> <xs:element name="Number" type="xs:integer"/> <xs:element name="FirstName" type="xs:NCName"/> <xs:element name="LastName" type="xs:NCName"/> </xs:sequence> </xs:complexType> </xs:schema>
The schema still has one problem: with a schema like this, you can expect the following messages to validate:
<HolidayRequest xmlns="http://mycompany.com/hr/schemas">
<Holiday>
<StartDate>this is not a date</StartDate>
<EndDate>neither is this</EndDate>
</Holiday>
<!-- ... -->
</HolidayRequest>
Clearly, we must make sure that the start and end date are really dates.
XML Schema has an excellent built-in date
type which
we can use. We also change the NCName
s to
string
s. Finally, we change the sequence
in
<HolidayRequest/>
to all
.
This tells the XML parser that the order of
<Holiday/>
and
<Employee/>
is not significant. Our final
XSD now looks like this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:hr="http://mycompany.com/hr/schemas" elementFormDefault="qualified" targetNamespace="http://mycompany.com/hr/schemas"> <xs:element name="HolidayRequest"> <xs:complexType> <xs:all> <xs:element name="Holiday" type="hr:HolidayType"/> <xs:element name="Employee" type="hr:EmployeeType"/> </xs:all> </xs:complexType> </xs:element> <xs:complexType name="HolidayType"> <xs:sequence> <xs:element name="StartDate" type="xs:date"/> <xs:element name="EndDate" type="xs:date"/> </xs:sequence> </xs:complexType> <xs:complexType name="EmployeeType"> <xs:sequence> <xs:element name="Number" type="xs:integer"/> <xs:element name="FirstName" type="xs:string"/> <xs:element name="LastName" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema>
|
|
We use the |
|
|
We store this file as hr.xsd
.
4. Service contract
A service contract is generally expressed as a WSDL file. Note that in Spring-WS, writing the WSDL by hand is not required . Based on the XSD and some conventions, Spring-WS can create the WSDL for you, as explained in the section entitled Section 3.6, “Implementing the Endpoint” . You can skip to the next section if you want to; the remainder of this section will show you how to write your own WSDL by hand.
We start our WSDL with the standard preamble, and by importing our existing XSD. To
separate the schema from the definition, we will use a separate namespace for the WSDL definitions:
http://mycompany.com/hr/definitions
.
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:schema="http://mycompany.com/hr/schemas" xmlns:tns="http://mycompany.com/hr/definitions" targetNamespace="http://mycompany.com/hr/definitions"> <wsdl:types> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:import namespace="http://mycompany.com/hr/schemas" schemaLocation="hr.xsd"/> </xsd:schema> </wsdl:types>
Next, we add our messages based on the written schema types. We only have one message: one with the
<HolidayRequest/>
we put in the schema:
<wsdl:message name="HolidayRequest"> <wsdl:part element="schema:HolidayRequest" name="HolidayRequest"/> </wsdl:message>
We add the message to a port type as an operation:
<wsdl:portType name="HumanResource"> <wsdl:operation name="Holiday"> <wsdl:input message="tns:HolidayRequest" name="HolidayRequest"/> </wsdl:operation> </wsdl:portType>
That finished the abstract part of the WSDL (the interface, as it were), and leaves the concrete part.
The concrete part consists of a binding
, which tells the client how
to invoke the operations you've just defined; and a service
, which tells it
where
to invoke it.
Adding a concrete part is pretty standard: just refer to the abstract part you defined previously, make sure
you use document/literal
for the soap:binding
elements
(rpc/encoded
is deprecated), pick a soapAction
for the operation
(in this case http://mycompany.com/RequestHoliday
, but any URI will do), and determine the
location
URL where you want request to come in (in this case
http://mycompany.com/humanresources
):
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:schema="http://mycompany.com/hr/schemas" xmlns:tns="http://mycompany.com/hr/definitions" targetNamespace="http://mycompany.com/hr/definitions"> <wsdl:types> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:import namespace="http://mycompany.com/hr/schemas" schemaLocation="hr.xsd"/> </xsd:schema> </wsdl:types> <wsdl:message name="HolidayRequest"> <wsdl:part element="schema:HolidayRequest" name="HolidayRequest"/> </wsdl:message> <wsdl:portType name="HumanResource"> <wsdl:operation name="Holiday"> <wsdl:input message="tns:HolidayRequest" name="HolidayRequest"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HumanResourceBinding" type="tns:HumanResource"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="Holiday"> <soap:operation soapAction="http://mycompany.com/RequestHoliday"/> <wsdl:input name="HolidayRequest"> <soap:body use="literal"/> </wsdl:input> </wsdl:operation> </wsdl:binding> <wsdl:service name="HumanResourceService"> <wsdl:port binding="tns:HumanResourceBinding" name="HumanResourcePort"> <soap:address location="http://localhost:8080/holidayService/"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
We import the schema defined in Section 3.3, “Data Contract” . |
|
We define the |
|
The |
|
We define the |
|
We define the |
|
We use a document/literal style. |
|
The literal |
|
The |
|
The |
This is the final WSDL. We will describe how to implement the resulting schema and WSDL in the next section.
5. Creating the project
In this section, we will be using Maven2 to create the initial project structure for us. Doing so is not required, but greatly reduces the amount of code we have to write to setup our HolidayService.
The following command creates a Maven2 web application project for us, using the Spring-WS archetype (that is, project template)
mvn archetype:create -DarchetypeGroupId=org.springframework.ws \ -DarchetypeArtifactId=spring-ws-archetype \ -DarchetypeVersion=1.5.9 \ -DgroupId=com.mycompany.hr \ -DartifactId=holidayService
This command will create a new directory called holidayService
. In this directory,
there is a 'src/main/webapp'
directory, which will contain the root of the WAR file.
You will find the standard web application deployment descriptor 'WEB-INF/web.xml'
here, which defines a Spring-WS MessageDispatcherServlet
and maps all incoming
requests to this servlet:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <display-name>MyCompany HR Holiday Service</display-name> <!-- take especial notice of the name of this servlet --> <servlet> <servlet-name>spring-ws </servlet-name> <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>spring-ws</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
In addition to the above 'WEB-INF/web.xml'
file, you will also need another,
Spring-WS-specific configuration file, named 'WEB-INF/spring-ws-servlet.xml'
.
This file contains all of the Spring-WS-specific beans such as EndPoints
,
WebServiceMessageReceivers
, and suchlike, and is used to create a new Spring container.
The name of this file is derived from the name of the attendant servlet (in this case
'spring-ws'
) with '-servlet.xml'
appended to it. So if you defined a
MessageDispatcherServlet
with the name 'dynamite'
, the name of the
Spring-WS-specific configuration file would be 'WEB-INF/dynamite-servlet.xml'
.
(You can see the contents of the 'WEB-INF/spring-ws-servlet.xml'
file for this
example in ???
.)
6. Implementing the Endpoint
In Spring-WS, you will implement Endpoints to handle incoming XML messages. There are two flavors of endpoints: message endpoints and payload endpoints . Message endpoints give access to the entire XML message, including SOAP headers. Typically, the endpoint will only be interested in the payload of the message, that is the contents of the SOAP body. In that case, creating a payload endpoint makes more sense.
6.1. Handling the XML Message
In this sample application, we are going to use JDom
to handle
the XML message. We are also using XPath
, because
it allows us to select particular parts of the XML JDOM tree, without requiring strict schema
conformance. We extend our endpoint from AbstractJDomPayloadEndpoint
,
because that will give us a JDOM element to execute the XPath queries on.
package com.mycompany.hr.ws; import java.text.SimpleDateFormat; import java.util.Date; import com.mycompany.hr.service.HumanResourceService; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.xpath.XPath; import org.springframework.ws.server.endpoint.AbstractJDomPayloadEndpoint; public class HolidayEndpoint extends AbstractJDomPayloadEndpoint { private XPath startDateExpression; private XPath endDateExpression; private XPath nameExpression; private final HumanResourceService humanResourceService; public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMExceptio n { this.humanResourceService = humanResourceService; Namespace namespace = Namespace.getNamespace("hr", "http://mycompany.com/hr/schemas"); startDateExpression = XPath.newInstance("//hr:StartDate"); startDateExpression.addNamespace(namespace); endDateExpression = XPath.newInstance("//hr:EndDate"); endDateExpression.addNamespace(namespace); nameExpression = XPath.newInstance("concat(//hr:FirstName,' ',//hr:LastName)"); nameExpression.addNamespace(namespace); } protected Element invokeInternal(Element holidayRequest) throws Exception { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date startDate = dateFormat.parse(startDateExpression.valueOf(holidayRequest)); Date endDate = dateFormat.parse(endDateExpression.valueOf(holidayRequest)); String name = nameExpression.valueOf(holidayRequest); humanResourceService.bookHoliday(startDate, endDate, name); return null; } }
The |
|
The |
Using JDOM is just one of the options to handle the XML: other options include DOM, dom4j, XOM, SAX, and StAX, but also marshalling techniques like JAXB, Castor, XMLBeans, JiBX, and XStream. We chose JDOM because it gives us access to the raw XML, and because it is based on classes (not interfaces and factory methods as with W3C DOM and dom4j), which makes the code less verbose. We use XPath because it is less fragile than marshalling technologies: we don't care for strict schema conformance, as long as we can find the dates and the name.
Because we use JDOM, we must add some dependencies to the Maven pom.xml
, which is in the
root of our project directory. Here is the relevant section of the POM:
<dependencies> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>1.5.9</version> </dependency> <dependency> <groupId>jdom</groupId> <artifactId>jdom</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>javax.xml.soap</groupId> <artifactId>saaj-api</artifactId> <version>1.3</version> <scope>runtime</scope> </dependency> <dependency> <groupId>com.sun.xml.messaging.saaj</groupId> <artifactId>saaj-impl</artifactId> <version>1.3</version> <scope>runtime</scope> </dependency> </dependencies>
Here is how we would configure these classes in our spring-ws-servlet.xml
Spring XML configuration file:
<beans xmlns="http://www.springframework.org/schema/beans"> <bean id="holidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint"> <constructor-arg ref="hrService"/> </bean> <bean id="hrService" class="com.mycompany.hr.service.StubHumanResourceService"/> </beans>
6.2. Routing the Message to the Endpoint
Now that we have written an endpoint that handles the message, we must define how incoming messages
are routed to that endpoint. In Spring-WS, this is the responsibility of an
EndpointMapping
. In this tutorial, we will route messages based on
their content, by using a PayloadRootQNameEndpointMapping
. Here is how we
configure a PayloadRootQNameEndpointMapping
in spring-ws-servlet.xml
:
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"> <property name="mappings"> <props> <prop key="{http://mycompany.com/hr/schemas}HolidayRequest">holidayEndpoint</prop> </props> </property> <property name="interceptors"> <bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/> </property> </bean>
This means that whenever an XML message is received with the namespace
http://mycompany.com/hr/schemas
and the
HolidayRequest
local name, it will be routed to the
holidayEndpoint
.
(It also adds a PayloadLoggingInterceptor
,
that dumps incoming and outgoing messages to the log.)
7. Publishing the WSDL
Finally, we need to publish the WSDL. As stated in Section 3.4, “Service contract” , we don't need to write a WSDL ourselves; Spring-WS can generate one for us based on some conventions. Here is how we define the generation:
<bean id="holiday" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition"> <property name="schema" ref="schema"/> <property name="portTypeName" value="HumanResource"/> <property name="locationUri" value="/holidayService/"/> <property name="targetNamespace" value="http://mycompany.com/hr/definitions"/> </bean> <bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema"> <property name="xsd" value="/WEB-INF/hr.xsd"/> </bean>
The bean id determines the URL where the WSDL can be retrieved. In this case, the bean id is
|
|
The |
|
Next, we define the WSDL port type to be |
|
We set the location where the service can be reached:
|
|
Finally, we define the target namespace for the WSDL definition itself. Setting these is not required. If not set, we give the WSDL the same namespace as the schema. |
You can create a WAR file using mvn install . If you deploy the application (to Tomcat, Jetty, etc.), and point your browser at this location , you will see the generated WSDL. This WSDL is ready to be used by clients, such as soapUI , or other SOAP frameworks.
That concludes this tutorial. The tutorial code can be found in the full distribution of Spring-WS. The next step would be to look at the echo sample application that is part of the distribution. After that, look at the airline sample, which is a bit more complicated, because it uses JAXB, WS-Security, Hibernate, and a transactional service layer. Finally, you can read the rest of the reference documentation.
相关推荐
【Java Web Services 教程】 Java Web Services 是一种利用 Java 技术开发网络服务的方式,它使得不同系统之间能够通过互联网进行数据交换和功能调用。这个教程将深入讲解 Java Web Services 的核心概念和技术,...
Web Services平台架构是构建分布式应用程序的一种重要方法,它允许不同系统和平台之间的应用程序通过网络进行交互。在Java平台上开发Web Services,我们可以利用一系列的技术和标准,以实现跨平台的互操作性。 首先...
在java开发services中,会用到: 1.webservices-api.jar 2.webservices-extra.jar 3.webservices-rt.jar 4.webservices-tools.jar 5.webservices-extra-api.jar 此压缩文件里就是这五个jar文件。
WebServices是一种基于互联网的、用于应用程序之间交互的技术。在本项目"WebServices 天气预报"中,开发者提供了一个简单的天气预报应用,旨在帮助初学者理解WebServices的工作原理及其在C# WinForm环境中的实现。这...
WEB SERVICES原理与研发实践
Web Services技术架构是一种基于互联网的、开放的、标准的接口技术,它允许不同的应用程序之间进行交互和数据交换。这一概念由微软的MCT(Microsoft Certified Trainer)和MVP(Microsoft Most Valuable ...
Exchange Web Services 2.2
【Web Services概述】 Web Services是一种计算分布式问题的技术,它允许不同系统间的应用程序通过网络进行通信,从而实现数据的共享和程序的互操作性。Web Services的核心目标是促进系统的整合、标准化,并提供一种...
例如,你可以使用`webservices-api`和`webservices-extra-api`来定义服务接口和数据模型,`webservices-rt`来处理服务的运行时逻辑,而`webservices-tools`则帮助你在开发过程中进行验证和调试。 总的来说,"web...
### Web Services 学习基础 #### 一、Web Services 概述 Web Services 是一种用于在不同平台上交换数据和服务的标准方式。它允许不同系统之间进行通信,并且可以在各种不同的编程语言和技术栈中运行。Web Services...
Web Services是一种基于网络的、平台无关的交互方式,它允许不同系统之间交换数据和服务。在.NET框架下,创建和使用Web Services相对简单,这得益于微软提供的强大支持。本篇文章将深入探讨.NET环境下Web Services的...
### MyEclipse+XFire开发Web Services #### 实验背景与目标 随着互联网技术的发展,Web Services作为一种重要的软件架构模式,在分布式系统中的应用越来越广泛。它允许不同平台、语言的应用程序通过标准协议(如...
本书的内容涵盖了Web Services的各种关键技术、Web Services的整体体系架构和应用体系架构,以及Web Services应用的设计和开发。本书以Web Services技术系列为主线,逐一详细分析解释包括Web Services的各种核心技术...
### 基于Web Services的旅游系统设计与实现 #### 概述 本文探讨了基于Web Services技术构建的旅游系统的设计与实现方案。随着信息技术的进步和互联网的普及,特别是Web Services技术的成熟,旅游行业的信息化水平...
首先,我们需要理解“Java端写的https webservices”。在Java中,可以使用JAX-WS或JAX-RS等标准来创建Web Services。这些服务可以通过HTTPS协议对外提供,从而允许远程客户端通过安全连接进行调用。在Java端,设置...
1. `webservices-api.jar`: 这个jar包包含了JAX-WS(Java API for XML Web Services)的核心API,它是Java平台上的标准Web服务规范。JAX-WS提供了创建、部署和消费Web服务的全面支持。它定义了诸如`javax.xml.ws`...
【webservices调用方法】与【TOMCAT+AXIS进行WEBSERVICE开发的配置和HELLOWORLD程序】相关的知识点: 1. **Web Services**:Web Services是一种通过网络进行通信的软件,允许不同系统间的互操作性。它们使用标准的...
RESTful Web Services是一种广泛应用于现代Web开发中的设计模式,它基于Representational State Transfer(表述性状态转移)原则,旨在创建高效、分布式的网络应用程序。本资料《RESTful Web Services中文高清版.pdf...
Flask Building Python Web Services 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除