简体   繁体   English

Spring Boot 如何返回我自己的验证约束错误消息

[英]Spring Boot how to return my own validation constraint error messages

I need to have my own error response body when something goes wrong with my request and I am trying to use the @NotEmpty constraint message attribute to return the error message,当我的请求出现问题时,我需要有自己的错误响应正文,并且我正在尝试使用@NotEmpty约束消息属性来返回错误消息,

This is my class that returns the error message using the body that I need:这是我的类,它使用我需要的正文返回错误消息:

package c.m.nanicolina.exceptions;


import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class CustomResponseEntityExceptionHandler {

    @ExceptionHandler(value = {MissingServletRequestParameterException.class})
    public ResponseEntity<ApiError> handleConflict(MissingServletRequestParameterException ex, WebRequest request) {
        ApiError apiError = new ApiError(ex.getMessage(), ex.getMessage(), 1000);
        return new ResponseEntity<ApiError>(apiError, null, HttpStatus.BAD_REQUEST);
    }
}

With this CustomResponseEntityExceptionHandler I can return my own response body in case of validation errors.有了这个CustomResponseEntityExceptionHandler我可以在验证错误的情况下返回我自己的响应正文。

What I am trying now is to get the message from the validation constraints.我现在正在尝试的是从验证约束中获取消息。

This is my controller with the NotEmpty constraint:这是我的带有NotEmpty约束的控制器:

package c.m.nanicolina.controllers;

import c.m.nanicolina.models.Product;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotEmpty;

@RestController
public class MinimumStockController {

    @RequestMapping(value = "/minimumstock")
    public Product product(
            @RequestParam(value = "product.sku") @NotEmpty(message = "Product.sku cannot be empty") String sku,
            @RequestParam(value = "stock.branch.id") String branchID) {
        return null;
    }
}

In my exception, I can't find a way to get that message Product.sku cannot be empty and show it in my error response.在我的例外情况下,我找不到获取该消息的方法Product.sku cannot be empty并在我的错误响应中显示它。

I have also checked the class MissingServletRequestParameterException and there is the method getMessage which is returning the default message.我还检查了类MissingServletRequestParameterException并且有返回默认消息的方法getMessage

Yes it is doable & spring very well supports it.是的,它是可行的,弹簧很好地支持它。 You are just missing some configuration to enable it in spring.您只是缺少一些配置以在 spring 中启用它。

  • Use Spring @Validated annotation to enable spring to validate controller使用 Spring @Validated注解启用 spring 来验证控制器
  • Handle ConstraintViolationException in your ControllerAdvice to catch all failed validation messages.处理ControllerAdvice ConstraintViolationException以捕获所有失败的验证消息。
  • Mark required=false in @RequestParam , so it will not throw MissingServletRequestParameterException and rather move to next step of constraint validation.@RequestParam标记required=false ,这样它就不会抛出 MissingServletRequestParameterException ,而是进入约束验证的下一步。
@ControllerAdvice
public class CustomResponseEntityExceptionHandler {

    @ExceptionHandler
  public ResponseEntity<ApiError> handle(ConstraintViolationException exception) {
        //you will get all javax failed validation, can be more than one
        //so you can return the set of error messages or just the first message
        String errorMessage = new ArrayList<>(exception.getConstraintViolations()).get(0).getMessage();
       ApiError apiError = new ApiError(errorMessage, errorMessage, 1000);    
       return new ResponseEntity<ApiError>(apiError, null, HttpStatus.BAD_REQUEST);
  }
}



@RestController
@Validated
public class MinimumStockController {

    @RequestMapping(value = "/minimumstock")
    public Product product(
            @RequestParam(value = "product.sku", required=false) @NotEmpty(message = "Product.sku cannot be empty") String sku,
            @RequestParam(value = "stock.branch.id", required=false) String branchID) {
        return null;
    }
}

NOTE: MissingServletRequestParameterException won't have access to javax validation messages, as it is thrown before constraint validation occurs in the request lifecycle.注意: MissingServletRequestParameterException将无法访问 javax 验证消息,因为它在请求生命周期中的约束验证发生之前被抛出。

If this can help, I found the solution for this issue here: https://howtodoinjava.com/spring-boot2/spring-rest-request-validation/如果这有帮助,我在这里找到了这个问题的解决方案: https : //howtodoinjava.com/spring-boot2/spring-rest-request-validation/

You have to add this method to your CustomResponseEntityExceptionHandler class:您必须将此方法添加到您的 CustomResponseEntityExceptionHandler 类:

 @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<String> details = new ArrayList<>();
        for(ObjectError error : ex.getBindingResult().getAllErrors()) {
            details.add(error.getDefaultMessage());
        }
        ErrorMessage error = new ErrorMessage(new Date(), details.toString());
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

You should put this on your handler.你应该把它放在你的处理程序上。

@ControllerAdvice
public class CustomResponseEntityExceptionHandler {

    @ExceptionHandler(value = { MissingServletRequestParameterException.class })
    public ResponseEntity<ApiError> handleConflict(MissingServletRequestParameterException ex, WebRequest request) {
        String message = ex.getParameterName() + " cannot be empty";
        ApiError apiError = new ApiError(ex.getMessage(), message, 1000);
        return new ResponseEntity < ApiError > (apiError, null, HttpStatus.BAD_REQUEST);
    }
}

UPDATE更新

I don't know how you can get a default message, but as a workaround, you could do the validation on your controller and throw an custom exception if the parameter is empty, then handle in your CustomResponseEntityExceptionHandler .我不知道如何获得默认消息,但作为一种解决方法,您可以在控制器上进行验证并在参数为空时抛出自定义异常,然后在您的CustomResponseEntityExceptionHandler进行处理。

Something like the following:类似于以下内容:

Set required=false设置required=false

@RequestMapping(value = "/minimumstock")
public Product product(@RequestParam(required = false) String sku, @RequestParam(value = "stock.branch.id") String branchID) {
    if (StringUtils.isEmpty(sku)) 
        throw YourException("Product.sku cannot be empty");

    return null;
}

Yes it is possible.对的,这是可能的。 Do this:做这个:

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ArgumentsErrorResponseDTO> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {

    ServiceException exception = ServiceException.wrap(ex, ErrorCode.FIELD_VALIDATION);
    BindingResult results = ex.getBindingResult();
    for (FieldError e: results.getFieldErrors()) {
        exception.addLog(e.getDefaultMessage(), e.getField());
    }
    // log details in log
    log.error("Invalid arguments exception: {}", exception.logWithDetails(), exception);
    return ResponseEntity.status(exception.getErrorCode().getHttpStatus())
            .body(ArgumentsErrorResponseDTO.builder()
                    .code(exception.getErrorCode().getCode())
                    .message(exception.getMessage())
                    .details(exception.getProperties())
                    .build());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM