什么是服务

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的更多相关文章

  1. webService

    什么是webService WebService,顾名思义就是基于Web的服务.它使用Web(HTTP)方式,接收和响应外部系统的某种请求.从而实现远程调用.  1:从WebService的工作模式上 ...

  2. 开始webservice了

    一.WebService到底是什么 一言以蔽之:WebService是一种跨编程语言和跨操作系统平台的远程调用技术. 所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用 ...

  3. Spring WebService入门

    Web service是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布 ...

  4. 浅谈跨域以及WebService对跨域的支持

    跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...

  5. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  6. Atitit webservice发现机制 WS-Discovery标准的规范attilax总结

    Atitit webservice发现机制 WS-Discovery标准的规范attilax总结 1.1. WS-Discovery标准1 1.2. 一.WS-Discovery1 1.2.1.   ...

  7. java调用CXF WebService接口的两种方式

    通过http://localhost:7002/card/services/HelloWorld?wsdl访问到xml如下,说明接口写对了. 2.静态调用 // 创建WebService客户端代理工厂 ...

  8. VS2010编写WebService与在IIS的发布<之简单讲解>

    工具VS2010,window环境win7 一:Webservice的创建与方法查看调用 1.新建空web应用程序项目 2.新建web服务 3.自动生成 4.直接跑起来,可以看到有2个方法 5.点击H ...

  9. webService学习之路(三):springMVC集成CXF后调用已知的wsdl接口

    webService学习之路一:讲解了通过传统方式怎么发布及调用webservice webService学习之路二:讲解了SpringMVC和CXF的集成及快速发布webservice 本篇文章将讲 ...

  10. webService学习之路(二):springMVC集成CXF快速发布webService

    继上一篇webService入门之后,http://www.cnblogs.com/xiaochangwei/p/4969448.html ,现在我将我周六在家研究的结果公布出来 本次集成是基于之前已 ...

随机推荐

  1. QPainterPath 不规则提示框(二)

    前一篇讲过不规则提示框,但是提示框的方向是固定的,不能达到随意变换方向的效果,本接讲述可以动态变换方向的提示框 先看效果图 图1 图2 图3 图4 如上图1所示,上一篇文章的代码可以达到类似效果 ​本 ...

  2. [Maven]Maven构建可执行的jar包(包含依赖jar包)

    ----------------------------------------------------------------- 原创博文,如需转载请注明出处! 博主:疲惫的豆豆 链接:http:/ ...

  3. KnockoutJS-快速入门

    虽然在WPF中接触过MVVM模式,可是刚开始在Web中接触到Knockout.JS让我大吃一惊,简化了好多工作量,原来可能需要一大堆的JS脚本完成的工作量,被释放许多.接触KnockoutJS一年多了 ...

  4. c++智能指针和二叉树(1): 图解层序遍历和逐层打印二叉树

    二叉树是极为常见的数据结构,关于如何遍历其中元素的文章更是数不胜数. 然而大多数文章都是讲解的前序/中序/后序遍历,有关逐层打印元素的文章并不多,已有文章的讲解也较为晦涩读起来不得要领.本文将用形象的 ...

  5. Linux framebuffer deferred io机制

    一.总体框架 deferred io机制主要用于驱动没有实现自刷新同时应用层又不想调用FBIOPAN_DISPLAY的一个折中方案,  使用ioctrl FBIOPAN_DISPLAY好处是节能, 驱 ...

  6. SmartSql 快速使用指南

    SmartSql 快速使用指南(https://github.com/Ahoo-Wang/SmartSql) ISmartSqlMapper 常用(部分)接口概述 函数 说明 Execute IDbC ...

  7. 开箱即用(out-of-box)的Redis序列号生成器,不用再写任何代码,你值得拥有

      先看整体效果 把简单的东西“傻瓜化”是软件开发追求的目标之一.请看下图: 左边是在 application.yml 里配置了3个生成器,右边可以直接注入到代码中使用,注意,不用写任何代码.这酸爽. ...

  8. 4.5管道实现机制和模拟构建管道「深入浅出ASP.NET Core系列」

    希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. 管道实现机制 要了解管道的实现机制,我们必须要深入框架的源码,幸亏微软开源了,我们可以访问GitHub的地址来下载 ...

  9. 【带着canvas去流浪(5)】绘制K线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...

  10. 数据库学习(MySQL):JDBC的简单增删改查实现

    本文为原创,转载请注明出处: https://www.cnblogs.com/Tom-shushu/p/9171896.html 这里我们先在数据库建立一个userinfo表: CREATE TABL ...