我们完全可以利用J2SE中的HttpURLConnection类来实现SOAP调用,而不一定需要AXIS之类的第三方组件包。下面就来仔细讲解:
通过HttpURLConnection来实现SOAP调用,无非就是向远端的WEB Service发出HTTP请求,请求的过程通过双方可以理解的XML格式流来传递数据信息。我以下面的SOAP请求的XML格式为基础来讲解:
1
user_id
user_password
1234567890
7D27 6025 901A 77E5 FF1A 7279 522B 7D27 6025 FF0C 5341 4E07 706B 6025 002E
1234567890
2000-10-10T09:35:12.123
这个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的简介。
下面附上实现类的代码,供参考(未优化,大家使用时要优化一下)
1、CSOAPClient
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
_params = new LinkedList();
private HttpURLConnection _httpConn=null;
private String _root_master_namespace_name=null;
private Hashtable _root_namespace=new Hashtable();
private boolean _setted_root_master_namespace_flag=false;
private boolean _hasHead=true;
private boolean _hasParamType=true;
private Hashtable _method_attrib=new Hashtable();
private Hashtable _method_attrib_namespace=new Hashtable();
private Hashtable _methodattrib_namespace=new Hashtable();
private Hashtable _methods_namespace=new Hashtable();
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 namespace_set=new Hashtable();
// 创建根节点 root;
Element root = new Element("Envelope");
Set 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 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 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 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;
}
}
}
2、CXML
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时将报告错误。
如果还有什么疑问,可直接联系我。