利用HttpURLConnection实现SOAP调用

我们完全可以利用J2SE中的HttpURLConnection类来实现SOAP调用,而不一定需要AXIS之类的第三方组件包。下面就来仔细讲解:
        通过HttpURLConnection来实现SOAP调用,无非就是向远端的WEB Service发出HTTP请求,请求的过程通过双方可以理解的XML格式流来传递数据信息。我以下面的SOAP请求的XML格式为基础来讲解:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SmInf="http://jx.ct10000.com/SmInf">
 <soapenv:Header />
 <soapenv:Body>
  <tns:SendInstantSms xmlns:tns="SmInf" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <sequenceId type="xsd:long">1</sequenceId>
   <accountCode type="xsd:string">user_id</accountCode>
   <accountPasswd type="xsd:string">user_password</accountPasswd>
   <sendPhoneNo type="xsd:string">1234567890</sendPhoneNo>
   <msgContent type="xsd:string">7D27 6025 901A 77E5 FF1A 7279 522B 7D27 6025 FF0C 5341 4E07 706B 6025 002E</msgContent>
   <recvPhoneNo type="xsd:string">1234567890</recvPhoneNo>
   <scheduleTime type="xsd:dateTime">2000-10-10T09:35:12.123</scheduleTime>
  </tns:SendInstantSms>
 </soapenv:Body>
</soapenv:Envelope>
        这个SOAP请求包格式并不能完全通用于任何场合,大家具体实现某个SOAP调用时,需要根据具体情况进行调整,可以通过Web Service服务提供商获取详情。
        通过HttpURLConnection实现SOAP调用的过程简要概述如下:
        1、拼接实现如上所示的SOAP请求包的XML格式的字符流;
        2、上面讲到过SOAP调用就是一个HTTP请求,因此通过HttpURLConnection类设置相应的请求属性;
        3、通过HttpURLConnection类的getOutputStream方法获得一个输出流,然后将SOAP请求包字符流写入此输出流;
        4、通过HttpURLConnection类的getResponseCode方法获得服务器响应代码,如果响应代码为200(即HttpURLConnection.HTTP_OK)则表示请求成功,否则请求失败,请求失败后,可以通过getErrorStream方法来了解具体的错误详情;
        5、通过HttpURLConnection类的getInputStream方法获得一个输入流,由此输入流获得服务器反馈结果数据;
        大体通过HttpURLConnection实现SOAP调用的过程就是这样。下面来看具体实现代码:

        编写CSOAPClient类,并定义成员变量_url和_httpConn,在构造函数中对其进行实例化。

        _url=new URL(url);          //这里url变量是SOAP服务的网址,如http://10.5.3.134/Webservices/methods1?wsdl
       _httpConn = (HttpURLConnection) _url.openConnection();   //这里就是获得一个SOAP服务的HttpURLConnection实例
       String send_soap=createSendSOAPPackage();    //createSendSOAPPackage函数就是用来构造如上所示SOAP请求的数据包的XML字符串
       _httpConn.setReadTimeout(TIME_OUT);        //为HttpURLConnection对象指定一个读超时
       _httpConn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 5.0; Windows XP; DigExt)");
       _httpConn.setRequestProperty( "Content-Length",String.valueOf( send_soap.length() ) );
       _httpConn.setRequestProperty("Content-Type","text/xml; charset=UTF-8");
       _httpConn.setRequestProperty("SOAPAction",_soap_action_str);
       //以上都是为HTTP请求设定请求属性,其中SOAPAction中用来指定SOAP Action的字符串。
       _httpConn.setRequestMethod( "POST" );   //为请求指定提交数据模式,对于调用Web Service来说请求模式要被设置成POST模式。
       _httpConn.setDoInput(true);
        _httpConn.setDoOutput(true);
        _httpConn.setUseCaches(false);
       _httpConn.connect();  //连接远程Url

       OutputStream out = _httpConn.getOutputStream();   //获取输出流对象
        out.write( send_soap.getBytes() );       //将要提交服务器的SOAP请求字符流写入输出流
        out.flush();
        out.close();

       int code=0;
        code = _httpConn.getResponseCode();    //用来获取服务器响应状态
       if (code == HttpURLConnection.HTTP_OK) {
            //服务器响应状态表示成功,这此处可以来获取服务器反馈的数据信息
            InputStream is=_httpConn.getInputStream();    //获取输入流对象,通过此对象可以获取服务器传回的数据信息
            InputStreamReader isr = new InputStreamReader(is,"utf-8");
            Document _doc=_sax.build(isr);     //此处Document是jdom中的类,因为要解析服务器传回的xml数据
            Element _root = _doc.getRootElement();  //此处Element是jdom中的类
            ......(略)
            
       }
       else{
            //如果服务器返回的HTTP状态不是HTTP_OK,则表示发生了错误,此时可以通过如下方法了解错误原因。
            InputStream is=_httpConn.getErrorStream();    //通过getErrorStream了解错误的详情,因为错误详情也以XML格式返回,因此也可以用JDOM来获取。
            InputStreamReader isr = new InputStreamReader(is,"utf-8");
            Document _doc=_sax.build(isr);     //此处Document是jdom中的类,因为要解析服务器传回的xml数据
            Element _root = _doc.getRootElement();  //此处Element是jdom中的类
            ......(略)
       }
       以上就是通过HttpURLConnection调用SOAP的简介。
      下面附上实现类的代码,供参考(未优化,大家使用时要优化一下)

