关于 java:从 Visual FoxPro 调用 JBoss Web 服务时出现”找不到子元素”错误

"Cannot find child element" error when calling JBoss Web Service from Visual FoxPro

我遇到了这个问题。我使用 Seam 框架创建了一个在 JBoss 5 之上运行的 Web 服务。 Web 服务有一个称为"登录"的方法。当我从 Java 客户端使用服务时,它工作正常,但是当我尝试从 Visual FoxPro 客户端(我真正需要)使用时,我收到一条错误消息:

1
Error 1429 - OLE IDispatch exception code 0 from ?: Cannot find child element: username

来自 JBoss 的错误堆栈跟踪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
12:02:32,396 ERROR [SOAPFaultHelperJAXWS] SOAP request exception
org.jboss.ws.WSException: Cannot find child element: username
    at org.jboss.ws.core.CommonSOAPBinding.getParameterFromMessage(CommonSOAPBinding.java:917)
    at org.jboss.ws.core.CommonSOAPBinding.unbindRequestMessage(CommonSOAPBinding.java:361)
    at org.jboss.ws.core.server.ServiceEndpointInvoker.invoke(ServiceEndpointInvoker.java:197)
    at org.jboss.wsf.stack.jbws.RequestHandlerImpl.processRequest(RequestHandlerImpl.java:474)
    at org.jboss.wsf.stack.jbws.RequestHandlerImpl.handleRequest(RequestHandlerImpl.java:295)
    at org.jboss.wsf.stack.jbws.RequestHandlerImpl.doPost(RequestHandlerImpl.java:205)
    at org.jboss.wsf.stack.jbws.RequestHandlerImpl.handleHttpRequest(RequestHandlerImpl.java:131)
    at org.jboss.wsf.common.servlet.AbstractEndpointServlet.service(AbstractEndpointServlet.java:85)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Unknown Source)

我的网络服务类:

1
2
3
4
5
6
7
8
9
10
11
12
@Name("ServiceName")
@WebService(name ="ServiceName", serviceName ="ServiceName")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@Stateless
public class ServiceName implements ServiceNameRemote {
    @WebMethod
    @Override
    public boolean login(@WebParam(name ="username") String username, @WebParam(name ="password") String password) {
        // logic..
        return result;
    }  
}

来自 localhost:8080/app-app/ServiceName?wsdl

的 WSDL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<definitions name="ServiceName"
targetNamespace="http://service.namespace/"
xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://service.namespace/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<types />
<message name="ServiceName_login">
    <part name="username" type="xsd:string" />
    <part name="password" type="xsd:string" />
</message>
<portType name="ServiceName">
    <operation name="login" parameterOrder="username password">
        <input message="tns:ServiceName_login" />
        <output message="tns:ServiceName_loginResponse" />
    </operation>
</portType>
<binding name="ServiceNameBinding" type="tns:ServiceName">
    <soap:binding style="rpc"
        transport="http://schemas.xmlsoap.org/soap/http" />
    <operation name="login">
        <soap:operation soapAction="" />
        <input>
            <soap:body namespace="http://service.namespace/"
                use="literal" />
        </input>
        <output>
            <soap:body namespace="http://service.namespace/"
                use="literal" />
        </output>
    </operation>
</binding>
<service name="ServiceName">
    <port binding="tns:ServiceNameBinding" name="ServiceNamePort">
        <soap:address
            location="http://localhost:8080/app-app/ServiceName" />
    </port>
</service>
</definitions>

客户端代码(使用 MS Soap Toolkit 3.0):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
LOCAL loServiceNamePort AS"XML Web Service"
* LOCAL loServiceNamePort AS"MSSOAP.SoapClient30"
* Do not remove or alter following line. It is used to support IntelliSense for your XML Web service.
*__VFPWSDef__: loServiceNamePort = http://localhost:8080/app-app/ServiceName?wsdl , ServiceName , ServiceNamePort
LOCAL loException, lcErrorMsg, loWSHandler
TRY
    loWSHandler = NEWOBJECT("WSHandler",IIF(VERSION(2)=0,"",HOME()+"FFC")+"_ws3client.vcx")
    loServiceNamePort = loWSHandler.SetupClient("http://localhost:8080/app-app/ServiceName?wsdl","ServiceName","ServiceNamePort")
    * Call your XML Web service here.  ex: leResult = loServiceNamePort.SomeMethod()
    MESSAGEBOX(loServiceNamePort.login("username","password"))
CATCH TO loException
    lcErrorMsg ="Error:"+TRANSFORM(loException.Errorno)+" -"+loException.Message
    DO CASE
    CASE VARTYPE(loServiceNamePort)#"O"
        * Handle SOAP error connecting to web service
        WAIT WINDOW"Error connecting to web service" NOWAIT
    CASE !EMPTY(loServiceNamePort.FaultCode)
        * Handle SOAP error calling method
        lcErrorMsg = lcErrorMsg + CHR(13) + loServiceNamePort.Detail
        WAIT WINDOW"SOAP error calling method" NOWAIT
    OTHERWISE
        * Handle other error
    ENDCASE
    * Use for debugging purposes
    MESSAGEBOX(lcErrorMsg)
FINALLY
ENDTRY

客户端代码(使用 PocketSOAP):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
LOCAL loException, lcErrorMsg, loFactory, loProxy
TRY
    loFactory = createObject("pocketsoap.Factory")
    loProxy = loFactory.CreateProxy("http://localhost:8080/app-app/ServiceName?wsdl","http://service.namespace/")
    MESSAGEBOX(loProxy.login("username","password"))
CATCH TO loException
    lcErrorMsg ="Error:"+TRANSFORM(loException.Errorno)+" -"+loException.Message
    DO CASE
    CASE VARTYPE(loServiceNamePort)#"O"
        * Handle SOAP error connecting to web service
        WAIT WINDOW"Error connecting to web service" NOWAIT
    CASE !EMPTY(loServiceNamePort.FaultCode)
        * Handle SOAP error calling method
        lcErrorMsg = lcErrorMsg + CHR(13) + loServiceNamePort.Detail
        WAIT WINDOW"SOAP error calling method" NOWAIT
    OTHERWISE
        * Handle other error
    ENDCASE
    * Use for debugging purposes
    MESSAGEBOX(lcErrorMsg)  
FINALLY
ENDTRY

我一直在寻找关于为什么会发生这种情况的解释,但没有找到。我尝试了在谷歌搜索时发现的几件事:我将具有相应值的命名空间属性添加到 @WebParam 注释中,添加了带有名称和命名空间的 @WebResult 注释,将 SOAP 绑定从 RPC 更改为 Document,但都无济于事。非常感谢您在这里给我的任何帮助。

编辑:我们放弃了 SOAP 服务,现在使用 REST 服务,我们发现它更易于从 Visual Fox 中使用,无需任何桥接应用程序。


没关系。通过 ASP.NET WS 转发 Java WS,并让 VFP 客户端使用它。它有效。