茫茫人海千千万万,感谢这一秒你看到这里。希望我的文章对你的有所帮助!
愿你在未来的日子,保持热爱,奔赴山海!
因为前段时间,需要使用到webService来调用公司的其他系统api接口,但是请求方式和我熟知的http请求不一样,是基于soap协议来传输xml数据格式,请求的参数极其复杂,需要封装多层xml数据格式,并且我不知道对方的api接口是什么语言,甚至不知道他们存在于什么平台。
那这与我们常见的httpapi接口有什么区别呢?
WebService主要是通过SOAP协议在Web上提供的软件服务,使用WSDL文档进行说明,并通过UDDI进行注册。WebService是一种跨编程语言和跨操作系统平台的远程调用技术,能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据WebService规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。
所以呢,如果你想是使用不同语言,不同平台,不同地方,想进行数据传输,自我推荐下,选择WebService就没错的!
常伴于三个元素兄弟:UDDI,WSDL,SOAP
UDDI:UDDI 是一种用于描述、发现、集成Web Service的技术,它是Web Service协议栈的一个重要部分。通过UDDI,企业可以根据自己的需要动态查找并使用Web服务,也可以将自己的Web服务动态地发布到UDDI注册中心,供其他用户使用。UDDI利用SOAP消息机制(标准的XML/HTTP)来发布,编辑,浏览以及查找注册信息。它采用XML格式来封装各种不同类型的数据,并且发送到注册中心或者由注册中心来返回需要的数据。
WSDL:是为了描述Web服务发布的XML格式。就是用机器能阅读的方式提供的一个正式描述文档而基于XML(标准通用标记语言下的一个子集)的语言,用于描述WebService及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的。
SOAP:简单对象访问协议,是交换数据的一种协议规范,是一种轻量的、简单的、基于XML标准通用标记语言下的一个子集)的协议。主要组成由Http协议和XML数据格式。WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC(远程调用技术)方法来调用WebService。

话不多说,看太多理论不如自己做个小demo测下来得爽快。所以Let’s GO!
做一个天气系统的demo,客户端发送城市名称,服务器端回应相应的天气。
创建一个空项目weatherServer出来,我使用的IDEA版本为2020.3版本。当然一开始我比较详细介绍啦



创建过程基本类似的。如果你想选择使用我,那么我会提议你先创建一个服务端,这样别人可以进行访问,或者使用他人的服务端都OK的啦。这里先会完成创建出一个服务端模块出来,后续的创建客户端模块基本类似。这里我们直接选择一个Maven项目即可,也可以自行选择一个普通Java项目都行。JDK为流行的JDK8即可。



最终得到的空模块服务端如下:

接下来就是开发服务端代码。提供简单的城市天气服务。
定义一个天气业务接口IWeatherService



代码如下:
package com.ws.service;
public interface IWeatherSerice {
/**
* 通过城市名得到对应的天气
* @param city 城市
* @return 天气
*/
public String queryWeather(String city);
}
编写对应的接口实现类WeatherServiceImpl

对应的代码如下:
package com.ws.service.impl;
import com.ws.service.IWeatherSerice;
import javax.jws.WebService;
@WebService // 用该注解修改表示当前类是一个服务类 必须加上的,不然启动服务的时候会报错。
public class WeatherServiceImpl implements IWeatherSerice {
@Override
public String queryWeather(String city) {
// 这里直接返回对应的城市和晴天!!!
return city + "的天气为:晴天!";
}
}
创建一个用于发布服务的类WeatherServerDemo。

对应的代码如下:
package com.ws.server;
import com.ws.service.impl.WeatherServiceImpl;
import javax.xml.ws.Endpoint;
public class WeatherServerDemo {
public static void main(String[] args) {
/**
* address: 服务地址 --> 提供访问的地址
* implementor: 服务类 --> 提供访问的接口的实现类
*/
Endpoint.publish("http://localhost:8086/weatherServer", new WeatherServiceImpl());
System.out.println("服务发布成功");
}
}
运行main方法,开启服务:

可以看到控制台,他没有运行完成后关闭,并且显示服务发布成功了。接下来就在线看看我们发布的服务。
访问刚才提供的访问的地址加上?wsdl,如:http://localhost:8086/weatherServer?wsdl

