maven을 통해 CXF에서 wsdl2java를 사용하여 웹 서비스 클라이언트를 생성하면 (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>
하고 있으므로 소스 생성기가 wsdlLocation을 비워 두도록 강제로 CXF 구성에 포함 하려고 시도했습니다. 그러나 이는 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;
}
그래서 내 질문은 :
-
모든 클래스가 CXF 및 JAXB에 의해 생성 된 경우에도 실제로 WSDL 위치가 필요합니까? 그렇다면 왜 그렇습니까?
-
실제로 WSDL 위치가 필요하지 않은 경우 CXF가이를 생성하지 않고 완전히 피하지 않도록하는 적절하고 깨끗한 방법은 무엇입니까?
-
그 해킹으로 어떤 부작용이 생길 수 있습니까? 우리는 여전히 어떤 일이 일어나는지 확인하기 위해 테스트 할 수 없으므로 누군가 미리 말할 수 있다면 좋을 것입니다.
답변
나는 오늘이 질문에 대한 정답을 찾아 냈다.
<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에서만 작동합니다.
답변
우리는 사용
wsdlLocation = "WEB-INF/wsdl/WSDL.wsdl"
즉, 클래스 경로에 상대적인 경로를 사용하십시오.
marshal / unmarshal 중 메시지 유효성 검사를 위해 런타임에 WSDL이 필요할 수 있다고 생각합니다.
답변
사용하는 사람들을 위해 org.jvnet.jax-ws-commons:jaxws-maven-plugin
빌드 타임에 WSDL에서 클라이언트를 생성합니다 :
- WSDL을 어딘가에 배치하십시오
src/main/resources
- 마 하지 접두사
wsdlLocation
로classpath:
- 접두사
wsdlLocation
로/
예:
- WSDL은
/src/main/resources/foo/bar.wsdl
- 구성
jaxws-maven-plugin
과<wsdlDirectory>${basedir}/src/main/resources/foo</wsdlDirectory>
및<wsdlLocation>/foo/bar.wsdl</wsdlLocation>
답변
1) 경우에 따라 가능합니다. WSDL에 정책과 같은 것들이 포함되어 런타임 동작을 지시하는 경우 런타임에 WSDL이 필요할 수 있습니다. 정책 관련 사물 등에는 아티팩트가 생성되지 않습니다. 또한 일부 모호한 RPC / Literal 사례에서는 필요한 모든 네임 스페이스가 생성 된 코드 (사양에 따라)로 출력되는 것은 아닙니다. 따라서 wsdl이 필요합니다. 그러나 모호한 경우.
2) 나는 무언가가 효과가 있다고 생각했다. CXF의 버전은 무엇입니까? 그것은 버그처럼 들립니다. 빈 문자열을 공백으로 시도해 볼 수 있습니다. 그것이 작동하는지 확실하지 않습니다. 즉, 코드에서 WSDL URL을 사용하고 null을 전달하는 생성자를 사용할 수 있습니다. wsdl은 사용되지 않습니다.
3) 위의 제한 사항.
답변
나는 생성 할 수 있었다
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>
답변
wsdl2java 사용을 피할 수 있습니까? CXF FrontEnd API를 즉시 사용하여 SOAP 웹 서비스를 호출 할 수 있습니다. 클라이언트 쪽에서 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/에서 볼 수 있습니다 .
답변
CXF 3.1.7 업데이트
내 경우에는 WSDL 파일을 src/main/resources
Eclipse의 Srouces 에이 경로를 추가했습니다 (프로젝트-> 빌드 경로-> 빌드 경로 구성 …-> 소스 [탭]-> 폴더 추가를 마우스 오른쪽 버튼으로 클릭하십시오).
다음은 내 pom
파일 모양과 wsdlLocation
필요한 옵션 이 없음을 보여줍니다 .
<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/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>classpath:wsdl/FOO_SERVICE.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
그리고 여기 생성 된 서비스가 있습니다. 알 수 있듯이 URL은 절대 파일 경로가 아닌 ClassLoader에서 가져옵니다.
@WebServiceClient(name = "EventService",
wsdlLocation = "classpath:wsdl/FOO_SERVICE.wsdl",
targetNamespace = "http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/")
public class EventService extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventService");
public final static QName EventPort = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventPort");
static {
URL url = EventService.class.getClassLoader().getResource("wsdl/FOO_SERVICE.wsdl");
if (url == null) {
java.util.logging.Logger.getLogger(EventService.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "classpath:wsdl/FOO_SERVICE.wsdl");
}
WSDL_LOCATION = url;
}