认识 WebService
什么是服务?
1)现在的应用程序变得越来越复杂,甚至只靠单一的应用程序无法完成全部的工作。更别说只使用一种语言了。
2)大家在写应用程序查询数据库时,并没有考虑过为什么可以将查询结果返回给上层的应用程序,甚至认为,这就是数据库应该做的,其实不然,这是数据库通过 TCP/IP 协议与另一个应用程序进行交流的结果,而上层是什么样的应用程序,是用什么语言,数据库本身并不知道,它只知道接收到了一份协议,这就是SQL92查询标准协议。
3)既然数据库可以依据某些标准对外部其他应用程序提供服务、而且不关心对方使用什么语言,那我们为什么就不能实现跨平台、跨语言的服务呢?只要我们用Java写的代码,可以被任意的语言所调用,我们就实现了跨平台,跨语言的服务!
复杂的网络应用:
WebService 定义:顾名思义就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求,从而实现远程调用。
Webservice 理解:我们可以调用互联网上查询天气信息Web服务,然后将它嵌入到我们的程序(C/S或B/S程序)当中来,当用户从我们的网点看到天气信息时,他会认为我们为他提供了很多的信息服务,但其实我们什么也没有做,只是简单了调用了一下服务器上的一段代码而已。WebService 可以将你的服务(一段代码)发布到互联网上让别人去调用,也可以调用别人机器上发布的 WebService,就像使用自己的代码一样。
既然 WebService 是一种远程调用技术,那么最直接的问题就是:1、我怎么去调用别人的程序。2、我的程序怎么才能被别人调用
作为一种通用技术,那么是否有通用的使用说明书呢?答案是肯定的:WSDL 就是 WebService 的说明书(网上有更详细的教程,这里不特别介绍)
WSDL:WebService Description Language——Web服务描述语言。 通过XML形式说明服务在什么地方——地址。通过XML形式说明服务提供什么样的方法——如何调用。
分享一个 Webservice 服务网站:http://www.webxml.com.cn
WSDL文档从下往上读,它包含几个值得注意的关键节点
Types:数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。(入参和出参的数据类型)
Message:通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构(入参和出参)。
Operation:对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对(方法)。
PortType:对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持(服务类)。
Binding:特定服务访问点与具体服务类的绑定(不看内容,看关系)。
Port:定义为webservice单个服务访问点。
Service:相关服务访问点的集合。
下面演示 jdk 怎样通过 WSDL 生成客户端代码,通过客户端代码完成调用。
1. wsimport 是 jdk 自带的,可以根据 wsdl 文档生成客户端调用代码的工具。
2. 无论服务器端的 WebService 是用什么语言写的,都将在客户端生成Java代码。服务器端用什么写的并不重要。
3. wsimport.exe位于 JAVA_HOME\bin 目录下。
常用参数为:
1)-d<目录> - 将生成.class文件。默认参数。
2)-s<目录> - 将生成.java文件和class文件。
3)-p<生成的新包名> -将生成的类,放于指定的包下。
(wsdlurl) - http://server:port/service?wsdl,必须的参数。
注意:-s不能分开,-s后面有个小点,用于指定源代码生成的目录。点即当前目录。如果使用了-s参数则会在目录下生成两份代码,一份为.class代码。一份为.java代码。.class代码,可以经过打包以后使用。.java代码可以直接Copy到我们的项目中运行。
我们在F盘下新建一个文件夹,将生成的代码保存在此文件夹中。现在文件夹里是空的
打开命令行,输入java命令。参照上面的命令解释,下面命令的意思是:生成 java 文件和 class 文件,创建子文件夹来放这些文件
最后生成的结果如下
上面是通过直接访问WSDL的URL这种方式来生成的,我们也可以把 WSDL下载下来,比如,放在f:/wsCode/EnglishChinese.wsdl
用下面的命令
生成效果是一样的
注意:如果用第一种方式生成报错,那么就把WSDL下载下来,删除报错提示的那几行,然后用第二种方式重新生成。
原因:wsimport 只适用于 SOAP1.1 协议,如果 WebService 是用 SOAP1.2 协议发布的,则使用 wsimport 导出代码会报错,生成的文件也不全。
生成的class文件是不需要的,只需要 java 文件,接下来就是使用这些java文件。
第一步:将jdk生成的java文件复制到项目中
写测试方法进行调用测试。这其实就是调用普通的Java方法,但是需要读懂 WSDL 明白创建哪些对象,调用哪些方法,这是关键!
调用WebService步骤
1)打开WSDL文档
2)从下往上读WSDL文档,先找到Services(服务访问点集合),根据Services里面binding属性找到binding元素,再根据binding元素的type属性找到绑定的portType(服务类)
3)根据WSDL的地址生成客户端代码 wsimport -s . -p com.jwen.trans d:/wsCode/EnglishChinese.wsdl
4)把客户端代码拷贝到项目中
5)创建服务访问点集合对象
6)根据服务访问点获得服务类
7)调用服务类的方法
下面演示 jdk 发布 WebService 服务
注意:用 jdk1.6.0_21 以后的版本发布一个 WebService 服务。在JDK1.6中JAX-WS规范定义了如何发布一个WebService服务。 JAX-WS是指Java Api for XML – WebService。
与Web服务相关的类,都位于javax.xml.ws.*包中。主要类有:
a)@WebService:它是一个注解,用在类上指定将此类发布成一个webservice服务.
b)Endpoint:此类为端点服务类,它的方法publish用于将一个已经添加了@WebService 注解对象绑定到一个地址的端口上。Endpoint 是 jdk 提供的一个专门用于发布服务的类,它的publish方法接收两个参数,一个是本地的服务地址,二是提供服务的类。它位于 javax.xml.ws.* 包中。
public static Endpoint.publish(String address, Object implementor) 在给定地址处针对指定的实现者对象创建并发布端点。stop方法用于停止服务。
其他注意事项:
1)给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。不支持静态方法,final方法。
2) 如果希望某个方法(非static,非final)不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
3) 如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
4) 服务类中不能没有方法
5) @WebMethod(exclude=true)屏蔽方法
项目结构如下图所示
HelloServer.java 的代码如下:
@WebService
public class HelloServer {
/**
* 1.需要方法权限是public
* 2.不能是final类型
* 3.方法不能是静态的
* 4.服务类至少有一个方法
* @param name
* @return
*/
public String sayHello(String name){
return name + " hello!";
} @WebMethod(exclude=true)
public String sayBye(String name){
return name + " bye!";
} }
ServerPublish.java 的代码如下:
public class ServerPublish { public static void main(String[] args) {
//jdk发布webservice服务, 第一个参数服务地址,第二个参数具体服务类
Endpoint.publish("http://127.0.0.1:8080/hello", new HelloServer());
} }
运行 main 方法后,在浏览器地址栏中输入 http://127.0.0.1:8080/hello?wsdl 查看 WSDL,可见,WebService成功发布。可以用前面介绍的方式进行调用。
调用WebService的方式是不是只有调用客户端代码这一种呢?显然不是,还是有其他方式的。
下面演示 ajax 调用WebService,注意运行前设置IE可信任站点和自定义级别
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
var xhr; function invoke(){
//创建ajax对象
xhr = new ActiveXObject("Microsoft.XMLHTTP");
//指定要访问的地址,就是我们WSDL地址,说明书
var url = "http://127.0.0.1:8080/hello?wsdl";
//打开连接,参数1.请求方式, 2,url地址. 3.是否同步,true异步,false同步
xhr.open("POST", url, true);
//指定发送的数据类型
xhr.setRequestHeader("Content-Type", "text/xml;charset=UTF-8");
//设置回调函数
xhr.onreadystatechange = _back;
var mytext = document.getElementById("mytext").value;
//定义消息体
var data ='<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="hello.ren.liang" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+'<soapenv:Body>'
+'<q0:sayHello>'
+' <arg0>'+mytext+'</arg0>'
+'</q0:sayHello>'
+'</soapenv:Body>'
+'</soapenv:Envelope>'; //发送消息体
xhr.send(data);
}
//回调函数
function _back(){
//判断成功状态
if(xhr.readyState == 4 && xhr.status == 200){
//以文本形式
var result = xhr.responseText;
//以xml文档对象
var obj = xhr.responseXML;
//解析文档
var returns = obj.getElementsByTagName("return");
alert(returns[0].text);
}
}
</script>
</head>
<body>
<input type="text" id="mytext">
<input type="button" value="click" onclick="invoke();">
</body>
</html>
Java 也可以通过 WSDL 直接调用 WebService
package com.rl.client; import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.List; import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; public class TestHttpURLConnClient { public static void main(String[] args) throws Exception {
//定义webservice的URL
URL url = new URL("http://127.0.0.1:8080/hello?wsdl");
//打开连接获得URLConnection
URLConnection uc = url.openConnection();
//强转成HttpURLConnection
HttpURLConnection httpuc = (HttpURLConnection)uc;
//打开输入输出的开关
httpuc.setDoInput(true);
httpuc.setDoOutput(true);
//设置请求方式
httpuc.setRequestMethod("POST");
//设置content-type text/xml;charset=UTF-8
httpuc.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
//组装消息体
String data = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://server.rl.com/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+"<soapenv:Body>"
+" <q0:sayBye>"
+" <arg0>wangwu</arg0>"
+" </q0:sayBye>"
+" </soapenv:Body>"
+"</soapenv:Envelope>";
//根据HttpURLConnection获得输出流
OutputStream out = httpuc.getOutputStream();
//用输出流把消息发送到服务端
out.write(data.getBytes());
//如果请求成功
if(httpuc.getResponseCode() == 200){
//获得输入流
InputStream in = httpuc.getInputStream();
//使用输入缓冲区
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//读取响应的消息
StringBuffer sb = new StringBuffer();
String line = null;
while((line = br.readLine()) != null){
sb.append(line);
}
//解析消息,定义SAXReader对象
SAXReader reader = new SAXReader();
//获得文档对象
Document doc = reader.read(new StringReader(sb.toString()));
//使用XPath的方式获得到return这个元素的集合
List<Element> eList = doc.selectNodes("//return");
//遍历元素集合
for(Element ele : eList){
System.out.println(ele.getText());
}
} } }
上面的两种方式共同点都是需要知道消息体的组织方式,与客户端调用相比较,上面的两种方式不需要导出代码,但需要组织消息体,而客户端调用对参数的处理则方便的多,因为对象都是现成的。
关于怎样查看消息体,参考https://www.cnblogs.com/jwen1994/p/10589150.html
自动生成的 WSDL 文档的名字有时不规范,可以手动进行修改。
修改前的普通代码
@WebService
public class HelloServer { @WebMethod(exclude=false)
public String sayHello(String name){
return name + " hello!";
} @WebMethod(exclude=false)
public String sayBye(String name){
return name + " bye!";
}
}
修改后的代码
@WebService(
serviceName="MyHelloServerService",
portName="MyHelloServer",
name="MyHelloServer",
targetNamespace="hello.jwen.com"
)
public class HelloServer {
/**
* 1.需要方法权限是public
* 2.不能是final类型
* 3.方法不能是静态的
* 4.服务类至少有一个方法
* @param name
* @return
*/
@WebMethod(exclude=false)
public String sayHello(String name){
return name + " hello!";
} @WebMethod(exclude=false)
public @WebResult(name="byeResult") String sayBye(@WebParam(name="personName") String name){
return name + " bye!";
}
}
参数说明:
@WebService(
portName="myHelloService",修改端口名字
serviceName="HelloServices",修改服务访问点集合名字
name="HelloService",修改服务类的名字
targetNamespace="hello.rl.com" 修改命名空间名字
)
@WebResult(name="sirHello")修改返回值的元素的父标签名字
@WebParam(name="sir")修改传入参数的元素的父标签名字
本文还没有解决的两个问题:
1、难道只能用 jdk 自带方法 EndPoint.publish 这种方式发布 WebService 吗?
2、使用 SOAP1.2 协议发布的 WebService 该用什么方式导出客户端代码呢?
请看这篇文章:https://www.cnblogs.com/jwen1994/p/10630417.html
认识 WebService的更多相关文章
- webService
什么是webService WebService,顾名思义就是基于Web的服务.它使用Web(HTTP)方式,接收和响应外部系统的某种请求.从而实现远程调用. 1:从WebService的工作模式上 ...
- 开始webservice了
一.WebService到底是什么 一言以蔽之:WebService是一种跨编程语言和跨操作系统平台的远程调用技术. 所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用 ...
- Spring WebService入门
Web service是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布 ...
- 浅谈跨域以及WebService对跨域的支持
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...
- 浅谈WebService的版本兼容性设计
在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...
- Atitit webservice发现机制 WS-Discovery标准的规范attilax总结
Atitit webservice发现机制 WS-Discovery标准的规范attilax总结 1.1. WS-Discovery标准1 1.2. 一.WS-Discovery1 1.2.1. ...
- java调用CXF WebService接口的两种方式
通过http://localhost:7002/card/services/HelloWorld?wsdl访问到xml如下,说明接口写对了. 2.静态调用 // 创建WebService客户端代理工厂 ...
- VS2010编写WebService与在IIS的发布<之简单讲解>
工具VS2010,window环境win7 一:Webservice的创建与方法查看调用 1.新建空web应用程序项目 2.新建web服务 3.自动生成 4.直接跑起来,可以看到有2个方法 5.点击H ...
- webService学习之路(三):springMVC集成CXF后调用已知的wsdl接口
webService学习之路一:讲解了通过传统方式怎么发布及调用webservice webService学习之路二:讲解了SpringMVC和CXF的集成及快速发布webservice 本篇文章将讲 ...
- webService学习之路(二):springMVC集成CXF快速发布webService
继上一篇webService入门之后,http://www.cnblogs.com/xiaochangwei/p/4969448.html ,现在我将我周六在家研究的结果公布出来 本次集成是基于之前已 ...
随机推荐
- 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,GC),大部分人都把这 ...
- Jenkins高级用法 - Jenkinsfile 介绍及实战经验
系列目录 1.Jenkins 安装 2.Jenkins 集群 3.Jenkins 持续集成 - ASP.NET Core 持续集成(Docker&自由风格&Jenkinsfile) 4 ...
- es6学习笔记-class之一概念
前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...
- MySQL系列--3.数据类型和连接查询
1.存储引擎 数据创建,查询,更新和删除操作都是通过数据引擎来进行的.不同的存储引擎存储限制不同,支持不同的索引机制等. 查询数据库支持的存储引擎 MySQL 5.7.2支持的存储引擎有:InnoDB ...
- SmartSql Map
SmartSqlMap 属性 说明 Scope 域,用于SqlMap定义Sql声明范围 Statement标签 属性 说明 Id 唯一性编号 Cache 缓存策略编号,引用自Cache标签 State ...
- Synchronized锁性能优化偏向锁轻量级锁升级 多线程中篇(五)
不止一次的提到过,synchronized是Java内置的机制,是JVM层面的,而Lock则是接口,是JDK层面的 尽管最初synchronized的性能效率比较差,但是随着版本的升级,synchro ...
- C++系列总结——多态
前言 封装隐藏了类内部细节,通过继承加虚函数的方式,我们还可以做到隐藏类之间的差异,这就是多态(运行时多态).多态意味一个接口有多种行为,今天就来说说C++的多态是怎么实现的. 编译时多态感觉没什么好 ...
- ssh远程连接vm 安装的ubuntu
准备工作 安装包 vmware 虚拟机.xshell.ubuntu 1.软件安装比较简单,这里不做介绍 2.选择虚拟机连接方式 3.添加虚拟IP 配置 编辑->虚拟网络编辑器->选择vm ...
- 自己实现的typeOf函数1
自己实现的typeOf函数:返回传入参数的类型 主要用于解决,js自带的typeof返回结果不精确:Ext JS中typeOf对字符串对象.元素节点.文本节点.空白文本节点判断并不准确的问题 js代码 ...
- 【设计模式】桥接模式 Bridge Pattern
开篇还是引用吕振宇老师的那篇经典的文章<设计模式随笔-蜡笔与毛笔的故事>.这个真是太经典了,没有比这个例子能更好的阐明桥接模式了,这里我就直接盗来用了. 现在市面上卖的蜡笔很多,各种型号, ...