那如何看这个wsdl文档呢?不怕,让我来教你看几个重要的部分就一目了然啦!注意:wsdl文档需要从下往上看
- :服务视图名称,WebService的服务端点
- :Web Services的通信协议,还描述Web Services的方法、输入、输出。
- :描述了WebService可执行的操作,通过binding指向portType
- :描述了服务中发布的方法,包括参数,返回值等。
- :定义了WebService中使用的数据类型

访问一个详细的参数页面:http://localhost:8086/weatherServer?xsd=1

结构:

为什么需要下载客户端代码,首先前面两个方式需要用到服务端代码的接口,然后如果你是访问远程的服务端,那你也就访问不了。
这里会介绍jdk自带的命令:wsimport
wsimport是jdk自带的webservice客户端工具,可以根据wsdl文档生成客户端调用代码(java代码).
wsimport.exe位于JAVA_HOME\bin目录下
常用参数为:
-d<目录> - 将生成.class文件。默认参数。
-s<目录> - 将生成.java文件。
-p<生成的新包名> -将生成的类,放于指定的包下
wsimport -s ./ http://localhost:8086/weatherServer?wsdl
生成步骤:
进入到客户端模块的src的java目录下


在该目录中,进入命令行模式,然后输入wsimport -s ./ http://localhost:8086/weatherServer?wsdl,下载刚才启动的服务端代码。注意:这一步得保证服务端是启动可访问状态。



这里得到的代码跟wsdl文档对应的名称可以一一对应。当然如果你想改包名的话,可以使用-p参数。
第一种方式:通过得到的代码,service方式调用。
结构如下:

代码如下:
package com.ws.client;
import com.ws.service.impl.WeatherServiceImpl;
import com.ws.service.impl.WeatherServiceImplService;
public class WeatherClientDemo1 {
public static void main(String[] args) {
// 1. 创建服务视图
WeatherServiceImplService weatherServiceImplService = new WeatherServiceImplService();
// 2. 得到服务实现类
WeatherServiceImpl weatherService = weatherServiceImplService.getPort(WeatherServiceImpl.class);
// 3. 调用接口的方法
String result = weatherService.queryWeather("广州");
// 4. 返回远程访问得到的结果 --> result = 广州的天气为:晴天!
System.out.println("result = " + result);
}
}
最终我们运行后得到的结果也正如所预料的一般:

之前这一步有什么缺陷呢,应该很清楚吧:我们固定了一个服务地址了,而且如果要改服务地址的话,可能还需要再生成一遍代码。
所以我们把服务地址写出来,结构如下:

代码如下:
package com.ws.client;
import com.ws.service.impl.WeatherServiceImpl;
import com.ws.service.impl.WeatherServiceImplService;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
public class WeatherClientDemo2 {
public static void main(String[] args) throws Exception {
// 1. 设置访问的服务端地址
URL url = new URL("http://localhost:8086/weatherServer?wsdl");
/*
2.设置服务名称和命名空间
namespaceURI: wsdl的命名空间(targetNamespace)
localPart: 是服务视图的名称(service的name值)
*/
QName qName = new QName("http://impl.service.ws.com/", "WeatherServiceImplService");
// 3. 生成服务视图
Service service = Service.create(url, qName);
// 4. 得到服务视图的实现类 --> WeatherServiceImpl
WeatherServiceImpl weatherServiceImpl = service.getPort(WeatherServiceImpl.class);
// 5. 调用接口方法得到结果! --> result = 深圳的天气为:晴天!
String result = weatherServiceImpl.queryWeather("深圳");
System.out.println("result = " + result);
}
}
这些对应的参数在wsdl的那个位置呢? 看我指给你:

这第二种方式是比较常用的方式,首先推荐!
在不需要下载服务端代码的,通过HTTPURLConnection的方式进行访问服务端。只是这里代码就相对比较长啦,而且需要自行定义XML字符串和解析字符串。
在pom.xml文件中加入一个dom4j的依赖包
<dependencies>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
结构如下:

创建对应的测试demo,大概结构如下:

