[英]Spring Boot: Is it possible to consume @RequestParam's as json?
[英]Spring Boot Validate JSON Mapped via ObjectMapper GET @RequestParam
驗證在我使用com.fasterxml.jackson.databind.ObjectMapper映射的春季啟動中傳遞到GET REST控制器中的復雜JSON對象的最簡單方法是什么?
這是控制器:
@RestController
@RequestMapping("/products")
public class ProductsController {
@GetMapping
public ProductResponse getProducts(
@RequestParam(value = "params") String requestItem
) throws IOException {
final ProductRequest productRequest =
new ObjectMapper()
.readValue(requestItem, ProductRequest.class);
return productRetriever.getProductEarliestAvailabilities(productRequest);
}}
我要驗證的DTO請求對象:
public class ProductRequest {
private String productId;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}}
我當時在考慮在請求DTO上使用注釋,但是當我這樣做時,它們不會觸發任何類型的異常,即@NotNull 。 我試着在控制器使用@Validated以及@Valid在@RequestParam並沒有什么導致了驗證觸發的各種組合。
以我的觀點, Hibernate Bean Validator
可能是隨時隨地驗證Bean的帶annotated
字段的最便捷方法之一。 就像setup
和forget
我按照此處給出的文檔中的說明進行操作
我使用Gradle,所以我將添加所需的依賴項,如下所示
// Hibernate Bean validator
compile('org.hibernate:hibernate-validator:5.2.4.Final')
我按照文檔中的描述設置了一個bean驗證器接口,然后使用它來驗證所有帶注釋的東西
public interface CustomBeanValidator {
/**
* Validate all annotated fields of a DTO object and collect all the validation and then throw them all at once.
*
* @param object
*/
public <T> void validateFields(T object);
}
實現上述接口,如下所示
@Component
public class CustomBeanValidatorImpl implements CustomBeanValidator {
ValidatorFactory valdiatorFactory = null;
public CustomBeanValidatorImpl() {
valdiatorFactory = Validation.buildDefaultValidatorFactory();
}
@Override
public <T> void validateFields(T object) throws ValidationsFatalException {
Validator validator = valdiatorFactory.getValidator();
Set<ConstraintViolation<T>> failedValidations = validator.validate(object);
if (!failedValidations.isEmpty()) {
List<String> allErrors = failedValidations.stream().map(failure -> failure.getMessage())
.collect(Collectors.toList());
throw new ValidationsFatalException("Validation failure; Invalid request.", allErrors);
}
}
}
我上面使用的ValidationsFatalException
是擴展RuntimeException
的自定義異常類。 如您所見,如果DTO有多個驗證錯誤,我將傳遞一條消息和一個violations
列表。
public class ValidationsFatalException extends RuntimeException {
private String message;
private Throwable cause;
private List<String> details;
public ValidationsFatalException(String message, Throwable cause) {
super(message, cause);
}
public ValidationsFatalException(String message, Throwable cause, List<String> details) {
super(message, cause);
this.details = details;
}
public List<String> getDetails() {
return details;
}
}
為了測試這是否有效,我從字面上使用您的代碼進行測試,這就是我所做的
CustomBeanValidator
並觸發它的validateFields
方法,將productRequest
傳遞給它,如下所示 ProductRequest
類 @NotNull
和@Length(min=5, max=10)
注釋了productId
Postman
發出的GET
請求的params
是url-encoded
json主體 假設CustomBeanValidator
在控制器中是自動CustomBeanValidator
的,那么在構造productRequest
對象之后,觸發驗證如下。
beanValidator.validateFields(productRequest);
如果基於使用的注釋有任何違規,以上內容將引發異常。
如標題中所述,我使用ExceptionController
來處理應用程序中的異常。
這是ValidationsFatalException
映射到我的exception handler
的框架的方式,然后我更新消息並根據異常類型設置所需的狀態代碼並返回自定義對象(即,您在下面看到的json)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({SomeOtherException.class, ValidationsFatalException.class})
public @ResponseBody Object handleBadRequestExpection(HttpServletRequest req, Exception ex) {
if(ex instanceof CustomBadRequestException)
return new CustomResponse(400, HttpStatus.BAD_REQUEST, ex.getMessage());
else
return new DetailedCustomResponse(400, HttpStatus.BAD_REQUEST, ex.getMessage(),((ValidationsFatalException) ex).getDetails());
}
原始params = {"productId":"abc123"}
網址編碼的parmas = %7B%22productId%22%3A%22abc123%22%7D
最終http://localhost:8080/app/product?params=%7B%22productId%22%3A%22abc123%22%7D
網址: http://localhost:8080/app/product?params=%7B%22productId%22%3A%22abc123%22%7D
結果:一切都很好。
原始params = {"productId":"ab"}
網址編碼的parmas = %7B%22productId%22%3A%22ab%22%7D
最終http://localhost:8080/app/product?params=%7B%22productId%22%3A%22ab%22%7D
網址: http://localhost:8080/app/product?params=%7B%22productId%22%3A%22ab%22%7D
結果:
{
"statusCode": 400,
"status": "BAD_REQUEST",
"message": "Validation failure; Invalid request.",
"details": [
"length must be between 5 and 10"
]
}
您可以擴展Validator
實現以提供field vs message
錯誤消息的映射。
你的意思是這樣嗎?
@RequestMapping("/products")
public ResponseEntity getProducts(
@RequestParam(value = "params") String requestItem) throws IOException {
ProductRequest request = new ObjectMapper().
readValue(requestItem, ProductRequest.class);
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<ProductRequest>> violations
= validator.validate(request);
if (!violations.isEmpty()) {
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok().build();
}
public class ProductRequest {
@NotNull
@Size(min = 3)
private String id;
public String getId() {
return id;
}
public String setId( String id) {
return this.id = id;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.