webservice笔记

1、根据定义契约的先后,有两种Web服务开发方法:
contract-first:先设计服务契约,然后开发代码;
contract-last:将现服务接口作为Web服务暴露,服务契约自动生成;


比较
开发contract-last web服务时,你实际上暴漏给客户的是应用的内部API。但是这个API可能会改变 -- 改变之后,你必须改变Web服务的契约,
这可能涉及到所有客户的改变。但是,如果你先设计契约,它反映的是你所希望暴露的外包API。这不像内部API改变的可能性那么大;
尽管许多工具和程序库能够将java类/接口暴露为一个Web服务,但是从java生成的契约不总能移植到其他平台上。例如java map;


contract-last
2、使用jax-ws暴露和调用contract-last soap web服务
Spring自带多种服务输出器,能够根据RMI、Hessian、Burlap或HTTP Invoker等Remoting技术将Bean输出为一个远程服务,但是Spring没有能够
将Bean暴露为SOAP服务的服务输出器。我们将使用Apache CXF,这是XFire事实上的继任者。


JAX-RPC不支持面向消息的Web服务,将一个EJB无状态会话Bean,让容器暴露一个SOAP端点。


JAX-WS 2.0,可以使用常规的JDK暴露端点,完全不需要JavaEE,是JAX-RPC的升级版。


为了通过线路发送对象,Bean需要使用Java XML绑定架构 -- JAXB。


在JAX-WS的世界里,对于创建Web服务,我们有许多选择。
如果你在Java EE 5(或更好)的容器中部署,可以简单地创建一个以javax.jws.WebService或者
javax.jws.WebServiceProvider注解的Bean,并且将其部署到Web应用的容器中。从那里,你需要进行一些中间步骤。
如果你使用JAX-RS(Java API for RESTful Web Services,是一个Java 编程语言的应用程序接口)引用实现,这些中间步骤涉及wsgen工具,这个工具
将生成暴露你的服务所需要的配置(sun-jaxws.xml文件)和包装器Bean。更现代的框架(如Apache CXF)没有这种步骤:你的Bean和Web服务实现在运行时
环境启动时生成;注解后的Bean的部署是最后一步。在这个方案中,Spring不需要为你做什么,可能只需要启用对应用上下文的访问等。为了这个目的,
你可能需要让你的服务扩展org.springframework.web.context.support.SpringBeanAutowiringSupport。你的服务端点将从@Autowired等注解中获益。


使用JDK中的JAX-WS端点支持暴露Web服务,同时使用spring容器
另一种选择是将JAX-WS服务部署在容器之外,例如使用独立的HTTP服务器。Spring提供一个工厂,能够输出Spring上下文中用javax.jws.WebService
或javax.jws.WebServiceProvider注解的Bean,然后使用JAXWS(如:org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter)运行时发布该服务。
如果你没有配置运行时并在JDK 6上运行,Spring将使用现有的HTTP服务支持和JDK中JAX-WS RI。
a)、注解serviceImpl;
public interface WeatherService{...}
@WebService(serviceName="weatherService") //javax.jws.WebService
public class WeatherServiceImpl implements WeatherServiceImpl{
@WebMethod(operationName="getTemperature")
public String getTemperature(){...}
...
}
b)、JAXWS运行时,service.xml:
<bean id="weatherServiceImpl" class="com.paic.weather.service.impl.WeatherServiceImpl"></bean>
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"></bean>
c)、server main方法
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("server.xml");
context.start();
d)、访问http://localhost:8080/WeatherService?wsdl
e)、client main方法,client.xml
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:client id="weatherService"
serviceClass="com.paic.weather.service.WeatherService"
address="http://localhost:8080/weatherService">
</jaxws:client>
WeatherService weatherService = (WeatherService)context.getBean("weatherService");
使用CXF暴露Web服务
使用SimpleJaxWsServiceExporter或者Java EE容器中的JAXWS支持,和Spring一起暴露一个单独的SOAP端点很简单,但是这些解决方案忽略了开发人员
(在tomcat上开发的人们)最大的横切面。对此,我们同样有丰富的选择。Tomcat本身不支持JAX-WS,所以我们需要嵌入一个JAX-WS运行时来帮助它。
选择很多,你可以自由挑选。Axis2和CXF是两个流行的选择,它们都是Apache项目。
java类同上;
a)、web.xml配置ContextLoaderListener、spring MVC、CXF;
b)、web-context.xml;
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<bean id="weatherServiceImpl" class="com.paic.weather.service.impl.WeatherServiceImpl"></bean>
<jaxws:endpoint implementorClass="com.paic.weather.service.impl.WeatherServiceImpl" address="/service/WeatherService">
<jaxws:binding>
<soap:soapBinding style="document" use="literal" version="1.1"></soap:soapBinding>
</jaxws:binding>
</jaxws:endpoint>
使用CXF调用Web服务
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:client id="weatherService"
serviceClass="com.paic.weather.service.WeatherService"
address="http://localhost:8120/webServiceDemo/service/WeatherService">
</jaxws:client>
WeatherService weatherService = (WeatherService)context.getBean("weatherService");


