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