org.axonframework.commandhandling.distributed.CommandDispatchException: 该命令不包含路由键

org.axonframework.commandhandling.distributed.CommandDispatchException: The command does not contain a routing key

我正在开发 Spring Boot + Axon + CQRS 示例。在此示例中,点击

curl -H "Content-Type : application/json" -d '{"company" : "apple", "description" : "My Kep"}' http://localhost:8080

我已经启动了以下服务器 (axonserver-4.0.jar),我看不到修复错误的方法。如果您需要任何其他详细信息,请告诉我?

-rw-r--r-- 1 user 1049089     6153 Oct 17 13:11 README.txt
-rw-r--r-- 1 user 1049089    16934 Oct 17 19:50 LICENSE.txt
drwxr-xr-x 1 user 1049089        0 Oct 22 22:26 kubernetes/
-rwxr-xr-x 1 user 1049089  3290320 Oct 22 22:26 axonserver-cli-4.0.jar*
-rwxr-xr-x 1 user 1049089 83303084 Oct 22 22:26 axonserver-4.0.jar*
drwxr-xr-x 1 user 1049089        0 Oct 22 22:26 ../
drwxr-xr-x 1 user 1049089        0 Oct 30 16:54 data/
-rw-r--r-- 1 user 1049089       13 Oct 30 16:54 AxonIQ.pid
drwxr-xr-x 1 user 1049089        0 Oct 30 16:54 ./

我收到以下错误:

org.axonframework.commandhandling.distributed.CommandDispatchException: The command [org.demo.DemoComplaintsApplication$FileComplaintCommand] does not contain a routing key.
    at org.axonframework.commandhandling.distributed.AbstractRoutingStrategy.getRoutingKey(AbstractRoutingStrategy.java:57) ~[axon-messaging-4.0.jar:4.0]
    at org.axonframework.axonserver.connector.command.AxonServerCommandBus.dispatch(AxonServerCommandBus.java:114) ~[axon-server-connector-4.0.jar:4.0]
    at org.axonframework.commandhandling.gateway.AbstractCommandGateway.send(AbstractCommandGateway.java:75) [axon-messaging-4.0.jar:4.0]
    at org.axonframework.commandhandling.gateway.DefaultCommandGateway.send(DefaultCommandGateway.java:78) [axon-messaging-4.0.jar:4.0]
    at org.axonframework.commandhandling.gateway.DefaultCommandGateway.send(DefaultCommandGateway.java:134) [axon-messaging-4.0.jar:4.0]
    at org.demo.DemoComplaintsApplication$ComplaintAPI.fileCompplaint(DemoComplaintsApplication.java:47) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_162]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_162]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_162]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_162]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_162]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_162]

pom.xml

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.axonframework</groupId>
            <artifactId>axon-spring-boot-starter</artifactId>
            <version>4.0</version>
        </dependency>
        <dependency>
            <groupId>org.axonframework</groupId>
            <artifactId>axon-core</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>runtime</scope>
        </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>

MainApp

@SpringBootApplication
public class DemoComplaintsApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoComplaintsApplication.class, args);
    }

    @RestController
    public static class ComplaintAPI {

        private final ComplaintQueryObjectRepository repostory;
        private final CommandGateway commandGateway;

        public ComplaintAPI(ComplaintQueryObjectRepository repostory, CommandGateway commandGateway) {
            this.repostory = repostory;
            this.commandGateway = commandGateway;
        }

        @PostMapping
        public CompletableFuture<String> fileCompplaint(@RequestBody Map<String, String> request) {
            String id = UUID.randomUUID().toString();
            return commandGateway
                    .send(new FileComplaintCommand(id, request.get("company"), request.get("description")));
        }

        @GetMapping
        public List<ComplaintQueryObject> findAll() {
            return repostory.findAll();
        }

        @GetMapping("/{id}")
        public ComplaintQueryObject find(@PathVariable String id) {
            //return repostory.findOne(id);
            return repostory.findById(id).get();
        }
    }

    @Aggregate
    public static class Complaint {
        @AggregateIdentifier
        private String complaintId;

        public Complaint() {
            super();
        }

        @CommandHandler
        public Complaint(FileComplaintCommand command) {
            apply(new ComplaintFileEvent(command.getId(), command.getCompany(), command.getDescription()));
        }

        @EventSourcingHandler
        public void on(ComplaintFileEvent event) {
            this.complaintId = event.getId();
        }
    }

    @Component
    public static class ComplaintQueryObjectUpdater {

        private final ComplaintQueryObjectRepository repository;

        public ComplaintQueryObjectUpdater(ComplaintQueryObjectRepository repository) {
            this.repository = repository;
        }

        @EventHandler
        public void on(ComplaintFileEvent event) {
            repository.save(new ComplaintQueryObject(event.getId(), event.getCompany(), event.getDescription()));
        }
    }

    public static class FileComplaintCommand {
        private String id;
        private String company;
        private String description;

        public FileComplaintCommand(String id, String company, String description) {
            super();
            this.id = id;
            this.company = company;
            this.description = description;
        }

        public String getId() {
            return id;
        }

        public String getCompany() {
            return company;
        }

        public String getDescription() {
            return description;
        }

    }

Curl 命令

$ curl -H "Content-Type:application/json" -d '{"company" : "apple", "description" : "My Kep"}' localhost:8080 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 392 0 345 100 47 11129 1516 --:--:-- --:--:-- --:--:-- 12645{"timestamp":1540911397422,"status":500,"error":"Internal Server Error","exception":"java.util.concurrent.CompletionException","message":"AxonServerCommandDispatchException{message=The command [org.demo.DemoComplaintsApplication$FileComplaintCommand] does not contain a routing key., errorCode='AXONIQ-4003', server='10296@841DTN2'}","path":"/"}

错误The command [...] does not contain a routing key是由于您的命令中缺少注释@TargetAggregateIdentifier的字段造成的。在轴突 LocalCommandBus 中,这仅在针对现有聚合体的命令中是必需的。在分布式版本中,创建聚合的命令也是必需的,因为 Axon 服务器命令总线查看它来做出路由决策。

因此,将 @TargetAggregateIdentifier 添加到 FileComplaintCommand 中的 id 字段。