本文使用ASP.Net的客户端来访问Java写的Web Service。Web Service返回的结果是一个DTO(JavaBean)。
日前看到很多朋友说用ASP的客户端调用Java写的Web Service返回结果是Null,本文也提供了一些看法,希望对大家有点帮助。
首先说一下机制,这里只涉及最简单的。
首先,传输的协议是Soap,说白了就是使用一个规范的XML文本来进行传输。客户端和WS端都根据规范来解析XML文本,以获得需要的数据。
下面是正文。
下来建立Java的Web Service端。
首先建立一个动态网页工程。
接下来我们建立一个DTO(JavaBean)来充当传输的介质。
代码如下:
- package demo;
- public class EmployeeDTO {
- String name;
- String dept;
- String age;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getDept() {
- return dept;
- }
- public void setDept(String dept) {
- this.dept = dept;
- }
- public String getAge() {
- return age;
- }
- public void setAge(String age) {
- this.age = age;
- }
- }
好了,现在我们来建立一个Web Service程序
代码如下:
- package demo;
- /**
- * Demo Web Service
- *
- * @author redria
- *
- */
- public class EmployeeWS {
- /**
- * Get Employee DTO Info
- *
- * @return
- */
- public EmployeeDTO getInfo() {
- //New DTO
- EmployeeDTO dto = new EmployeeDTO();
- dto.setName("Sol");
- dto.setDept("GGXX");
- dto.setAge("...?");
- //Return Value
- return dto;
- }
- }
现在我们准备好了,可以发布Web Service程序了。使用插件可以很方便的发布服务。这里使用附带WTP的Eclipse附带的工具来发布。
当然,在这里点击下面的生成Client也可以自动帮你生成Client端。因为本文使用ASP来生成客户端,所以这里就不说明Java的了
好了,现在测试一下我们的结果:
可以看到,我们Web Service完全正常。(这里如果不正常,可能是你的环境有问题)
现在我们将其发布到tomcat中去。
访问我们刚才发布的Web Service的wsdl文件。你可以看到:
说明我们的服务已经发布成功了。
现在来建立一个ASP.Net的客户端。
打开Visual Studio
新建一个ASP.Net Web Site工程
首先我们添加一个 Web 参照,将我们刚才发布的地址加入,就可以看到了。
好了,现在我们来添加吧。
之后来写前台的Aspx文件和后台的cs文件
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title>無題のページ</title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <asp:Button ID="BTN_GETINFO" runat="server" OnClick="BTN_GETINFO_Click" Text="获取信息" /><br />
- <br />
- <asp:Label ID="LB_NAME" runat="server" Text="Name:"></asp:Label>
- <asp:Label ID="LB_NAMERESULT" runat="server"></asp:Label><br />
- <asp:Label ID="LB_DEPT" runat="server" Text="Dept:"></asp:Label>
- <asp:Label ID="LB_DEPTRESULT" runat="server"></asp:Label><br />
- <asp:Label ID="LB_AGE" runat="server" Text="Age:"></asp:Label>
- <asp:Label ID="LB_AGERESULT" runat="server"></asp:Label></div>
- </form>
- </body>
- </html>
- using System;
- using System.Data;
- using System.Configuration;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
- public partial class _Default : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- }
- protected void BTN_GETINFO_Click(object sender, EventArgs e)
- {
- //call Web Service
- localhost.EmployeeWSService service = new localhost.EmployeeWSService();
- localhost.EmployeeDTO dto = service.getInfo();
- this.LB_NAMERESULT.Text = dto.name;
- this.LB_DEPTRESULT.Text = dto.dept;
- this.LB_AGERESULT.Text = dto.age;
- }
- }
好了,现在来运行看看结果。
好了,看起来,我们已经完全成功了。
接下来我们把Web Service放到Axis2中间来看看。
首先,由于发布的路径不一样我们需要相应的修改Web Service的wsdl文件。
修改address地址如下
- <wsdlsoap:address location="http://localhost:8080/axis2/services/EmployeeWSService"/>
好了,现在打包发布吧。使用Axis2官方提供的插件可以很方便发布,这里就不多说了,不懂可以参照我关于ESB(ServiceMix)的那片文章中有提到,或者自己在网上搜搜,相关说明很多。
发布后我们可以在Axis2的Service列表中看到
接下来修改我们再来新建一个Asp的客户端,来看看有什么区别。
我们新建一个Aspx页面。
现在我们将Axis2的服务添加到Web 参照中去。
为了不和前一个Web Service冲突,我们将名字改掉
下面来完成页面
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head runat="server">
- <title>無題のページ</title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <h1>使用Axis2的Web Service</h1>
- <asp:Button ID="BTN_GETINFO" runat="server" OnClick="BTN_GETINFO_Click" Text="获取信息" /><br />
- <br />
- <asp:Label ID="LB_NAME" runat="server" Text="Name:"></asp:Label>
- <asp:Label ID="LB_NAMERESULT" runat="server"></asp:Label><br />
- <asp:Label ID="LB_DEPT" runat="server" Text="Dept:"></asp:Label>
- <asp:Label ID="LB_DEPTRESULT" runat="server"></asp:Label><br />
- <asp:Label ID="LB_AGE" runat="server" Text="Age:"></asp:Label>
- <asp:Label ID="LB_AGERESULT" runat="server"></asp:Label>
- </div>
- </form>
- </body>
- </html>
- using System;
- using System.Data;
- using System.Configuration;
- using System.Collections;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
- public partial class Default2 : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- }
- protected void BTN_GETINFO_Click(object sender, EventArgs e)
- {
- //call Web Service
- Axis2.EmployeeWSService service = new Axis2.EmployeeWSService();
- Axis2.EmployeeDTO dto = service.getInfo();
- this.LB_NAMERESULT.Text = dto.name;
- this.LB_DEPTRESULT.Text = dto.dept;
- this.LB_AGERESULT.Text = dto.age;
- }
- }
好了,我们可以看到和前一个没有什么区别,那我们来尝试一下。
结果是,一点访问WebService,我们的程序就出错了,因为WebService的返回结果是null。(相信很多朋友在调用Java发布在各种服务上的WS,都或多或少发生了类似返回为null的问题)
可是我们同样的代码,为什么会有不同的结果?难道问题处在了Axis2上面?
我们可以确信,我们的代码没有错误,因为放在Axis2之前,我们的程序很正常。
然而看看WebService端,好像也没有出错,如果打log,会发现我们其实是成功调用了Web Service,Web Service也正确返回值了,为什么我们在客户端收到的是一个Null值?
要解决这个问题,我们可以尝试分析一下我们到底传输了什么soap。
我们使用一些包截取工具来截取我们传输的信息。
这里本文使用的是 Microsoft SOAP Toolkit Version 3 ,当然是用其它工具也行。
现在我们来分别截取一下我们两次调用返回的结果吧,看看有什么不同。(这里也可以使用我在关于ESB(ServiceMix)的那片文章中最后测试用的html,那个html就是把发送的soap和返回的soap都显示的网页)
我们第一次成功的返回soap是
- <?xml version='1.0' encoding='UTF-8'?>
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <soapenv:Body>
- <getInfoResponse xmlns:ns="http://demo">
- <getInfoReturn>
- <age>...?</age>
- <dept>GGXX</dept>
- <name>Sol</name>
- </getInfoReturn>
- </getInfoResponse>
- </soapenv:Body>
- </soapenv:Envelope>
而我们第二次使用Axis2返回的soap是
- <?xml version='1.0' encoding='UTF-8'?>
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
- <soapenv:Body>
- <ns:getInfoResponse xmlns:ns="http://demo">
- <ns:return type="demo.EmployeeDTO">
- <ns:age>...?</ns:age>
- <ns:dept>GGXX</ns:dept>
- <ns:name>Sol</ns:name>
- </ns:return>
- </ns:getInfoResponse>
- </soapenv:Body>
- </soapenv:Envelope>
这两个的区别在哪里呢?
<ns:return type="demo.EmployeeDTO">和<getInfoReturn>是区别。
Axis2中的return值不在像以前一样直接写明,而是使用名字为return的量,使用type来定义它的类型。
所以这里我们的接口不一样,就像我们去A码头接人,人却从B码头来了,我们自然什么都没有接到。
找到问题的所在,接下来我们只要修改wsdl中的return接口定义,就可以接到值了。
修改发布到Axis2的WS的wsdl文件
- <?xml version="1.0" encoding="UTF-8"?>
- <wsdl:definitions targetNamespace="http://demo" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://demo" xmlns:intf="http://demo" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <!--WSDLはApache Axis version: 1.4
- Built on Apr 22, 2006 (06:55:48 PDT)によって生成されました / [en]-(WSDL created by Apache Axis version: 1.4
- Built on Apr 22, 2006 (06:55:48 PDT))-->
- <wsdl:types>
- <schema elementFormDefault="qualified" targetNamespace="http://demo" xmlns="http://www.w3.org/2001/XMLSchema">
- <element name="getInfo">
- <complexType/>
- </element>
- <element name="getInfoResponse">
- <complexType>
- <sequence>
- <element name="return" type="impl:EmployeeDTO"/>
- </sequence>
- </complexType>
- </element>
- <complexType name="EmployeeDTO">
- <sequence>
- <element name="age" nillable="true" type="xsd:string"/>
- <element name="dept" nillable="true" type="xsd:string"/>
- <element name="name" nillable="true" type="xsd:string"/>
- </sequence>
- </complexType>
- </schema>
- </wsdl:types>
- <wsdl:message name="getInfoRequest">
- <wsdl:part element="impl:getInfo" name="parameters"/>
- </wsdl:message>
- <wsdl:message name="getInfoResponse">
- <wsdl:part element="impl:getInfoResponse" name="parameters"/>
- </wsdl:message>
- <wsdl:portType name="EmployeeWS">
- <wsdl:operation name="getInfo">
- <wsdl:input message="impl:getInfoRequest" name="getInfoRequest"/>
- <wsdl:output message="impl:getInfoResponse" name="getInfoResponse"/>
- </wsdl:operation>
- </wsdl:portType>
- <wsdl:binding name="EmployeeWSSoapBinding" type="impl:EmployeeWS">
- <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
- <wsdl:operation name="getInfo">
- <wsdlsoap:operation soapAction=""/>
- <wsdl:input name="getInfoRequest">
- <wsdlsoap:body use="literal"/>
- </wsdl:input>
- <wsdl:output name="getInfoResponse">
- <wsdlsoap:body use="literal"/>
- </wsdl:output>
- </wsdl:operation>
- </wsdl:binding>
- <wsdl:service name="EmployeeWSService">
- <wsdl:port binding="impl:EmployeeWSSoapBinding" name="EmployeeWS">
- <wsdlsoap:address location="http://localhost:8080/axis2/services/EmployeeWSService"/>
- </wsdl:port>
- </wsdl:service>
- </wsdl:definitions>
重新发布一下,再来测试我们的第二个客户端,果然成功的取到了值,问题圆满解决了。
注:Java客户端其实和Asp一样会遇到这种问题,问题的本质是一样的。
总结:现在功能强大的工具软件是我们的工作变得非常简单,遇到了这种问题,我们可以从它到底在传输什么着手,做些分析就可以找到问题的所在。尤其像Soap这样的东西,自己动手,丰衣足食么……