缺少必需的请求 body,但它在那里

Required request body is missing, but it's there

我有一个带有 UserStateDTO 请求 body 的 POST 端点。 Junit 测试运行良好;但是,我无法在浏览器中使用它,因为“缺少必需的请求 body”。如您所见, body 在那里... 这让我疯狂。请在下面找到错误和片段。

org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public void .....UserRestController.setState(UserStateDTO)
@PostMapping(value = "/state", consumes = MediaType.APPLICATION_JSON_VALUE)
public void setState(@RequestBody UserStateDTO userStateDTO) {
    if (userStateDTO != UserStateDTO.ACTIVE && userStateDTO != UserStateDTO.DISABLED) {
        throw new BusinessException(GeneralErrors.INVALID_REQUEST);
    }
    UserDTO userDTO = userService.getUser();
    userDTO.setState(userStateDTO);
    userService.updateUser(userDTO);
}
public enum UserStateDTO {
    ACTIVE("ACTIVE"),
    DISABLED("DISABLED");

    private final String state;

    private static final Map<String, UserStateDTO> states = new HashMap<>();

    UserStateDTO(String state) {
        this.state = state;
    }

    static {
        for (UserStateDTO u : UserStateDTO.values()) {
            states.put(u.getValue(), u);
        }
    }

    @JsonValue
    public String getValue() {
        return state;
    }

    @JsonCreator
    public static UserStateDTO fromValue(String state) {
        return states.get(StringUtils.upperCase(state));
    }

}

fetch("http://localhost:4200/user/state", {
  "headers": {
    "accept": "application/json, text/plain, */*",
    "accept-language": "en,hu;q=0.9,nb;q=0.8",
    "content-type": "application/json",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin",
    "x-xsrf-token": "-"
  },
  "referrer": "http://localhost:4200/",
  "referrerPolicy": "strict-origin-when-cross-origin",
  "body": "{\"state\":\"ACTIVE\"}",
  "method": "POST",
  "mode": "cors",
  "credentials": "include"
});

您好,欢迎来到 Whosebug。

这是您的问题的解决方案。您应该使用具有 UserStateDTO 类型属性 state 的 class,因为您的请求是 {"state" : "ACTIVE"}

新建一个 class 名为 UserStateWrapperDto

public class UserStateWrapperDto {

    private UserStateDTO state;

    public UserStateDTO getState() {
        return state;
    }

    public void setState(UserStateDTO state) {
        this.state = state;
    }
}

然后更改您的控制器方法以获取 UserStateWrapperDto

类型的参数
    @PostMapping(value = "/state", consumes = MediaType.APPLICATION_JSON_VALUE)
    public void setState(@RequestBody UserStateWrapperDto userStateWrapperDTO) {
        if (userStateWrapperDTO.getState() != UserStateDTO.ACTIVE && userStateWrapperDTO.getState()  != UserStateDTO.DISABLED) {
            throw new BusinessException(GeneralErrors.INVALID_REQUEST);
        }
       UserDTO userDTO = userService.getUser();
        userDTO.setState(userStateDTO.getState());
        userService.updateUser(userDTO);
    }
}

通过此请求使用您的网络服务:

{
    "state" : "ACTIVE"
}

谢谢

您必须在枚举中添加 getState() 方法。正确代码如下:

public enum UserStateDTO {
  ACTIVE("ACTIVE"),
  DISABLED("DISABLED");

  private final String state;

  private static final Map<String, UserStateDTO> states = new HashMap<>();

  UserStateDTO (String state) {
    this.state = state;
  }

  static {
    for (UserStateDTO u : UserStateDTO.values()) {
        states.put(u.getValue(), u);
    }
  }

  public String getState() {
    return state;
  }

  @JsonValue
  public String getValue() {
    return state;
  }

  @JsonCreator
  public static UserStateDTO fromValue(String state) {
    return states.get(StringUtils.upperCase(state));
  }
}

或者您可以在方法 fromValue() 内部添加注解 @JsonProperty("state"),它绑定您的请求正文值而不 getter。 正确方法如下:

  @JsonCreator
  public static UserStateDTO fromValue(@JsonProperty("state") String state) {
    return states.get(StringUtils.upperCase(state));
  }