CSOAPClient.java

package util;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Set;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 *
 * @author zhaob
 */
public class CSOAPClient {
    private static int TIME_OUT=15000;
    
    private URL _url = null;
    private String _service_id=null;
    private String _method=null;
    private String _soap_action_str=null;
    private LinkedList<NParam> _params = new LinkedList<NParam>();
    private HttpURLConnection _httpConn=null;

    private String _root_master_namespace_name=null;
    private Hashtable<String,String> _root_namespace=new Hashtable<String,String>();
    private boolean _setted_root_master_namespace_flag=false;

    private boolean _hasHead=true;
    private boolean _hasParamType=true;

    private Hashtable<String,String> _method_attrib=new Hashtable<String,String>();
    private Hashtable<String,String> _method_attrib_namespace=new Hashtable<String,String>();
    private Hashtable<String,String> _methodattrib_namespace=new Hashtable<String,String>();
    private Hashtable<String,String> _methods_namespace=new Hashtable<String,String>();

    public CSOAPClient(String url,String service_id,String method,String soap_action) throws Exception {
        _url=new URL(url);          //SOAP服务的网址
        if((service_id==null)||(service_id.trim().equals(""))){
            _service_id=null;
        }
        else{
            _service_id=service_id;
        }
        
        _method=method;
        _soap_action_str=soap_action;
        createSocket();
        
    }

    public void setHasParamType(boolean v){
        _hasParamType=v;
    }

    public void setHasHead(boolean v){
        _hasHead=v;
    }

    protected void createSocket() throws Exception {
        if(_httpConn==null){
//            Properties systemProperties = System.getProperties();
//            systemProperties.setProperty("http.proxyHost","192.168.1.1");
//            systemProperties.setProperty("http.proxyPort","8080");
            _httpConn = (HttpURLConnection) _url.openConnection();;
            
        }
    }

    public void addParams(String params_name,Object v,EParamType type){
        NParam np=new NParam(params_name,v,type);
        _params.add(np);
    }

    public void addMethodNamespace(String namespace_name,String namespace_v){
        _methods_namespace.put(namespace_name,namespace_v);
    }

    public void addMethodAttrib(String attrib_name,String v,String namespace_name,String namespace_v){
        _method_attrib.put(attrib_name, v);
        _method_attrib_namespace.put(attrib_name, namespace_name);
        _methodattrib_namespace.put(namespace_name,namespace_v);
    }

    public void addMethodAttrib(String attrib_name,String v){
        _method_attrib.put(attrib_name, v);
    }

