简单WebService规范 JAX-WS实现例子

   Web 服务分为Server、Client 两部分,Server 公开Web 服务,Client 调用Web 服务,JAX-WS 的服务端、客户端双方传输数据使用的SOAP 消息格式封装数据,在后面我们会看到其实SOAP 信封内包装的就是一段XML 代码。

 I.服务端示例:
    我们先看一个服务器端示例:

(1.)公开Web 服务的接口IHelloService:

1 import javax.jws.WebService;
2     @WebService
3     public interface IHelloService {
4     Customer selectMaxAgeStudent(Customer c1, Customer c2);
5     Customer selectMaxLongNameStudent(Customer c1, Customer c2);
6     }
View Code

我们看到这个接口很简单,仅仅是使用类级别注解@WebService 就标注了这个接口的方法将公开为Web 服务,使用了这个注解的接口的所有方法都将公开为Web 服务的操作,如果你想屏蔽某个方法,可以使用方法注解@Method 的exclude=true.我们也通常把公开为Web服务的接口叫做SEI(Service EndPoint Interface)服务端点接口。
    (2.)实现类HelloServiceImpl:

 1 import javax.jws.WebService;
 2     @WebService
 3     public class HelloServiceImpl implements IHelloService {
 4     @Override
 5     public Customer selectMaxAgeStudent(Customer c1, Customer c2) {
 6     if (c1.getBirthday()。getTime() > c2.getBirthday()。getTime())
 7     return c2;
 8     else
 9     return c1;
10     }
11     @Override
12     public Customer selectMaxLongNameStudent(Customer c1, Customer c2)
13     {
14     if (c1.getName()。length() > c2.getName()。length())
15     return c1;
16     else
17     return c2;
18     }
19     }
View Code

这个实现类没有任何特殊之处,但是如果你的实现类还实现了其他的接口,那么你需要在实现类上使用@WebService 注解的endpointInterface 属性指定那个接口是SEI(全类名)。
    (3.)Customer 类:

 1 import java.util.Date;
 2     import javax.xml.bind.annotation.XmlRootElement;
 3     @XmlRootElement(name = "Customer" 4     public class Customer {
 5     private long id;
 6     private String name;
 7     private Date birthday;
 8     public long getId() {
 9     return id;
10     }
11     public void setId(long id) {
12     this.id = id;
13     }
14     public String getName() {
15     return name;
16     }
17     public void setName(String name) {
18     this.name = name;
19     }
20     public Date getBirthday() {
21     return birthday;
22     }
23     public void setBirthday(Date birthday) {
24     this.birthday = birthday;
25     }
26     }
View Code

这个类是公开为Web 服务的接口中的参数类型和返回值,因此你需要使用JAXB 注解告诉CXF 如何在XML和Java Object 之间处理,因为前面说过SOAP 消息格式包装的是一段XML代码,那么无论是服务器端还是客户端在接收到SOAP 消息时都需要将XML 转化为JavaObject,在发送SOAP 消息时需要将Java Object 转化为XML.

JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到 XML实例文档。从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地 结合XML数据和处理函数。
    JDK中JAXB相关的重要Annotation:
    @XmlType,将Java类或枚举类型映射到XML模式类型
    @XmlAccessorType(XmlAccessType.FIELD) ,控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标 注)字段到XML.其他值还有XmlAccessType.PROPERTY和XmlAccessType.NONE.
    @XmlAccessorOrder,控制JAXB 绑定类中属性和字段的排序。
    @XmlJavaTypeAdapter,使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML.
    @XmlElementWrapper ,对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。
    @XmlRootElement,将Java类或枚举类型映射到XML元素。
    @XmlElement,将Java类的一个属性映射到与属性同名的一个XML元素。
    @XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。
    其他:
    对于要序列化(marshal)为XML的Java类,绝不能把成员变量声明为public,否则运行将抛出异常com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException.
    对于JAXB相关的重要Annotation的声明,如@Xml……,可以放在成员变量的setter()或getter()方法上,两者中任选其一即 可,但决不能放在成员变量上,否则运行将抛出异常 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException.
    (4.)发布Web 服务:

