引言

相比大家都或多或少的了解过或者听说过关于Webservice的相关知识, 常见的WebService实现方式有很多种:

  • –Axis1
  • –Axis2
  • –xfire
  • –CXF

采用每种实现方式都可以, 本例将采用CXF方式, 采用CXF是spring搭建webservice 最流行的一种方式, 可以用较少的代码来很容易实现一个Webservice的接口, 并且还可以通过注解的方式来自定义WSDL页面的内容, 使得接口的调用更加友好

实现

1. 引入依赖

<!-- Start CXF -->
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>3.3.2</version>
		</dependency>
		<dependency>
		    <groupId>org.apache.cxf</groupId>
		    <artifactId>cxf-rt-frontend-jaxws</artifactId>
		    <version>3.3.2</version>
		</dependency>
		<dependency>
			<!-- 如果CXF不集成到Web服务器中,必须添加该引用 -->
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>3.3.2</version>
		</dependency>
<!-- End CXF -->

2. 定义接口

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import org.apache.cxf.annotations.WSDLDocumentation;
import org.apache.cxf.annotations.WSDLDocumentationCollection;

@WebService
(
        name="diWebInter",  // 服务实现类的名称
        serviceName="diWebInterService",  // 默认在发布的服务实现者的名称后面添加Service
        portName="diWebInterPort",   // 服务类型的名称: 默认在 发布的服务实现者(MyWebService) 后面添加 port
        targetNamespace="http://www.dix.com"    // 发布ws服务的命名空间,此空间默认为当前服务包路径的 "倒写"此名称也是 wsimport 命令生成 java类时默认的包路径 -p
)
@WSDLDocumentationCollection(  
	    {  
	        @WSDLDocumentation(value = "webserviceDemo "
	        						 + "调用的方法为: diWebIntegration(String jsArr),  "
	        						 + "参数格式: JSONArray格式的字符串.",  
	                           placement = WSDLDocumentation.Placement.TOP) 
	    }  
)
public interface IUserService {
    
    // 注意 一定要加 action: 命名空间+方法名,  如果不加, 使用非cxf客户端调用的时候报错
	@WebMethod(operationName="diWebIntegration", action = "http://www.dix.com/diWebIntegration")
	@WSDLDocumentation( "调用该接口进行数据传输")
	public String diWebIntegration(@WebParam(name="jsArr", targetNamespace="http://www.dix.com") String jsArr);
	}
}

3. 实现类

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import org.apache.cxf.annotations.WSDLDocumentation;
import org.apache.cxf.annotations.WSDLDocumentationCollection;

@WebService
(
        name="diWebInter",  // 服务实现类的名称
        serviceName="diWebInterService",  // 默认在发布的服务实现者的名称后面添加Service
        portName="diWebInterPort",   // 服务类型的名称: 默认在 发布的服务实现者(MyWebService) 后面添加 port
        targetNamespace="http://www.dix.com"    // 发布ws服务的命名空间,此空间默认为当前服务包路径的 "倒写"此名称也是 wsimport 命令生成 java类时默认的包路径 -p
)
@WSDLDocumentationCollection(  
	    {  
	        @WSDLDocumentation(value = "webserviceDemo  "
	        						 + "调用的方法为: diWebIntegration(String jsArr),  "
	        						 + "参数格式: JSONArray格式的字符串.",  
	                           placement = WSDLDocumentation.Placement.TOP) 
	    }  
)
public class  IUserServiceImpl implements IUserService {
    
    // 注意 一定要加 action: 命名空间+方法名,  如果不加, 使用非cxf客户端调用的时候报错
	@WebMethod(operationName="diWebIntegration", action = "http://www.dix.com/diWebIntegration")
	@WSDLDocumentation( "调用该接口进行数据传输")
	public String diWebIntegration(@WebParam(name="jsArr", targetNamespace="http://www.dix.com") String jsArr) {
		System.out.println("WebService sayHello "+jsArr);
		return "sayHello "+jsArr;
	}
}

