如果RequestBody参数的某些属性为null,如何返回400 HTTP错误代码?

Neu*_*ino 5 java rest spring spring-mvc jackson

我有以下示例:

这是请求正文:

public class UserLoginData
    implements Serializable {

    private static final long serialVersionUID = 1L;

    private String username;
    private String password;
    //... getter and setters
}
Run Code Online (Sandbox Code Playgroud)

这是控制器:

@RequestMapping(value = {"/login"}, method = RequestMethod.POST)
@ResponseBody
public LoginResponse login(@RequestBody(required = true) UserLoginData loginData){
    //... some code
 }
Run Code Online (Sandbox Code Playgroud)

这就是我调用服务的方式:

POST /login
{"username":"neuquino"}
Run Code Online (Sandbox Code Playgroud)

我希望Spring返回HTTP 400 BAD REQUEST错误,因为密码丢失了.但不是这样,它返回HTTP 500 INTERNAL SERVER错误,带有以下堆栈跟踪:

java.lang.NullPointerException
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:948) ~[spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838) ~[spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
    ...
Run Code Online (Sandbox Code Playgroud)

如何向Spring指定用户名和密码是请求正文中的必填字段?

Neu*_*ino 7

@ Bart的回答对于找到我的最终解决方案非常有用:

public class UserLoginData
    implements Serializable {

    private static final long serialVersionUID = 1L;

    @NotNull
    @NotBlank
    private String username;

    @NotNull
    @NotBlank
    private String password;
    //... getter and setters
}
Run Code Online (Sandbox Code Playgroud)

在我的控制器上我有:

public LoginResponse login(
        @RequestBody(required = true) @Valid UserLoginData loginData){
    //... login code
}
Run Code Online (Sandbox Code Playgroud)

直到这里非常相似,但它更清晰,因为控制器的方法没有错误验证.取而代之的是,我使用了另一个带有ControllerAdvice注释的类

@ControllerAdvice
public class RestErrorHandler {

    private MessageSource messageSource;

    @Autowired
    public RestErrorHandler(@Qualifier("messageSource") MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ValidationError processValidationError(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();

        return this.processFieldErrors(fieldErrors);
    }

    private ValidationError processFieldErrors(List<FieldError> fieldErrors) {
        ValidationError dto = new ValidationError();

        for (FieldError fieldError : fieldErrors) {
            String localizedErrorMessage = this.resolveLocalizedErrorMessage(fieldError);
            dto.getErrors().put(fieldError.getField(), localizedErrorMessage);
        }

        return dto;
    }

    private String resolveLocalizedErrorMessage(FieldError fieldError) {
        Locale currentLocale = LocaleContextHolder.getLocale();
        String localizedErrorMessage = this.messageSource.getMessage(fieldError, currentLocale);

        return localizedErrorMessage;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我的服务正在返回:

{
  "errors":{
    "country":"country cannot be null"
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望它可以帮助别人.

为了得到这个解决方案,我也使用了这篇文章中的内容.