1. 程式人生 > >(六)發送、接收SOAP消息(1)

(六)發送、接收SOAP消息(1)

action nco enc local ring get 消息 元素 opera

一.為什麽要用soap

  • 原本我們使用web服務都是根據wsdl生成客戶端(生成一堆java文件)然後再調用,本章節講解如何用soap消息來替代這種方式。

二、SOAP消息格式

技術分享

  • SOAP(簡單對象訪問協議)是基於XML的消息格式。下面是一個簡單的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> ... message data ... <soap:Fault> </soap:Fault> </soap:Body> </soap:Envelope>
  • 正如你可以看到一個SOAP消息包括:

    • Envelope
    • Header
    • Body
      • Message Data
      • Fault (optional)

    相同的SOAP消息結構用於客戶端和Web Service服務器之間的請求和響應。

    Body內的Fault元素是可選的。只有Web服務中發生內部錯誤裏才返回。否則,返回正常信息數據。

    SOAP不指定一個消息從客戶端如何獲取到Web Service,但最常見的情況是通過HTTP。

三、案例

  3.1  發布服務

  • 服務接口
package service;

import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

@WebService
public interface IFirstService {

    @WebResult(name = "addResult")
    
public int add(@WebParam(name = "x") int x, @WebParam(name = "y") int y); }
  • 服務接口實現類
package service;

import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

@WebService(endpointInterface = "service.IFirstService")
public class IFirstServiceImpl implements IFirstService {

    @Override
    public int add(int x, int y) {

        return x + y;
    }

}
  • 發布服務
package publish;

import javax.xml.ws.Endpoint;

import service.IFirstServiceImpl;

public class TestPublish {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:3030/first", new IFirstServiceImpl());
        
        System.out.println("發布成功.....");
    }
}
  • 查看wsdl文件
<definitions targetNamespace="http://service/" name="IFirstServiceImplService">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://service/" schemaLocation="http://localhost:3030/first?xsd=1" />
        </xsd:schema>
    </types>
    <message name="add">
        <part name="parameters" element="tns:add" />
    </message>
    <message name="addResponse">
        <part name="parameters" element="tns:addResponse" />
    </message>
    <portType name="IFirstService">
        <operation name="add">
            <input wsam:Action="http://service/IFirstService/addRequest"
                message="tns:add" />
            <output wsam:Action="http://service/IFirstService/addResponse"
                message="tns:addResponse" />
        </operation>
    </portType>
    <binding name="IFirstServiceImplPortBinding" type="tns:IFirstService">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
            style="document" />
        <operation name="add">
            <soap:operation soapAction="" />
            <input>
                <soap:body use="literal" />
            </input>
            <output>
                <soap:body use="literal" />
            </output>
        </operation>
    </binding>
    <service name="IFirstServiceImplService">
        <port name="IFirstServiceImplPort" binding="tns:IFirstServiceImplPortBinding">
            <soap:address location="http://localhost:3030/first" />
        </port>
    </service>
</definitions>
  • http://localhost:3030/first?xsd=1文件
<xs:schema version="1.0" targetNamespace="http://service/">
    <xs:element name="add" type="tns:add" />
    <xs:element name="addResponse" type="tns:addResponse" />
    <xs:complexType name="add">
        <xs:sequence>
            <xs:element name="x" type="xs:int" />
            <xs:element name="y" type="xs:int" />
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="addResponse">
        <xs:sequence>
            <xs:element name="addResult" type="xs:int" />
        </xs:sequence>
    </xs:complexType>
</xs:schema>

二、客戶端發送soap消息、接收soap消息

  • 這裏不再用工具生成客戶端
package test;

import java.net.URL;
import java.rmi.RemoteException;

import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;

import org.w3c.dom.Node;

public class TestMain {
    public static void main(String[] args) throws RemoteException {

        /**
         * 發送soap消息
         * 
         */

        try {
            // 創建一個message工廠
            MessageFactory factory = MessageFactory.newInstance();
            //獲取soapMessage對象
            SOAPMessage send_message = factory.createMessage();
            SOAPPart soapPart=send_message.getSOAPPart();
            
            /**
             * 獲取head和body對象
             */
            SOAPEnvelope soapEnvelope=soapPart.getEnvelope();
            
            SOAPBody soapBody=soapEnvelope.getBody();
            SOAPHeader soapHeader=soapEnvelope.getHeader();
            
            /**
             * 把數據封裝到body元素裏
             */
            
            //添加add標簽
            QName addName=new QName("http://service/", "add","ns");
            SOAPBodyElement soapBodyElement=soapBody.addBodyElement(addName);
            
            //添加add標簽中的子標簽
            soapBodyElement.addChildElement(new QName("x")).setValue("1");;
            soapBodyElement.addChildElement(new QName("y")).setValue("10");;
            
            //打印發送到服務端的soap消息
            send_message.writeTo(System.out);
            
            /*
             * 將消息發送到服務端
             */
            URL wsdlDocumentLocation=new URL("http://localhost:3030/first?wsdl");
            QName serviceName=new QName("http://service/", "IFirstServiceImplService");
            Service service=Service.create(wsdlDocumentLocation, serviceName);
            
            /**
             * createDispatch方法第一個參數的Qname的構造方法的參數為port標簽的name值
             * Mode
             * Service.Mode.MESSAGE:發送是XML的Doucment對象
             * Service.Mode.PAYLOAD:發送的是XML的字符串
             */
            QName portName=new QName("http://service/","IFirstServiceImplPort");
            Dispatch<SOAPMessage> dispatch=service.createDispatch(portName,SOAPMessage.class,Service.Mode.MESSAGE);
            
            
            //發送soap消息,並接收服務端返回的soap消息
            SOAPMessage respon_message=dispatch.invoke(send_message);
            
            System.out.println("服務端返回soap消息");
            respon_message.writeTo(System.out);
            
            /**
             * 解析從服務端返回的soap消息
             */
            SOAPPart part=respon_message.getSOAPPart();
             SOAPEnvelope envelope=part.getEnvelope();
            SOAPBody body=envelope.getBody();
            Node node=body.getElementsByTagName("addResult").item(0);
            
            System.out.println();
            System.out.println("result=="+node.getTextContent());
            
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

結果:

技術分享

(六)發送、接收SOAP消息(1)