    public void setRootMasterNamespace(){
        if(!_setted_root_master_namespace_flag){
            _root_master_namespace_name="soapenv";
            _root_namespace.put(_root_master_namespace_name, "http://schemas.xmlsoap.org/soap/envelope/");
            _setted_root_master_namespace_flag=true;
        }
    }

    public void setRootMasterNamespace(String name){
        if(!_setted_root_master_namespace_flag){
            _root_master_namespace_name=name;
            _root_namespace.put(_root_master_namespace_name, "http://schemas.xmlsoap.org/soap/envelope/");
            _setted_root_master_namespace_flag=true;
        }
    }

    public void addRootNamespace(String name,String v){
        _root_namespace.put(name, v);
    }

    public String createSendSOAPPackage(){
        Hashtable<String,Namespace> namespace_set=new Hashtable<String,Namespace>();
        // 创建根节点 root;
        Element root = new Element("Envelope");
        Set<String> sets=_root_namespace.keySet();
        Namespace master_namespace=null;
        for(String s:sets){
            String v=_root_namespace.get(s);
            Namespace sn=Namespace.getNamespace(s, v);
            namespace_set.put(s, sn);
            if(s.equals(_root_master_namespace_name)){
                root.setNamespace(sn);
                master_namespace=sn;
            }
            else{
                root.addNamespaceDeclaration(sn);
            }
            
        }
        
        // 根节点添加到文档中;
        Document doc = new Document(root);

        if(_hasHead){
            //创建Header节点
            Element head=new Element("Header");
            head.setNamespace(master_namespace);
            //加入根节点
            root.addContent(head);
        }
        
        //创建Body节点
        Element body=new Element("Body");
        body.setNamespace(master_namespace);
        //加入根节点
        root.addContent(body);

        //创建调用的方法节点
        Element method=new Element(_method);
        body.addContent(method);
        Set<String> method_attrib_set=_method_attrib.keySet();
        boolean flag=false;
        Namespace ns=null;
                
        for(String attrib_name:method_attrib_set){
            String attrib_v=_method_attrib.get(attrib_name);
            flag=_method_attrib_namespace.containsKey(attrib_name);
            if(flag){
                String namespace_name=_method_attrib_namespace.get(attrib_name);
                flag=namespace_set.containsKey(namespace_name);
                if(flag){
                    ns=namespace_set.get(namespace_name);
                    
                }
                else{
                    String namespace_v=_methodattrib_namespace.get(namespace_name);
                    ns=Namespace.getNamespace(namespace_name, namespace_v);
                    method.setNamespace(ns);
                    namespace_set.put(namespace_name, ns);
                }
                Attribute attrib=new Attribute(attrib_name, attrib_v,ns);
                method.setAttribute(attrib);
            }
            else{
                Attribute attrib=new Attribute(attrib_name, attrib_v);
                method.setAttribute(attrib);
            }
        }
        Set<String> methods_attrib=_methods_namespace.keySet();
        for(String namespace_name:methods_attrib){
            flag=namespace_set.containsKey(namespace_name);
            if(flag){
                
            }
            else{
                String namespace_v=_methods_namespace.get(namespace_name);
                ns=Namespace.getNamespace(namespace_name, namespace_v);
                method.setNamespace(ns);
                namespace_set.put(namespace_name, ns);
            }
        }
        if(_service_id!=null){
            Namespace nsl=Namespace.getNamespace("tns", _service_id);
            method.setNamespace(nsl);
        }
        
        //创建调用方法的参数节点
        int count=_params.size();
        for(int i=0;i<count;i++){
            NParam np=_params.get(i);
            String param_name=np.getName();
            String param_value=np.getValue().toString();
            String param_type=np.getType().getValue();

            Element param=new Element(param_name);
            method.addContent(param);
            param.setText(param_value);
            if(_hasParamType){
                Attribute param_attrib=new Attribute("type", param_type);
                param.setAttribute(param_attrib);
            }
            
            
        }

        //定义输出
        XMLOutputter XMLOut = new XMLOutputter();
        //设置格式
        Format format = Format.getPrettyFormat();
        format.setEncoding("UTF-8"); //设置 xml文件的字符为UTF-8
        format.setIndent(" "); //设置xml文件的缩进为4个空格
        XMLOut.setFormat(format);

        return XMLOut.outputString(doc);
    }

