Soap

soap是什么

SOAP 是一种网络通信协议

SOAP即Simple Object Access Protocol简易对象访问协议

SOAP 用于跨平台应用程序之间的通信

SOAP 被设计用来通过因特网(http)进行通信

SOAP = HTTP+XML,其实就是通过HTTP发xml数据

SOAP 很简单并可扩展支持面向对象

SOAP 允许您跨越防火墙

SOAP 将被作为 W3C 标准来发展

使用TCP/IP Monitor监视Soap协议

使用TCP/IP Monitor可以监视tcp/ip协议的报文内容,由于http是基于Tcp的应用协议,而webservice是基于http实现,所以通过tcp/ip monitor可以监视webservice请求及响应的内容。

Soap1.1:

客户端代码:

     //定义url,参数为wsdl地址
URL url = new URL("http://127.0.0.1:54321/weather?wsdl");
//定义qname,第一个参数是命名空间,第二个参数名称是wsdl里边的服务名
QName qName = new QName("http://server.jaxws.webservice.itcast.cn/", "WeatherInterfaceImplService");
//创建服务视图
Service service = Service.create(url, qName);
//通过服务视图得到服务端点
WeatherInterfaceImpl weatherInterfaceImpl =service.getPort(WeatherInterfaceImpl.class);
//调用webservice
System.out.println(weatherInterfaceImpl.queryWeather("郑州"));

请求:

注意蓝底标注

POST /weather HTTP/1.1
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://server.jaxws.ws.itcast.cn/WeatherServer/queryWeatherRequest"
User-Agent: JAX-WS RI 2.2.8 svn-revision#13980
Host: 127.0.0.1:4321
Connection: keep-alive
Content-Length: 232 <?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:queryWeather xmlns:ns2="http://server.jaxws.ws.itcast.cn/">
<arg0>郑州</arg0>
</ns2:queryWeather>
</S:Body>
</S:Envelope>

响应:

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8 <?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:queryWeatherResponse xmlns:ns2="http://server.jaxws.ws.itcast.cn/">
<return>天气晴朗</return>
</ns2:queryWeatherResponse>
</S:Body>
</S:Envelope>

soap协议体包含下列元素

必需有 Envelope 元素,此元素将整个 XML 文档标识为一条 SOAP 消息

可选的 Header 元素,包含头部信息

必需有Body 元素,包含所有的调用和响应信息

可选的 Fault 元素,提供有关在处理此消息所发生错误的信息

soap消息基本结构

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
... ...
</soap:Header>
<soap:Body>
... ...
<soap:Fault>
... ...
</soap:Fault>
</soap:Body>
</soap:Envelope>

http发送soap协议测试

webservice使用soap协议传输数据,soap是基于http的应用协议,可以使用http发送soap协议数据完成webservice的请求。

本例子解析响应的xml数据使用dom4j。

/**
* 通过http发送soap协议请求webservice
* @author SMN
* @version V1.0
*/
public class HttpRequestSoap { public static void main(String[] args) throws IOException {
//webservice地址
String webservice_url = "http://127.0.0.1:1234/weather";
//发送的soap协议内容
String soap_xml = soap_xml("郑州");
System.out.println(soap_xml);
//创建url
URL url = new URL(webservice_url);
//创建http链接对象
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
//设置请求方法
httpURLConnection.setRequestMethod("POST");
//设置Content-type
httpURLConnection.setRequestProperty("Content-type", "text/xml;charset=\"utf-8\"");
//使用http进行输出
httpURLConnection.setDoOutput(true);
//使用http进行输入
httpURLConnection.setDoInput(true); //通过输出流发送数据
OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(soap_xml.getBytes());
outputStream.close(); //接收服务端响应数据
InputStream inputStream = httpURLConnection.getInputStream(); //使用buffer存在读取的数据
byte[] buffer = new byte[1024]; //使用字节输出流存储读取的数据
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while(true){
int len = inputStream.read(buffer);
//如果流水读取完则退出循环
if(len == -1){
break;
}
byteArrayOutputStream.write(buffer,0,len);
} //得到响应数据
String response_string = byteArrayOutputStream.toString(); System.out.println(response_string); parseXml(response_string);
}
//soap协议内容
public static String soap_xml(String cityName){
String soap_xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<S:Body>"
+ "<ns2:queryWeather xmlns:ns2=\"http://impl.sei.jaxws.ws.itcast.cn/\">"
+ "<arg0>"+ cityName + "</arg0>"
+ "</ns2:queryWeather>"
+ "</S:Body>"
+ "</S:Envelope>"; return soap_xml;
} //解析响应的xml
public static String parseXml(String xmlString){
String result = null; try {
Document document = DocumentHelper.parseText(xmlString);
//创建xpath解析对象
DefaultXPath defaultXPath = new DefaultXPath("//ns2:queryWeatherResponse");
//指定命名空间
defaultXPath.setNamespaceURIs(Collections.singletonMap("ns2", "http:// impl.sei.jaxws.ws.itcast.cn/")); List<Element> elements= defaultXPath.selectNodes(document); Element response = elements.get(0); List<Element> results = response.selectNodes("return"); System.out.println(results.get(0).getText()); } catch (DocumentException e) {
e.printStackTrace();
} return result;
} }