1  import javax.xml.ws.Endpoint;
2     public class SoapServer {
3     public static void main(String[] args) {
4     Endpoint.publish("http://127.0.0.1:8080/helloService",new HelloServiceImpl());
5     }
6     }
View xml

 注意我们发布Web 服务使用的是javax.xml.ws.*包中的EndPoint 的静态方法publish()。
    (5.)查看WSDL:
    我们访问http://127.0.0.1:8080/helloService?wsdl 地址,您会看到很长的XML 文件(由于浏览器的问题,如果你看到的是空白页面,请查看源代码),这就是WSDL(WebService DefinitionLanguage),对于你要访问的Web 服务,只要在其地址后加上,就可以在浏览器中查看用于描述Web 服务的WSDL,这也是一种XML,Web 服务能够被各种编程语言书写的程序访问就是通过WSDL 这种通用的契约来完成的。如果你已经看到WSDL,那么表示我们的Web 服务发布成功了。你可能会差异,我们没有
    借助Tomcat 这样的Web 服务器,直接运行一个main 方法是怎么发布的Web 服务呢?其实CXF 内置了Jetty(Servlet 容器),因此你不需要将你的程序部署到Tomcat 等Web 服务器也可以正常发布Web 服务。
    (6)。返回的WSDL:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2     <!--
 3     Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01.
 4     -->
 5     <!--
 6     Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01.
 7     -->
 8     -<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://JASWS/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://JASWS/" name="HelloServiceImplService">
 9     -<types>
10     -<xsd:schema>
11     <xsd:import namespace="http://JASWS/" schemaLocation="http://127.0.0.1:8080/helloService?xsd=1" />
12     </xsd:schema>
13     </types>
14     -<message name="selectMaxLongNameStudent">
15     <part name="parameters" element="tns:selectMaxLongNameStudent" />
16     </message>
17     -<message name="selectMaxLongNameStudentResponse">
18     <part name="parameters" element="tns:selectMaxLongNameStudentResponse" />
19     </message>
20     -<message name="selectMaxAgeStudent">
21     <part name="parameters" element="tns:selectMaxAgeStudent" />
22     </message>
23     -<message name="selectMaxAgeStudentResponse">
24     <part name="parameters" element="tns:selectMaxAgeStudentResponse" />
25     </message>
26     -<portType name="HelloServiceImpl">
27     -<operation name="selectMaxLongNameStudent">
28     <input wsam:Action="http://JASWS/HelloServiceImpl/selectMaxLongNameStudentRequest" message="tns:selectMaxLongNameStudent" />
29     <output wsam:Action="http://JASWS/HelloServiceImpl/selectMaxLongNameStudentResponse" message="tns:selectMaxLongNameStudentResponse" />
30     </operation>
31     -<operation name="selectMaxAgeStudent">
32     <input wsam:Action="http://JASWS/HelloServiceImpl/selectMaxAgeStudentRequest" message="tns:selectMaxAgeStudent" />
33     <output wsam:Action="http://JASWS/HelloServiceImpl/selectMaxAgeStudentResponse" message="tns:selectMaxAgeStudentResponse" />
34     </operation>
35     </portType>
36     -<binding name="HelloServiceImplPortBinding" type="tns:HelloServiceImpl">
37     <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
38     -<operation name="selectMaxLongNameStudent">
39     <soap:operation soapAction="" />
40     -<input>
41     <soap:body use="literal" />
42     </input>
43     -<output>
44     <soap:body use="literal" />
45     </output>
46     </operation>
47     -<operation name="selectMaxAgeStudent">
48     <soap:operation soapAction="" />
49     -<input>
50     <soap:body use="literal" />
51     </input>
52     -<output>
53     <soap:body use="literal" />
54     </output>
55     </operation>
56     </binding>
57     -<service name="HelloServiceImplService">
58     -<port name="HelloServiceImplPort" binding="tns:HelloServiceImplPortBinding">
59     <soap:address location="http://127.0.0.1:8080/helloService" />
60     </port>
61     </service>
62     </definitions>
View Code