4. 启动类

启动类调用有两种方式可以实现, 一种是JDK Endpoint, 还有一种是cxf.frontend, 但是在测试过程中发现自定义的一些注解不生效

import javax.xml.ws.Endpoint;
 
import org.apache.cxf.frontend.ServerFactoryBean;
 
public class WebServicePublish {
 
	public static void main(String[] args) {
     // JDK Endpoint方式调用
	String address = "http://localhost:10068/webservice/path";
    Endpoint.publish(address , new IUserServiceImpl ());
    System.out.println("发布webservice成功!");
  
  /*cxf.frontend方式调用, 在测试时, 发现该方法调用, 自定的注释不生效*/
//		ServerFactoryBean sf=new ServerFactoryBean();
//		//服务实现类  
//		sf.setServiceClass(IUserServiceImpl .class);
//		//服务的发布地址  
//		sf.setAddress("http://localhost:8080/WS_Server/Webservice");
//		//服务的实例  
//		sf.setServiceBean(new WebServiceImpl());
//		//发布服务  
//		sf.create();
//		System.out.println("server ready……");
	}
}

5.启动成功效果图

当我们发布成之后, 在浏览器访问我们的接口地址
http://192.168.1.183:10068/webservice/path + ?wsdl后缀, 看到如下结果

优雅的实现一个Webservice服务端(CXF)_xml

具体内容:

<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://www.dix.com" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="diWebInterService"targetNamespace="http://www.dix.com">
<wsdl:documentation>
数据对接接口: 供第三方系统调用, 调用的方法为: diWebIntegration(String jsArr), 参数格式: JSONArray格式的字符串.
</wsdl:documentation>
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.dix.com" elementFormDefault="unqualified" targetNamespace="http://www.dix.com" version="1.0">
<xs:element name="diWebIntegration" type="tns:diWebIntegration"/>
<xs:element name="diWebIntegrationResponse" type="tns:diWebIntegrationResponse"/>
<xs:complexType name="diWebIntegration">
<xs:sequence>
<xs:element form="qualified" minOccurs="0" name="jsArr" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="diWebIntegrationResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="diWebIntegrationResponse">
<wsdl:part element="tns:diWebIntegrationResponse" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:message name="diWebIntegration">
<wsdl:part element="tns:diWebIntegration" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:portType name="diWebInter">
<wsdl:operation name="diWebIntegration">
<wsdl:documentation>调用该接口进行数据传输</wsdl:documentation>
<wsdl:input message="tns:diWebIntegration" name="diWebIntegration"></wsdl:input>
<wsdl:output message="tns:diWebIntegrationResponse" name="diWebIntegrationResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="diWebInterServiceSoapBinding" type="tns:diWebInter">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="diWebIntegration">
<soap:operation soapAction="http://www.dix.com/diWebIntegration" style="document"/>
<wsdl:input name="diWebIntegration">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="diWebIntegrationResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="diWebInterService">
<wsdl:port binding="tns:diWebInterServiceSoapBinding" name="diWebInterPort">
<soap:address location="http://localhost:8080/WS_Server/Webservice"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

6. 总结(注解解释)

可以看到,一个webservice的接口就发布成功了, 注意到我们在上面用了好多注解, 那么具体都是什么意思呢, 一起来看下:

@WebService
  • –1、serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)
  • –2、endpointInterface: 服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口
  • – 3、name:此属性的值包含XML Web Service的名称。在默认情况下,该值是实现XML Web Service的类的名称,wsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
  • –4、portName: wsdl:portName。缺省值为 WebService.name+Port。
  • –5、targetNamespace:指定你想要的名称空间,认是使用接口实现类的包名的反缀
  • –6、wsdlLocation:指定用于定义 Web Service 的 WSDL 文档的 Web 地址。Web 地址可以是相对路径或绝对路径。(字符串)
    注意:实现类上可以不添加Webservice注解
