抛出 javax.validation.ConstraintViolationException 时获取字段名称

问题描述 投票:0回答:8

当 PathVariable 'name' 未通过验证时,会抛出 javax.validation.ConstraintViolationException。有没有办法在抛出的 javax.validation.ConstraintViolationException 中检索参数名称?

@RestController
@Validated
public class HelloController {

@RequestMapping("/hi/{name}")
public String sayHi(@Size(max = 10, min = 3, message = "name should    have between 3 and 10 characters") @PathVariable("name") String name) {
  return "Hi " + name;
}
spring bean-validation
8个回答
26
投票

如果检查

getPropertyPath()
的返回值,您会发现它是
Iterable<Node>
并且迭代器的最后一个元素是字段名称。以下代码对我有用:

// I only need the first violation
ConstraintViolation<?> violation = ex.getConstraintViolations().iterator().next();
// get the last node of the violation
String field = null;
for (Node node : violation.getPropertyPath()) {
    field = node.getName();
}

20
投票

以下异常处理程序显示了它的工作原理:

@ExceptionHandler(ConstraintViolationException.class)

ResponseEntity<Set<String>> handleConstraintViolation(ConstraintViolationException e) {
    Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();

Set<String> messages = new HashSet<>(constraintViolations.size());
messages.addAll(constraintViolations.stream()
        .map(constraintViolation -> String.format("%s value '%s' %s", constraintViolation.getPropertyPath(),
                constraintViolation.getInvalidValue(), constraintViolation.getMessage()))
        .collect(Collectors.toList()));

return new ResponseEntity<>(messages, HttpStatus.BAD_REQUEST);

}

您可以使用

访问无效值(名称)
 constraintViolation.getInvalidValue()

您可以使用

访问属性名称“name”
constraintViolation.getPropertyPath()

10
投票

使用此方法(例如 ConstraintViolationException 实例):

Set<ConstraintViolation<?>> set =  ex.getConstraintViolations();
    List<ErrorField> errorFields = new ArrayList<>(set.size());
    ErrorField field = null;
    for (Iterator<ConstraintViolation<?>> iterator = set.iterator();iterator.hasNext(); ) {
        ConstraintViolation<?> next =  iterator.next();
       System.out.println(((PathImpl)next.getPropertyPath())
                .getLeafNode().getName() + "  " +next.getMessage());


    }

6
投票

仅获取参数名称,即

Path
的最后一部分。

violations.stream()
                .map(violation -> String.format("%s value '%s' %s", StreamSupport.stream(violation.getPropertyPath().spliterator(), false).reduce((first, second) -> second).orElse(null),
                        violation.getInvalidValue(), violation.getMessage())).collect(Collectors.toList());

2
投票

我遇到了同样的问题,但也从 getPropertyPath 得到了“sayHi.arg0”。我选择向 NotNull 注释添加一条消息,因为它们是我们公共 API 的一部分。喜欢:

 @NotNull(message = "timezone param is mandatory")

您可以拨打电话

获取消息

ConstraintViolation#getMessage()


2
投票

要获取字段名称和消息,请使用以下代码:

@ExceptionHandler(value = {ConstraintViolationException.class})
public ResponseEntity<Object> handleConstraintViolationException(
    ConstraintViolationException ex, WebRequest request) {
    log.error(INVALID_REQUEST, ex);
    Map<String, Object> errors = new HashMap<>();
    if (!ex.getConstraintViolations().isEmpty()) {
        for (ConstraintViolation constraintViolation : ex.getConstraintViolations()) {
            String fieldName = null;
            for (Node node : constraintViolation.getPropertyPath()) {
                fieldName = node.getName();
            }
            errors.put(fieldName, constraintViolation.getMessage());
        }
    }
    return new ResponseEntity<>(getErrorResponse(code, errors), getHttpCode());
}

0
投票

在ControllerAdvice类中,我们可以处理ConstraintViolationException

import javax.validation.Path;
import javax.validation.Path.Node;
import org.hibernate.validator.internal.engine.path.PathImpl;

....
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<FieldErrorResponse> handleConstraintViolationException(final ConstraintViolationException ex, WebRequest request) {

    List<FieldError> errors = ex.getConstraintViolations().stream()
      .map(violation -> new FieldError(getFieldFromPath(violation.getPropertyPath()), violation.getMessage(), violation.getInvalidValue()))
      .collect(Collectors.toList());
    ....
}

private String getFieldFromPath(Path fieldPath) {

    PathImpl pathImpl = (PathImpl) fieldPath;
    return pathImpl.getLeafNode().toString();

    // OR
    /**
    Iterator<Node> nodes = fieldPath.iterator();
    String fieldName = null;
    while (nodes.hasNext()) {
      fieldName = nodes.next().toString();
    }
    return fieldName;
    */
}

有两种方法可以获取字段名称。首先,使用 hibernate 类。如果你没有,你可以使用注释的方法。


0
投票

请找到以下代码。

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public Map<String,String> handleValidationException(ConstraintViolationException ex){
    Map<String,String> errorMap = new HashMap<>();
    ex.getConstraintViolations().forEach(error -> {
        errorMap.put(error.getPropertyPath().toString(), error.getMessage());
    });
    return errorMap;
}

}

© www.soinside.com 2019 - 2024. All rights reserved.