179

CXF から wsdl2java を使用して Web サービス クライアントを生成すると (wsimport に似たものを生成します)、maven を介してサービスを開始すると、次のようなコードが表示されます。

@WebServiceClient(name = "StatusManagement", 
                  wsdlLocation = "c:/some_absolute_path_to_a_wsdl_file.wsdl",
                  targetNamespace = "http://tempuri.org/") 
public class StatusManagement extends Service {

    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
    public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
    static {
        URL url = null;
        try {
            url = new URL("c:/some_absolute_path_to_a_wsdl_file.wsdl");
        } catch (MalformedURLException e) {
            System.err.println("Can not initialize the default wsdl from c:/some_absolute_path_to_a_wsdl_file.wsdl");
            // e.printStackTrace();
        }
        WSDL_LOCATION = url;
    }

ハードコーディングされた絶対パスは本当に最悪です。生成されたクラスは、私のコンピューター以外では機能しません。

最初のアイデアは、WSDL ファイル (およびそれがインポートするすべての WSDL と XSD) を jar ファイルのどこかに置き、クラスパスを指定することです。しかし、私たちはこれを避けたいと思っています。これらはすべて WSDL と XSD に基づいて CXF と JAXB によって生成されたため、実行時に WSDL を知る必要はありません。

wsdlLocation 属性は WSDL の場所をオーバーライドすることを目的としており (少なくともこれは私がどこかで読んだものです)、デフォルト値は "" です。Maven を使用しているため<wsdlLocation></wsdlLocation>、CXF の構成内に含めて、ソース ジェネレーターに強制的に wsdlLocation を空白のままにしようとしました。ただし、これは XML タグが空であるため、単純に XML タグを無視します。を使用して、本当に醜い恥ずべきハックを行いました<wsdlLocation>" + "</wsdlLocation>

これにより、他の場所も変更されます。

@WebServiceClient(name = "StatusManagement", 
                  wsdlLocation = "" + "",
                  targetNamespace = "http://tempuri.org/") 
public class StatusManagement extends Service {

    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
    public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
    static {
        URL url = null;
        try {
            url = new URL("" + "");
        } catch (MalformedURLException e) {
            System.err.println("Can not initialize the default wsdl from " + "");
            // e.printStackTrace();
        }
        WSDL_LOCATION = url;
    }

だから、私の質問は次のとおりです。

  1. すべてのクラスが CXF と JAXB によって生成されたとしても、本当に WSDL の場所が必要ですか? はいの場合、なぜですか?

  2. WSDL の場所が本当に必要ない場合、CXF にそれを生成させず、完全に回避させる適切でクリーンな方法は何ですか?

  3. そのハックで得られる悪い副作用は何ですか? 何が起こるかをテストすることはまだできないので、誰かが前もって言ってくれたらうれしいです.

4

10 に答える 10

223

私はついに今日、この質問に対する正しい答えを見つけました。

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration> 
                <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>${project.basedir}/src/main/resources/wsdl/FooService.wsdl</wsdl>
                        <wsdlLocation>classpath:wsdl/FooService.wsdl</wsdlLocation>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

の値の前に を付けたことに注意してwsdlLocationくださいclasspath:。これにより、wsdl が絶対パスではなくクラスパスにあることがプラグインに通知されます。次に、次のようなコードが生成されます。

@WebServiceClient(name = "FooService", 
                  wsdlLocation = "classpath:wsdl/FooService.wsdl",
                  targetNamespace = "http://org/example/foo") 
public class Foo_Service extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://org/example/foo", "Foo");
    public final static QName FooSOAPOverHTTP = new QName("http://org/example/foo", "Foo_SOAPOverHTTP");
    static {
        URL url = Foo_Service.class.getClassLoader().getResource("wsdl/FooService.wsdl");
        if (url == null) {
            java.util.logging.Logger.getLogger(Foo_Service.class.getName())
                .log(java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "classpath:wsdl/FooService.wsdl");
        }       
        WSDL_LOCATION = url;
    }

これはバージョン 2.4.1 以降の cxf-codegen-plugin でのみ機能することに注意してください。

于 2012-03-26T16:10:28.363 に答える
22

を使用しております

wsdlLocation = "WEB-INF/wsdl/WSDL.wsdl"

つまり、クラスパスに対する相対パスを使用します。

マーシャリング/アンマーシャリング中のメッセージの検証のために、実行時に WSDL が必要になる可能性があると思います。

于 2011-01-13T16:05:49.440 に答える
10

1)場合によっては、はい。WSDLにポリシーなどが含まれていて、実行時の動作を指示する場合は、実行時にWSDLが必要になることがあります。ポリシー関連のものなどのアーティファクトは生成されません。また、一部のあいまいなRPC /リテラル​​の場合、必要なすべての名前空間が生成されたコードに出力されるわけではありません(仕様ごと)。したがって、wsdlが必要になります。しかし、あいまいなケース。

2)私は何かがうまくいくと思いました。CXFのバージョンは何ですか?それはバグのように聞こえます。そこに空の文字列(スペースだけ)を試すことができます。それがうまくいくかどうかわからない。とは言うものの、コードでは、WSDLURLを取得してnullを渡すコンストラクターを使用できます。wsdlは使用されません。

