JAX-WS 客户端:访问本地 WSDL 的正确路径是什么?

新手上路,请多包涵

问题是我需要从我提供的文件构建一个 Web 服务客户端。我已将此文件存储在本地文件系统中,而当我将 WSDL 文件保存在正确的文件系统文件夹中时,一切都很好。当我将它部署到服务器或从文件系统文件夹中删除 WSDL 时,代理无法找到 WSDL 并引发错误。我在网上搜索过,发现了以下帖子,但我无法使其正常工作:

JAX-WS 从 jar 加载 WSDL

http://www.java.net/forum/topic/glassfish/metro-and-jaxb/client-jar-cant-find-local-wsdl-0

http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html

我使用的是 NetBeans 6.1(这是一个遗留应用程序,我必须使用这个新的 Web 服务客户端进行更新)。下面是 JAX-WS 代理类:

     @WebServiceClient(name = "SOAService", targetNamespace = "http://soaservice.eci.ibm.com/", wsdlLocation = "file:/C:/local/path/to/wsdl/SOAService.wsdl")
public class SOAService
    extends Service
{

    private final static URL SOASERVICE_WSDL_LOCATION;
    private final static Logger logger = Logger.getLogger(com.ibm.eci.soaservice.SOAService.class.getName());

    static {
        URL url = null;
        try {
            URL baseUrl;
            baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
            url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
        } catch (MalformedURLException e) {
            logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
            logger.warning(e.getMessage());
        }
        SOASERVICE_WSDL_LOCATION = url;
    }

    public SOAService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    public SOAService() {
        super(SOASERVICE_WSDL_LOCATION, new QName("http://soaservice.eci.ibm.com/", "SOAService"));
    }

    /**
     * @return
     *     returns SOAServiceSoap
     */
    @WebEndpoint(name = "SOAServiceSOAP")
    public SOAServiceSoap getSOAServiceSOAP() {
        return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class);
    }

    /**
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns SOAServiceSoap
     */
    @WebEndpoint(name = "SOAServiceSOAP")
    public SOAServiceSoap getSOAServiceSOAP(WebServiceFeature... features) {
        return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class, features);
    }

}

这是我使用代理的代码:

    WebServiceClient annotation = SOAService.class.getAnnotation(WebServiceClient.class);
   // trying to replicate proxy settings
   URL baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource("");//note : proxy uses "."
   URL url = new URL(baseUrl, "/WEB-INF/wsdl/client/SOAService.wsdl");
   //URL wsdlUrl = this.getClass().getResource("/META-INF/wsdl/SOAService.wsdl");
   SOAService serviceObj = new SOAService(url, new QName(annotation.targetNamespace(), annotation.name()));
   proxy = serviceObj.getSOAServiceSOAP();
   /* baseUrl;

   //classes\com\ibm\eci\soaservice
   //URL url = new URL(baseUrl, "../../../../wsdl/SOAService.wsdl");

   proxy = new SOAService().getSOAServiceSOAP();*/
   //updating service endpoint
   Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
   ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
   ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WebServiceUrl);

NetBeans 将 WSDL 的副本放在 web-inf/wsdl/client/SOAService 中,所以我也不想将它添加到 META-INF 中。服务类位于 WEB-INF/classes/com/ibm/eci/soaservice/ 中,baseurl 变量包含它的文件系统完整路径 (c:\path\to\the\project…\soaservice )。上面的代码引发了错误:

javax.xml.ws.WebServiceException:无法在以下位置访问 WSDL:file:/WEB-INF/wsdl/client/SOAService.wsdl。它失败了:\WEB-INF\wsdl\client\SOAService.wsdl(找不到路径)

那么,首先,我应该更新代理类的 wsdllocation 吗?那么如何让WEB-INF/classes/com/ibm/eci/soaservice中的SOAService类在\WEB-INF\wsdl\client\SOAService.wsdl中搜索WSDL呢?

编辑:我找到了这个其他链接 - http://jianmingli.com/wp/?cat=41 ,它说要将 WSDL 放入类路径中。不好意思问:如何把它放到web应用程序类路径中?

原文由 user260192 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 935
2 个回答

最好的选择是使用 jax-ws-catalog.xml

当您编译本地 WSDL 文件时,覆盖 WSDL 位置并将其设置为类似于

http://localhost/wsdl/SOAService.wsdl

别担心,这只是一个 URI 而不是 URL ,这意味着您不必在该地址拥有可用的 WSDL。

您可以通过将 wsdllocation 选项传递给 wsdl to java 编译器来完成此操作。

这样做会将您的代理代码从

static {
    URL url = null;
    try {
        URL baseUrl;
        baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
        url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
    } catch (MalformedURLException e) {
        logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
        logger.warning(e.getMessage());
    }
    SOASERVICE_WSDL_LOCATION = url;
}

static {
    URL url = null;
    try {
        URL baseUrl;
        baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
        url = new URL(baseUrl, "http://localhost/wsdl/SOAService.wsdl");
    } catch (MalformedURLException e) {
        logger.warning("Failed to create URL for the wsdl Location: 'http://localhost/wsdl/SOAService.wsdl', retrying as a local file");
        logger.warning(e.getMessage());
    }
    SOASERVICE_WSDL_LOCATION = url;
}

