天天看點

WebService使用介紹(二)Soap

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