JAVA的 WebService规范 JAX-WS实现例子

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

I.服务端示例:

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

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

    package cn.outofmemory.JASWS;
    import javax.jws.WebService;
    @WebService
    public interface IHelloService {
    Customer selectMaxAgeStudentCustomer c1, Customer c2);
    Customer selectMaxLongNameStudentCustomer c1, Customer c2);
    }

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

(2)实现类HelloServiceImpl:

    package cn.outofmemory.JASWS;
    import javax.jws.WebService;
    @WebService
    public class HelloServiceImpl implements IHelloService {
    @Override
    public Customer selectMaxAgeStudentCustomer c1, Customer c2 {
    if c1.getBirthday().getTime() > c2.getBirthday().getTime())
    return c2;
    else
    return c1;
    }
    @Override
    public Customer selectMaxLongNameStudentCustomer c1, Customer c2
    {
    if c1.getName().length() > c2.getName().length())
    return c1;
    else
    return c2;
    }
    }

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

(3)Customer 类:

    package cn.outofmemory.JASWS;
    import java.util.Date;
    import javax.xml.bind.annotation.XmlRootElement;
    @XmlRootElementname = "Customer"
    public class Customer {
    private long id;
    private String name;
    private Date birthday;
    public long getId() {
    return id;
    }
    public void setIdlong id {
    this.id = id;
    }
    public String getName() {
    return name;
    }
    public void setNameString name {
    this.name = name;
    }
    public Date getBirthday() {
    return birthday;
    }
    public void setBirthdayDate birthday {
    this.birthday = birthday;
    }
    }

这个类是公开为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 服务:

    package cn.outofmemory.JASWS;
    import javax.xml.ws.Endpoint;
    public class SoapServer {
    public static void mainString[] args {
    Endpoint.publish"http://127.0.0.1:8080/helloService",new HelloServiceImpl());
    }
    }

注意我们发布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:

 xml version="1.0" encoding="UTF-8"?>
    
    
    - 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://outofmemory.cn/JASWS/" name="HelloServiceImplService">
    -
    -
     namespace="http://outofmemory.cn/JASWS/" schemaLocation="http://127.0.0.1:8080/helloService?xsd=1" />
    
    
    - name="selectMaxLongNameStudent">
     name="parameters" element="tns:selectMaxLongNameStudent" />
    
    - name="selectMaxLongNameStudentResponse">
     name="parameters" element="tns:selectMaxLongNameStudentResponse" />
    
    - name="selectMaxAgeStudent">
     name="parameters" element="tns:selectMaxAgeStudent" />
    
    - name="selectMaxAgeStudentResponse">
     name="parameters" element="tns:selectMaxAgeStudentResponse" />
    
    - name="HelloServiceImpl">
    - name="selectMaxLongNameStudent">
     wsam:Action="http://JASWS/HelloServiceImpl/selectMaxLongNameStudentRequest" message="tns:selectMaxLongNameStudent" />
     wsam:Action="http://JASWS/HelloServiceImpl/selectMaxLongNameStudentResponse" message="tns:selectMaxLongNameStudentResponse" />
    
    - name="selectMaxAgeStudent">
     wsam:Action="http://JASWS/HelloServiceImpl/selectMaxAgeStudentRequest" message="tns:selectMaxAgeStudent" />
     wsam:Action="http://JASWS/HelloServiceImpl/selectMaxAgeStudentResponse" message="tns:selectMaxAgeStudentResponse" />
    
    
    - name="HelloServiceImplPortBinding" type="tns:HelloServiceImpl">
     transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    - name="selectMaxLongNameStudent">
     soapAction="" />
    -
     use="literal" />
    
    -
     use="literal" />
    
    
    - name="selectMaxAgeStudent">
     soapAction="" />
    -
     use="literal" />
    
    -
     use="literal" />
    
    
    
    - name="HelloServiceImplService">
    - name="HelloServiceImplPort" binding="tns:HelloServiceImplPortBinding">
     location="http://127.0.0.1:8080/helloService" />
    
    
    

下一节来分析该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 服务,代码如下所示:

    package cn.outofmemory.JASWS;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.GregorianCalendar;
    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
    public class SoapClient {
    public static void mainString[] args throws ParseException {
    JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
    soapFactoryBean.setAddress"http://127.0.0.1:8080/helloService");
    soapFactoryBean.setServiceClassIHelloService.class);
    Object o = soapFactoryBean.create();
    IHelloService helloService = IHelloService o;
    Customer c1 = new Customer();
    c1.setId1);
    c1.setName"A");
    GregorianCalendar calendar = GregorianCalendar
    GregorianCalendar
    .getInstance();
    calendar.setTimenew SimpleDateFormat"yyyy-MM-dd").parse"1989-01-28"));
    c1.setBirthdaynew Date"2013-01-01"));
    Customer c2 = new Customer();
    c2.setId2);
    c2.setName"B");
    calendar.setTimenew SimpleDateFormat"yyyy-MM-dd").parse"1990-01-28"));
    c2.setBirthdaynew Date"2013-02-01"));
    System.out.printlnhelloService.selectMaxAgeStudentc1,c2).getName());
    }
    }

你可能感兴趣的:(程序设计)