【问题标题】:Spring Boot how to return my own validation constraint error messagesSpring Boot如何返回我自己的验证约束错误信息
【发布时间】:2018-12-22 05:19:31
【问题描述】:

当我的请求出现问题并且我尝试使用@NotEmpty约束消息属性返回错误消息时,我需要有自己的错误响应正文,

这是我的类,它使用我需要的正文返回错误消息:

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

有了这个CustomResponseEntityExceptionHandler,我可以在出现验证错误时返回我自己的响应正文。

我现在正在尝试从验证约束中获取消息。

这是我的控制器,带有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;
    }
}

在我的例外情况下,我找不到获取该消息 Product.sku cannot be empty 并将其显示在我的错误响应中的方法。

我还检查了 MissingServletRequestParameterException 类,有一个方法 getMessage 返回默认消息。

【问题讨论】:

    标签: java validation spring-boot exception-handling query-parameters


    【解决方案1】:

    如果这有帮助,我在这里找到了解决此问题的方法:https://howtodoinjava.com/spring-boot2/spring-rest-request-validation/

    您必须将此方法添加到您的 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);
        }
    

    【讨论】:

      【解决方案2】:

      是的,这是可能的。这样做:

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

      【讨论】:

        【解决方案3】:

        是的,它是可行的,而且 spring 很好地支持它。您只是缺少一些配置以在 spring 中启用它。

        • 使用Spring@Validated注解开启spring验证控制器
        • ControllerAdvice 中处理 ConstraintViolationException 以捕获所有失败的验证消息。
        • @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;
            }
        }
        

        注意:MissingServletRequestParameterException 将无法访问 javax 验证消息,因为它在请求生命周期中发生约束验证之前被抛出。

        【讨论】:

          【解决方案4】:

          你应该把它放在你的处理程序上。

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

          更新

          我不知道如何获取默认消息,但作为一种解决方法,您可以在控制器上进行验证并在参数为空时抛出自定义异常,然后在您的 CustomResponseEntityExceptionHandler 中处理。

          类似于以下内容:

          设置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;
          }
          

          【讨论】:

          • 但是有没有办法让我从控制器中的@NotEmpty 注释中获取消息?
          • @Gerep 我不知道你能不能做到,但我已经用解决方法更新了我的答案。希望这会有所帮助。
          猜你喜欢
          • 2017-04-14
          • 1970-01-01
          • 2018-04-30
          • 1970-01-01
          • 1970-01-01
          • 2018-01-29
          • 2022-10-14
          • 1970-01-01
          • 2020-09-04
          相关资源
          最近更新 更多