Spring Boot注解校验List元素时获取违规项索引自定义错误响应
解决方案
你当前已经拿到了带列表索引标记的字段错误路径,只需要完成排序、索引提取、消息格式化三步即可实现预期效果,注意不要用无序的HashMap存储错误集合,会打乱返回顺序。
核心处理逻辑
- 对所有字段错误按列表索引升序排序,保证错误返回顺序和入参列表顺序一致
- 通过正则从字段名(格式为
contact[x].email)中提取元素索引,转换为从1开始计数的日常序号 - 把序号拼接到对应错误提示文本中,最终用有序List存储格式化后的错误信息
完整修改后的异常处理器代码
import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.*; @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public Map<String, Object> handleValidationExceptions(MethodArgumentNotValidException ex) { Map<String, Object> body = new LinkedHashMap<>(); body.put("timestamp", new Date()); body.put("status", HttpStatus.BAD_REQUEST.value()); // 正则匹配字段路径中的列表索引 Pattern indexPattern = Pattern.compile("contact\\[(\\d+)\\]"); List<String> errors = ex.getBindingResult().getFieldErrors().stream() // 按列表索引升序排序 .sorted(Comparator.comparingInt(e -> extractIndex(e.getField(), indexPattern))) // 格式化错误消息 .map(fieldError -> { int seq = extractIndex(fieldError.getField(), indexPattern) + 1; String rawMsg = fieldError.getDefaultMessage(); return rawMsg.replace("E-mail address ", String.format("E-mail address %d: ", seq)); }) .collect(Collectors.toList()); body.put("errors", errors); return body; } // 提取字段路径中的列表索引值 private int extractIndex(String fieldPath, Pattern pattern) { Matcher matcher = pattern.matcher(fieldPath); return matcher.find() ? Integer.parseInt(matcher.group(1)) : 0; }
最终返回效果
修改后接口返回格式完全符合预期:
{ "timestamp": "2022-06-16T00:43:50.878+00:00", "status": 400, "errors": [ "E-mail address 1: 'tesaaaaaaaaaaaaaaaaaaaaaaaaaaaat@test.com' must be between 0 and 20 characters long", "E-mail address 2: 'tesaaaaaaaaaaaaaaaaaaaaaaaaaaaat@test.com' must be between 0 and 20 characters long" ] }
可选优化
- 如果后续有其他嵌套列表的校验场景,可以调整正则规则,不写死
contact字段名,通用提取所有[数字]格式的索引值 - 如果错误消息前缀不固定,可以调整消息拼接逻辑,直接把序号追加到消息最前端即可,不需要做字符串替换
内容的提问来源于stack exchange,提问作者askwer
相关产品推荐
相关产品推荐

