jax-ws实现Webservice入门教程 (客户端调用服务端实现)

术语

SEI:Service Endpoint Interface

JAX:Java API for XML Web Servcie

JAX-WS RI:JAX-WS Reference Implementation


创建 Web Service方式

JAX-WS 2.0有两种创建Web Service的开发过程:自顶向下和自底向上。自顶向下方式指通过一个WSDL文件来创建Web Service;自底向上是从Java类出发创建Web Service。

自顶向下:

  1. SEI(对应WSDL中的一个Web Service port,在Java中表现为一个接口);
  2. SEI实现类;
  3. WSDL和XSD文件;

自底向上:

  1. 声明某个类为@WebService,即将它声明为SEI实现类,然后对需要暴露的方法标注为@WebMethod;
  2. 运行wsgen命令生成其他所需文件;
  3. 发布Web Service;

Endpoint发布服务

 

Java1.6中自带了JAX-WS API,使得我们可以很方便、简单的开发一个基于Java的WebService应用。下面看一个JAX-WS中的HelloWord应用。

 

一、创建WebService Endpoint接口

首先我们来定义Server端的WebService服务接口,如下:

Java代码   收藏代码
  1. package test;  
  2.   
  3. import javax.jws.WebService;  
  4.   
  5. @WebService  
  6. public interface Calculator {  
  7.   
  8.     public int add(int a, int b);  
  9.   
  10.     public int multi(int a, int b);  
  11. }  

 

这里看到在类定义上,加了一个“@WebService”的annotation,这是定义JAX-WS定义WebService的关键,这个annotation用来告诉java解析器你希望把这个接口中的方法发布成一些WebService的服务。

 

有了接口定义,下面给出一个实现:

Java代码   收藏代码
  1. package test;  
  2.   
  3. import javax.jws.WebService;  
  4.   
  5. @WebService(endpointInterface = "test.Calculator")  
  6. public class CalculatorImpl implements Calculator {  
  7.   
  8.     public int add(int a, int b) {  
  9.         return a + b;  
  10.     }  
  11.   
  12.     public int multi(int a, int b) {  
  13.         return a * b;  
  14.     }  
  15.   
  16.     public int minus(int a, int b) {  
  17.         return a - b;  
  18.     }  
  19. }  

 

 这里WebService annotation里加了一个参数"endpointInterface",这个参数用来指定这个WebService的抽象服务接口,例如此处如果不用"endpointInterface"指定接口,那么生成的WebService服务有三个操作"add","multi"和"minus",也就是定义在当前类中的方法集;如果指定了endpointInterface,则只有"add","multi",即定义在Calculator中的方法集。

 

二、发布服务

 

上面就已经定义好了服务接口和服务实现类,然后就可以发布了。发布也是相当的简单,只需要一条语句:

Java代码   收藏代码
  1. package test;  
  2.   
  3. import javax.xml.ws.Endpoint;  
  4.   
  5. public class Server {  
  6.   
  7.     public static void main(String[] args) {  
  8.         Endpoint.publish("http://localhost:8088/calculator",  
  9.                 new CalculatorImpl());  
  10.     }  
  11.   
  12. }  

 这里publish方法需要两个参数:

  • address:服务对外暴露的用于调用服务的地址
  • implementor:服务的实现对象