Soap1.2:

下载 jaxws-ri-2.2.8

Jaxws实现soap1.2需要加入jaxws扩展包,从sun下载jaxws-ri-2.2.8,解压jaxws-ri-2.2.8并将lib下的jar包加载到java工程中。

添加BindingType

在SEI实现类上添加如下注解

@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)

请求:

POST /weather HTTP/1.1
Accept: application/soap+xml, multipart/related
Content-Type: application/soap+xml; charset=utf-8;action="http://server.jaxws.ws.itcast.cn/WeatherServer/queryWeatherRequest"
User-Agent: JAX-WS RI 2.2.8 svn-revision#13980
Host: 127.0.0.1:4321
Connection: keep-alive
Content-Length: 230 <?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Body>
<ns2:queryWeather xmlns:ns2="http://server.jaxws.ws.itcast.cn/">
<arg0>郑州</arg0>
</ns2:queryWeather>
</S:Body>
</S:Envelope>

响应:

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: application/soap+xml; charset=utf-8
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Body>
<ns2:queryWeatherResponse xmlns:ns2="http://server.jaxws.ws.itcast.cn/">
<return>天气晴朗</return>
</ns2:queryWeatherResponse>
</S:Body>
</S:Envelope>

Soap1.1与soap1.2异同

相同之处:

soap1.1和soap1.2都是使用post方法

都包括Envelope和body

内容类型context-type不同:

soap1.1使用text/xml

soap1.2使用application/soap+xml

命名空间Envelope xmlns不同:

soap1.1使用http://schemas.xmlsoap.org/soap/envelope/

soap1.2使用http://www.w3.org/2003/05/soap-envelope

webservice 发送xml数据

由于xml的跨平台特性,企业中在实际开发接口时方法只定义一个参数传递复杂的xml数据,这样做可以省去自定义复杂java数据类型的麻烦,且webservice接口简单,接口双方将xml数据格式规定好,实质上是通过webservice的soap协议传递xml数据。

功能说明:

创建区域查询webservice服务,客户端调用服务端查询区域信息,客户端向服务端传递xml格式数据,服务端向客户端响应xml格式数据。

接口描述:

客户端发送数据格式:

<?xml version="1.1"  encoding="utf-8"?>
<queryarea>
<parentid> </parentid>//父级区域id
<start></start>//起始记录,从1开始
<end></end>//结束记录
</queryarea>

服务端响应数据格式:

<?xml version="1.0" encoding="UTF-8"?>
<areas>
<area>
<areaid> </areaid>//区域id
<areaname></areaname>//区域名称
<arealevel></arealevel>//区域等级
<parentid></parentid>//父级区域id
</area>
//…..
</areas>

服务端:

Dao

public class Area {
private String areaid;
private String areaname;
private String parentid;
private String arealevel;
private int start;
private int end;
...
...
public interface AreaDao {
/**
* 区域查询
* @param parentid 父级区域id
* @param start 查询开始下标
* @param end 查询结束下标
* @return
* @throws Exception
*/
public List<Area> queryArea(String parentid,int start,int end) throws Exception;
}
public class AreaDaoImpl implements AreaDao {

    //区域查询sql
private static String sql = "SELECT areaid,areaname,arealevel,parentid FROM AREA where parentid = ? LIMIT ?,?"; public List<Area> queryArea(String parentid,int start,int end){ //数据库链接
Connection connection = null; //预编译statement
PreparedStatement preparedStatement = null; //结果集
ResultSet resultSet = null; //区域列表
List<Area> areaList = new ArrayList<Area>();
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//连接数据库
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/webservice", "root", "mysql");
//创建preparedStatement
preparedStatement = connection.prepareStatement(sql); //查询的记录数
int length = end - start +1;
//起始坐标
start = start -1;
//设置查询参数
preparedStatement.setString(1, parentid);
preparedStatement.setInt(2, start);
preparedStatement.setInt(3, length);
//获取结果集
resultSet = preparedStatement.executeQuery(); //结果集解析
while(resultSet.next()){
Area area = new Area();
area.setAreaid(resultSet.getString("areaid"));
area.setAreaname(resultSet.getString("areaname"));
area.setArealevel(resultSet.getString("arealevel"));
area.setParentid(resultSet.getString("arealevel"));
areaList.add(area);
} } catch (Exception e) {
e.printStackTrace();
} return areaList; }
}

