Apache Camel 和网络服务
Apache Camel and web services
我正在尝试了解如何将 Apache Camel 与任何提供 WSDL 的 Web 服务集成以生成其 类 以随后调用他的方法来 return 一些请求。
我研究了一点 camel-spring-ws 和 camel-cxf 包。如我所见,Spring Web 服务组件不支持使用 WSDL,但 CXF 支持,但它仅支持与托管在 CXF 中的 JAX-WS 服务的连接。
如果我从客户那里收到 WSDL,我可以使用 CXF 吗?或者我需要创建一个自定义组件来使用他的方法吗?
据我所知,实现它的最简单方法是创建一个 Process 或 Bean 来调用远程 Web服务。
我尝试实现一个生产者来调用远程网络服务。我的beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<cxf:cxfEndpoint
id="osvEndpoint"
address="http://10.193.1.90:8767/"
serviceClass="siemens_hiq8000.SiemensHiq8000PortType"/>
<bean id="osvWebServiceProcessor" class="br.com.willianantunes.processor.OsvWebServiceProcessor" />
</beans>
我的路线:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<routeContext id="osvWebServiceInvoke" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://test?cron=0/10+*+*+*+*+?"/>
<process ref="osvWebServiceProcessor" />
<to uri="cxf:bean:osvEndpoint"/>
<to uri="log:live?level=INFO" />
</route>
</routeContext>
</beans>
还有我的处理器:
public class OsvWebServiceProcessor implements Processor
{
@Override
public void process(Exchange exchange) throws Exception
{
Message inMessage = exchange.getIn();
// The method to be called
inMessage.setHeader(CxfConstants.OPERATION_NAME, "getVersion");
// Parameters to be passed into the web service
List<Object> params = new ArrayList<Object>();
ResultCodeStructHolder resultCodeStructHolder = new ResultCodeStructHolder();
VersionDataHolder versionDataHolder = new VersionDataHolder();
params.add(resultCodeStructHolder);
params.add(versionDataHolder);
inMessage.setBody(params);
}
}
方法getVersion需要一些参数如下:
public void getVersion(siemens_hiq8000.holders.ResultCodeStructHolder result,
siemens_hiq8000.holders.VersionDataHolder versionData) throws java.rmi.RemoteException;
我怎样才能通过它们?这些持有者必须填充 Web 服务的响应。当我 运行 我的项目时,出现以下错误:
[main] INFO org.apache.cxf.service.factory.ReflectionServiceFactoryBean - Creating Service {http://siemens_hiq8000/}SiemensHiq8000PortType from class siemens_hiq8000.SiemensHiq8000PortType
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.cxf.wsdl11.WSDLEndpointFactory.createEndpointInfo(Lorg/apache/cxf/service/model/ServiceInfo;Lorg/apache/cxf/service/model/BindingInfo;Ljava/util/List;)Lorg/apache/cxf/service/model/EndpointInfo;
at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpointInfo(AbstractWSDLBasedEndpointFactory.java:287)
at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:144)
at org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:91)
at org.apache.camel.component.cxf.CxfSpringEndpoint.createClient(CxfSpringEndpoint.java:116)
at org.apache.camel.component.cxf.CxfProducer.doStart(CxfProducer.java:76)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.startService(DefaultCamelContext.java:2869)
at org.apache.camel.impl.DefaultCamelContext.doAddService(DefaultCamelContext.java:1097)
at org.apache.camel.impl.DefaultCamelContext.addService(DefaultCamelContext.java:1058)
at org.apache.camel.impl.ProducerCache.doGetProducer(ProducerCache.java:405)
at org.apache.camel.impl.ProducerCache.acquireProducer(ProducerCache.java:123)
at org.apache.camel.processor.SendProcessor.doStart(SendProcessor.java:219)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.DelegateAsyncProcessor.doStart(DelegateAsyncProcessor.java:79)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.RedeliveryErrorHandler.doStart(RedeliveryErrorHandler.java:1272)
at org.apache.camel.support.ChildServiceSupport.start(ChildServiceSupport.java:44)
at org.apache.camel.support.ChildServiceSupport.start(ChildServiceSupport.java:31)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.interceptor.DefaultChannel.doStart(DefaultChannel.java:153)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:61)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.MulticastProcessor.doStart(MulticastProcessor.java:1060)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.DelegateAsyncProcessor.doStart(DelegateAsyncProcessor.java:79)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.impl.RouteService.startChildService(RouteService.java:340)
at org.apache.camel.impl.RouteService.warmUp(RouteService.java:182)
at org.apache.camel.impl.DefaultCamelContext.doWarmUpRoutes(DefaultCamelContext.java:3090)
at org.apache.camel.impl.DefaultCamelContext.safelyStartRouteServices(DefaultCamelContext.java:3020)
at org.apache.camel.impl.DefaultCamelContext.doStartOrResumeRoutes(DefaultCamelContext.java:2797)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:2653)
at org.apache.camel.impl.DefaultCamelContext.access[=14=]0(DefaultCamelContext.java:167)
at org.apache.camel.impl.DefaultCamelContext.call(DefaultCamelContext.java:2467)
at org.apache.camel.impl.DefaultCamelContext.call(DefaultCamelContext.java:2463)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:2486)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:2463)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:2432)
at org.apache.camel.spring.SpringCamelContext.maybeStart(SpringCamelContext.java:255)
at org.apache.camel.spring.SpringCamelContext.onApplicationEvent(SpringCamelContext.java:121)
at org.apache.camel.spring.CamelContextFactoryBean.onApplicationEvent(CamelContextFactoryBean.java:332)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at org.apache.camel.spring.Main.createDefaultApplicationContext(Main.java:216)
at org.apache.camel.spring.Main.doStart(Main.java:156)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.main.MainSupport.run(MainSupport.java:150)
at br.com.willianantunes.test.Program.main(Program.java:12)
解决方案
想要让camel-cxf像producer一样的小伙伴,按照下面的步骤为例:
- 首先,我下载了可用于 OpenScape Voice 的最后一个 WSDL 文件 here in this developer page。
- 客户端代码需要在选项 serviceClass 中通知 SEI(服务端点接口)。您可以生成发出以下命令:
wsdl2java -client -d "TargetFolderHere" -autoNameResolution "OpenScape-Voice_V8.00.28.01.wsdl"
- 将生成的客户端 类 插入到您的项目中。这同样适用于 WSDL 文件。
在您的 beans.xml 中告知 cxfEndpoint 配置。
<import resource="classpath:META-INF/cxf/cxf.xml" />
<cxf:cxfEndpoint xmlns:urn="urn:openscape-voice"
id="osvEndpoint"
address="http://10.193.1.90:8767/"
serviceClass="voice.openscape.OpenscapeVoicePortType"
wsdlURL="OpenScape-Voice_V8.00.28.01.wsdl"
serviceName="urn:openscape_voice">
</cxf:cxfEndpoint>
<bean id="osvWebServiceProcessor" class="br.com.willianantunes.processor.OsvWebServiceProcessor" />
调用web服务前,配置一个处理器通知参数和执行方法
Message inMessage = exchange.getIn();
// The method to be called
inMessage.setHeader(CxfConstants.OPERATION_NAME, "GetVersion");
// Parameters to be passed into the web service
List<Object> params = new ArrayList<Object>();
Holder<ResultCodeStruct> result = new Holder<>();
Holder<VersionData> versionData = new Holder<>();
params.add(result);
params.add(versionData);
inMessage.setBody(params);
现在您可以配置路由并插入您的 camelContext 作为 ref 来完成任务。
<routeContext id="osvWebServiceInvoke" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://test?cron=0/10+*+*+*+*+?"/>
<process ref="osvWebServiceProcessor"/>
<to uri="cxf:bean:osvEndpoint"/>
<to uri="log:live?level=INFO"/>
</route>
</routeContext>
日志打印如下:
- Quartz scheduler 'DefaultQuartzScheduler-main-application' initialized from an externally provided properties instance.
- Quartz scheduler version: 2.2.1
- Job Camel_main-application.test (triggerType=CronTriggerImpl, jobClass=CamelJob) is scheduled. Next fire date is Tue Mar 31 09:12:00 BRT 2015
- AllowUseOriginalMessage is enabled. If access to the original message is not needed, then its recommended to turn this option off as it may improve performance.
- StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
- Creating Service {urn:openscape-voice}openscape_voice from WSDL: OpenScape-Voice_V8.00.28.01.wsdl
- Could not find endpoint/port for {urn:openscape-voice}openscape_voicePortTypePort in wsdl. Using {urn:openscape-voice}openscape_voice.
- Route: route1 started and consuming from: Endpoint[quartz2://test?cron=0%2F10+*+*+*+*+%3F]
- Starting scheduler.
- Scheduler DefaultQuartzScheduler-main-application_$_NON_CLUSTERED started.
- Total 1 routes, of which 1 is started.
- Apache Camel 2.15.0 (CamelContext: main-application) started in 10.759 seconds
- Exchange[ExchangePattern: InOnly, BodyType: org.apache.cxf.message.MessageContentsList, Body: [null, javax.xml.ws.Holder@508696f5, javax.xml.ws.Holder@333cf1ba]]
我在 CXF 依赖方面遇到了一些问题,所以这是我的 pom.xml:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>
<!-- Apache CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-bindings-soap</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- End of Apache CXF -->
您可以设计一个新的处理器或一个 bean 来从 Web 服务中获取带有响应的正文消息(不是纯 SOAP 消息,而是以前使用的 POJO)。
@Namphibian 提供的答案还可以,也符合我的目的。
您指的是 Web 服务的合同优先或自上而下的开发。在这种方法中,您从 WSDL 定义生成存根代码并在您的开发中使用这些 类 等。我已经做了很多,我已经使用了 .Net 中创建的服务中的 WSDL,Java、PHP 甚至 Delphi(虽然 Delphi 打破了 WSI 合规性甚至不去那里)。
CXF 将从几乎任何您可以将库指向的 WSDL 生成 类。首先,您需要在 Maven POM 文件中添加一个条目,告诉 Maven 从 WSDL 为您生成 类。
将以下内容添加到您的 POM 文件中:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>get the latest version or the version you want</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>
${basedir}/target/generated/src/main/java
</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>
URI/FILE PATH OF WSDL HERE
</wsdl>
<extraargs>
<extraarg>-impl</extraarg> <-- use this if you want to implement the service i.e. create it
<extraarg>-client</extraarg> <-- us this if you want to generate a client for the service.
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
您现在可以运行 maven 目标 mvn generate-source
以生成所需的存根 类 以使用此文件。
我通常会投入 processor/bean 进行实际实施,因为我生产和/或使用的大多数 Web 服务都具有相当复杂的数据结构。然而,这实际上取决于服务。
所以简而言之,您可以使用 CXF 为几乎(Delphi 伙计们,您在听吗?)生成存根 类 网络服务,然后在处理器中使用这些生成的 类实现客户端和/或服务器。
更新:
根据您上面的示例,您的方向是正确的。首先,我想讨论一些关于 camel 中的 CXF 的事情,这是一个重要的概念。 CXF bean 与其他 bean 略有不同,例如当您看到以下代码时:
<from uri="file://....."/>
<to uri="mock"/>
文件组件是一个生产者,毕竟它生产文件,模拟组件是一个消费者,因为它获取文件组件产生的数据并使用它来完成它的任务。
Web 服务稍微扭曲了这个概念。当您有如下路线时:
cxf bean 称为生产者,因为它调用 Web 服务。当您将 cxf bean 用作消费者或在路由的 <from>
部分中时,它会变得很有趣。
这是一个网络服务消费者的例子:
<from uri="cxf:bean:someService" />
CXF bean 正在使用 Web 服务调用,然后将消息发送到其他各个部分。这允许您公开一些非常复杂的东西,例如从 FTP 服务器下载文件,通过 JDBC 调用丰富内容,然后针对 SAP 系统将丰富的数据作为 Web 服务进行处理。您的路由将 <from>
中的 cxf bean 作为服务公开,其余路由可以完成所有集成,但它作为 Web 服务公开。非常强大的概念。
在您的情况下,您的网络服务 bean 是生产者或客户。我通常不为客户端使用 cxf bean,因为我使用的服务可能相当复杂,我需要 Java 的全部功能来处理这些情况。因此,我将向您展示如何以这种方式进行操作。
所以在我的世界里,我会做以下骆驼路线:
<routeContext id="osvWebServiceInvoke" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://test?cron=0/10+*+*+*+*+?"/>
<process ref="osvWebServiceProcessor" />
<to uri="log:live?level=INFO" />
</route>
</routeContext>
我的处理器 bean 将更改为:
public class OsvWebServiceProcessor implements Processor
{
@Override
public void process(Exchange exchange) throws Exception
{
Message inMessage = exchange.getIn();
/*
SInce i dont have access to the WSDL and XSD I cant say how the following code will look but essentially you would need to call the web-service here in Java code and get the result back.
*/
outSOAPMsg= siemens_hiq8000.SiemensHiq8000PortType.OperationName(inSOAPMsg)
//set the reply into the inbody and send onto other components for processing.
inMessage.setBody(outSOAPMsg);
}
}
查看您的代码,我意识到您的存根 类 似乎未正确生成。我强烈建议您将我的 post 中描述的项目添加到您的 POM 文件中。如果你可以 post 一些 WSDL 和 XSD 文件,我可以给你更多描述性的答案。
我的主要职责之一是使用 camel 作为客户端使用不同的 Web 服务。这是我通常使用的方法,从不 运行 解决任何问题,它每次都非常有效。
1) 在你的 camel-config.xml 文件中定义端点:
<
bean id="service_name_CXFEndpoint" class="org.apache.camel.component.cxf.CxfEndpoint" />
2) 在路由中使用配置文件中定义的端点进行 Web 服务消费:
私有字符串CXF_SERVICE_ENDPOINT =
"cxf:bean:service_name_CXFEndpoint?address=wsdl_uri_location&serviceClass=service_name_from_the_stubs&loggingFeatureEnabled=true";
服务名需要复制wsdl的内容,粘贴到.wsdl文件中,生成webservice client。为此,您需要右键单击 wsdl 文件>webservices>Generate Client。然后你需要select JbossWS for the runtime(你必须先在首选项中设置它)。生成存根后,查找主要服务 class。然后复制它的整个位置。(例如,对于位于 com.test 的名为 WebServiceClass 的 class 将是 serviceClass=com.test.WebService.class)
3)定义消费路由:
from("direct:web_service")
.routeId("service_name")
.bean(ServiceWSProcessor,"processRequest")
.to(CXF_SERVICE_ENDPOINT)
.bean(ServiceWSProcessor,"processResponse")
.end();
现在,您向该处理器发送一个请求,该处理器将转到 Web 服务端点并给您一个响应。
4) 为请求响应编写一个处理器(在本例中为 serviceWS 处理器)。
@Component(value="serviceWSProcessor")
public class ServiceWSProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceWSProcessor.class);
public void processRequest(Exchange exchange) throws Exception {
Message in = exchange.getIn();
Message out = exchange.getOut();
try {
LOGGER.info("Service - START");
Request Request = in.getBody(Request.class);
//This depends on your WSDL File. Test the process in SOAP UI and see how the request looks like and code
//accordingly.
List<Object> list = new ArrayList<Object>();
list.add(header);
list.add(body);
//for this, you need to check the service for what are the parameters for that method and what response its expecting.
out.setHeader(CxfConstants.OPERATION_NAME, "method_name");
out.setBody(list);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void processResponse(Exchange exchange) throws Exception {
Message in = exchange.getIn();
Message out = exchange.getOut();
try {
Response response = null; //Code this based on what response you should set to the final body. check the message
//contents list in debug mode to see what response you are getting.
try {
MessageContentsList result = (MessageContentsList) in.getBody();
if (result != null) {
response = (Response)result.get(0);
out.setHeader(Constants.HEADER_SERVICE_RESPONSE_SUCCESS, Constants.SERVICE_RESPONSE_SUCCESS_Y);
} else {
out.setHeader(Constants.HEADER_SERVICE_RESPONSE_SUCCESS, Constants.SERVICE_RESPONSE_SUCCESS_N);
}
} catch (Exception e) {
e.printStackTrace();
out.setHeader(Constants.HEADER_SERVICE_RESPONSE_SUCCESS, Constants.SERVICE_RESPONSE_SUCCESS_N);
}
LOGGER.info("Service - END");
out.setBody(response));
}
catch (Exception e) {
LOGGER.error("Service - ERROR");
out.setBody(e.getMessage());
}
}
}
有关 camel 和 spring-ws 所需的依赖项列表,请查看此页面。
https://github.com/gauthamhs/Java/blob/master/JavaEE/Dependencies-Important-Camel-Spring.xml
如果您需要其他帮助或有任何疑虑,请告诉我。
此致,
高瑟姆
我正在尝试了解如何将 Apache Camel 与任何提供 WSDL 的 Web 服务集成以生成其 类 以随后调用他的方法来 return 一些请求。
我研究了一点 camel-spring-ws 和 camel-cxf 包。如我所见,Spring Web 服务组件不支持使用 WSDL,但 CXF 支持,但它仅支持与托管在 CXF 中的 JAX-WS 服务的连接。
如果我从客户那里收到 WSDL,我可以使用 CXF 吗?或者我需要创建一个自定义组件来使用他的方法吗?
据我所知,实现它的最简单方法是创建一个 Process 或 Bean 来调用远程 Web服务。
我尝试实现一个生产者来调用远程网络服务。我的beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<cxf:cxfEndpoint
id="osvEndpoint"
address="http://10.193.1.90:8767/"
serviceClass="siemens_hiq8000.SiemensHiq8000PortType"/>
<bean id="osvWebServiceProcessor" class="br.com.willianantunes.processor.OsvWebServiceProcessor" />
</beans>
我的路线:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<routeContext id="osvWebServiceInvoke" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://test?cron=0/10+*+*+*+*+?"/>
<process ref="osvWebServiceProcessor" />
<to uri="cxf:bean:osvEndpoint"/>
<to uri="log:live?level=INFO" />
</route>
</routeContext>
</beans>
还有我的处理器:
public class OsvWebServiceProcessor implements Processor
{
@Override
public void process(Exchange exchange) throws Exception
{
Message inMessage = exchange.getIn();
// The method to be called
inMessage.setHeader(CxfConstants.OPERATION_NAME, "getVersion");
// Parameters to be passed into the web service
List<Object> params = new ArrayList<Object>();
ResultCodeStructHolder resultCodeStructHolder = new ResultCodeStructHolder();
VersionDataHolder versionDataHolder = new VersionDataHolder();
params.add(resultCodeStructHolder);
params.add(versionDataHolder);
inMessage.setBody(params);
}
}
方法getVersion需要一些参数如下:
public void getVersion(siemens_hiq8000.holders.ResultCodeStructHolder result,
siemens_hiq8000.holders.VersionDataHolder versionData) throws java.rmi.RemoteException;
我怎样才能通过它们?这些持有者必须填充 Web 服务的响应。当我 运行 我的项目时,出现以下错误:
[main] INFO org.apache.cxf.service.factory.ReflectionServiceFactoryBean - Creating Service {http://siemens_hiq8000/}SiemensHiq8000PortType from class siemens_hiq8000.SiemensHiq8000PortType
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.cxf.wsdl11.WSDLEndpointFactory.createEndpointInfo(Lorg/apache/cxf/service/model/ServiceInfo;Lorg/apache/cxf/service/model/BindingInfo;Ljava/util/List;)Lorg/apache/cxf/service/model/EndpointInfo;
at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpointInfo(AbstractWSDLBasedEndpointFactory.java:287)
at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:144)
at org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:91)
at org.apache.camel.component.cxf.CxfSpringEndpoint.createClient(CxfSpringEndpoint.java:116)
at org.apache.camel.component.cxf.CxfProducer.doStart(CxfProducer.java:76)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.startService(DefaultCamelContext.java:2869)
at org.apache.camel.impl.DefaultCamelContext.doAddService(DefaultCamelContext.java:1097)
at org.apache.camel.impl.DefaultCamelContext.addService(DefaultCamelContext.java:1058)
at org.apache.camel.impl.ProducerCache.doGetProducer(ProducerCache.java:405)
at org.apache.camel.impl.ProducerCache.acquireProducer(ProducerCache.java:123)
at org.apache.camel.processor.SendProcessor.doStart(SendProcessor.java:219)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.DelegateAsyncProcessor.doStart(DelegateAsyncProcessor.java:79)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.RedeliveryErrorHandler.doStart(RedeliveryErrorHandler.java:1272)
at org.apache.camel.support.ChildServiceSupport.start(ChildServiceSupport.java:44)
at org.apache.camel.support.ChildServiceSupport.start(ChildServiceSupport.java:31)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.interceptor.DefaultChannel.doStart(DefaultChannel.java:153)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:61)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.MulticastProcessor.doStart(MulticastProcessor.java:1060)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:59)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:103)
at org.apache.camel.util.ServiceHelper.startServices(ServiceHelper.java:89)
at org.apache.camel.processor.DelegateAsyncProcessor.doStart(DelegateAsyncProcessor.java:79)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74)
at org.apache.camel.impl.RouteService.startChildService(RouteService.java:340)
at org.apache.camel.impl.RouteService.warmUp(RouteService.java:182)
at org.apache.camel.impl.DefaultCamelContext.doWarmUpRoutes(DefaultCamelContext.java:3090)
at org.apache.camel.impl.DefaultCamelContext.safelyStartRouteServices(DefaultCamelContext.java:3020)
at org.apache.camel.impl.DefaultCamelContext.doStartOrResumeRoutes(DefaultCamelContext.java:2797)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:2653)
at org.apache.camel.impl.DefaultCamelContext.access[=14=]0(DefaultCamelContext.java:167)
at org.apache.camel.impl.DefaultCamelContext.call(DefaultCamelContext.java:2467)
at org.apache.camel.impl.DefaultCamelContext.call(DefaultCamelContext.java:2463)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:2486)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:2463)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:2432)
at org.apache.camel.spring.SpringCamelContext.maybeStart(SpringCamelContext.java:255)
at org.apache.camel.spring.SpringCamelContext.onApplicationEvent(SpringCamelContext.java:121)
at org.apache.camel.spring.CamelContextFactoryBean.onApplicationEvent(CamelContextFactoryBean.java:332)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at org.apache.camel.spring.Main.createDefaultApplicationContext(Main.java:216)
at org.apache.camel.spring.Main.doStart(Main.java:156)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.main.MainSupport.run(MainSupport.java:150)
at br.com.willianantunes.test.Program.main(Program.java:12)
解决方案
想要让camel-cxf像producer一样的小伙伴,按照下面的步骤为例:
- 首先,我下载了可用于 OpenScape Voice 的最后一个 WSDL 文件 here in this developer page。
- 客户端代码需要在选项 serviceClass 中通知 SEI(服务端点接口)。您可以生成发出以下命令:
wsdl2java -client -d "TargetFolderHere" -autoNameResolution "OpenScape-Voice_V8.00.28.01.wsdl"
- 将生成的客户端 类 插入到您的项目中。这同样适用于 WSDL 文件。
在您的 beans.xml 中告知 cxfEndpoint 配置。
<import resource="classpath:META-INF/cxf/cxf.xml" /> <cxf:cxfEndpoint xmlns:urn="urn:openscape-voice" id="osvEndpoint" address="http://10.193.1.90:8767/" serviceClass="voice.openscape.OpenscapeVoicePortType" wsdlURL="OpenScape-Voice_V8.00.28.01.wsdl" serviceName="urn:openscape_voice"> </cxf:cxfEndpoint> <bean id="osvWebServiceProcessor" class="br.com.willianantunes.processor.OsvWebServiceProcessor" />
调用web服务前,配置一个处理器通知参数和执行方法
Message inMessage = exchange.getIn(); // The method to be called inMessage.setHeader(CxfConstants.OPERATION_NAME, "GetVersion"); // Parameters to be passed into the web service List<Object> params = new ArrayList<Object>(); Holder<ResultCodeStruct> result = new Holder<>(); Holder<VersionData> versionData = new Holder<>(); params.add(result); params.add(versionData); inMessage.setBody(params);
现在您可以配置路由并插入您的 camelContext 作为 ref 来完成任务。
<routeContext id="osvWebServiceInvoke" xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="quartz2://test?cron=0/10+*+*+*+*+?"/> <process ref="osvWebServiceProcessor"/> <to uri="cxf:bean:osvEndpoint"/> <to uri="log:live?level=INFO"/> </route> </routeContext>
日志打印如下:
- Quartz scheduler 'DefaultQuartzScheduler-main-application' initialized from an externally provided properties instance.
- Quartz scheduler version: 2.2.1
- Job Camel_main-application.test (triggerType=CronTriggerImpl, jobClass=CamelJob) is scheduled. Next fire date is Tue Mar 31 09:12:00 BRT 2015
- AllowUseOriginalMessage is enabled. If access to the original message is not needed, then its recommended to turn this option off as it may improve performance.
- StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
- Creating Service {urn:openscape-voice}openscape_voice from WSDL: OpenScape-Voice_V8.00.28.01.wsdl
- Could not find endpoint/port for {urn:openscape-voice}openscape_voicePortTypePort in wsdl. Using {urn:openscape-voice}openscape_voice.
- Route: route1 started and consuming from: Endpoint[quartz2://test?cron=0%2F10+*+*+*+*+%3F]
- Starting scheduler.
- Scheduler DefaultQuartzScheduler-main-application_$_NON_CLUSTERED started.
- Total 1 routes, of which 1 is started.
- Apache Camel 2.15.0 (CamelContext: main-application) started in 10.759 seconds
- Exchange[ExchangePattern: InOnly, BodyType: org.apache.cxf.message.MessageContentsList, Body: [null, javax.xml.ws.Holder@508696f5, javax.xml.ws.Holder@333cf1ba]]
我在 CXF 依赖方面遇到了一些问题,所以这是我的 pom.xml:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>
<!-- Apache CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-bindings-soap</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- End of Apache CXF -->
您可以设计一个新的处理器或一个 bean 来从 Web 服务中获取带有响应的正文消息(不是纯 SOAP 消息,而是以前使用的 POJO)。
@Namphibian 提供的答案还可以,也符合我的目的。
您指的是 Web 服务的合同优先或自上而下的开发。在这种方法中,您从 WSDL 定义生成存根代码并在您的开发中使用这些 类 等。我已经做了很多,我已经使用了 .Net 中创建的服务中的 WSDL,Java、PHP 甚至 Delphi(虽然 Delphi 打破了 WSI 合规性甚至不去那里)。
CXF 将从几乎任何您可以将库指向的 WSDL 生成 类。首先,您需要在 Maven POM 文件中添加一个条目,告诉 Maven 从 WSDL 为您生成 类。
将以下内容添加到您的 POM 文件中:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>get the latest version or the version you want</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>
${basedir}/target/generated/src/main/java
</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>
URI/FILE PATH OF WSDL HERE
</wsdl>
<extraargs>
<extraarg>-impl</extraarg> <-- use this if you want to implement the service i.e. create it
<extraarg>-client</extraarg> <-- us this if you want to generate a client for the service.
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
您现在可以运行 maven 目标 mvn generate-source
以生成所需的存根 类 以使用此文件。
我通常会投入 processor/bean 进行实际实施,因为我生产和/或使用的大多数 Web 服务都具有相当复杂的数据结构。然而,这实际上取决于服务。
所以简而言之,您可以使用 CXF 为几乎(Delphi 伙计们,您在听吗?)生成存根 类 网络服务,然后在处理器中使用这些生成的 类实现客户端和/或服务器。
更新:
根据您上面的示例,您的方向是正确的。首先,我想讨论一些关于 camel 中的 CXF 的事情,这是一个重要的概念。 CXF bean 与其他 bean 略有不同,例如当您看到以下代码时:
<from uri="file://....."/>
<to uri="mock"/>
文件组件是一个生产者,毕竟它生产文件,模拟组件是一个消费者,因为它获取文件组件产生的数据并使用它来完成它的任务。
Web 服务稍微扭曲了这个概念。当您有如下路线时:
cxf bean 称为生产者,因为它调用 Web 服务。当您将 cxf bean 用作消费者或在路由的 <from>
部分中时,它会变得很有趣。
这是一个网络服务消费者的例子:
<from uri="cxf:bean:someService" />
CXF bean 正在使用 Web 服务调用,然后将消息发送到其他各个部分。这允许您公开一些非常复杂的东西,例如从 FTP 服务器下载文件,通过 JDBC 调用丰富内容,然后针对 SAP 系统将丰富的数据作为 Web 服务进行处理。您的路由将 <from>
中的 cxf bean 作为服务公开,其余路由可以完成所有集成,但它作为 Web 服务公开。非常强大的概念。
在您的情况下,您的网络服务 bean 是生产者或客户。我通常不为客户端使用 cxf bean,因为我使用的服务可能相当复杂,我需要 Java 的全部功能来处理这些情况。因此,我将向您展示如何以这种方式进行操作。
所以在我的世界里,我会做以下骆驼路线:
<routeContext id="osvWebServiceInvoke" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://test?cron=0/10+*+*+*+*+?"/>
<process ref="osvWebServiceProcessor" />
<to uri="log:live?level=INFO" />
</route>
</routeContext>
我的处理器 bean 将更改为:
public class OsvWebServiceProcessor implements Processor
{
@Override
public void process(Exchange exchange) throws Exception
{
Message inMessage = exchange.getIn();
/*
SInce i dont have access to the WSDL and XSD I cant say how the following code will look but essentially you would need to call the web-service here in Java code and get the result back.
*/
outSOAPMsg= siemens_hiq8000.SiemensHiq8000PortType.OperationName(inSOAPMsg)
//set the reply into the inbody and send onto other components for processing.
inMessage.setBody(outSOAPMsg);
}
}
查看您的代码,我意识到您的存根 类 似乎未正确生成。我强烈建议您将我的 post 中描述的项目添加到您的 POM 文件中。如果你可以 post 一些 WSDL 和 XSD 文件,我可以给你更多描述性的答案。
我的主要职责之一是使用 camel 作为客户端使用不同的 Web 服务。这是我通常使用的方法,从不 运行 解决任何问题,它每次都非常有效。
1) 在你的 camel-config.xml 文件中定义端点:
< bean id="service_name_CXFEndpoint" class="org.apache.camel.component.cxf.CxfEndpoint" />
2) 在路由中使用配置文件中定义的端点进行 Web 服务消费:
私有字符串CXF_SERVICE_ENDPOINT = "cxf:bean:service_name_CXFEndpoint?address=wsdl_uri_location&serviceClass=service_name_from_the_stubs&loggingFeatureEnabled=true";
服务名需要复制wsdl的内容,粘贴到.wsdl文件中,生成webservice client。为此,您需要右键单击 wsdl 文件>webservices>Generate Client。然后你需要select JbossWS for the runtime(你必须先在首选项中设置它)。生成存根后,查找主要服务 class。然后复制它的整个位置。(例如,对于位于 com.test 的名为 WebServiceClass 的 class 将是 serviceClass=com.test.WebService.class)
3)定义消费路由:
from("direct:web_service")
.routeId("service_name")
.bean(ServiceWSProcessor,"processRequest")
.to(CXF_SERVICE_ENDPOINT)
.bean(ServiceWSProcessor,"processResponse")
.end();
现在,您向该处理器发送一个请求,该处理器将转到 Web 服务端点并给您一个响应。
4) 为请求响应编写一个处理器(在本例中为 serviceWS 处理器)。
@Component(value="serviceWSProcessor")
public class ServiceWSProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceWSProcessor.class);
public void processRequest(Exchange exchange) throws Exception {
Message in = exchange.getIn();
Message out = exchange.getOut();
try {
LOGGER.info("Service - START");
Request Request = in.getBody(Request.class);
//This depends on your WSDL File. Test the process in SOAP UI and see how the request looks like and code
//accordingly.
List<Object> list = new ArrayList<Object>();
list.add(header);
list.add(body);
//for this, you need to check the service for what are the parameters for that method and what response its expecting.
out.setHeader(CxfConstants.OPERATION_NAME, "method_name");
out.setBody(list);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void processResponse(Exchange exchange) throws Exception {
Message in = exchange.getIn();
Message out = exchange.getOut();
try {
Response response = null; //Code this based on what response you should set to the final body. check the message
//contents list in debug mode to see what response you are getting.
try {
MessageContentsList result = (MessageContentsList) in.getBody();
if (result != null) {
response = (Response)result.get(0);
out.setHeader(Constants.HEADER_SERVICE_RESPONSE_SUCCESS, Constants.SERVICE_RESPONSE_SUCCESS_Y);
} else {
out.setHeader(Constants.HEADER_SERVICE_RESPONSE_SUCCESS, Constants.SERVICE_RESPONSE_SUCCESS_N);
}
} catch (Exception e) {
e.printStackTrace();
out.setHeader(Constants.HEADER_SERVICE_RESPONSE_SUCCESS, Constants.SERVICE_RESPONSE_SUCCESS_N);
}
LOGGER.info("Service - END");
out.setBody(response));
}
catch (Exception e) {
LOGGER.error("Service - ERROR");
out.setBody(e.getMessage());
}
}
}
有关 camel 和 spring-ws 所需的依赖项列表,请查看此页面。
https://github.com/gauthamhs/Java/blob/master/JavaEE/Dependencies-Important-Camel-Spring.xml
如果您需要其他帮助或有任何疑虑,请告诉我。
此致, 高瑟姆