启动这个Server类,就可以访问服务了。要测试服务有没有启动,可以输入http://localhost:8088/calculator?wsdl,如果一切正常,就可以看到一个wsdl定义内容,表示服务已经成功启动。

 

  • service调用服务
  • 上一节中介绍了怎么基于JAX-WS的API创建服务端,这一节介绍一下创建一个客户端调用WebService服务。

     

    要创建一个Client端也相当简单,不过需要知道几个东西:

     

    1. wsdl文件路径

     

    需要读取服务端提供的wsdl定义文件。例如:

    Java代码   收藏代码
    1. URL url = new URL("http://localhost:8088/calculate?wsdl");  

     

    2. 要调用的Service的QName

     

    一个wsdl中可能定义了多个Service,所以需要指定要调用的service名。例如:

    Java代码   收藏代码
    1. QName qName = new QName("http://test/",  
    2.                 "CalculatorImplService");  

     

     

    3. 创建Service

     

    有了wsdl的service的qname以后,就可以创建对应的service对象了:

    Java代码   收藏代码
    1. Service service = Service.create(url, qName);  

     

    4. 取得相应的Port

     

    有了Service,然后就可以取得Service中的某个Port,例如:

    Java代码   收藏代码
    1. Calculator port = service.getPort(Calculator.class);  

     这里有几点可能需要说明:

    1.  
      1. getPort()方法的参数:这个方法总是需要指定一个serviceEndpointInterface的类对象serviceEndpointInterface类需要加@WebService的annotation
      2. serviceEndpointInterface的targetNamespace需要匹配对应的portType的namespace。默认是"http://包名/",必要时需要定义@WebService的targetNamespace属性加以改变
      3. serviceEndpointInterface的name总是需要匹配要调用的PortType的name。默认是类名,必要时需要指定@WebService的name属性加以改变
      4. serviceEndpointInterface中需要有对应于要调用的operation的方法定义
      5. 最后调用方法

    5. 调用方法

     

    最后相应的信息都取到以后,就可以调用希望的方法了,例如:

    Java代码   收藏代码
    1. System.out.println(port.add(12));  

wsimport和调试工具

前两节中简单的介绍了一下基本的JAX-WS API的使用,这一节更进一步的介绍一些其他的内容

 

一、wsimport工具的使用

 