3)上記の制限のみ。

于 2010-12-15T22:03:14.377 に答える
6

生み出すことができました

static {
    WSDL_LOCATION = null;
}

wsdlurl が null になるように pom ファイルを構成することにより、次のようになります。

    <plugin>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-codegen-plugin</artifactId>
        <executions>
            <execution>
                <id>generate-sources</id>
                <phase>generate-sources</phase>
                <configuration>
                    <sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
                    <wsdlOptions>
                        <wsdlOption>
                            <wsdl>${basedir}/src/main/resources/service.wsdl</wsdl>
                            <extraargs>
                                <extraarg>-client</extraarg>
                                <extraarg>-wsdlLocation</extraarg>
                                <wsdlurl />
                            </extraargs>
                        </wsdlOption>
                    </wsdlOptions>
                </configuration>
                <goals>
                    <goal>wsdl2java</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
于 2011-08-02T16:23:40.867 に答える
4

wsdl2java の使用を避けることは可能ですか? CXF フロントエンド API を使用して、SOAP Web サービスをすぐに呼び出すことができます。唯一の問題は、クライアント側で SEI と VO を作成する必要があることです。これがサンプルコードです。

package com.aranin.weblog4j.client;

import com.aranin.weblog4j.services.BookShelfService;
import com.aranin.weblog4j.vo.BookVO;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class DemoClient {
    public static void main(String[] args){
        String serviceUrl = "http://localhost:8080/weblog4jdemo/bookshelfservice";
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(BookShelfService.class);
        factory.setAddress(serviceUrl);
        BookShelfService bookService = (BookShelfService) factory.create();

        //insert book
        BookVO bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Earth");

        String result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Empire");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Arthur C Clarke");
        bookVO.setBookName("Rama Revealed");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        //retrieve book

        bookVO = bookService.getBook("Foundation and Earth");

        System.out.println("book name : " + bookVO.getBookName());
        System.out.println("book author : " + bookVO.getAuthor());

    }
}

ここで完全なチュートリアルを見ることができますhttp://weblog4j.com/2012/05/01/developing-soap-web-service-using-apache-cxf/

于 2013-03-29T04:49:31.993 に答える
3

@Martin Devillers ソリューションは正常に機能します。完全を期すために、以下の手順を提供します。

  1. wsdl を次のようなリソース ディレクトリに配置します。src/main/resource
  2. pom ファイルに、以下のように wsdlDirectory と wsdlLocation の両方を追加します (wsdlLocation の先頭にある / を忘れないでください)。wsdlDirectory はコードを生成するために使用され、wsdlLocation は実行時に動的プロキシを作成するために使用されます。

    <wsdlDirectory>src/main/resources/mydir</wsdlDirectory>
    <wsdlLocation>/mydir/my.wsdl</wsdlLocation>
    
  3. 次に、Javaコード(引数なしのコンストラクターを使用)で:

    MyPort myPort = new MyPortService().getMyPort();
    
  4. これは pom ファイルの完全なコード生成部分で、生成されたコードには流暢な API が含まれています。

    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.5</version>
    
    <dependencies>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-fluent-api</artifactId>
            <version>3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-tools</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>
    
    <executions>
        <execution>
            <id>wsdl-to-java-generator</id>
            <goals>
                <goal>wsimport</goal>
            </goals>
            <configuration>
                <xjcArgs>
                    <xjcArg>-Xfluent-api</xjcArg>
                </xjcArgs>
                <keep>true</keep>
                <wsdlDirectory>src/main/resources/package</wsdlDirectory>
                <wsdlLocation>/package/my.wsdl</wsdlLocation>
                <sourceDestDir>${project.build.directory}/generated-sources/annotations/jaxb</sourceDestDir>
                <packageName>full.package.here</packageName>
            </configuration>
        </execution>
    </executions>
    

于 2019-11-19T10:24:12.117 に答える