目录
?
1???? 定义Service
2???? 服务端发布Service
3???? 客户端访问Service
4???? 基于Spring的Jax-ws WebService
4.1???? Service定义
4.2???? 服务端发布Service
4.3???? 客户端获取Service
?
?????? Jax-ws是WebService的一种规范。
1?????? 定义Service
?????? Jax-ws的WebService定义是通过注解进行的,我们必须在其WebService类的接口上使用@WebService注解进行标记。
?
@WebService public interface HelloWorld { public String sayHi(String who); }
????????
如上,我们把HelloWorld定义为一个WebService,其对应有一个sayHi操作。其对应的实现类如下:?
?
public class HelloWorldImpl implements HelloWorld { @Override public String sayHi(String who) { return "Hi, " + who; } }
2?????? 服务端发布Service
?????? 对于Jax-ws WebService而言,发布Service有两种方式。
第一种:
?
public class Server { private final static String ADDRESS = "http://localhost:8080/test/jaxws/services/HelloWorld"; public static void main(String args[]) { HelloWorld hw = new HelloWorldImpl(); Endpoint.publish(ADDRESS, hw); } }
?
第二种:?
?
public class Server { private final static String ADDRESS = "http://localhost:8080/test/jaxws/services/HelloWorld"; public static void main(String args[]) { HelloWorld hw = new HelloWorldImpl(); JaxWsServerFactoryBean jwsFactory = new JaxWsServerFactoryBean(); jwsFactory.setAddress(ADDRESS); //指定WebService的发布地址 jwsFactory.setServiceClass(HelloWorld.class);//WebService对应的类型 jwsFactory.setServiceBean(hw);//WebService对应的实现对象 jwsFactory.create(); } }
?
?????? 发布之后我们就可以通过发布地址?wsdl查看WebService的定义了(WSDL是WebService Document Location的简称,即WebService文档位置的意思)。通过在浏览器输入http://localhost:8080/test/jaxws/services/HelloWorld?wsdl我们可以看到如下内容:
?
This XML file does not appear to have any style information associated with it. The document tree is shown below. <wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://jaxws.sample.cxftest.tiantian.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloWorldImplService" targetNamespace="http://jaxws.sample.cxftest.tiantian.com/"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://jaxws.sample.cxftest.tiantian.com/" elementFormDefault="unqualified" targetNamespace="http://jaxws.sample.cxftest.tiantian.com/" version="1.0"> <xs:element name="sayHi" type="tns:sayHi" /> <xs:element name="sayHiResponse" type="tns:sayHiResponse" /> <xs:complexType name="sayHi"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="xs:string" /> </xs:sequence> </xs:complexType> <xs:complexType name="sayHiResponse"> <xs:sequence> <xs:element minOccurs="0" name="return" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="sayHiResponse"> <wsdl:part element="tns:sayHiResponse" name="parameters"></wsdl:part> </wsdl:message> <wsdl:message name="sayHi"> <wsdl:part element="tns:sayHi" name="parameters"></wsdl:part> </wsdl:message> <wsdl:portType name="HelloWorld"> <wsdl:operation name="sayHi"> <wsdl:input message="tns:sayHi" name="sayHi"></wsdl:input> <wsdl:output message="tns:sayHiResponse" name="sayHiResponse"></wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloWorldImplServiceSoapBinding" type="tns:HelloWorld"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="sayHi"> <soap:operation soapAction="" style="document" /> <wsdl:input name="sayHi"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="sayHiResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloWorldImplService"> <wsdl:port binding="tns:HelloWorldImplServiceSoapBinding" name="HelloWorldImplPort"> <soap:address location="http://localhost:8080/test/jaxws/services/HelloWorld" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
???
?????? 我们可以看到在上面我们的sayHi操作的参数who变成了arg0,这是因为接口在被编译为class文件的时候不能保存参数名,有时候这会影响可读性。如果需要参数名显示的可读性强一些的话,我们可以使用@WebParam来指定,如:
?
@WebService(serviceName="!@#$%^", name="123456") public interface HelloWorld { public String sayHi(@WebParam(name="who") String who); }
?
@WebService的serviceName可以用来指定service的名称,默认情况下如果Service是通过Endpoint.publish()方法发布的则serviceName为实现类的简单名称+Service(如HelloWorldImplService),如果是通过JaxWsServerFactoryBean的create方法发布的则为接口的简单名称+Service(如HelloWorldService)。name属性可以用来指定service对应的portName,默认情况下如果Service是通过Endpoint.publish()方法发布的则portName为实现类的简单名称+Port(如HelloWorldImplPort),如果是通过JaxWsServerFactoryBean的create方法发布的则为接口的简单名称+Port(如HelloWorldPort)。?
3?????? 客户端访问Service
类似于WebService简单实现里面的ClientProxyFactoryBean,在使用Jax-ws时我们可以通过JaxWsProxyFactoryBean来访问服务,如:
?
public class Client { private final static String ADDRESS = "http://localhost:8080/test/jaxws/services/HelloWorld"; public static void main(String args[]) { JaxWsProxyFactoryBean jwpFactory = new JaxWsProxyFactoryBean(); jwpFactory.setAddress(ADDRESS); jwpFactory.setServiceClass(HelloWorld.class); HelloWorld hw = (HelloWorld)jwpFactory.create(); String response = hw.sayHi("world"); System.out.println(response); } }
?
除了上面的方式之外,我们还可以这样获取Service:
?
//第一个参数为服务发布的targetNameSpace,可以通过查看对应的wsdl文件获得,默认是发布Service所在包的包名倒过来的形式;第二个参数是serviceName private final static QName SERVICE_NAME = new QName("http://jaxws.sample.cxftest.tiantian.com/", "HelloWorldService"); //第一个参数是服务发布的targetNameSpace,第二个参数是portName private final static QName PORT_NAME = new QName("http://jaxws.sample.cxftest.tiantian.com/", "HelloWorldPort"); //服务发布的地址 private final static String ADDRESS = "http://localhost:8080/test/jaxws/services/HelloWorld"; public static void main(String args[]) { Service service = Service.create(SERVICE_NAME); //根据portName、服务发布地址、数据绑定类型创建一个Port。 service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, ADDRESS);//默认是SOAP1.1Binding //获取服务 HelloWorld hw = service.getPort(HelloWorld.class); String response = hw.sayHi("world"); System.out.println(response); } ??
?
?????? 在上面的代码中我们只需要有一个Service实例,就能通过它来获取真正的WebService,所以,我们如果把上面的代码改成如下形式也是可以的。?
?
//第一个参数为服务发布的targetNameSpace,可以通过查看对应的wsdl文件获得,默认是发布Service所在包的包名倒过来的形式;第二个参数是serviceName private final static QName SERVICE_NAME = new QName("http://jaxws.sample.cxftest.tiantian.com/", "HelloWorldService"); //第一个参数是服务发布的targetNameSpace,第二个参数是portName private final static QName PORT_NAME = new QName("http://jaxws.sample.cxftest.tiantian.com/", "HelloWorldPort"); //服务发布的地址 private final static String ADDRESS = "http://localhost:8080/test/jaxws/services/HelloWorld"; public static void main(String args[]) { Service service = Service.create(null); //根据portName、服务发布地址、数据绑定类型创建一个Port。 service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, ADDRESS);//默认是SOAP1.1Binding //获取服务 HelloWorld hw = service.getPort(HelloWorld.class); String response = hw.sayHi("world"); System.out.println(response); }
?
???????
上面这种通过Service来获取WebService的方法是不适用前面介绍的简单WebService实现的,即不适用获取通过ServerFactoryBean发布的WebService。
?
4?????? 基于Spring的Jax-ws WebService
4.1???? Service定义?
?????? Service定义跟之前的定义是一样的。?
4.2???? 服务端发布Service
?????? 首先在web.xml文件中定义一个CXFServlet,用于发布和拦截WebService请求。
?
<!-- Jax-ws实现 --> <servlet> <display-name>jaxws-cxf</display-name> <servlet-name>jaxws-cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>config-location</param-name> <param-value>WEB-INF/jaxws-cxf-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>jaxws-cxf</servlet-name> <url-pattern>/jaxws/services/*</url-pattern> </servlet-mapping>
??
?????? 接下来在我们的WebService配置文件里面定义我们的WebService发布,即CXFServlet指定的jaxws-cxf-servlet.xml文件(默认是cxf-servlet.xml文件)。这里我们定义如下:
?
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- 相当于使用Endpoint.publish()进行服务发布 --> <jaxws:endpoint address="/HelloWorld" implementorClass="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/> <!-- 相当于使用JaxWsServerFactoryBean进行服务发布 --> <jaxws:server address="/HelloWorld2" serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/> <!-- JaxWsServerFactoryBean使用外部bean作为服务进行发布 --> <jaxws:server address="/HelloWorld3" serviceBean="#hw"/> <!-- 普通bean对象 --> <bean id="hw" class="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/> <!-- JaxWsServerFactoryBean使用内部bean作为服务进行发布 --> <jaxws:server address="/HelloWorld4"> <jaxws:serviceBean> <bean class="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/> </jaxws:serviceBean> </jaxws:server> </beans>
4.3???? 客户端获取Service
?????? 客户端可以直接从Spring的bean配置文件中把WebService配置为一个个普通的Spring bean对象进行使用。只是在定义之前需要往bean配置文件中引入Jax-ws的命名空间。这里我们在classpath下定义一个jaxws-cxf-client.xml文件,其内容如下所示:
?
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:client id="hw" address="http://localhost:8080/test/jaxws/services/HelloWorld" serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld" /> <jaxws:client id="hw2" address="http://localhost:8080/test/jaxws/services/HelloWorld2" serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"/> <jaxws:client id="hw3" address="http://localhost:8080/test/jaxws/services/HelloWorld3" serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"/> <jaxws:client id="hw4" address="http://localhost:8080/test/jaxws/services/HelloWorld4" serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"/> </beans>
?
?????? 之后我们就可以把这些定义好的WebService当做一个普通的bean对象来使用了,如:
?
public class SpringClient { public static void main(String args[]) { ApplicationContext context = new ClassPathXmlApplicationContext("jaxws-cxf-client.xml"); accessService(context, "hw"); accessService(context, "hw2"); accessService(context, "hw3"); accessService(context, "hw4"); } private static void accessService(ApplicationContext context, String beanName) { HelloWorld hw = context.getBean(beanName, HelloWorld.class); System.out.println(hw.sayHi("world")); } }
?
??
?
?