service

public interface AreaService {
/**
* 区域查询
* @param queryinfo 查询信息,xml格式详见接口描述
* @return
* @throws Exception
*/
public String queryArea(String queryinfo) throws Exception;
}
@WebService
public class AreaServiceImpl implements AreaService { //区域查询dao
private AreaDao areaDao = new AreaDaoImpl(); @Override
public String queryArea(String queryinfo) throws Exception { //解析查询条件
Area area_query = parseXml(queryinfo); //调用dao查询区域
List<Area> listAreas = areaDao.queryArea(area_query.getParentid(),area_query.getStart(), area_query.getEnd()); //将list数据传为xml数据
Document document = DocumentHelper.createDocument(); Element root = DocumentHelper.createElement("areas");
document.setRootElement(root); for(Area area:listAreas){ Element element_area= root.addElement("area");
element_area.addElement("areaid").addText(area.getAreaid());
element_area.addElement("areaname").addText(area.getAreaname());
element_area.addElement("arealevel").addText(area.getArealevel());
element_area.addElement("parentid").addText(area.getParentid()); }
//转换后的xml数据
String responseString = document.asXML();
//返回给客户端
return responseString;
} //解析查询信息
private Area parseXml(String xmlString){ Area areainfo = new Area(); try {
Document document = DocumentHelper.parseText(xmlString); String start = document.selectSingleNode("/queryarea/start").getText();
String end = document.selectSingleNode("/queryarea/end").getText();
String parentid = document.selectSingleNode("/queryarea/parentid").getText(); areainfo.setStart(Integer.parseInt(start));
areainfo.setEnd(Integer.parseInt(end));
areainfo.setParentid(parentid); } catch (DocumentException e) {
e.printStackTrace();
} return areainfo; } }

发布服务

public class AreaServer {
public static void main(String[] args) {
//发布区域查询服务
Endpoint.publish("http://127.0.0.1:12345/queryarea", new AreaServiceImpl());
}
}

客户端:

public class AreaClient {
public static void main(String[] args) throws MalformedURLException, Exception_Exception {
//区域查询服务地址
URL url = new URL("http://127.0.0.1:12345/queryarea");
QName qName =new QName("http://service.area.ws.itcast.cn/", "AreaServiceImplService"); //创建service
Service service = Service.create(url, qName);
//创建porttype
AreaServiceImpl areaService = service.getPort(AreaServiceImpl.class);
//调用服务接口查询区域
String queryString = areaService.queryArea(queryXmlString("1.",1,20));
//服务端响应的xml数据
System.out.println(queryString);
//xml数据解析
parseXml(queryString);
} //查询的xml信息
public static String queryXmlString(String parentid,int start,int end){ String queryString= "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<queryarea>"
+ "<parentid>"+parentid+"</parentid>"
+ "<start>"+start+"</start>"
+ "<end>"+end+"</end>"
+ "</queryarea>"; return queryString; }
//将服务端响应的xml数据解析为list
public static List<Area> parseXml(String xmlString){
List<Area> areas = new ArrayList<Area>();
try {
Document document = DocumentHelper.parseText(xmlString); List<Node> areaList = document.selectNodes("//areas/area");
for(Node node:areaList){
Area area_i =new Area();
Element element = (Element)node;
area_i.setAreaid(element.elementText("areaid"));
area_i.setAreaname(element.elementText("areaname"));
area_i.setArealevel(element.elementText("arealevel"));
area_i.setParentid(element.elementText("parentid"));
System.out.println(area_i);
areas.add(area_i);
}
} catch (DocumentException e) {
e.printStackTrace();
}
return areas; } }

总结:

Webservice发送xml数据其实是将xml数据作为大字符串发送,工作量主要在解析xml数据上。虽然解析xml数据比较麻烦但是webservice接口简单,大家遵守xml格式开发接口,这种方式在企业中也较常用。

建议:数据量大的xml建议使用SAX解析提高解析速度。

http://www.cnblogs.com/lm970585581/p/7728280.html