    public CXML call() throws Exception {
        String send_soap=createSendSOAPPackage();
        System.out.println("Request XML:");
        System.out.println(send_soap);

        _httpConn.setReadTimeout(TIME_OUT);
        _httpConn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 5.0; Windows XP; DigExt)");
        _httpConn.setRequestProperty( "Content-Length",String.valueOf( send_soap.length() ) );
        System.out.println("Content-Length:"+String.valueOf( send_soap.length() ));
        _httpConn.setRequestProperty("Content-Type","text/xml; charset=UTF-8");
        System.out.println("Content-Type:text/xml; charset=UTF-8");
//        _httpConn.setRequestProperty("soapActionString",_soap_action_str);
        _httpConn.setRequestProperty("SOAPAction",_soap_action_str);
        System.out.println("SOAPAction:"+_soap_action_str);
        _httpConn.setRequestMethod( "POST" );
        System.out.println("Request Method:POST");
        _httpConn.setDoInput(true);
        _httpConn.setDoOutput(true);
        _httpConn.setUseCaches(false);
        
        _httpConn.connect();
        
        OutputStream out = _httpConn.getOutputStream();
        out.write( send_soap.getBytes() );
        out.flush();
        out.close();

        int code=0;
        code = _httpConn.getResponseCode();
        CXML xmlobj=null;
        if (code == HttpURLConnection.HTTP_OK) {
            xmlobj=new CXML(_httpConn.getInputStream(),_root_master_namespace_name,_root_namespace.get(_root_master_namespace_name));
            
        }
        else{
            System.out.println("Response Code: "+String.valueOf(code));

            xmlobj=new CXML(_httpConn.getErrorStream(),_root_master_namespace_name,_root_namespace.get(_root_master_namespace_name));
            
            System.out.println("错误详情: ");
            String faultcode=xmlobj.getElementTextByXPath("/soapenv:Envelope/soapenv:Body/soapenv:Fault/faultcode");
            System.out.println("错误代码: "+faultcode);
            String faultstring=xmlobj.getElementTextByXPath("/soapenv:Envelope/soapenv:Body/soapenv:Fault/faultstring");
            System.out.println("错误描述: "+faultstring);
            
        }
        
        return xmlobj;
    }

    public void destroy(){
        if(_httpConn!=null){
           _httpConn=null;

        }
    }

    public String toUTF8(String str) {
         if ("".equals(str)) {
             return "";
         }

         StringBuffer strBuff = new StringBuffer("");
         try {
             byte b[] = str.getBytes("UTF-16");
             for (int n = 0; n < b.length; n++) {
                 str = (Integer.toHexString(b[n] & 0XFF));
                 if (str.length() == 1) {
                     strBuff.append("0").append(str);
                 } else {
                     strBuff.append(str);
                 }
             }

             // 去除第一个标记字符
             str = strBuff.toString().toUpperCase().substring(4);
             // System.out.println(str);
             char[] chs = str.toCharArray();
             strBuff.delete(0, strBuff.length());
             for (int i = 0; i < chs.length; i = i + 4) {
                 strBuff.append(chs[i])
                        .append(chs[i + 1])
                        .append(chs[i + 2])
                        .append(chs[i + 3])
                        .append(" ");
             }
         } catch (Exception e) {
             System.out.print(e.getStackTrace());
             e.getStackTrace();
         }

         return strBuff.toString();
     }

    public final class NParam {
        private String _name=null;
        private Object _value=null;
        private EParamType _type=null;

        public NParam(String name,Object value,EParamType type){
            _name=name;
            _value=value;
            _type=type;
        }

        public String getName() {
            return _name;
        }

        public EParamType getType() {
            return _type;
        }

        public Object getValue() {
            return _value;
        }
        
    }

    public enum EParamType{
        String("xsd:string"),Integer("xsd:integer"),Long("xsd:long"),Datetime("xsd:dateTime");
        private final String _v;
        private EParamType(String v) {
            this._v = v;
        }
        public String getValue() {
            return _v;
        }
    }
}



