WebService
1. 常见的远程调用协议与技术
IOS的七层模型:
- 第一层:应用层。定义了用于在网络中进行通信和传输数据的接口;
- 第二层:表示层。定义不同的系统中数据的传输格式,编码和解码规范等;
- 第三层:会话层。管理用户的会话,控制用户间逻辑连接的建立和中断;
- 第四层:传输层。管理着网络中的端到端的数据传输;
- 第五层:网络层。定义网络设备间如何传输数据;
- 第六层:链路层。将上面的网络层的数据包封装成数据帧,便于物理层传输;
- 第七层:物理层。这一层主要就是传输这些二进制数据。
Socket通信:Socket属于传输层,它是对TCP/IP协议的实现,包含TCP/UPD,它是所有通信协议的基础。
特点: 开启端口,该通信是长连接的通信 ,很容易被防火墙拦截,虽可以通过心跳机制来实现 ,但开发难度复杂;性能相对于其他的通信协议是最优的(客户端的大型网络游戏基本都是Socket通信);传输的数据一般是字符串 ,可读性不强。
Http协议:属于应用层的协议,对Socket进行了封装,HttpClient项目提供了通过java编程发送Http请求。
soap(http+xml):simple object access protocol(简单对象访问协议),xml是无关乎平台与语言的,使用http协议发送和接受xml数据来实现跨平台跨语言的远程调用。实现的技术是即将介绍的WebService。
RPC(Remote Procedure Call Protocol):使用C/S方式,采用http协议,发送请求到服务器,等待服务器返回结果。这个请求包括一个参数集和一个文本集,通常形成“classname.methodname”形式。优点是跨语言跨平台,C端、S端有更大的独立性,缺点是不支持对象,无法在编译器检查错误,只能在运行期检查。流行的RPC框架有gRPC、Thrift、Dubbo。
RMI:RMI是个典型的为java定制的远程通信协议,传输的标准格式是Java Object Stream;基于Java串行化机制将请求的Java Object信息转化为流,传输协议是Socket。缺点是只能基于Java语言。
JMS: JMS是Java的消息服务,JMS的客户端之间可以通过JMS服务进行异步的消息传输。JMS支持两种消息模型:Point-to-Point(P2P)和Publish/Subscribe(Pub/Sub),即点对点和发布订阅模型。 JMS规定的传输格式是Message,将参数信息放入Message中,传输协议不限。
2. WebService技术
WebService是一种跨编程语言和跨操作系统平台的远程调用技术,从表面上看,WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。我们把调用这个WebService的应用程序叫做客户端,而把提供这个WebService的应用程序叫做服务端。从深层次看,WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义了应用程序如何在Web上实现互操作性。XML+XSD,SOAP和WSDL是构成WebService平台的三大技术;并且WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:
- 1.注册到UDDI服务器,以便被人查找;
- 2.直接告诉给客户端调用者。
XML+XSD:WebService采用HTTP协议作为传输协议,采用XMl格式封装数据,XML的优点在于它与平台和语言无关,XSD(XML Schema)来定义一套标准的数据类型,无论你使用什么语言的数据类型都会被转换为XSD类型。
SOAP(Simple Object Access Protocol):WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。
WSDL:用于描述WebService及其函数、参数和返回值的XML。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应WebService的代理类代码。
UUDI:一种目录服务,企业可以使用它对Webservices进行注册和搜索。
2.1 使用WebService调用第三方接口
http://www.webxml.com.cn/zh_cn/index.aspx此网站提供了发布了的WebService服务。
WebService的调用有三种方式:
- http#get
- http#post
- http#post+xml(soap)
package com.ws.client;
/**
* @desc 国内手机号码归属地查询WEB服务:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx
* @author yutao
* @create 2018-06-26 9:33
*/
public class MobileCodeService {
/**
* Http GET请求
* @param mobileCode
* @param userID
*/
public void get(String mobileCode,String userID){
try {
URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode="+mobileCode+"&userID="+userID);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(5000); //设置连接超时
httpURLConnection.setRequestMethod("GET"); //GET请求
if (httpURLConnection.getResponseCode()==httpURLConnection.HTTP_OK) { //请求返回码200
InputStream inputStream = httpURLConnection.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); //内存流
byte[] bytes = new byte[1024];
int len = -1;
while ((len=inputStream.read(bytes))!=-1) {
byteArrayOutputStream.write(bytes,0,len);
}
System.out.println(byteArrayOutputStream.toString()); //返回的是xml字符串
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Http POST请求
* @param mobileCode
* @param userID
*/
public void post(String mobileCode,String userID) {
/** org.apache.commons.httpclient.HttpClient访问网络的实现步骤:
* 1. 准备一个请求客户端:浏览器
* 2. 准备请求方式: GET 、POST
* 3. 设置要传递的参数
* 4.执行请求
* 5. 获取结果
*/
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo");
postMethod.setParameter("mobileCode",mobileCode);
postMethod.setParameter("userID",userID);
try {
int code = httpClient.executeMethod(postMethod);
if (code == 200) {
String result = postMethod.getResponseBodyAsString();
System.out.println(result);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* soap 请求(HTTP#POST + xml)
*/
public void soap() {
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx");
try {
File file = new File("F:\\idea\\project\\webservice\\src\\main\\resources\\soap.xml");
InputStreamRequestEntity inputStreamRequestEntity = new InputStreamRequestEntity(new FileInputStream(file),"text/xml; charset=utf-8");
postMethod.setRequestEntity(inputStreamRequestEntity); //设置POST请求请求体
int code = httpClient.executeMethod(postMethod);
if (code == HttpURLConnection.HTTP_OK) {
System.out.println(postMethod.getResponseBodyAsString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MobileCodeService mobileCodeService = new MobileCodeService();
mobileCodeService.get("13456789000","");
}
}
2.1.1 使用WSDL
上述的三种调用方式返回的数据都是xml字符串 <?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://WebXml.com.cn/">13456789000:浙江 杭州 浙江移动大众卡</string>
对于这样的数据我们每次取得岂不是都要编写xml解析,显然不是我们希望得到的。通过工具可以根据WebService的WSDL生成对应编程语言的代理类,原理如下图:
WSDL地址:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
使用JDK的wsimport指令生成代理类:
/**
* -d表示输出的.class文件位置,-s表示输出的.java文件位置,-p表示输出的包名
* wsimport无法生成SOAP12、GET、POST请求的代理类
*/
wsimport -d D:/ -s D:/src -p com.ws.proxy http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
将生成的源码放入项目上述指定的包中或将生成的class文件打成jar包引入项目中,即可使用。
/**
* 返回的xml都会通过代理类处理成了String字符串或其他集合数据等
*/
public class MobileCodeWSTest {
public static void main(String[] args) {
//获取MobileCodeWS服务
MobileCodeWS ws = new MobileCodeWS();
//获取SOAP请求的服务
MobileCodeWSSoap mobileCodeWSSoap = ws.getMobileCodeWSSoap();
//调用该服务的getMobileCodeInfo方法
String mobileCodeInfo = mobileCodeWSSoap.getMobileCodeInfo("18712343850", "");
System.out.println(mobileCodeInfo);
//调用该服务的getDatabaseInfo方法,ArrayOfString是生成的代理类,通过getString方法返回List集合
ArrayOfString databaseInfo = mobileCodeWSSoap.getDatabaseInfo();
List<String> list = databaseInfo.getString();
for (String s : list) {
System.out.println(s);
}
}
}
2.2 服务端WebService发布
2.2.1 WSDL
http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL解析如下:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://WebXml.com.cn/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="http://WebXml.com.cn/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <!--targetNamespace是命名空间,默认使用cn.com.WebXml作为生成代理类的包-->
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <!--文档-->
<a href="http://www.webxml.com.cn/" target="_blank">WebXml.com.cn</a> <strong>国内手机号码归属地查询WEB服务</strong>,提供最新的国内手机号码段归属地数据,每月更新。<br />使用本站 WEB 服务请注明或链接本站:<a href="http://www.webxml.com.cn/" target="_blank">http://www.webxml.com.cn/</a> 感谢大家的支持!<br />&nbsp;
</wsdl:documentation>
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://WebXml.com.cn/">
<s:element name="getMobileCodeInfo"> <!--输入参数信息,对外提供WebService的输入参数类-->
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="mobileCode" type="s:string" /> <!--输入参数名及参数类型-->
<s:element minOccurs="0" maxOccurs="1" name="userID" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="getMobileCodeInfoResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="getMobileCodeInfoResult" type="s:string" /> <!--返回参数名及类型-->
</s:sequence>
</s:complexType>
</s:element>
<s:element name="getDatabaseInfo">
<s:complexType />
</s:element>
<s:element name="getDatabaseInfoResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="getDatabaseInfoResult" type="tns:ArrayOfString" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="ArrayOfString"> <!-- 服务定义返回的类型,对外提供WebService的类型类 -->
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="s:string" />
</s:sequence>
</s:complexType>
<s:element name="string" nillable="true" type="s:string" />
<s:element name="ArrayOfString" nillable="true" type="tns:ArrayOfString" />
</s:schema>
</wsdl:types>
<wsdl:message name="getMobileCodeInfoSoapIn"> <!--服务端口输入参数信息-->
<wsdl:part name="parameters" element="tns:getMobileCodeInfo" /> <!--参数信息在上面<wsdl:types>中-->
</wsdl:message>
<wsdl:message name="getMobileCodeInfoSoapOut"> <!--服务端口返回参数信息-->
<wsdl:part name="parameters" element="tns:getMobileCodeInfoResponse" /> <!--参数信息在上面<wsdl:types>中-->
</wsdl:message>
<wsdl:message name="getDatabaseInfoSoapIn">
<wsdl:part name="parameters" element="tns:getDatabaseInfo" />
</wsdl:message>
<wsdl:message name="getDatabaseInfoSoapOut">
<wsdl:part name="parameters" element="tns:getDatabaseInfoResponse" />
</wsdl:message>
<wsdl:message name="getMobileCodeInfoHttpGetIn">
<wsdl:part name="mobileCode" type="s:string" />
<wsdl:part name="userID" type="s:string" />
</wsdl:message>
<wsdl:message name="getMobileCodeInfoHttpGetOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="getDatabaseInfoHttpGetIn" />
<wsdl:message name="getDatabaseInfoHttpGetOut">
<wsdl:part name="Body" element="tns:ArrayOfString" />
</wsdl:message>
<wsdl:message name="getMobileCodeInfoHttpPostIn">
<wsdl:part name="mobileCode" type="s:string" />
<wsdl:part name="userID" type="s:string" />
</wsdl:message>
<wsdl:message name="getMobileCodeInfoHttpPostOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="getDatabaseInfoHttpPostIn" />
<wsdl:message name="getDatabaseInfoHttpPostOut">
<wsdl:part name="Body" element="tns:ArrayOfString" />
</wsdl:message>
<wsdl:portType name="MobileCodeWSSoap"> <!--服务端口类型,对外提供WebService业务类或接口-->
<wsdl:operation name="getMobileCodeInfo"> <!-- 操作名 -->
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><br /><h3>获得国内手机号码归属地省份、地区和手机卡类型信息</h3><p>输入参数:mobileCode = 字符串(手机号码,最少前7位数字),userID = 字符串(商业用户ID) 免费用户为空字符串;返回数据:字符串(手机号码:省份 城市 手机卡类型)。</p><br /></wsdl:documentation>
<wsdl:input message="tns:getMobileCodeInfoSoapIn" /> <!--输入参数,对应上面<wsdl:message>-->
<wsdl:output message="tns:getMobileCodeInfoSoapOut" /> <!--返回参数,对应上面<wsdl:message>-->
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><br /><h3>获得国内手机号码归属地数据库信息</h3><p>输入参数:无;返回数据:一维字符串数组(省份 城市 记录数量)。</p><br /></wsdl:documentation>
<wsdl:input message="tns:getDatabaseInfoSoapIn" />
<wsdl:output message="tns:getDatabaseInfoSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="MobileCodeWSHttpGet">
<wsdl:operation name="getMobileCodeInfo">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><br /><h3>获得国内手机号码归属地省份、地区和手机卡类型信息</h3><p>输入参数:mobileCode = 字符串(手机号码,最少前7位数字),userID = 字符串(商业用户ID) 免费用户为空字符串;返回数据:字符串(手机号码:省份 城市 手机卡类型)。</p><br /></wsdl:documentation>
<wsdl:input message="tns:getMobileCodeInfoHttpGetIn" />
<wsdl:output message="tns:getMobileCodeInfoHttpGetOut" />
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><br /><h3>获得国内手机号码归属地数据库信息</h3><p>输入参数:无;返回数据:一维字符串数组(省份 城市 记录数量)。</p><br /></wsdl:documentation>
<wsdl:input message="tns:getDatabaseInfoHttpGetIn" />
<wsdl:output message="tns:getDatabaseInfoHttpGetOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="MobileCodeWSHttpPost">
<wsdl:operation name="getMobileCodeInfo">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><br /><h3>获得国内手机号码归属地省份、地区和手机卡类型信息</h3><p>输入参数:mobileCode = 字符串(手机号码,最少前7位数字),userID = 字符串(商业用户ID) 免费用户为空字符串;返回数据:字符串(手机号码:省份 城市 手机卡类型)。</p><br /></wsdl:documentation>
<wsdl:input message="tns:getMobileCodeInfoHttpPostIn" />
<wsdl:output message="tns:getMobileCodeInfoHttpPostOut" />
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><br /><h3>获得国内手机号码归属地数据库信息</h3><p>输入参数:无;返回数据:一维字符串数组(省份 城市 记录数量)。</p><br /></wsdl:documentation>
<wsdl:input message="tns:getDatabaseInfoHttpPostIn" />
<wsdl:output message="tns:getDatabaseInfoHttpPostOut" />
</wsdl:operation>
</wsdl:portType>
<!-- 服务Soap访问方式 -->
<wsdl:binding name="MobileCodeWSSoap" type="tns:MobileCodeWSSoap"> <!--服务端口类型,对应上面的</wsdl:portType>-->
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<!--该服务提供了以下二种操作-->
<wsdl:operation name="getMobileCodeInfo"> <!--操作名称(对外暴露调用的方法名)-->
<soap:operation soapAction="http://WebXml.com.cn/getMobileCodeInfo" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<soap:operation soapAction="http://WebXml.com.cn/getDatabaseInfo" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!-- 服务Soap12访问方式-->
<wsdl:binding name="MobileCodeWSSoap12" type="tns:MobileCodeWSSoap">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getMobileCodeInfo">
<soap12:operation soapAction="http://WebXml.com.cn/getMobileCodeInfo" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<soap12:operation soapAction="http://WebXml.com.cn/getDatabaseInfo" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!--服务Get访问方式-->
<wsdl:binding name="MobileCodeWSHttpGet" type="tns:MobileCodeWSHttpGet">
<http:binding verb="GET" />
<wsdl:operation name="getMobileCodeInfo">
<http:operation location="/getMobileCodeInfo" />
<wsdl:input>
<http:urlEncoded />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<http:operation location="/getDatabaseInfo" />
<wsdl:input>
<http:urlEncoded />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!--服务Post访问方式-->
<wsdl:binding name="MobileCodeWSHttpPost" type="tns:MobileCodeWSHttpPost">
<http:binding verb="POST" />
<wsdl:operation name="getMobileCodeInfo">
<http:operation location="/getMobileCodeInfo" />
<wsdl:input>
<mime:content type="application/x-www-form-urlencoded" />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getDatabaseInfo">
<http:operation location="/getDatabaseInfo" />
<wsdl:input>
<mime:content type="application/x-www-form-urlencoded" />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MobileCodeWS"> <!--服务名,对外提供WebService的服务类-->
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><a href="http://www.webxml.com.cn/" target="_blank">WebXml.com.cn</a> <strong>国内手机号码归属地查询WEB服务</strong>,提供最新的国内手机号码段归属地数据,每月更新。<br />使用本站 WEB 服务请注明或链接本站:<a href="http://www.webxml.com.cn/" target="_blank">http://www.webxml.com.cn/</a> 感谢大家的支持!<br />&nbsp;</wsdl:documentation>
<wsdl:port name="MobileCodeWSSoap" binding="tns:MobileCodeWSSoap"> <!--服务端口名及服务访问方式(Soap、Soap12、Get、Post,对应上面的<wsdl:binding>)-->
<soap:address location="http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx" /> <!--服务访问地址-->
</wsdl:port>
<wsdl:port name="MobileCodeWSSoap12" binding="tns:MobileCodeWSSoap12">
<soap12:address location="http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx" />
</wsdl:port>
<wsdl:port name="MobileCodeWSHttpGet" binding="tns:MobileCodeWSHttpGet">
<http:address location="http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx" />
</wsdl:port>
<wsdl:port name="MobileCodeWSHttpPost" binding="tns:MobileCodeWSHttpPost">
<http:address location="http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
2.2.2 WebService注解
@WebService
/**
* 用于注解在需要作为WebService发布的类或接口上
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface WebService {
//服务端口类型名,修改<wsdl:portType>的name属性
String name() default "";
//命名空间,修改targetNamespaces属性
String targetNamespace() default "";
//服务名,修改<wsdl:service>的name属性
String serviceName() default "";
//端口服务名,修改<wsdl:service>下<wsdl:port>的name属性
String portName() default "";
//wsdl地址,修改wsdl:service>下<*:address>的location属性
String wsdlLocation() default "";
//服务接口全路径, 指定做SEI(Service EndPoint Interface)服务端点接口
String endpointInterface() default "";
}
@WebMethod
/**
* 注释表示作为一项 WebService 操作的方法
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface WebMethod {
//操作名,修改<wsdl:operation>的name属性
String operationName() default "";
//定义此操作的行为。对于 SOAP 绑定,此值将确定 SoapAction属性的信息。缺省值为 Java 方法的名称
String action() default "";
//如果为true,方法将不会被发布
boolean exclude() default false;
}
@WebParam
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface WebParam {
//请求参数名,修改<s:sequence>下<xs:element>的name属性
String name() default "";
//修改<wsdl:part>的name属性
String partName() default "";
//指定返回值的 XML 名称空间
String targetNamespace() default "";
//此值表示此方法的参数流的方向
WebParam.Mode mode() default WebParam.Mode.IN;
//指定参数是在Http请求头还是请求体中
boolean header() default false;
public static enum Mode {
IN,
OUT,
INOUT;
private Mode() {
}
}
}
@WebResult
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface WebResult {
//返回参数名,修改<s:sequence>下<xs:element>的name属性
String name() default "";
//指定 RPC 或 DOCUMENT/BARE 操作的结果的部件名称。缺省值为@WebResult.name。(字符串)
String partName() default "";
//指定返回值的 XML 名称空间
String targetNamespace() default "";
//指定响应头中是否附带结果
boolean header() default false;
}
2.2.3 发布示例
@WebService
public interface JobService {
public String getJob(String username);
}
@WebService(
serviceName = "jobServiceWS", //服务名
portName = "jobServiceWsSoap", //服务端口名
name = "jobServiceWSSoapService", //portType名
targetNamespace = "http://job.ws.com" //命名空间 ,默认包名com.ws.job
// endpointInterface = "com.ws.server.service.JobService" //服务端点接口(Service EndPoint Interface),只发布该接口的方法
)
public class JobServiceImpl implements JobService {
@Override
@WebMethod(exclude = false,operationName = "getUserJob")
public @WebResult(name = "job") String getJob(@WebParam(name = "user") String username) {
return "Java工程师";
}
@WebMethod(exclude = true)
public String getAddress() {
return "上海";
}
public static void main(String[] args) {
Endpoint.publish("http://localhost:9090/jobService",new JobServiceImpl());
}
}
2.2.3 CXF框架
Apache CXF 是一个开源的 Services 框架,CXF 帮助您来构建和开发 Services ,这些 Services 可以支持多种协议,比如:SOAP、POST/HTTP、RESTful HTTP, CXF 大大简化了 Service可以天然地和 Spring 进行无缝集成。Apache CXF是 Celtrix (ESB框架)和 XFire(webserivice) 合并而成。
特点:
- 与Spring、Servlet做了无缝对接,cxf框架里面集成了Servlet容器Jetty
- 支持注解的方式来发布webservice
- 能够显示一个webservice的服务列表
- 能够添加拦截器:输入拦截器、输出拦截器 :输入日志信息拦截器、输出日志拦截器、用户权限认证的拦截器
web.xml
<!-- 添加 CXF 的Servlet ,处理 webservice的请求,类似于SpringMVC的DispatcherServlet -->
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
@WebService(serviceName="languageManager")
public interface LanguageService {
public @WebResult(name="language")String getLanguage(@WebParam(name="position")int position);
}
public class LanguageServiceImpl implements LanguageService {
/* (non-Javadoc)
* @see cn.it.ws.cxf.a.LanguageService#getLanguage(int)
*/
@Override
public String getLanguage(int position){
String language=null;
switch (position) {
case 1:
language="java";
break;
case 2:
language="C";
break;
case 3:
language="Objective-C";
break;
case 4:
language="C#";
break;
default:
break;
}
return language;
}
}
/**通过cxf框架发布webservice
* 1. ServerFactoryBean
* - 不设置注解也可以发布webservice服务, 不支持注解
* - 不支持拦截器的添加
* 2. JaxWsServerFactoryBean
* - 支持注解
* - 可以添加拦截器
* 3. webservice 访问流程:
* 1. 检测本地代理描述的wsdl是否与服务端的wsdl一致 ,俗称为握手
* 2. 通过soap协议实现通信 ,采用的是post请求 , 数据封装在满足soap规约的xml中
* 3. 返回数据 同样采用的是soap通信, 数据封装在满足soap规约的xml中
*/
public class PubsherWS {
public static void main() {
LanguageService languageService=new LanguageServiceImpl();
//ServerFactoryBean bean=new ServerFactoryBean();
JaxWsServerFactoryBean bean=new JaxWsServerFactoryBean();
//Endpoint :地址 , 实现对象
bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService");
bean.setServiceClass(LanguageService.class);//对外提供webservcie的业务类或者接口
bean.setServiceBean(languageService);//服务的实现bean
//添加输入拦截器 :输入显示日志信息的拦截器,ServerFactoryBean 不支持
bean.getInInterceptors().add(new LoggingInInterceptor());
//添加输出拦截器 :输出显示日志信息的拦截器,ServerFactoryBean 不支持
bean.getOutInterceptors().add(new LoggingOutInterceptor());
bean.create();//创建,发布webservice
}
}
实际使用中,WebService都应用于Web项目,需要在Tomcat服务器启动后发布。可以将bean注册到Spring IOC容器中:
<!-- 配置cxf
地址: http://192.168.43.185:8080/CXF_Server/ws/languageOder
组成 : http://192.168.43.185:8080 +CXF_Server( 项目名)+ws(过滤的路径)+/languageOder(自定义部分)
服务类 :
服务的实现类:
拦截器
-->
<bean id="languageService" class="com.ws.cxf.LanguageServiceImpl"></bean>
<jaxws:server serviceName="languageService" address="languageOder" serviceClass="com.ws.cxf.LanguageService">
<jaxws:serviceBean>
<ref bean="languageService"></ref>
</jaxws:serviceBean>
<!-- 配置输入显示日志信息的拦截器 -->
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
</jaxws:inInterceptors>
<!-- 配置输出显示日志信息的拦截器 -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxws:outInterceptors>
</jaxws:server>
上一篇: Docker报错Job for docker.service failed because the control process exited with error code.
下一篇: SpringBoot启动报错Cannot determine embedded database driver class for database type NONE
推荐阅读