Проблема получения MessageAttributes в слушателе SNS / SQS Spring-облака - PullRequest
0 голосов
/ 13 февраля 2019

Я использую spring-boot-1.5.10 и spring-cloud и использую spring-cloud-starter-aws-messaging .Я могу отправить и получить сообщение, но не могу получить атрибуты сообщения SNS.Любая помощь будет действительно заметной.Пожалуйста, найдите код ниже,

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.19.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aws.sample</groupId>
    <artifactId>aws</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aws</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.SR5</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-aws</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-aws-messaging</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

controller.java

@RestController
@RequestMapping(value = "/sns")
@AllArgsConstructor
public class SimpleSnsController {

    private NotificationMessagingTemplate notificationMessagingTemplate;

    @PostMapping("/saveEmployee")
    public String save(@RequestBody Employee employee){
        Map<String,Object> headers = new HashMap<>();
        headers.put("subject", "send employee details to sqs");
        headers.put("name","murugan");
        headers.put("traceId","sample");
        //notificationMessagingTemplate.sendNotification("sample-sns", employee, "send employee details to sqs");

        notificationMessagingTemplate.convertAndSend("sample-sns", employee, headers);
        return "success";
    }

    //@SqsListener(value = "sample-queue")
    @SqsListener(value = "${sqs.consumer.name}")
    public void receiveSnsSqs(String message, @NotificationMessage Employee employee) {
        System.out.println("SNS Consumer received the message::"+message);
        System.out.println("SNS Consumer received the notificationMessage::"+employee);
        //Here i would like to get the message attribute
    }
}

получено сообщение:

{
  "Type" : "Notification",
  "MessageId" : "ba9dab52-aae8-5940-a3e2-ff8c8458ef52",
  "TopicArn" : "arn:aws:sns:XXX",
  "Message" : "{\"name\":\"David\",\"age\":\"31\",\"designation\":\"developer\"}",
  "Timestamp" : "2019-02-13T14:40:48.501Z",
  "SignatureVersion" : "1",
  "Signature" : "XXX",
  "SigningCertURL" : "XXX",
  "UnsubscribeURL" : "XXX",
  "MessageAttributes" : {
    "traceId" : {"Type":"String","Value":"sample"},
    "subject" : {"Type":"String","Value":"send employee details to sqs"},
    "name" : {"Type":"String","Value":"murugan"},
    "id" : {"Type":"String","Value":"68bf17f2-0f88-4cc5-0609-0ccd42b19ce4"},
    "SenderId" : {"Type":"String","Value":"David"},
    "contentType" : {"Type":"String","Value":"application/json;charset=UTF-8"},
    "timestamp" : {"Type":"Number.java.lang.Long","Value":"1550068848349"}
  }
}

Я хотел бы получить атрибут messageAttribute, например name, traceId в приемнике, который я установил в производителе SNS.Я много просмотрел, но не смог найти никакого решения.Любая помощь будет действительно заметной.

1 Ответ

0 голосов
/ 25 апреля 2019

Попробуйте включить необработанную доставку сообщений.Он не будет переносить исходное сообщение SNS и позволит вам получать сообщение и заголовки с помощью обычных аннотаций @Header, @ Headers

https://docs.aws.amazon.com/sns/latest/dg/sns-large-payload-raw-message-delivery.html

Если вы не можете использовать Raw MessageПри доставке я сделал новую аннотацию, чтобы помочь в получении заголовка уведомления

@ NotificationHeader

import org.springframework.core.annotation.AliasFor;
import org.springframework.messaging.handler.annotation.ValueConstants;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface NotificationHeader {
    /**
     * Alias for {@link #name}.
     */
    @AliasFor("name")
    String value() default "";

    /**
     * The name of the request header to bind to.
     */
    @AliasFor("value")
    String name() default "";

    /**
     * Whether the header is required.
     * <p>Default is {@code true}, leading to an exception if the header is
     * missing. Switch this to {@code false} if you prefer a {@code null}
     * value in case of a header missing.
     * @see #defaultValue
     */
    boolean required() default true;

    /**
     * The default value to use as a fallback.
     * <p>Supplying a default value implicitly sets {@link #required} to {@code false}.
     */
    String defaultValue() default ValueConstants.DEFAULT_NONE;
}

* NotificationHeaderArgumentResolver

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.cloud.aws.messaging.support.NotificationMessageArgumentResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.support.HeaderMethodArgumentResolver;
import org.springframework.util.Assert;

public class NotificationHeaderArgumentResolver extends HeaderMethodArgumentResolver {

    private NotificationMessageArgumentResolver notificationArgumentResolver;

    public NotificationHeaderArgumentResolver(ConversionService cs, ConfigurableBeanFactory beanFactory) {
        super(cs, beanFactory);

        notificationArgumentResolver = new NotificationMessageArgumentResolver(new NoOptMessageConverter());
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(NotificationHeader.class);
    }

    @Override
    @Nullable
    protected Object resolveArgumentInternal(MethodParameter parameter, Message<?> message, String name)
            throws Exception {

        Message notificationMessage = (Message) notificationArgumentResolver.resolveArgument(parameter, message);

        return super.resolveArgumentInternal(parameter, notificationMessage, name);
    }

    @Override
    protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
        NotificationHeader annotation = parameter.getParameterAnnotation(NotificationHeader.class);
        Assert.state(annotation != null, "No Header annotation");
        return new HeaderNamedValueInfo(annotation);
    }

    private static class HeaderNamedValueInfo extends NamedValueInfo {

        private HeaderNamedValueInfo(NotificationHeader annotation) {
            super(annotation.name(), annotation.required(), annotation.defaultValue());
        }
    }

    public static class NoOptMessageConverter implements MessageConverter {
        @Override
        public Message<?> toMessage(Object payload, @Nullable MessageHeaders headers) {
            return null;
        }

        @Override
        public Object fromMessage(Message<?> message, Class<?> targetClass) {
            return message;
        }
    }
}

* NotificationHeaderConfiguration

    @Bean
    public QueueMessageHandlerFactory queueMessageHandlerFactory() {
        QueueMessageHandlerFactory queueMessageHandlerFactory = new QueueMessageHandlerFactory();

        queueMessageHandlerFactory.setArgumentResolvers(Collections.singletonList(new NotificationHeaderArgumentResolver(null, null)));

        return queueMessageHandlerFactory;
    }
...