CXML.java

package util;

import java.io.InputStream;
import java.io.InputStreamReader;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

/**
 *
 * @author zhaob
 */
public class CXML {

    private SAXBuilder _sax=new SAXBuilder();
    private Document _doc=null;
    private Element _root = null;
    private Namespace _master_namespace=null;

    public CXML(InputStream is,String namespace_name,String namespace_v) throws Exception {
        InputStreamReader isr = new InputStreamReader(is,"utf-8");
        _doc=_sax.build(isr);
        _root = _doc.getRootElement();
        _master_namespace=Namespace.getNamespace(namespace_name, namespace_v);

    }

    public String getElementTextByXPath(String xpath) throws Exception {
        String rtn=null;

        XPath xpathobj=XPath.newInstance(xpath);
        xpathobj.addNamespace(_master_namespace);
        Element obj=(Element)xpathobj.selectSingleNode(_doc);
        rtn=obj.getTextTrim();

        return rtn;
    }

    public String toString(){
        XMLOutputter o=new XMLOutputter();
        //设置格式
        Format format = Format.getPrettyFormat();
        format.setEncoding("UTF-8"); //设置 xml文件的字符为UTF-8
        format.setIndent(" "); //设置xml文件的缩进为4个空格
        o.setFormat(format);
        String xmlstr=o.outputString(_doc);
        
        return xmlstr;
    }
}



3、CSOAPClinetTest   这是一个JUNIT的测试类,看其中RUN方法即可。

package util;

import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import util.CSOAPClient.EParamType;

/**
 *
 * @author zhaob
 */
public class CSOAPClinetTest {

    public CSOAPClinetTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    // TODO add test methods here.
    // The methods must be annotated with annotation @Test. For example:
    //
    // @Test
    // public void hello() {}

    @Test
    public void run(){
        CSOAPClient soap_client=null;

        try{
            soap_client=new CSOAPClient("http://10.20.4.21:8080/Webservices/SmsInf","SmInf","SendInstantSms","http://w.rr.com/SmsInf/SendInstantSms");
        }
        catch(Exception e){
            System.out.println("Error:"+e.getMessage());
        }
        if(soap_client!=null){
            soap_client.setHasHead(true);
            soap_client.setRootMasterNamespace("soapenv");
            soap_client.addRootNamespace("SmInf", "http://x.rr.com/SmInf");
            soap_client.addMethodAttrib("encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/","soapenv","");
            soap_client.setHasParamType(true);

            soap_client.addParams("sequenceId", 2, EParamType.Long);
            soap_client.addParams("accountCode", "user_id", EParamType.String);
            soap_client.addParams("accountPasswd", "user_password", EParamType.String);
            soap_client.addParams("sendPhoneNo", "1234567890", EParamType.String);
            soap_client.addParams("msgContent", soap_client.toUTF8("紧急通知:特别紧急,十万火急."), EParamType.String);
            soap_client.addParams("recvPhoneNo", "07919999999", EParamType.String);
            soap_client.addParams("scheduleTime", "2000-10-10T09:35:12.123", EParamType.Datetime);

            try{
                CXML xmlobj=soap_client.call();
                System.out.println("返回的XML:");
                System.out.println(xmlobj.toString());
            }
            catch(Exception e){
                System.out.println("Error:"+e.getMessage());
            }

        }
    }
}



4、注意:运行此代码需要加入JDOM的全部lib目录下的包,否则使用XPATH时将报告错误。
如果还有什么疑问,可直接联系我。

你可能感兴趣的:(利用HttpURLConnection实现SOAP调用)