认识 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 ,现在我将我周六在家研究的结果公布出来 本次集成是基于之前已 ...
随机推荐
- QPainterPath 不规则提示框(二)
前一篇讲过不规则提示框,但是提示框的方向是固定的,不能达到随意变换方向的效果,本接讲述可以动态变换方向的提示框 先看效果图 图1 图2 图3 图4 如上图1所示,上一篇文章的代码可以达到类似效果 本 ...
- [Maven]Maven构建可执行的jar包(包含依赖jar包)
----------------------------------------------------------------- 原创博文,如需转载请注明出处! 博主:疲惫的豆豆 链接:http:/ ...
- KnockoutJS-快速入门
虽然在WPF中接触过MVVM模式,可是刚开始在Web中接触到Knockout.JS让我大吃一惊,简化了好多工作量,原来可能需要一大堆的JS脚本完成的工作量,被释放许多.接触KnockoutJS一年多了 ...
- c++智能指针和二叉树(1): 图解层序遍历和逐层打印二叉树
二叉树是极为常见的数据结构,关于如何遍历其中元素的文章更是数不胜数. 然而大多数文章都是讲解的前序/中序/后序遍历,有关逐层打印元素的文章并不多,已有文章的讲解也较为晦涩读起来不得要领.本文将用形象的 ...
- Linux framebuffer deferred io机制
一.总体框架 deferred io机制主要用于驱动没有实现自刷新同时应用层又不想调用FBIOPAN_DISPLAY的一个折中方案, 使用ioctrl FBIOPAN_DISPLAY好处是节能, 驱 ...
- SmartSql 快速使用指南
SmartSql 快速使用指南(https://github.com/Ahoo-Wang/SmartSql) ISmartSqlMapper 常用(部分)接口概述 函数 说明 Execute IDbC ...
- 开箱即用(out-of-box)的Redis序列号生成器,不用再写任何代码,你值得拥有
先看整体效果 把简单的东西“傻瓜化”是软件开发追求的目标之一.请看下图: 左边是在 application.yml 里配置了3个生成器,右边可以直接注入到代码中使用,注意,不用写任何代码.这酸爽. ...
- 4.5管道实现机制和模拟构建管道「深入浅出ASP.NET Core系列」
希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. 管道实现机制 要了解管道的实现机制,我们必须要深入框架的源码,幸亏微软开源了,我们可以访问GitHub的地址来下载 ...
- 【带着canvas去流浪(5)】绘制K线图
目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...
- 数据库学习(MySQL):JDBC的简单增删改查实现
本文为原创,转载请注明出处: https://www.cnblogs.com/Tom-shushu/p/9171896.html 这里我们先在数据库建立一个userinfo表: CREATE TABL ...