在 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,因此没有调用您创建的自定义方法。
还有:
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);
}
}
我正在尝试使用 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,因此没有调用您创建的自定义方法。
还有:
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);
}
}