当 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;
}
如果检查
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();
}
以下异常处理程序显示了它的工作原理:
@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()
使用此方法(例如 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());
}
仅获取参数名称,即
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());
我遇到了同样的问题,但也从 getPropertyPath 得到了“sayHi.arg0”。我选择向 NotNull 注释添加一条消息,因为它们是我们公共 API 的一部分。喜欢:
@NotNull(message = "timezone param is mandatory")
您可以拨打电话
获取消息ConstraintViolation#getMessage()
要获取字段名称和消息,请使用以下代码:
@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());
}
在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 类。如果你没有,你可以使用注释的方法。
请找到以下代码。
@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;
}
}