在 Springboot 中做请求验证时,响应不符合预期

While Doing Request Validation in Springboot, Response is not as expected

我正在尝试使用 hibernate-validator 验证 json-resquest,它按预期工作,但邮递员中没有响应。

Customer.java

import java.time.LocalDate;
import java.util.List;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "cin", "firstName"})
public class Customer {

    @JsonProperty("cin")
    private String cin;

    @JsonProperty("firstName")
    @NotEmpty(message = "First Name must have some values")
    @Size(min = 2, message = "First Name must greater or equal to 2 characters")
    private String firstName;


//getters and setters

}

错误class - 将错误包装在一个对象中。

public class Errors {

    private Integer status;
    private String message;
    private List<String> details;

    public Errors(Integer status, String message, List<String> details) {
        super();
        this.status = status;
        this.message = message;
        this.details = details;
    }
    
// Getters and Setters

}

ControllerAdvice class

import java.util.List;
import java.util.stream.Collectors;

import javax.validation.ConstraintViolationException;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import com.ecommerce.ms.customer.model.Errors;

@ControllerAdvice
@ResponseBody
public class CustomerExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value=ConstraintViolationException.class)
    public final ResponseEntity<Errors> handleConstraintViolation(ConstraintViolationException ex, WebRequest request) {
        List<String> details = ex.getConstraintViolations().parallelStream().map(e -> e.getMessage())
                .collect(Collectors.toList());
        Errors error = new Errors(HttpStatus.BAD_REQUEST.value(), "Request Validation Error", details);
        return ResponseEntity.badRequest().body(error);
    }
}

CustomerController.java

 * 
 */

import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;
import javax.ws.rs.core.MediaType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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 com.ecommerce.ms.customer.api.service.CustomerService;
import com.ecommerce.ms.customer.model.Customer;

@RestController
@RequestMapping("/api/customers")
public class CustomerController {

    @Autowired
    private CustomerService customerService;

    @GetMapping("/status")
    public String getStatus() {
        return "ok";
    }

    @PostMapping(consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
    public ResponseEntity<Customer> addCustomer(@Valid @RequestBody Customer customer) {
        return ResponseEntity.accepted().body(customerService.addCustomer(customer));
    }
}

已添加 Hibernate-validator pom.xml,我期待以下原因。

{
   "status":400,
"message": "Request Validation Error",
"details":["First Name must greater or equal to 2 characters"]
}

我正在尝试获得正确的响应正文,但我在邮递员中找不到它。

查看 ResponseEntityExceptionHandler 没有这样的方法来处理 ConstraintValidationExceptions,因此没有调用您创建的自定义方法。

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.html

还有:

You cannot catch ConstraintViolationException.class because it's not propagated to that layer of your code, it's caught by the lower layers, wrapped and rethrown under another type. So that the exception that hits your web layer is not a ConstraintViolationException.

参考:SpringBoot doesn't handle org.hibernate.exception.ConstraintViolationException

正确用法的一个示例是使用方法 handleMethodArgumentNotValid 和 return 错误作为正文:

@RestControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler{

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

        Map<String, Object> responseBody = new LinkedHashMap<>();

        List<String> allErrors = new ArrayList<>();
        ex.getBindingResult().getAllErrors().forEach(error -> allErrors.add(error.getDefaultMessage()));
        responseBody.put("Errors:", allErrors);

        return new ResponseEntity<>(responseBody, headers, status);
    }

}