web service
1. web service的概念
Webservice一种使用http发送SOAP协议数据的远程调用技术,
其中,远程调用技术可理解为:
一个系统远程调用另一个系统的服务,目标获取另一个系统的业务数据
2. webservice的三要素
2.1 WSDL
wsdl,全称是web server definition language,
是服务器端的定义语言,可理解为是服务器端的使用说明书
说明接口/类、方法、参数和返回值,
随服务发布成功自动生成XML格式文档
文档的结构图
<service> 服务视图,webservice的服务结点,它包括了服务端点
<binding> 为每个服务端点定义消息格式和协议细节
<portType> 服务端点,描述 web service可被执行的操作方法,以及相关的消息,
通过binding指向portType
<message> 定义一个操作(方法)的数据参数(可有多个参数)
<types> 定义 web service 使用的全部数据类型
阅读顺序: 由下向上
2.2 SOAP
1. 概述:
soap是一种在http上传输的xml格式的数据,
可以跨防火墙(http协议的端口是80,不会被拦截),
可以跨平台(由于soap是由xml传输数据,xml是跨平台,因此soap也可以跨平台),
SOAP = HTTP + XML ,并不是webservice的专有协议
2.协议结构:
必需有 Envelope 元素,将整个 XML 文档标识为一条 SOAP 消息
可选的 Header 元素,包含头部信息
必需有 Body 元素,包含所有的调用和响应信息
可选的 Fault 元素,提供有关在处理此消息所发生错误的信息
3.SOAP的版本
版本主要是1.1版本和1.2版本
共同点:
请求方式相同,都是post请求
协议的格式相同,都含有envlope和body标签
不同点:
content-type不同:
1.1版本中,Content-type: text/xml; charset=utf-8,
1.2版本中, Content-Type: application/soap+xml; charset=utf-8;
命名空间不同:
1.1版本中, <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
1.2版本中, <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
2.3 UDDI(不重要)
uddi目录服务,提供webservice服务端的注册和搜索功能
3.快速入门
3.1 服务器端开发
服务器端开发主要包括三个步骤:
步骤一: 开发接口
package cn.xiaoge.ws.server;
public interface WeatherInterface {
public String getWeather(String cityName);
}
步骤二: 开发接口的实现类(实现类上一定要添加@webService 注解)
@WebService
public class WeatherInterfaceImpl implements WeatherInterface {
@Override
public String getWeather(String cityName) {
System.out.println("服务连接中...");
String weather = cityName + ":晴...";
return weather;
}
}
步骤三: 发布服务(利用Endpoint的publish方法进行发布)
public class WeatherServer {
public static void main(String[] args) {
Endpoint.publish("http://127.0.0.1:12345/weather", new WeatherInterfaceImpl());
}
}
确认是否发布成功:
在浏览器地址栏中输入: http://127.0.0.1:12345/weather,查看是否有内容显示
文档说明在http://127.0.0.1:12345/weather?wsdl中
3.2 客户端开发
客户端开发包括四个步骤:
1.解析服务文件
在命令窗口中,定位到解析文件后要存放的位置,输入命令:
wsimport –s . http://127.0.0.1:12345/weather?wsdl
2.创建服务视图
WeatherInterfaceImplService weatherInterfaceImplService =
new WeatherInterfaceImplService();
3.创建实现类的实体
WeatherInterfaceImpl weatherInterfaceImpl =
weatherInterfaceImplService.getPort(WeatherInterfaceImpl.class);
4.调用实体类中的方法
String weather = weatherInterfaceImpl.getWeather("北京");
5.打印结果
System.out.println(weather);
注意:解析后的文件尽量不要与原始的服务端文件放到同一个包或项目
3.3 命令wsimport
命令wsimport是jdk提供的一个根据使用说明书(WSDL地址)生成客户端代码工具
命令wsimport位置:%JAVA_HOME%\bin
命令wsimport常用的参数:
-d,默认的参数,生成*.class文件
-s,生成*.java文件
-p,指定代码的包名,如果不输入该参数,默认包名是WSDL中命名空间的倒序
命令wsimport仅支持SOAP1.1客户端的生成
4. webservice的四种客户端开发方式
4.1 生成客户端调用方式(例:天气查询服务)
步骤一: 解析服务
wsimport -s . 服务的wsdl
步骤二: 创建服务视图
WeatherInterfaceImplService weatherInterfaceImplService =
new WeatherInterfaceImplService();
步骤三: 创建实现类的实体
WeatherInterfaceImpl weatherInterfaceImpl =
weatherInterfaceImplService.getPort(WeatherInterfaceImpl.class);
步骤四: 调用实现类的方法
String weather = weatherInterfaceImpl.getWeather("北京");
步骤五: 打印结果
System.out.println(weather);
4.2 客户端编码调用方式
步骤一:解析服务 生成客户端代码
命令: wsimport -s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
步骤二:创建服务视图
//1 创建url
URL url =
new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");
//2 创建QName(NameSpace的最后一定要加”/”)
QName serviceName =new QName("http://WebXml.com.cn/", "MobileCodeWS");
//3 创建service
Service service = Service.create(url, serviceName);
步骤三:创建实现类的实体
MobileCodeWSSoap mobileCodeWSSoap = service.getPort(MobileCodeWSSoap.class);
步骤四:调用实体类中的方法
String mobileCodeInfo = mobileCodeWSSoap.getMobileCodeInfo("13666666666", "");
步骤五:打印结果
System.out.println("13666666666的详细信息:"+mobileCodeInfo);
4.3 HttpUrlConnection调用方式
步骤一:创建服务地址
//1.创建服务地址(是服务的地址,不是服务的视图)
URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx");
步骤二:打开一个通向服务的连接
//2.打开一个连接
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
步骤三:设置连接的参数
//1.设置请求方式
urlConnection.setRequestMethod("POST");
//2.设置请求的格式
urlConnection.setRequestProperty("content-type", "text/xml;charset=utf-8");
//3.设置输入输出权限
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
步骤四:组织soap协议,准备发送给服务器端
String soapxml = getXml("15512345678");
OutputStream os = urlConnection.getOutputStream();
os.write(soapxml.getBytes());
步骤五:接收服务器端的响应,并打印
//判断响应码是否是200
if(200 == urlConnection.getResponseCode()){
//准备输入流
InputStream is = urlConnection.getInputStream();
//将inputStream封装成字符流
InputStreamReader isr = new InputStreamReader(is);
//将字符流成bufferedInputStream
BufferedReader br = new BufferedReader(isr);
//接收拼接数据
StringBuffer sb = new StringBuffer();
//临时数据接收
String temp = null;
if((temp = br.readLine()) != null){
sb.append(temp);
}
System.out.println(sb.toString());
//关闭资源流
br.close();
isr.close();
is.close();
}
os.close();
其中,在第四步中,用到了getXml(String phonenum);方法,具体代码如下:
public static String getXml(String phoneNum){
String soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<soap12:Envelope
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">"
+"<soap12:Body>"
+"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"
+"<mobileCode>"+phoneNum+"</mobileCode>"
+"<userID></userID>"
+"</getMobileCodeInfo>"
+"</soap12:Body>"
+"</soap12:Envelope>";
return soapXml;
}
4.4 Ajax的调用方式
步骤一:
准备页面
<body>
<input type="text" id="phoneNum"/>
<input type="button" value="查询" onclick="javascript:getMobileInfo();"/>
</body>
步骤二:
准备ajax
<script type="text/javascript">
function getMobileInfo(){
//1.准备xmlHttpRequest
var xhr;
if (window.XMLHttpRequest) { // 适用于所有新型浏览器
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // 适用于IE5.0 与 IE6.0
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//2.打开连接
xhr.open("post", "http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx", true);
//3.注册回调函数
xhr.onreadystatechange=function(){
//判断请求是否发送成功,且相应是否成功
if(4 == xhr.readyState && 200 == xhr.status){
//如果相应成功,就打印数据
alert(xhr.responseText);
}
}
//4.设置请求头,准备soap数据
xhr.setRequestHeader("content-type", "text/xml;charset=utf-8");
var soapxml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">"
+"<soap12:Body>"
+"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"
+"<mobileCode>"+document.getElementById("phoneNum").value+"</mobileCode>"
+"<userID></userID>"
+"</getMobileCodeInfo>"
+"</soap12:Body>"
+"</soap12:Envelope>";
//判断是否拼装成功
alert(soapxml);
//5.发送数据
xhr.send(soapxml);
}
</script>
5. 用注解修改WSDL内容
5.1 相关注解
@WebService-定义服务,在public class上边
targetNamespace:指定命名空间
name:portType的名称
portName:port的名称
serviceName:服务名称
endpointInterface:SEI接口地址,如果一个服务类实现了多个接口,只需要发布一个接口的方法, 可通过此注解指定要发布服务的接口。
@WebMethod-定义方法,在公开方法上边
operationName:方法名
exclude:设置为true表示此方法不是webservice方法,反之则表示webservice方法
@WebResult-定义返回值,在方法返回值前边
name:返回结果值的名称
@WebParam-定义参数,在方法参数前边
name:指定参数的名称
注意:注解都标注在服务的实现类中,不要标记错位置
5.2 注解开发demo
@WebService(
targetNamespace="http://weather.xiaoge.cn/",
serviceName="WeatherWS",
portName="WeatherWSSoap",
name="WeatherWSSoap"
)
public class WeatherInterfaceImpl implements WeatherInterface {
@Override
@WebMethod(operationName="getWeather")
public @WebResult(name="weather") String getWeather( @WebParam(name="cityName") String cityName) {
String weather = cityName + ":晴...";
return weather;
}
}
5.3 注解的作用
通过注解,可以更加形像的描述Web服务。对自动生成的wsdl文档进行修改,为使用者提供一个更加清晰的wsdl文档.
当修改了WebService注解之后,会影响客户端生成的代码。调用的方法名和参数名也发生了变化,此时如果调用服务端需要重新生成客户端代码.