下一节来分析该WSDL的结构和组成元素。

(7)。 客户端调用程序
    我们从上面可以知道Web 服务只向客户端暴漏WSDL,那么客户端必须将WSDL 转换为自己的编程语言书写的代码。JAX-WS 的各种实现都提供相应的工具进行WSDL 与JAVA 之间的互相转换,你可以在CXF 的运行包中找到bin 目录,其中的wsdl2java.bat 可以将WSDL转换为JAVA 类,bin 目录的各种bat 的名字可以很容易知道其作用,但要注意JAVA 类转换为WSDL 最好使用前面的URL?wsdl 的方式获得,因为这样得到的是最准确的。你可以在命令行将当前目录切换到CXF 的bin 目录,然后运行wsdl2java –h 查看这个批处理命令的各个参数的作用,常用的方式就是 wsdljava –p 包路径 –d 目标文件夹 wsdl 的 url地址。现在我们将前面的WSDL生成客户端代码:
    wsdl2java -p net.ilkj.soap.client –d E:\ http://127.0.0.1:8080/helloService?wsdl
    你会在E 盘根目录找到生成的客户端代码,然后将它复制到Eclipse 工程即可使用。
    如果你使用MyEclipse,可以按照如下步骤从WSDL 生成客户端代码:
    New--->Other--->MyEclipse--->Web Services--->Web Services Client,然后依据设置向导即可完成,但最好还是使用CXF 的wsdl2java 来完成,因为CXF2.2+版本开始支持JAX-WS2.1规范,而MyEclipse 自带的好像是XFire 的wsdl2java,生成的客户端代码可能不是最新规范的。
    我们上面的WSDL 会生成如下所示的客户端代码:

Customer.java
    HelloServiceImplService.java
    IHelloService.java
    ObjectFactory.java
    package-info.java
    SelectMaxAgeStudent.java
    SelectMaxAgeStudentResponse.java
    SelectMaxLongNameStudent.java
    SelectMaxLongNameStudentResponse.java
    其中package-info.java、ObjectFactory.java 是JAXB需要的文件;HelloServiceImplService.java继承自javax.xml.ws.Service 类,用于提供WSDL 的客户端视图,里面使用的是大量javax.xml.ws.*包中的注解;剩下的类是Web 服务的接口、方法参数、响应值的类。
    在 CXF 中使用JaxWsProxyFactoryBean 客户端代理工厂调用Web 服务,代码如下所示:

 1 import java.text.ParseException;
 2     import java.text.SimpleDateFormat;
 3     import java.util.Date;
 4     import java.util.GregorianCalendar;
 5     import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
 6     public class SoapClient {
 7     public static void main(String[] args) throws ParseException {
 8     JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
 9     soapFactoryBean.setAddress("http://127.0.0.1:8080/helloService");
10     soapFactoryBean.setServiceClass(IHelloService.class);
11     Object o = soapFactoryBean.create();
12     IHelloService helloService = (IHelloService) o;
13     Customer c1 = new Customer();
14     c1.setId(1);
15     c1.setName("A");
16     GregorianCalendar calendar = (GregorianCalendar)
17     GregorianCalendar
18     .getInstance();
19     calendar.setTime(new SimpleDateFormat("yyyy-MM-dd")。parse("1989-01-28"));
20     c1.setBirthday(new Date("2013-01-01"));
21     Customer c2 = new Customer();
22     c2.setId(2);
23     c2.setName("B");
24     calendar.setTime(new SimpleDateFormat("yyyy-MM-dd")。parse("1990-01-28"));
25     c2.setBirthday(new Date("2013-02-01"));
26     System.out.println(helloService.selectMaxAgeStudent(c1,c2)。getName());
27     }
28     }
View Code

 

 

posted @ 2014-07-01 17:13  yuyinniaoniao  阅读(245)  评论(0)    收藏  举报