您的位置:首页 > 编程语言 > Java开发

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

2015-10-30 11:56 120 查看
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 selectMaxAgeStudent(Customer c1, Customer c2);
Customer selectMaxLongNameStudent(Customer 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 selectMaxAgeStudent(Customer c1, Customer c2) {
if (c1.getBirthday().getTime() > c2.getBirthday().getTime())
return c2;
else
return c1;
}
@Override
public Customer selectMaxLongNameStudent(Customer 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;
@XmlRootElement(name = "Customer")
public class Customer {
private long id;
private String name;
private Date birthday;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date 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 main(String[] 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"?>
<!--
Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01.
-->
<!--
Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01.
-->
-<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://outofmemory.cn/JASWS/" name="HelloServiceImplService">
-<types>
-<xsd:schema>
<xsd:import namespace="http://outofmemory.cn/JASWS/" schemaLocation="http://127.0.0.1:8080/helloService?xsd=1" />
</xsd:schema>
</types>
-<message name="selectMaxLongNameStudent">
<part name="parameters" element="tns:selectMaxLongNameStudent" />
</message>
-<message name="selectMaxLongNameStudentResponse">
<part name="parameters" element="tns:selectMaxLongNameStudentResponse" />
</message>
-<message name="selectMaxAgeStudent">
<part name="parameters" element="tns:selectMaxAgeStudent" />
</message>
-<message name="selectMaxAgeStudentResponse">
<part name="parameters" element="tns:selectMaxAgeStudentResponse" />
</message>
-<portType name="HelloServiceImpl">
-<operation name="selectMaxLongNameStudent">
<input wsam:Action="http://JASWS/HelloServiceImpl/selectMaxLongNameStudentRequest" message="tns:selectMaxLongNameStudent" />
<output wsam:Action="http://JASWS/HelloServiceImpl/selectMaxLongNameStudentResponse" message="tns:selectMaxLongNameStudentResponse" />
</operation>
-<operation name="selectMaxAgeStudent">
<input wsam:Action="http://JASWS/HelloServiceImpl/selectMaxAgeStudentRequest" message="tns:selectMaxAgeStudent" />
<output wsam:Action="http://JASWS/HelloServiceImpl/selectMaxAgeStudentResponse" message="tns:selectMaxAgeStudentResponse" />
</operation>
</portType>
-<binding name="HelloServiceImplPortBinding" type="tns:HelloServiceImpl">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
-<operation name="selectMaxLongNameStudent">
<soap:operation soapAction="" />
-<input>
<soap:body use="literal" />
</input>
-<output>
<soap:body use="literal" />
</output>
</operation>
-<operation name="selectMaxAgeStudent">
<soap:operation soapAction="" />
-<input>
<soap:body use="literal" />
</input>
-<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
-<service name="HelloServiceImplService">
-<port name="HelloServiceImplPort" binding="tns:HelloServiceImplPortBinding">
<soap:address location="http://127.0.0.1:8080/helloService" />
</port>
</service>
</definitions>


下一节来分析该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[/code] 
你会在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 main(String[] args) throws ParseException {
JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
soapFactoryBean.setAddress("http://127.0.0.1:8080/helloService");
soapFactoryBean.setServiceClass(IHelloService.class);
Object o = soapFactoryBean.create();
IHelloService helloService = (IHelloService) o;
Customer c1 = new Customer();
c1.setId(1);
c1.setName("A");
GregorianCalendar calendar = (GregorianCalendar)
GregorianCalendar
.getInstance();
calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1989-01-28"));
c1.setBirthday(new Date("2013-01-01"));
Customer c2 = new Customer();
c2.setId(2);
c2.setName("B");
calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1990-01-28"));
c2.setBirthday(new Date("2013-02-01"));
System.out.println(helloService.selectMaxAgeStudent(c1,c2).getName());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: