Apache -camel: Как обработать объект json (отправленный curl) в заголовки? - PullRequest
1 голос
/ 17 февраля 2020

У меня есть приложение для весенней загрузки с apache верблюдом. В этом у меня есть верблюжий контекст. Я пытаюсь отправить json через curl со значением пары ключей и обработать его по маршруту.

Отправка данных:

curl --header "Content-Type: application/json" -X POST -d '{"msgId=EB2C7265-EF68-4F8F-A709-BEE2C52E842B", "ticket":"ERR001"}' http://lcalhost:8888/api/erroradmin

Camel-context. xml:

<?xml version="1.0" encoding="utf-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" 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.xsd         http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
        <camelContext xmlns="http://camel.apache.org/schema/spring" useMDCLogging="true">
            <properties>
                <property key="CamelLogEipName" value="ThisLogger"/>
            </properties>
            <dataFormats>
                <!-- here we define a Json data format with the id jack and that it should use the TestPojo as the class type when
                     doing unmarshal. The unmarshalTypeName is optional, if not provided Camel will use a Map as the type -->
                <json id="jack" library="Jackson" unmarshalTypeName="java.util.HashMap"/>
            </dataFormats>

            <restConfiguration component="jetty" port="8888" bindingMode="json">
                <dataFormatProperty key="prettyPrint" value="true"/>
            </restConfiguration>

            <rest path="/api/erroradmin">
                <get uri="{id}">
                    <to uri="direct:processErrorAdminGet"/>
                </get>
                <post>
                    <to uri="direct:processErrorAdminPost"/>
                </post>
            </rest>

            <route id="processErrorAdminPost">
                <from uri="direct:processErrorAdminPost"/>
                <log message="Route(processErrorAdminPost): ${body}"/>
                <unmarshal>
                    <custom ref="jack"/>
                </unmarshal>
                <log message="Route(processErrorAdminPost): ${body}"/>

            </route>
        </camelContext>
    </beans>

Я получаю следующую Stacktrace:

org. apache .camel.InvalidPayloadException: Нет доступного тела типа: java .io.InputStream, но имеет значение : {msgId = D507B9EE-176D-4F3 C -88E7-9E36CC2B9731, ticket = ERR001} типа: java .util.LinkedHashMap on: HttpMessage@0x28c1a31a. Причина: преобразователь типов недоступен для преобразования из типа: java .util.LinkedHashMap к необходимому типу: java .io.InputStream со значением {msgId = D507B9EE-176D-4F3 C -88E7-9E36CC2B9731, ticket = ERR001}. Обмен [09395660-c947-47f1-b00f-d0d3030a39d1]. Вызывается: [org. apache .camel.NoTypeConversionAvailableException - нет доступных преобразователей типов для преобразования из типа: java .util.LinkedHashMap в требуемый тип: java .io.InputStream со значением {msgId = D507B9EE-176D -4F3 C -88E7-9E36CC2B9731, билет = ERR001}]

Ответы [ 2 ]

1 голос
/ 20 февраля 2020

После поиска и чтения некоторое время я нашел решение.

Способ сделать это - использовать JsonPath. Сейчас в Java DSL есть много примеров, но в XML DSL их немного. Наконец-то я нашел рабочий пример.

Мой верблюжий контекст теперь выглядит так:

<camelContext xmlns="http://camel.apache.org/schema/spring" useMDCLogging="true" streamCache="true">
    <properties>
        <property key="CamelLogEipName" value="SomeLogger"/>
    </properties>

     <dataFormats>
            <json id="json" library="Jackson"/>     
     </dataFormats>

    <restConfiguration component="jetty" port="9090" >
        <dataFormatProperty key="prettyPrint" value="true"/>
    </restConfiguration>

    <rest path="/api/erroradmin">
        <post>
            <to uri="direct:error" />
        </post>
    </rest>

    <route id="error">
        <from uri="direct:error"/>
        <log message="Route(error): ${body}"/>

        <setHeader headerName="errMessageId">
            <jsonpath suppressExceptions="true">$[0].msgId</jsonpath>
        </setHeader>
        <setHeader headerName="errTicket">
            <jsonpath suppressExceptions="true">$[0].ticket</jsonpath>
        </setHeader>               
        <setHeader headerName="errHandled">
            <jsonpath suppressExceptions="true">$[0].handled</jsonpath>
        </setHeader>

        <log message="Route(error): Header name: errMessageId -> ${header[errMessageId]}"/>
        <log message="Route(error): Header name: errTicket -> ${header[errTicket]}"/>
        <log message="Route(error): Header name: errHandled -> ${header[errHandled]}"/>
    </route>