@WebMethod

该注释表示作为一项 Web Service 操作的方法,将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类。

要点: 仅支持在使用 @WebService 注释来注释的类上使用 @WebMethod 注释

  • –1、operationName:指定与此方法相匹配的wsdl:operation 的名称。缺省值为 Java 方法的名称。(字符串)
  • –2、action:定义此操作的行为。对于 SOAP 绑定,此值将确定 SOAPAction 头的值。缺省值为 Java 方法的名称。(字符串)
  • – 3、exclude:指定是否从 Web Service 中排除某一方法。缺省值为 false。(布尔值)
@WebParam

注释用于定制从单个参数至 Web Service 消息部件和 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类。

  • –1、name :参数的名称。如果操作是远程过程调用(RPC)类型并且未指定partName 属性,那么这是用于表示参数的 wsdl:part 属性的名称。
    如果操作是文档类型或者参数映射至某个头,那么 -name 是用于表示该参数的 XML 元素的局部名称。如果操作是文档类型、
    参数类型为 BARE 并且方式为 OUT 或 INOUT,那么必须指定此属性。(字符串)
  • –2、partName:定义用于表示此参数的 wsdl:part属性的名称。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为BARE 时才使用此参数。(字符串)
  • –3、targetNamespace:指定参数的 XML 元素的 XML 名称空间。当属性映射至 XML 元素时,仅应用于文档绑定。缺省值为 Web Service 的 targetNamespace。(字符串)
  • –4、mode:此值表示此方法的参数流的方向。有效值为 IN、INOUT 和 OUT。(字符串)
  • –5、header:指定参数是在消息头还是消息体中。缺省值为 false。(布尔值)
@WebResult

注释用于定制从返回值至 WSDL 部件或 XML 元素的映射。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类。

  • –1、name:当返回值列示在 WSDL 文件中并且在连接上的消息中找到该返回值时,指定该返回值的名称。对于 RPC 绑定,这是用于表示返回值的 wsdl:part属性的名称。对于文档绑定,-name参数是用于表示返回值的 XML 元素的局部名。对于 RPC 和 DOCUMENT/WRAPPED 绑定,缺省值为 return。对于 DOCUMENT/BARE 绑定,缺省值为方法名 + Response。(字符串)
  • –2、targetNamespace:指定返回值的 XML 名称空间。仅当操作类型为 RPC 或者操作是文档类型并且参数类型为 BARE 时才使用此参数。(字符串)
  • –3、header:指定头中是否附带结果。缺省值为false。(布尔值)
  • –4、partName:指定 RPC 或 DOCUMENT/BARE 操作的结果的部件名称。缺省值为
@HandlerChain

注释用于使 Web Service 与外部定义的处理程序链相关联。只能通过对 SEI 或实现类使用 @HandlerChain 注释来配置服务器端的处理程序。
但是可以使用多种方法来配置客户端的处理程序。可以通过对生成的服务类或者 SEI 使用 @HandlerChain 注释来配置客户端的处理程序。此外,可以按程序在服务上注册您自己的 HandlerResolver 接口实现,或者按程序在绑定对象上设置处理程序链。

  • –1、file:指定处理程序链文件所在的位置。文件位置可以是采用外部格式的绝对 java.net.URL,也可以是类文件中的相对路径。(字符串)
  • –2、name:指定配置文件中处理程序链的名称。
@Oneway

注释将一个方法表示为只有输入消息而没有输出消息的 Web Service 单向操作。将此注释应用于客户机或服务器服务端点接口(SEI)上的方法,或者应用于 JavaBeans 端点的服务器端点实现类

@WSDLDocumentationCollection

自定义wsdl页面的提示, 使用在接口或者类上

@WSDLDocumentation

自定义wsdl页面提示, 使用在方法上

看到这, 是不是感觉实现一个webservice的服务端接口也并不是很繁琐呢