首页 > 解决方案 > 在 Springboot 中进行请求验证时,响应不符合预期

问题描述

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

客户.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

}

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

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 类

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);
    }
}

客户控制器.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"]
}

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

标签: javaspringspring-bootrequest-validation

解决方案


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

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

同样:

您无法捕获 ConstraintViolationException.class,因为它不会传播到代码的该层,而是被较低层捕获,包装并重新抛出另一种类型。因此,遇到 Web 层的异常不是 ConstraintViolationException。

参考:SpringBoot 不处理 org.hibernate.exception.ConstraintViolationException

正确使用的示例是使用方法 handleMethodArgumentNotValid 并将错误作为正文返回:

@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);
    }

}

推荐阅读