注意 file:// 在 URL 构造函数中更改为 http://。

现在出现在 jax-ws-catalog.xml 中。如果没有 jax-ws-catalog.xml,jax-ws 确实会尝试从该位置加载 WSDL

 http://localhost/wsdl/SOAService.wsdl

并失败,因为没有这样的 WSDL 可用。

但是使用 jax-ws-catalog.xml 您可以在 jax-ws 尝试访问 WSDL @ 时将其重定向到本地打包的 WSDL

 http://localhost/wsdl/SOAService.wsdl

.

这是 jax-ws-catalog.xml

 <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
        <system systemId="http://localhost/wsdl/SOAService.wsdl"
                uri="wsdl/SOAService.wsdl"/>
    </catalog>

您正在做的是告诉 jax-ws 何时需要从中加载 WSDL

 http://localhost/wsdl/SOAService.wsdl

,它应该从本地路径 wsdl/SOAService.wsdl 加载它。

现在你应该把 wsdl/SOAService.wsdl 和 jax-ws-catalog.xml 放在哪里?这是百万美元的问题,不是吗?

它应该在应用程序 jar 的 META-INF 目录中。

所以像这样

ABCD.jar
|__ 元信息
    |__ jax-ws-catalog.xml
    |__ wsdl
        |__ SOAService.wsdl

这样,您甚至不必覆盖访问代理的客户端中的 URL。 WSDL 是从您的 JAR 中获取的,您可以避免在代码中使用硬编码的文件系统路径。

有关 jax-ws-catalog.xml 的更多信息 http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html

希望有帮助

原文由 user507484 发布,翻译遵循 CC BY-SA 2.5 许可协议

我们成功采用的另一种方法是使用 wsimport(来自 Ant,作为 Ant 任务)生成 WS 客户端代理代码并指定 wsdlLocation 属性。

 <wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}">
</wsimport>

由于我们为带有多个 WSDL 的项目运行此脚本,因此脚本动态解析 $(wsdl.file} 值,该值设置为 /META-INF/wsdl/YourWebServiceName.wsdl 相对于 JavaSource 位置(或 /src,取决于您的项目设置方式。在构建过程中,WSDL 和 XSD 文件被复制到此位置并打包到 JAR 文件中。(类似于上面 Bhasakar 描述的解决方案)

 MyApp.jar
|__META-INF
   |__wsdl
      |__YourWebServiceName.wsdl
      |__YourWebServiceName_schema1.xsd
      |__YourWebServiceName_schmea2.xsd

注意:确保 WSDL 文件使用的是对任何导入的 XSD 的相对引用,而不是 http URL:

   <types>
    <xsd:schema>
      <xsd:import namespace="http://valueobject.common.services.xyz.com/" schemaLocation="YourWebService_schema1.xsd"/>
    </xsd:schema>
    <xsd:schema>
      <xsd:import namespace="http://exceptions.util.xyz.com/" schemaLocation="YourWebService_schema2.xsd"/>
    </xsd:schema>
  </types>

生成 的代码中,我们发现:

 /**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2-b05-
 * Generated source version: 2.1
 *
 */
@WebServiceClient(name = "YourService", targetNamespace = "http://test.webservice.services.xyz.com/", wsdlLocation = "/META-INF/wsdl/YourService.wsdl")
public class YourService_Service
    extends Service
{

    private final static URL YOURWEBSERVICE_WSDL_LOCATION;
    private final static WebServiceException YOURWEBSERVICE_EXCEPTION;
    private final static QName YOURWEBSERVICE_QNAME = new QName("http://test.webservice.services.xyz.com/", "YourService");

    static {
        YOURWEBSERVICE_WSDL_LOCATION = com.xyz.services.webservice.test.YourService_Service.class.getResource("/META-INF/wsdl/YourService.wsdl");
        WebServiceException e = null;
        if (YOURWEBSERVICE_WSDL_LOCATION == null) {
            e = new WebServiceException("Cannot find '/META-INF/wsdl/YourService.wsdl' wsdl. Place the resource correctly in the classpath.");
        }
        YOURWEBSERVICE_EXCEPTION = e;
    }

    public YourService_Service() {
        super(__getWsdlLocation(), YOURWEBSERVICE_QNAME);
    }

    public YourService_Service(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    /**
     *
     * @return
     *     returns YourService
     */
    @WebEndpoint(name = "YourServicePort")
    public YourService getYourServicePort() {
        return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class);
    }

    /**
     *
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns YourService
     */
    @WebEndpoint(name = "YourServicePort")
    public YourService getYourServicePort(WebServiceFeature... features) {
        return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class, features);
    }

    private static URL __getWsdlLocation() {
        if (YOURWEBSERVICE_EXCEPTION!= null) {
            throw YOURWEBSERVICE_EXCEPTION;
        }
        return YOURWEBSERVICE_WSDL_LOCATION;
    }

}

也许这也有帮助。这只是一种不使用“目录”方法的不同方法。

原文由 mark 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题