在第二节中(http://liugang594.iteye.com/blog/1343608),可以看到要手动创建一个client端进行一次正确的调用,需要关注的东西还是挺多的,尤其是定义一个符合格式的方法定义在参数相当复杂的情况下是相当不容易的。

 

这里JDK中提供了一个 wsimport 的工具,路径为 “JDK_PATH/bin”,可以相当方便的用来创建相应wsdl的Service类文件和Port类文件。

 

-d:生成客户端执行类的class文件的存放目录
-s:生成客户端执行类的源文件的存放目录
-keep:表示导出webservice的class文件时是否也导出源代码java文件

 

 

要使用wsimport,命令行如下:

Java代码   收藏代码
  1. wsimport -keep http://localhost:9999/ws/hello?wsdl  

 

然后就会根据这个wsdl生成几个相应的类文件,例如使用第一节的例子会生成8个类文件


 

其中主要的是一个Service类 CalculatorImplService.java 和 一个EndpointInterface类 Calculator。

 

有了这些类以后,就可以很简单的实现Client端了,例如:

Java代码   收藏代码
  1. CalculatorImplService service = new CalculatorImplService();  
  2. Calculator calculator = service.getPortName();  
  3. System.out.println(calculator.add(12));  

 

如此方便,不能自己。

 

二、查看来往的Soap消息

 

由于所有的消息都是通过类的方法被Java在后台封装了,所以一大不利处就是没法查看具体发送的Soap消息和返回的结果。

 

所以需要一个工具用来查看与特定的Server和Port上消息的交互。有一大堆工具可以做这个,这里我介绍一下Eclipse里的TCP/IP Monitor工具如何来做。

 

打开 "Window->Preferences->Run/Debug->TCP/IP Monitor"菜单就可以看到TCP/IP Monitor的配置页了,如下。(如果你的eclipse里没有这一项,那可能是你的版本比较低,建议更新一个版本试试,我的版本是3.6.2)


 

点击“add”按钮,就可以新建一个Monitor,配置说明如下:

  1. Local monitoring port:定义用来中转的本地端口。例如你本来想访问的时候本地的8000端口,你在此处定义的是8001端口,那你的访问端口也需要改成8001,然后由monitor把你的请求进行转发。
  2. Host name:你要监视的与本地通信的主机地址
  3. Port:你要监视的与本地通信的主机端口
  4. Type:通信方式,有HTTP和TCP/IP两个选项
  5. Timeout:超时设置

定义完以后,选中这个配置,点击"start",监视器即起用。

 

然后通过"Window->Show View->Other->Debug->TCP/IP Monitor",打开监视视图:


 

即可。

 

例如我有一个wsdl的定义地址为:http://localhost:8086/calculator?wsdl

 

本来我的Client端的实现代码应该是:

 

Java代码   收藏代码
  1. URL url = new URL("http://localhost:8086/calculator?wsdl");  
  2. QName qName = new QName("http://www.liulutu.com/calculator/",  
  3. "CalculatorImplService");  
  4. Service service = Service.create(url, qName);  
  5. Calculator port = service.getPort(Calculator.class);  
  6. System.out.println(port.add(12));  

 一旦我使用了诸如上面的监视器,并且想监视这个WebService的请求成响应,那么这里url的端口就需要由8086改成8087:

Java代码   收藏代码
  1. URL url = new URL("http://localhost:8087/calculator?wsdl");  
  2. QName qName = new QName("http://www.liulutu.com/calculator/",  
  3. "CalculatorImplService");  
  4. Service service = Service.create(url, qName);  
  5. Calculator port = service.getPort(Calculator.class);  
  6. System.out.println(port.add(12));  

 通过监视器来进行中间的转发,即可观察到来往的消息交互:



wsgen

wsgen   是在JDK自带的一个工具,该命 令的主要功能是用来生成合适的JAX-WS。它读取Web Service的类文件(Hello.class),同时生成所有用于发布Web Service所依赖的源代码文件、经过编译过的二进制类文件、WSDL文件和相关的xsd文件。

-wsdl参数代表生成webservice

-s参数代表生成的.java文件目录

-d 参数代表生成的编译class文件目录

-r 参数代表生成的.wsdl文件与.xsd文件目录

-cp参数代表classpath,即读取的类文件(Hello.class)所在的目录(不包括类文件的包目录)

例子:wsgen -wsdl -r d:/wsdl -s d:/src -d d:/build -cp d:/test/WebRoot/WEB-INF/classes com.test.Hello


部署到web容器

在之前的介绍里,web service的发布都是通过调用:

Java代码   收藏代码
  1. Endpoint.publish()  

方法来启动一个java内嵌的web容器来实现的,这里要介绍一下怎么把生成的web service部署到一个web容器中去。

首先去下载JAX-WS RI组件,这个组件和CXF一样都是实现JAX-WS标准规范的。下载地址自己百度,我下载的是2.1.1版本,双击jar包后得到如下目录


然后新建一个普通的web项目,如下



注意这里多了一个wsdl文件夹和sun-jaxws.xml,均位于WEB-INF下。接着使用wsgen命令,生成部署所需的文件。

 

Java代码   收藏代码
  1. wsgen -cp E:\JaxWSProject\WebRoot\WEB-INF\classes ctsjavacoe.ws.fromjava.Hello -wsdl -r ../wsdl -d . -s ../../../src

 

运行完上面命令行后,会得到wsdl、xsd文件和一些java源文件、字节码文件。


 

最后,将我们下载的jawxs ri组件目录下的lib目录拷贝到项目的lib目录下,这是因为我并不是非常清楚每个包的作用,因此全部拷贝,免得报错。

 

sun的jax-ws实现提供了两个类用来配置web容器的web.xml,实现从url到web service实现类的映射:

监听类:com.sun.xml.ws.transport.http.servlet.WSServletContextListener

Servlet:com.sun.xml.ws.transport.http.servlet.WSServlet

 

其中WSServletContextListener又会去查找和web.xml在同一级目录下的另一个文件sun-jaxws.xml,整个过程的流程图大约为:


 

sun-jaxws.xml文件的schema可以在下载的jax-ws RI的docs目录下找着(sun-jaxws.xsd)。

在初始化期间,WSServletContextListener会读取WEB-INF目录下的 sun-jaxws.xml和web.xml,将web service的实现类与某个url进行绑定,这个绑定是通过一个WSServlet类间接进行的。每次来一个请求后,WSServletContextListener就会进行拦截,根据请求的url,找到对应的web service的实现,调用其他方法。

 

这里直接给出calculator的web.xml和sun-jaxws.xml的一个实现:


Sun-jaxws.xml代码  


	
 


Web.xml代码  


	
		index.jsp
	
	  
          
                com.sun.xml.ws.transport.http.servlet.WSServletContextListener  
          
      
	
		Hello
		com.sun.xml.ws.transport.http.servlet.WSServlet
		2
	
	
		Hello
		/HelloService
	



然后把这个项目部署到web服务器中,部署方式和一般项目没什么两样,输入wsdl的url后就可以访问了

例如:http://localhost:8080/JaxWSProject/HelloService?wsdl


转载自:http://blog.csdn.net/gjb724332682/article/details/46293167


你可能感兴趣的:(webservice)