contract-first
3、Web服务契约
Web服务的契约包括数据契约、服务契约;
数据契约:描述复杂的数据类型和Web服务的请求和响应消息。数据契约一般用XSD定义,但是你也可以使用DTDs、RELAX NG或Schematron;
服务契约:描述Web服务的操作。服务契约用WSDL定义;
当使用综合的Web服务开发框架(如Spring-WS)时,服务契约通常能够自动生成,但是你必须自己创建数据契约;
1)创建样板XML消息
表示特定城市的气温temperatureInfo.xml
<TemperatureInfo city="Houston" date="2007-12-01">
<min>5.0</min>
<max>10.0</max>
<average>8.0</average>
</TemperatureInfo>
定义一个请求操作request.xml
<GetTemperaturesRequest
xmlns="http://localhost:8080/weather/schemas">
<city>Houston</city>
<date>2007-12-01</date>
<date>2007-12-08</date>
<date>2007-12-15</date>
</GetTemperaturesRequest>
定义一个响应response.xml
<GetTemperaturesResponse
xmlns="http://localhost:8080/weather/schemas">
<TemperatureInfo city="Houston" date="2007-12-01">
<min>5.0</min>
<max>10.0</max>
<average>8.0</average>
</TemperatureInfo>
<TemperatureInfo city="Houston" date="2007-12-08">
<min>5.0</min>
<max>10.0</max>
<average>8.0</average>
</TemperatureInfo>
<TemperatureInfo city="Houston" date="2007-12-15">
<min>5.0</min>
<max>10.0</max>
<average>8.0</average>
</TemperatureInfo>
</GetTemperaturesResponse>
2)从样板XML消息生成XSD文件,工具Apache XMLBeans可以生成;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://localhost:8080/weather/schemal"
xmlns:xs="http://www.w3c.org/2001/XMLSchema">
<xs:element name="GetTemperaturesRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="city"/>
<xs:element type="xs:date" name="date" maxOccurs="5" minOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetTemperaturesResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="TemperatureInfo" maxOccurs="5" minOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:float" name="min"/>
<xs:element type="xs:float" name="max"/>
<xs:element type="xs:float" name="average"/>
</xs:sequence>
<xs:attribute type="xs:string" name="city" use="optional"/>
<xs:attribute type="xs:string" name="date" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
3)预览生成的WSDL文件
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions ...
targetNamespace="http://localhost:8080/weather/schemas">
<wsdl:types>
... copied from XSD file
</wsdl:types>
<wsdl:message name="GetTemperaturesRequest">
<wsdl:part element="schema:GetTemperaturesRequest"
name="GetTemperaturesRequest">
</wsdl:part>
</wsdl:message>
<wsdl:message name="GetTemperaturesResponse">
<wsdl:part element="schema:GetTemperaturesResponse"
name="GetTemperaturesResponse">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="Weather">
<wsdl:operation name="GetTemperatures">
<wsdl:input message="schema:GetTemperaturesRequest"
name="GETemperaturesRequest">
</wsdl:input>
<wsdl:output message="schema:GetTemperaturesReponse"
name="GETemperaturesReponse">
</wsdl:input>
</wsdl:peration>
</wsdl:portType>
<wsdl:service name="WeatherService">
<wsdl:port binding="schema:WeatherBinding" name="WeatherPort">
<soap:address
location="http://localhost:8080/weather/services"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
4)wsdl文件结构详解
Types - 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。
Message - 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。
Operation - 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对。  
PortType - 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。
Binding - 特定端口类型的具体协议和数据格式规范的绑定。  
Port - 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。  
Service- 相关服务访问点的集合。
4、使用Spring-ws实现Web服务
Srping-ws提供一组机制,让你开发contract-first web服务。构建Spring-WS web服务的必要工作如下。
a、为Spring-WS设置和设置Spring MVC应用;
b、将Web服务请求映射到端点;
c、创建服务端点以处理请求消息并返回响应消息;
d、为Web服务发布WSDL文件;
Web服务中端点的概念和Web应用中的控制器很类似。不同之处在于,Web控制处理器HTTP请求和响应,而服务端点处理XML请求消息和响应消息。
它们都需要调用其他后端服务来处理请求。
Spring-WS提供各种抽象端点类,让你使用不同XML处理技术(如dom4j等)和API处理请求和响应XML消息。
在web.xml中,你必须配置Spring-WS的MessageDispatcherServlet servlet,这和典型的Spring MVC应用的DispatcherServlet不同。这个servlet
专用于将Web服务消息分派给合适的端点,并检测Spring-WS的框架机制;
<servlet>
<servlet-name>springWs</servlet-name>
<servlet-class>
org.springframework.ws.transport.http.MessageDispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springWs</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
在weather-servlet.xml中声明serviceImpl;
<bean id="weatherService" class="...WeatherServiceImpl"/>
将web服务请求映射到端点;
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://service.weather.paic.com/schemas}GetHelloWorldRequest">
temperatureEndpoint
</prop>
</props>
</property>
</bean>
创建服务端点:解析request,返回response;
public class TemperatureDom4jEndpoint extends AbstractDom4jPayloadEndpoint{...}
<bean id="temperatureEndpoint" class="com.paic.endpoint.TemperatureDom4jEndpoint">
<property name="weatherService" ref="weatherService"></property>
</bean>
创建数据契约,helloWorld.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://service.weather.paic.com/schemas"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="GetHelloWorldRequest">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="hello"></xs:element>
<xs:element type="xs:string" name="world"></xs:element>
<xs:element type="xs:date" name="date"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetHelloWorldResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="HelloWorldDTO">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="hello"></xs:element>
<xs:element type="xs:string" name="world"></xs:element>
<xs:element type="xs:date" name="date"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
发布WSDL文件;
<!-- 用来生成WSDL文件,bean的id即WSDL文件的名字 -->
<bean id="helloWorld" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition">
<property name="builder">
<bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder">
<property name="schema" value="/WEB-INF/helloWorld.xsd"/>
<property name="portTypeName" value="HelloWorld"/>
<property name="locationUri"
value="http://localhost:8080/myWebService3/services"/>
</bean>
</property>
</bean>
5、使用Spring-WS调用Web服务;
在客户端使用Spring-WS时,Web服务可以通过核心模板类WebServiceTemplate调用,类似于JdbcTemplate,定义了用于
发送请求和接收响应消息的模板方法;
为了对客户隐藏低级调用细节,你可以为远程Web服务建一个本地代理。这个代理也实现WeatherService接口,并将本地方法调用转换为远程Web服务调用;
public class WeatherServiceProxy implements WeatherTestService{...}
配置client.xml
<bean id="client"
class="client.WeatherServiceClient">
<property name="weatherService" ref="weatherServiceProxy"/>
</bean>
<bean id="weatherServiceProxy"
class="com.paic.proxy.WeatherServiceProxy">
<property name="webServiceTemplate"
ref="webServiceTemplate"/>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="defaultUri" value="http://localhost:8080/myWebService3/services"></property>
</bean>
6、用XML编组开发Web服务;
为了用contract-first方法开发Web服务,你必须处理请求和响应XML消息。如果直接使用XML解析API解析XML消息,你就必须使用低级API
一个接一个地处理XML元素,这是笨拙而低效的任务;
Spring-WS支持使用XML编组技术对XML文档的对象进行编组和反编组,这样,你可以处理对象属性而不是XML元素,这种技术也称对象-XML映射(OXM),
因为你实际上在对象和XML文档对象之间相互映射。
为了用XML编组技术实现端点,你必须扩展AbstractMarshallingPayloadEndpoint类,并为之配置一个XML编组器。
Spring-WS支持各种XML编组API,包括JAXB1.0、JAXB2.0、Castor、XMLBeans、JiBX、XStream;
a)使用XML编组的第一步是根据XML消息格式创建对象模型,即DTO;
public class GetHelloWorldRequest(String hello, String world, Date date);
public class GetHelloWorldResponse(HelloWorldDTO dto);
b)创建了对象模型,你就可以扩展AbstractMarshallingPayloadEndpoint类,编写一个编组端点。
public class TemperatureMarshallingEndpoint extends AbstractMarshallingPayloadEndpoint{weatherService}
c)在weather-servlet.xml中给编组端点设置marshaller和unmarshaller属性;
<bean id="temperatureEndpoint" class="com.paic.weather.endpoint.TemperatureMarshallingEndpoint">
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="marshaller"></property>
<property name="weatherService" ref="weatherService"></property>
</bean>
<bean id="marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:mapping.xml"></property>
</bean>
<!-- 用来生成WSDL文件 -->
<bean id="helloWorld" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition">
<property name="builder">
<bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder">
<property name="schema" value="/WEB-INF/helloWorld.xsd"/>
<property name="portTypeName" value="HelloWorld"/>
<property name="locationUri"
value="http://localhost:8080/myWebService4/services"/>
</bean>
</property>
</bean>
d)Castor需要一个映射配置文件,以廖杰如何进行对象和XML文档间的映射;
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="com.paic.weather.GetHelloWorldRequest">
<map-to xml="GetHelloWorldRequest"
ns-uri="http://service.weather.paic.com/schemas"/>
<field name="hello" type="string">
<bind-xml name="hello" node="element"/>
</field>
<field name="world" type="string">
<bind-xml name="world" node="element"/>
</field>
<field name="date" type="string"
handler="com.paic.weather.DateFieldHandler">
<bind-xml name="date" node="element"/>
</field>
</class>
<class name="com.paic.weather.GetHelloWorldResponse">
<map-to xml="GetHelloWorldResponse"
ns-uri="http://service.weather.paic.com/schemas"/>
<field name="helloWorldDTO"
type="com.paic.weather.dto.HelloWorldDTO">
<bind-xml name="HelloWorldDTO" node="element"/>
</field>
</class>
<class name="com.paic.weather.dto.HelloWorldDTO">
<map-to xml="HelloWorldDTO"
ns-uri="http://service.weather.paic.com/schemas"/>
<field name="hello" type="string">
<bind-xml name="hello" node="element"/>
</field>
<field name="world" type="string">
<bind-xml name="world" node="element"/>
</field>
<field name="date" type="string"
handler="com.paic.weather.DateFieldHandler">
<bind-xml name="date" node="element"/>
</field>
</class>
</mapping>
时间类型转换器:DateFieldHandler
public class DateFieldHandler extends GeneralizedFieldHandler{}
7、用XML编组调用Web服务;
Spring-WS客户还可以进行请求以及响应对象和XML消息间的编组和反编组。
public class WeatherServiceProxy extends WebServiceGatewaySupport implements WeatherService{}
client.xml
<bean id="client"
class="client.WeatherServiceClient">
<property name="weatherService" ref="weatherServiceProxy"/>
</bean>
<bean id="weatherServiceProxy"
class="com.paic.proxy.WeatherServiceProxy">
<property name="defaultUri"
value="http://localhost:8080/myWebService4/services"/>
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="marshaller"></property>
</bean>
<bean id="marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:mapping.xml"></property>
</bean>


