简体   繁体   English

Spring @Valid 消息未通过响应

[英]Spring @Valid Message Not Coming Through in Response

I have a CQRS Rest API using Spring and Axon.我有一个使用 Spring 和 Axon 的 CQRS Rest API。 Validation is setup for inputs using the javax.validation library.使用javax.validation库为输入设置验证。 The validation is working properly, and catching that the 'username' needs to be at least 2 character long.验证工作正常,并发现“用户名”需要至少 2 个字符长。 However the message associated with the failed validation is not showing up in the response to the Post request.但是,与验证失败相关的消息不会显示在对 Post 请求的响应中。

The response is ultimately missing 'errors' and 'message' info and I am not sure why.响应最终缺少“错误”和“消息”信息,我不知道为什么。 Doesn't MethodArgumentNotValidException get pushed to the try-catch block and get handled? MethodArgumentNotValidException不会被推送到 try-catch 块并得到处理吗? If the validation is working properly, why isn't the message going out with the '400' status response?如果验证工作正常,为什么消息没有以“400”状态响应发出?

What am I missing?我错过了什么?

This is the response I am trying to get:这是我试图得到的回应:

{
    "timestamp": "2022-04-24T01:23:27.809+00:00",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "Size.registerUserCommand.user.account.username",
                "Size.user.account.username",
                "Size.username",
                "Size.java.lang.String",
                "Size"
            ],
            "arguments": [
               {
                    "codes": [
                        "registerUserCommand.user.account.username",
                        "user.account.username"
                    ],
                    "arguments": null,
                    "defaultMessage": "user.account.username",
                    "code": "user.account.username"
               },
               2134838498,
               2
           ],
           "defaultMessage": "username must have a minimum of 2 characters",
           "objectName": "registerUserCommand",
           "field": "user.account.username",
           "rejectedValue": "m",
           "bindingFailure": false,
           "code": "Size
        }
    ],
    "message": "Validation failed for object='registerUserCommand'. Error count: 1",
    "path": "/api/v1/registerUser"
}

This is the response I actually get:这是我实际得到的回应:

{
    "timestamp": "2022-04-24T01:23:27.809+00:00",
    "status": 400,
    "error": "Bad Request",
    "message": "",
    "path": "/api/v1/registerUser"
}

Post request that is being sent to the controller:发送到控制器的发布请求:

{
    "user": {
        "firstname": "Mike",
        "lastname": "Jacobs",
        "emailAddress": "mike@spripgbank.com",
        "account": {
            "username": "m",
            "password": "mik959593e0",
            "roles": [
                "READ_PRIVILEGE"
            ]
        }
    }
}

Console output from Post request: Post 请求的控制台输出:

2022-04-24 20:32:21.339  INFO 11040 --- [nio-8081-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-04-24 20:32:21.340  INFO 11040 --- [nio-8081-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-04-24 20:32:21.343  INFO 11040 --- [nio-8081-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 3 ms
2022-04-24 20:32:22.120  WARN 11040 --- [nio-8081-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<com.springbank.user.cmd.api.dto.RegisterUserResponse> com.springbank.user.cmd.api.controllers.RegisterUserController.registerUser(com.springbank.user.cmd.api.commands.RegisterUserCommand): [Field error in object 'registerUserCommand' on field 'user.account.username': rejected value [m]; codes [Size.registerUserCommand.user.account.username,Size.user.account.username,Size.username,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [registerUserCommand.user.account.username,user.account.username]; arguments []; default message [user.account.username],2147483647,2]; default message [username must have a min of 2 characters]] ]

The Controller that accepts the request:接受请求的控制器:

    package com.springbank.user.cmd.api.controllers;

    import com.springbank.user.cmd.api.commands.RegisterUserCommand;
    import com.springbank.user.cmd.api.dto.RegisterUserResponse;
    import org.axonframework.commandhandling.gateway.CommandGateway;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.validation.Valid;
    import java.util.UUID;
    
    @RestController
    @RequestMapping(path = "/api/v1/registerUser")
    public class RegisterUserController {
         private final CommandGateway commandGateway;

         @Autowired
         public RegisterUserController(CommandGateway commandGateway) {
             this.commandGateway = commandGateway;
         }
    
         @PostMapping
         public ResponseEntity<RegisterUserResponse> registerUser(@Valid @RequestBody RegisterUserCommand command) {
             var id = UUID.randomUUID().toString();
             command.setId(id);
    
             try{
                commandGateway.send(command);
                return new ResponseEntity<>(new RegisterUserResponse( id, "User Successfully Registered"), HttpStatus.CREATED);
    
             }catch (Exception e) {
                 var safeErrorMessage = "Error while processing register user request for id - " + id;
                 System.out.println(e.toString());
    
                 return new ResponseEntity<>(new RegisterUserResponse( id, safeErrorMessage), HttpStatus.INTERNAL_SERVER_ERROR);
             }
         }
    }

The Command:命令:

package com.springbank.user.cmd.api.commands;

import com.springbank.user.core.models.User;
import lombok.Builder;
import lombok.Data;
import org.axonframework.modelling.command.TargetAggregateIdentifier;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

@Data
@Builder
public class RegisterUserCommand {

    @TargetAggregateIdentifier
    private String id;
    @NotNull(message = "Need to supply User info")
    @Valid
    private User user;
}

The User model:用户模型:

package com.springbank.user.core.models;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Document(collection = "users")
public class User {
    @Id
    private String id;
    @NotEmpty(message = "firstname is mandatory")
    private String firstname;
    @NotEmpty(message = "lastname is mandatory")
    private String lastname;
    @Email(message = "please provide a valid email")
    private String emailAddress;
    @NotNull(message = "Please provide account Credentials")
    @Valid
    private Account account;
}

Account model where the validation is happening:进行验证的帐户模型:

package com.springbank.user.core.models;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Account {
    @Size(min = 2, message = "username must have a min of 2 characters")
    private String username;
    @Size(min = 7, message = "password must have a min of 7 characters")
    private String password;
    @NotNull(message = "specify at least one user role")
    private List<Role> roles;
}

The RegisterUserResponse:注册用户响应:

package com.springbank.user.cmd.api.dto;


public class RegisterUserResponse extends BaseResponse{
    private String id;

    public RegisterUserResponse(String id, String message) {
        super(message);
        this.id = id;
    }
}

    

The BasicResponse:基本反应:

package com.springbank.user.cmd.api.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class BaseResponse {
    private String Message;
}

Since you annotate the controller method argument with @Valid RegisterUserCommand , the validation of the object will take place before the execution enters your try/catch block.由于您使用@Valid RegisterUserCommand注释控制器方法参数,因此对象的验证将在执行进入您的 try/catch 块之前进行。

If you look at the below method located in ResponseEntityExceptionHandler then you'll see that the default implementation looks like this.如果您查看位于ResponseEntityExceptionHandler中的以下方法,那么您会看到默认实现如下所示。 As you can see, the default is to send null as body, which causes the details to be left out.如您所见,默认情况下将 null 作为正文发送,这会导致细节被遗漏。

protected ResponseEntity<Object> handleMethodArgumentNotValid(
        MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

    return handleExceptionInternal(ex, null, headers, status, request);
}

Hence, if you want to handle that error differently you would need to add a customized exception handling for that exception type and override the default handler.因此,如果您想以不同方式处理该错误,则需要为该异常类型添加自定义异常处理并覆盖默认处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM