问题背景:java代码调用.Net webservice服务
问题描述:
1.java部分【正常情况,无任何问题】:首先在eclipse或者MyEclipse中创建webservice client 项目【创建过程省略,基操】;然后代码调用.Net webservice,代码如下
import com.xxx.xxx.ApiService;
public class Testapi1 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApiService ase = new ApiService();
String reqmsg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<Request>"
//这里的XML文档内容省略部分,不方便显示
+ "</Request>";
String msg = ase.getApiServiceSoap().invoke(reqmsg);
System.out.print(msg);
}
}
2.java部分【
调用方式:使用axis.jar包进行调用
异常情况:
a.java代码已经请求了,然而.Net webservice服务中收不到任何数据,也没有任何接收的信号,这里表示接口还未连通;
b.java代码请求了,.Net webservice能接收到请求的信号,但是请求的 参数中为空或者空字符串】
先贴上一段原始java代码,此代码能调用,.net webservice接收到请求,却无法收到参数值:
//本段代码为问题代码,代码逻辑没有问题,但是执行后,.net webservice能收到信号,却无法收到参数值
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
public class TestClient {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String reqmsg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<Request>"
//XML具体内容不方便显示
+ "</Request>";
Test02(reqmsg);
}
private static void Test02(String reqstr) {
try {
String wsdlUrl = "http://127.0.0.1:8080/ApiService.asmx?wsdl";
String methodNamespace = "http://xxx.xxx.com";
String wsdlMethod = "invoke";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(wsdlUrl));
call.setOperationName(new QName(methodNamespace, wsdlMethod));
//这里请注意,后面会再次提到
call.addParameter("xmlData", XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setTimeout(30 * 1000);
// 设置方法中参数的值,获取接口返回结果
Object result = call.invoke(new Object[] { reqstr});
System.out.print("返回数据:" + result.toString());
} catch (ServiceException e) {
// TODO Auto-generated catch block
System.out.print("创建call异常:" + e.getMessage());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
System.out.print("Url创建异常:" + e.getMessage());
} catch (RemoteException e) {
// TODO Auto-generated catch block
System.out.print("返回数据异常:" + e.getMessage());
}
}
}
以上就是问题问题描述2,就是本文的主要内容,下面介绍我的处理过程
处理过程:
a.java代码已经请求了,然而.Net webservice服务中收不到任何数据,也没有任何接收的信号,这里表示接口还未连通;此时我在.net 代码中加了两个属性,我放两段代码,第一段为原始代码,第二段为更新后的代码
using CollectService.Modules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
namespace CollectService
{
/// <summary>
/// ApiService 的摘要说明
/// </summary>
[WebService(Namespace = "http://xxx.xxx.com")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class ApiService : System.Web.Services.WebService
{
/// <summary>
/// 获取实时数据
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
[WebMethod]
public string invoke(string xmlData)
{
CommonTool.WriteTextRecordByTime("ApiLog", "DataModel.GetResponseXmlContent|接收到数据:" + xmlData);
string res = "SUCCESS";
return res;
}
}
}
using CollectService.Modules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
namespace CollectService
{
/// <summary>
/// ApiService 的摘要说明
/// </summary>
[WebService(Namespace = "http://xxx.xxx.com")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
//本条属性就是新加的
[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement, Use = SoapBindingUse.Literal)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class ApiService : System.Web.Services.WebService
{
/// <summary>
/// 获取实时数据
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
[WebMethod]
public string invoke(string xmlData)
{
CommonTool.WriteTextRecordByTime("ApiLog", "DataModel.GetResponseXmlContent|接收到数据:" + xmlData);
string res = "SUCCESS";
return res;
}
}
}
[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement, Use = SoapBindingUse.Literal)],这一条属性就是新加的,然后用java代码调用,发现能收到请求信号,但是产生了新的问题:参数xmlData为空。
b.新的问题:.net webservice接收到请求信号,但是没有参数值。
此时需要在java中更改一段代码,即可解决问题,下面贴上最终的代码例程:
//本段代码为正常代码,最终例程版本
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
public class TestClient {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String reqmsg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<Request>"
//XML具体内容不方便显示
+ "</Request>";
Test02(reqmsg);
}
private static void Test02(String reqstr) {
try {
String wsdlUrl = "http://127.0.0.1:8080/ApiService.asmx?wsdl";
String methodNamespace = "http://xxx.xxx.com";
String wsdlMethod = "invoke";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(wsdlUrl));
call.setOperationName(new QName(methodNamespace, wsdlMethod));
//这里请注意,这里就是更新的地方
call.addParameter(new QName(methodNamespace, "xmlData"), XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setTimeout(30 * 1000);
// 设置方法中参数的值,获取接口返回结果
Object result = call.invoke(new Object[] { reqstr});
System.out.print("返回数据:" + result.toString());
} catch (ServiceException e) {
// TODO Auto-generated catch block
System.out.print("创建call异常:" + e.getMessage());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
System.out.print("Url创建异常:" + e.getMessage());
} catch (RemoteException e) {
// TODO Auto-generated catch block
System.out.print("返回数据异常:" + e.getMessage());
}
}
}
其中注意的一段代码为:call.addParameter(new QName(methodNamespace, "xmlData"), XMLType.XSD_STRING, ParameterMode.IN);
额外解释:QName全称是qualified name,表示合格且有限制 的 名称或者格式。例如:
<A xmlns:xsl="http://XXX">
<xsl:tname>
</xsl:tname>
</A>
第一行:xsl命名空间前缀与命名空间http://XXX相联系
第二行:xsl为名字空间前缀,tname为xml元素名称
可以这样说:xsl:tname就是一个Qname,即xml元素,其中的xsl结合tname产生一个特定的xml元素,起到修饰限定作用。
soap协议传输格式同样合适,数据为xml同样适合。
我的理解是:在参数中限定了xml格式,会更加规范。
以上就是本人此次处理问题的过程,完全是实践真知,一步一步填坑总结出来的。
以上是本人处理此问题的第一种方案,后面的内容为本人根据猜想,处理成功后的第二种方案。
以下是本人在上一次处理后,再次查看代码,发现的另外一种方式,当我发现这种方式后,也被自己气到了,真相原来就这一笔画。我贴上关键的代码截图
//此方法为请求失败的代码段
private static void Test02(String reqstr) {
try {
String wsdlUrl = "http://127.0.0.1:8080/ApiService.asmx?wsdl";
//这里的方法命名空间请注意 注意 注意 注意!!!
String methodNamespace = "http://xxx.xxx.com";
String wsdlMethod = "invoke";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(wsdlUrl));
call.setOperationName(new QName(methodNamespace, wsdlMethod));
//这里请注意,这里就是更新的地方
call.addParameter("xmlData", XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setTimeout(30 * 1000);
// 设置方法中参数的值,获取接口返回结果
Object result = call.invoke(new Object[] { reqstr});
System.out.print("返回数据:" + result.toString());
} catch (ServiceException e) {
// TODO Auto-generated catch block
System.out.print("创建call异常:" + e.getMessage());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
System.out.print("Url创建异常:" + e.getMessage());
} catch (RemoteException e) {
// TODO Auto-generated catch block
System.out.print("返回数据异常:" + e.getMessage());
}
}
//此方法为请求成功的代码段
private static void Test02(String reqstr) {
try {
String wsdlUrl = "http://127.0.0.1:8080/ApiService.asmx?wsdl";
//这里的方法命名空间请注意 注意 注意 注意!!!
String methodNamespace = "http://xxx.xxx.com/";
String wsdlMethod = "invoke";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(wsdlUrl));
call.setOperationName(new QName(methodNamespace, wsdlMethod));
call.addParameter("xmlData", XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(XMLType.XSD_STRING);
call.setTimeout(30 * 1000);
// 设置方法中参数的值,获取接口返回结果
Object result = call.invoke(new Object[] { reqstr});
System.out.print("返回数据:" + result.toString());
} catch (ServiceException e) {
// TODO Auto-generated catch block
System.out.print("创建call异常:" + e.getMessage());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
System.out.print("Url创建异常:" + e.getMessage());
} catch (RemoteException e) {
// TODO Auto-generated catch block
System.out.print("返回数据异常:" + e.getMessage());
}
}
可以看到,上述就一笔只差。
请求失败的方法会报错如下图
正确的方法只是将命名空间加上一笔;当然,只是这样的话,可能在.Net webservice中依然获取不到参数,这个时候只需要在.Net webservice中每个接口方法加上:[SoapRpcMethod(Use = SoapBindingUse.Literal, Action = "http://XXX.XXX.com/invoke", RequestNamespace = "http://XXX.XXX.com/", ResponseNamespace = "http://XXX.XXX.com/")]即可。
即第二种解决方案为:
1.java代码的命名空间填写完整,最后那一个字符 “/” 不能少。上面代码已经很详细了。
2..Net webservice中,接口的那个类上面添加属性如下图