当PathVariable'name'未通过验证时,抛出javax.validation.ConstraintViolationException。有没有办法在抛出的javax.validation.ConstraintViolationException中检索参数名称?
// hard coding songs.get(0) could lead to issues as well but at least fix the index i
for (int i = 0; i < songs.get(0).size(); i++)
{
TextView textView = new TextView(this);
...
//Error is thrown here
textView.setText(songs.get(0).getVerses().get(i);
...
}
答案 0 :(得分:9)
以下异常处理程序显示了它的工作原理:
@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()
您可以访问媒体名称&#39; name&#39;与
constraintViolation.getPropertyPath()
答案 1 :(得分:4)
使用此方法(ex是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());
}
答案 2 :(得分:3)
我有同样的问题,但也得到了#34; sayHi.arg0&#34;来自getPropertyPath。我选择向NotNull注释添加消息,因为它们是我们公共API的一部分。像:
@NotNull(message = "timezone param is mandatory")
您可以致电
获取消息ConstraintViolation#的getMessage()
答案 3 :(得分:2)
如果检查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();
}
答案 4 :(得分:0)
仅获取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());
答案 5 :(得分:0)
支持这样的嵌套字段
class A{int id;@Valid B b;}
class B{@NotNull String a;}
我的代码是
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ElementKind;
import javax.validation.Path;
import javax.validation.Path.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.ServletWebRequest;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ControllerAdvice
public class ValidateControllerAdvice
{
@Autowired
private MessageSource messageSource;
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public @ResponseBody Map<String, Object> handleConstraintViolation(ConstraintViolationException e,
ServletWebRequest request)
{
final Map<String, Object> result=new LinkedHashMap<>();
result.put("timestamp", LocalDateTime.now());
result.put("path", request.getRequest().getRequestURI());
result.put("status", HttpStatus.BAD_REQUEST.value());
result.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase());
result.put("errors", e.getConstraintViolations().stream()
.map(cv -> this.getErrorData(cv, request.getLocale())));
return result;
}
private ErrorData getErrorData(ConstraintViolation<?> violation, Locale locale)
{
String msg =this.messageSource.getMessage(violation.getMessageTemplate(),
new Object[]{violation.getLeafBean().getClass().getSimpleName(),
violation.getPropertyPath().toString(), violation.getInvalidValue()},
violation.getMessage(), locale);
Path exceptionPath = violation.getPropertyPath();
List<Node> path = StreamSupport.stream(exceptionPath.spliterator(), false)
.collect(Collectors.toList());
LinkedList<Node> realPath = new LinkedList<>();
for(int i = path.size() -1; i >= 0; --i)
{
if(!path.get(i).getKind().equals(ElementKind.PROPERTY))
{
break;
}
realPath.addFirst(path.get(i));
}
String field = realPath.stream()
.map(n -> n.toString())
.collect(Collectors.joining("."));
String objectName=violation.getLeafBean().getClass().getSimpleName();
Object rejectedValue=violation.getInvalidValue();
ErrorData result=new ErrorData(msg, objectName, field, rejectedValue);
return result;
}
}
import lombok.Data;
import lombok.AllArgsConstructor;
@Data
@AllArgsConstructor
public class ErrorData
{
private String message;
private String objectName;
private String field;
private Object rejectedValue;
}
答案 6 :(得分:0)
要获取字段名称和消息,请使用以下代码:
@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());
}