代码如下:可以复制到IDEA仔细观看。
package com.ws.client;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class WeatherClientDemo3 {
public static void main(String[] args) throws Exception {
// 1. 设置访问的服务端地址
URL url = new URL("http://localhost:8086/weatherServer?wsdl");
// 2.打开一个通向服务地址的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 3.设置参数, --> POST必须大写,否则抛出异常
connection.setRequestMethod("POST");
// 这里是text/xml不是text/html
connection.setRequestProperty("content-Type", "text/xml;charset=utf-8");
// 4.设置输入输出,默认是false没有读写的权限
connection.setDoOutput(true);
connection.setDoInput(true);
// 5.组织SOAP数据,发送请求
String soapXml = getXmlString("佛山");
System.out.println("soapXml = " + soapXml);
// 6. 将数据写入到输出流中
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
dos.write(soapXml.getBytes("utf-8"));
dos.flush();
// 7. 判断远程访问是否成功,如果响应码为200即为成功
if (connection.getResponseCode() == 200) {
// 8. 获取相应的输入流,得到对应的结果
InputStream ips = connection.getInputStream();
Scanner scanner = new Scanner(ips);
StringBuffer buffer = new StringBuffer();
while (scanner.hasNextLine()) {
buffer.append(scanner.nextLine());
}
scanner.close();
// 得到为xml字符串
System.out.println("buffer = " + buffer);
// 9. 解析xml字符串获得返回的字符串
String xml = parseXmlToString(buffer);
System.out.println("xml = " + xml);
}
}
private static String parseXmlToString(StringBuffer buffer) {
try {
// 得到对应的文档对象
Document document = DocumentHelper.parseText(buffer.toString());
// "//"从任意位置的节点上选择名称为 item 的节点。
Node node = document.selectSingleNode("//return");
return node.getText();
} catch (DocumentException e) {
e.printStackTrace();
}
return null;
}
private static String getXmlString(String string) {
String xml = "<?xml version=\"1.0\" ?>"
+ "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<S:Body>" + "<ns2:queryWeather xmlns:ns2=\"http://impl.service.ws.com/\">"
+ "<arg0>" + string
+ "</arg0>" + "</ns2:queryWeather>" + "</S:Body>"
+ "</S:Envelope>\"";
return xml;
}
}
得到的结果:

可以看出,可以得到相对应的结果。
因为我是采用XML格式封装数据的嘛,所以在传输过程中,可能需要传输额外的标签,然而标签越来越大的话,导致webservice性能下降。
发布一个服务(对内/对外),不考虑客户端类型,不考虑语言,不考虑性能,建议使用WebService。
服务端已经确定使用WebService,客户端不能选择,就必须使用WebService。
在系统考虑性能情况下,不建议使用WebService。
同构程序(一个公司中系统之间的接口)下不建议使用WebService,比如java用RMI(远程方法调用),不需要翻译成XML的数据。
相信各位看官都对webService如何使用及其它的概念和一些知识点都有了稍稍的了解吧,不确定用到人的是否很多,这里只做入门练习,当然如果我们要整合到SpringBoot项目中,甚至我们可以集成相关依赖来使用webService,例如我们可以使用SpringBoot使用CXF集成WebService。那我们应不应该学习这一门技术呢?其实我觉得看需求,如果需要用到了,我们可以快速了解下,用一用小demo快速入门,接着使用集成CXF来整合到项目中,从而达到这门技术的应用到实际项目中去!
我个人其实也没有接触过,只因项目中需要来调用这样webService接口的需求,所以我也是刚入门,而且现在各网页接口基本都是基于http请求来做的,所以我们可以当了解了解咯,走过路过,瞧一瞧,保证不吃亏呀!!!

让我们也一起加油吧!本人不才,如有什么缺漏、错误的地方,也欢迎各位人才大佬评论中批评指正!当然如果这篇文章确定对你有点小小帮助的话,也请亲切可爱的人才大佬们给个点赞、收藏下吧,一键三连,非常感谢!

学到这里,今天的世界打烊了,晚安!虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!
感谢各位看到这里!愿你韶华不负,青春无悔!
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po