Apache Camel遍历List

时间:2014-11-24 13:03:45

标签: spring apache rest apache-camel integration

我是Apache Camel的新手,我在理解如何实现简单的集成任务时遇到了问题:

  1. REST服务通过Apache Camel路由调用Spring Bean
  2. Spring Bean返回一组类(ArrayList)
  3. 我需要迭代集合中的每个项目,并通过自定义转换器将其转换为另一种类型。

    似乎我应该使用Split和Aggregator,但是如何约束Aggregator来使用原始列表中的所有项目,而不是更多,也不是更少。另外,如何将一个项目转换为另一个项目?我应该使用类型转换器吗?

    有人能为我提供一个简单的例子吗?

    更新1

    抱歉,我不得不撤消对提供的示例的接受,因为它实际上没有回答我的问题。这是用例资格: 我需要从to("bean:someBean")调用中拆分和转换方法返回值,而不是从某个端点拆分和转换输入值。

    所以用例是

    1. 呼叫一些端点;例如,关于休息服务的GET请求,在我的情况下:from("endpoint")
    2. 调用bean并获取它的返回值;例如Listto("bean:someBean")
    3. 将返回值转换为另一个List
    4. 将转化后的List返回给消费者
    5. 更新2

      所以,我可以确认使用end()方法并不能解决我的问题。

      以下是代码:

      rest("some/service").get().produces("application/json").to("bean:someBean?method=getListOfObjects").route().split(body(), (oldExchange, newExchange) -> {
                      List<ObjectToConvert> oldList = oldExchange.getIn(List.class);
                      List<NewObject> convertedList = taskList.stream().map(ObjectToConvert::new).collect(Collectors.toList());
                      newExchange.getOut().setBody(convertedList);
      
                      return newExchange;
                  }).end();
      

      使用这种路由,我在应用服务器上遇到以下异常:

      19:30:21,126 ERROR [org.jboss.as.controller.management-operation] (XNIO-1 task-5) JBAS014613: Operation ("full-replace-deployment") failed - address: (undefined) - failure description: {"JBAS014671: Failed services" => {"jboss.undertow.deployment.default-server.default-host./CamundaLearningCamel" => "org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./CamundaLearningCamel: Failed to start service
          Caused by: java.lang.RuntimeException: org.apache.camel.RuntimeCamelException: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Split[{body} -> []] <<< in route: Route(route2)[[From[rest:get:task/all?produces=application%2... because of Definition has no children on Split[{body} -> []]
          Caused by: org.apache.camel.RuntimeCamelException: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Split[{body} -> []] <<< in route: Route(route2)[[From[rest:get:task/all?produces=application%2... because of Definition has no children on Split[{body} -> []]
          Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Split[{body} -> []] <<< in route: Route(route2)[[From[rest:get:task/all?produces=application%2... because of Definition has no children on Split[{body} -> []]
          Caused by: java.lang.IllegalArgumentException: Definition has no children on Split[{body} -> []]"}}
      

3 个答案:

答案 0 :(得分:3)

以下是拆分聚合并转换列表消息的完整示例。

  1. 骆驼分离器提供聚合的内置聚合器 原始交换中的所有拆分消息。所以分离器只是 聚合每个列表(交换)的消息发送“direct:start”。你必须提供一个自定义 聚合策略,因为默认的将使用原始 交换,在我的例子中InOrder。聚合策略是 分裂定义的第二个参数。
  2. 类型转换器让我们有机会使用convertBodyTo DSL。您还可以使用bean,处理器或自定义聚合策略中的所有转换来实现这一目标。

    package org.mydemocamel.app;
    import org.apache.camel.*;
    import org.apache.camel.builder.RouteBuilder;
    import org.apache.camel.component.mock.MockEndpoint;
    import org.apache.camel.processor.aggregate.AggregationStrategy;
    import org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy;
    import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy;
    import org.apache.camel.processor.aggregate.UseOriginalAggregationStrategy;
    import org.apache.camel.support.TypeConverterSupport;
    import org.apache.camel.test.junit4.CamelTestSupport;
    import org.apache.camel.util.toolbox.FlexibleAggregationStrategy;
    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    public class CamelSplitAggregateConvertTest extends CamelTestSupport {
    
        @Produce
        private ProducerTemplate template;
    
        @EndpointInject(uri = "mock:out")
        private MockEndpoint mock;
    
        @Test
        public void testSplitAggregateConvertOrder(){
            InOrder inOrder1 = new InOrder();
            inOrder1.setId("1");
    
            InOrder inOrder2 = new InOrder();
            inOrder2.setId("2");
    
            List<InOrder> inOrderList = new ArrayList<InOrder>();
            inOrderList.add(inOrder1);
            inOrderList.add(inOrder2);
    
            template.sendBody("direct:start", inOrderList);
    
            mock.expectedMessageCount(1);
            Exchange outList = mock.getReceivedExchanges().get(0);
            List<OutOrder> outOrderList = outList.getIn().getBody(List.class);
    
            assertEquals(1, outOrderList.get(0).getId());
            assertEquals(2, outOrderList.get(1).getId());
    
    
        }
    
        @Override
        protected RouteBuilder createRouteBuilder() throws Exception {
            return new RouteBuilder() {
                @Override
                public void configure() throws Exception {
    
                    context.getTypeConverterRegistry().addTypeConverter(OutOrder.class, InOrder.class, new MyOrderTypeConverter());
    
                    from("direct:start")
                    .split(body(), new AggregationStrategy() {
                        @Override
                        public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
                            if (oldExchange == null) {
                                List<OutOrder> orders = new ArrayList<OutOrder>();
                                OutOrder newOrder = newExchange.getIn().getBody(OutOrder.class);
                                orders.add(newOrder);
                                newExchange.getIn().setBody(orders);
                                return newExchange;
                            }
                            List<OutOrder> orders = oldExchange.getIn().getBody(List.class);
                            OutOrder newOutOrder = newExchange.getIn().getBody(OutOrder.class);
                            orders.add(newOutOrder);
                            oldExchange.getIn().setBody(orders);
                            return oldExchange;
                        }
                    })
                    .convertBodyTo(OutOrder.class)
                    .end()  //splitter ends here and the exchange body  is now List<OutOrder> 
                    .to("mock:out");
    
                }
            };
        }
    
        private static class MyOrderTypeConverter extends TypeConverterSupport {
    
            @SuppressWarnings("unchecked")
            public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
                // converter from inorder to outorder bean
                OutOrder order = new OutOrder();
                order.setId(Integer.parseInt(((InOrder) value).getId()));
                return (T) order;
            }
        }
    
        private static class OutOrder {
            private int id;
    
            public void setId(int id) {
                this.id = id;
            }
    
            public int getId() {
                return id;
            }
        }
    
        private static class InOrder {
            private String id;
    
            public void setId(String id) {
                this.id = id;
            }
    
            public String getId() {
                return id;
            }
        }
    }
    

答案 1 :(得分:1)

你是对的是拆分器和聚合器,&#34;拆分聚合请求/回复样本&#34;来自http://camel.apache.org/splitter.html显示了您的需求。

你需要一个&#34;转换&#34;拆分器后的对象列表? 如果是,那么点#34;在聚合策略中使用列表&#34;来自http://camel.apache.org/aggregator2.html看起来正确满足您的需求。

亲切的问候, soilworker

答案 2 :(得分:1)

为了将来参考,您可以使用Java DSL的loop构造迭代列表的另一种方法。这是一个例子:

from("direct:myDirect")
.loop(header("LIST_LENGTH")) // You will set this header in the processor before with the list lenght.
.process(new Processor(){

      @Override
      public void proocess(Exchange arg0){
          MyObj currentElement = (MyObj) arg0.getIn().getBody(List.class).get(LOOP_INDEX);
          // Do your processing here.
      }
})
.end()
.end();

LOOP_INDEX属性将包含当前迭代,从0开始到LIST_LENGHT标头值,因此您可以使用它从列表中获取当前元素。

注意双end()方法调用:一个用于结束循环,另一个用于结束路由。

文档:http://camel.apache.org/loop.html