</camelContext>

При доступе к ключу соответствующего узла я получаю значение во вновь установленном заголовке.

JSON отправляется так: вы отправляете:

curl -XPOST http://localhost: 9090 / api / erroradmin -d '[ {"var1": 10, "var2": 20}] '--header "Content-Type: application / json"

Используемые зависимости:

    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-jackson</artifactId>
        <version>${camel.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-jsonpath</artifactId>
        <version>${camel.version}</version>
    </dependency>
  </dependencies>

Надеюсь, что это кому-то пригодится в будущем!

РЕДАКТИРОВАТЬ: Обязательно используйте верблюд 2.25.0 и выше. Очевидно, что при использовании camel- json 2.24.1 вместе с той же версией ядра camel- json загрузит устаревшую зависимость под названием json -smart, которая пропускает некоторые классы для правильной работы JsonPath.

1 голос
/ 18 февраля 2020

Добро пожаловать в Stackoverflow! Я твердо верю, что упоминание bindingMode="json" в строке 13 является root причиной этого сбоя. В руководстве написано

При использовании привязки вы также должны указать тип POJO для сопоставления. Это является обязательным для входящих сообщений и необязательным для исходящих.

Я действительно боюсь XML DSL, но вот приблизительный эквивалент остальных DSL в Java.

@Component
@Slf4j
public class MySpringBootRouter extends RouteBuilder {

    @Override
    public void configure() {

        restConfiguration()
                .component("undertow")
                .host("127.0.0.1")
                .port(9090)
                //This works only when a POJO mapping is possible - Ref: https://camel.apache.org/manual/latest/rest-dsl.html
                //<quote>When using binding you must also configure what POJO type to map to. This is mandatory for incoming messages, and optional for outgoing.</quote>
                //.bindingMode(RestBindingMode.json)
                .dataFormatProperty("prettyPrint", "true");


        rest("/api")
                .post("/erroradmin")
                .to("direct:postError")

                .get("/erroradmin/{id}").to("direct:getError");

        from("direct:getError")
                .process(exchange -> {
                    exchange.getMessage().setBody(("{'messageID':'" + UUID.randomUUID().toString() + "','ticketID':'1234'}"));
                });

        from("direct:postError")
                .unmarshal()
                .json(JsonLibrary.Jackson)
                .process(exchange -> {
                    log.info("Type of incoming body:{}", exchange.getIn().getBody().getClass().getName());
                    log.info("Incoming body:{}", exchange.getIn().getBody());
                }).transform().constant("{'httpResponse:200':'OK'}");
    }

}

Как только это произойдет, и я отправлю полезную нагрузку с помощью cURL, как показано ниже

curl -d '{"msgId":"EB2C7265-EF68-4F8F-A709-BEE2C52E842B", "ticket":"ERR001"}' -H "Content-Type: application/json" -X POST http://localh
ost:9090/api/erroradmin

В журналах вы увидите что-то подобное ниже

2020-02-18 11:44:13.032  INFO 2708 --- [  XNIO-1 task-4] o.a.c.community.so.MySpringBootRouter    : Type of incoming body:java.util.LinkedHashMap
2020-02-18 11:44:13.032  INFO 2708 --- [  XNIO-1 task-4] o.a.c.community.so.MySpringBootRouter    : Incoming body:{msgId=EB2C7265-EF68-4F8F-A709-BEE2C52E842B, ticket=ERR001}

О, кстати, Ваш исходный JSON груз был поврежден. Весь проект Java доступен здесь , если вы будете sh играть


Редактировать: дополнительный шаг обработки заголовка

        from("direct:postError")
                .unmarshal()
                .json(JsonLibrary.Jackson)
                .process(exchange -> {
                    LinkedHashMap map = exchange.getIn().getBody(LinkedHashMap.class);
                    map.keySet().stream().forEach( item -> exchange.getIn().setHeader(item.toString(),map.get(item)));
                })
//This step is just to print the Headers. Doesnt do anything useful
                .process( exchange -> {
                    log.info(String.valueOf(exchange.getIn().getHeaders()));
                })
                .transform().constant("{'httpResponse:200':'OK'}");
...