WebService使用介绍(二)的更多相关文章

  1. WebService的介绍概念 收藏

    WebService学习总结(二)——WebService相关概念介绍 一.WebService是什么? 1. 基于Web的服务:服务器端整出一些资源让客户端应用访问(获取数据) 2. 一个跨语言.跨 ...

  2. Lucene.Net 2.3.1开发介绍 —— 二、分词(六)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(六) Lucene.Net的上一个版本是2.1,而在2.3.1版本中才引入了Next(Token)方法重载,而ReusableStrin ...

  3. Lucene.Net 2.3.1开发介绍 —— 二、分词(五)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(五) 2.1.3 二元分词 上一节通过变换查询表达式满足了需求,但是在实际应用中,如果那样查询,会出现另外一个问题,因为,那样搜索,是只 ...

  4. Lucene.Net 2.3.1开发介绍 —— 二、分词(三)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(三) 1.3 分词器结构 1.3.1 分词器整体结构 从1.2节的分析,终于做到了管中窥豹,现在在Lucene.Net项目中添加一个类关 ...

  5. Lucene.Net 2.3.1开发介绍 —— 二、分词(四)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(四) 2.1.2 可以使用的内置分词 简单的分词方式并不能满足需求.前文说过Lucene.Net内置分词中StandardAnalyze ...

  6. Lucene.Net 2.3.1开发介绍 —— 二、分词(二)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(二) 1.2.分词的过程 1.2.1.分词器工作的过程 内置的分词器效果都不好,那怎么办?只能自己写了!在写之前当然是要先看看内置的分词 ...

  7. Lucene.Net 2.3.1开发介绍 —— 二、分词(一)

    原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(一) Lucene.Net中,分词是核心库之一,当然,也可以将它独立出来.目前Lucene.Net的分词库很不完善,实际应用价值不高.唯 ...

  8. {Django基础十之Form和ModelForm组件}一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 ModelForm

    Django基础十之Form和ModelForm组件 本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Model ...

  9. MySQL之多表查询一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习

    MySQL之多表查询 阅读目录 一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习 一 介绍 本节主题 多表连接查询 复合条件连接查询 子查询 首先说一下,我们写项目一般都会建 ...

随机推荐

  1. 洛谷P3804 【模板】后缀自动机

    题目描述 给定一个只包含小写字母的字符串 SS , 请你求出 SS 的所有出现次数不为 11 的子串的出现次数乘上该子串长度的最大值. 输入输出格式 输入格式: 一行一个仅包含小写字母的字符串 SS ...

  2. MySQL——用户与密码

    mysql安装完成之后,在/var/log/mysqld.log文件中给root生成了一个默认密码.通过下面的方式找到root默认密码,然后登录mysql进行修改: grep 'temporary p ...

  3. Zookeeper 面试总结

    1:Zookeeper是什么? 答:ZooKeeper是一个开源的分布式协调服务,是集群的管理者,监视集群节点反馈信息进行下一步合理操作. Zookeeper提供的服务:管理用户程序提交的数据:为用户 ...

  4. 1. tty终端接收数据原理

    1. 串口接收数据原理(以“ls”命令为例) (1) 每个终端设备都有一个接收缓冲区,保存原始数据.shell程序一直在休眠,等待合适的字符: (2) 串口接收到'l'字符,把它保存下来: (3) 串 ...

  5. python字符串,数组操作

    今天倒是学到了很多知识,了解了python的基本数组,以及可变类型和不可变类型,还有元组,列表,字典等等的用法 然后作业如下 其中在做往list列表加东西时候遇到了小毛病,用户从控制台输入的是一个字符 ...

  6. pyc是个什么鬼?

    1.Python是一门解释型语音? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释型语音,我就这样一直相信下去,知道发现了*.pyc文件的存在.如果是解释型语音,那 ...

  7. 2-Linux C语言指针与内存-学习笔记

    Linux C语言指针与内存 前面我们对于: c语言的基本用法 makeFile文件的使用 main函数的详解 标准输入输出流以及错误流管道 工具与原理 指针与内存都是c语言中的要点与难点 指针 数组 ...

  8. java泛型<? extends E> 有上限通配符与<? Super E>有上限通配符

    通配符?,?表示占位,表明将来使用的时候在指明类型 <?>无限定的通配符, 是让泛型能够接受未知类型的数据 <? extends E> 有上限通配符,能够接受指定类及其子类类型 ...

  9. Ubuntu server中 samba的安装和简单配置

    samba是Linux系统上的一种文件共享协议,可以实现Windows系统访问Linux系统上的共享资源,现在介绍一下如何在Ubuntu 14.04上安装和配置samba 工具/原料   Ubuntu ...

  10. 第5模块闯关Bootstrap

    “行(row)”必须包含在 .container (固定宽度)或 .container-fluid (100% 宽度)中,以便为其赋予合适的排列(aligment)和内补(padding). 通过“行 ...