8、使用注解创建服务端点
通过扩展一个Spring-WS端点基类,你的端点类将绑定到Spring-WS类层次结构,每个端点类只能处理一类Web服务请求。
Spring-WS支持用@Endpoint注解将任意的类注解为服务端点,而不用扩展框架专用类。你也可以在端点类中集合多个处理程序,
从而处理多种Web服务请求;
@Endpoint
public class TemperatureMarshallingEndpoint{
...
@PayloadRoot(localPart="GetHelloWorldRequest", namespace=namespaceUri)
public Object invokeInternal(Object requestObject) throws Exception {...}
}
weather-servlet.xml
<bean id="weatherService"
class="com.paic.weather.service.impl.WeatherServiceImpl"/>


<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
</bean>
<bean id="temperatureEndpoint" class="com.paic.weather.endpoint.TemperatureMarshallingEndpoint">
<property name="weatherService" ref="weatherService"></property>
</bean>
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="marshaller"></property>
</bean>
<bean id="marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:mapping.xml"></property>
</bean>
<!-- 用来生成WSDL文件 -->
<bean id="helloWorld" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition">
<property name="builder">
<bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder">
<property name="schema" value="/WEB-INF/helloWorld.xsd"/>
<property name="portTypeName" value="HelloWorld"/>
<property name="locationUri"
value="http://localhost:8080/myWebService4/services"/>
</bean>
</property>
</bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值