From 63be8cb6b36595ab2187e00a8485c4a9187ab1e9 Mon Sep 17 00:00:00 2001
From: qinyujie <943868899@qq.com>
Date: Wed, 28 Feb 2024 00:38:28 +0800
Subject: [PATCH] 3.5.2
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
修复JSON入参中列表元素参数校验问题
---
pom.xml | 2 +-
.../advice/ValidationExceptionAdvice.java | 139 ++++++++++++++----
2 files changed, 108 insertions(+), 33 deletions(-)
diff --git a/pom.xml b/pom.xml
index a0c1375..5ea0386 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.feiniaojin
graceful-response
- 3.5.1-boot3
+ 3.5.2-boot3
Graceful Response for Boot3
Help Spring Boot web application responses gracefully!
https://github.com/feiniaojin/graceful-response.git
diff --git a/src/main/java/com/feiniaojin/gracefulresponse/advice/ValidationExceptionAdvice.java b/src/main/java/com/feiniaojin/gracefulresponse/advice/ValidationExceptionAdvice.java
index 96f059f..4009ae0 100644
--- a/src/main/java/com/feiniaojin/gracefulresponse/advice/ValidationExceptionAdvice.java
+++ b/src/main/java/com/feiniaojin/gracefulresponse/advice/ValidationExceptionAdvice.java
@@ -14,9 +14,13 @@
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.annotation.Order;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
@@ -53,6 +57,9 @@ public class ValidationExceptionAdvice {
@Resource
private GracefulResponseProperties gracefulResponseProperties;
+ private static ExpressionParser parser = new SpelExpressionParser();
+
+
@ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
@ResponseBody
public Response exceptionHandler(Exception e) throws Exception {
@@ -72,48 +79,54 @@ public Response exceptionHandler(Exception e) throws Exception {
}
//Controller方法的参数校验码
- //Controller方法>Controller类>DTO入参属性>DTO入参类>配置文件默认参数码>默认错误码
+ //Controller方法>Controller类>DTO入参属性>DTO入参属性所在类>DTO入参根类>配置文件默认参数码>默认错误码
+ //这个取值顺序的逻辑是按照个性化程度由高到底排序的
private ResponseStatus handleBindException(BindException e) throws Exception {
- List allErrors = e.getBindingResult().getAllErrors();
+ BindingResult bindingResult = e.getBindingResult();
+ List allErrors = bindingResult.getAllErrors();
String msg = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
String code;
- //Controller方法上的注解
+ //Controller方法和类上的注解
ValidationStatusCode validateStatusCode = this.findValidationStatusCodeInController();
if (validateStatusCode != null) {
code = validateStatusCode.code();
return responseStatusFactory.newInstance(code, msg);
}
- //属性校验上的注解,只会取第一个属性上的注解,因此要配置
- //hibernate.validator.fail_fast=true
+
+ //DTO入参属性
List fieldErrors = e.getFieldErrors();
- if (!CollectionUtils.isEmpty(fieldErrors)) {
- FieldError fieldError = fieldErrors.get(0);
- String fieldName = fieldError.getField();
- Object target = e.getTarget();
- Field field = null;
- Class> clazz = null;
- Object obj = target;
- if (fieldName.contains(".")) {
- String[] strings = fieldName.split("\\.");
- for (String fName : strings) {
- clazz = obj.getClass();
- field = obj.getClass().getDeclaredField(fName);
- field.setAccessible(true);
- obj = field.get(obj);
- }
- } else {
- clazz = target.getClass();
- field = target.getClass().getDeclaredField(fieldName);
- }
+ FieldError fieldError = fieldErrors.get(0);
+ String fieldName = fieldError.getField();
+ Field field = null;
+ Class> clazz = null;
+ Object target = bindingResult.getTarget();
+ //不包含.,说明直接是根路径
+ if (!fieldName.contains(".")) {
+ clazz = target.getClass();
+ } else {
+ String fieldParentPath = fieldParentPath(fieldName);
+ fieldName = fieldSimpleName(fieldName);
+ Expression expression = parser.parseExpression(fieldParentPath);
+ clazz = expression.getValue(target).getClass();
+ }
+ field = clazz.getDeclaredField(fieldName);
- ValidationStatusCode annotation = field.getAnnotation(ValidationStatusCode.class);
- //属性上找到注解
- if (annotation != null) {
- code = annotation.code();
- return responseStatusFactory.newInstance(code, msg);
- }
- //类上面找到注解
- annotation = clazz.getAnnotation(ValidationStatusCode.class);
+ ValidationStatusCode annotation = field.getAnnotation(ValidationStatusCode.class);
+ //属性上找到注解
+ if (annotation != null) {
+ code = annotation.code();
+ return responseStatusFactory.newInstance(code, msg);
+ }
+ //属性所在类上面找到注解
+ annotation = clazz.getAnnotation(ValidationStatusCode.class);
+ if (annotation != null) {
+ code = annotation.code();
+ return responseStatusFactory.newInstance(code, msg);
+ }
+
+ //根类上找注解
+ if (target.getClass() != clazz) {
+ annotation = target.getClass().getAnnotation(ValidationStatusCode.class);
if (annotation != null) {
code = annotation.code();
return responseStatusFactory.newInstance(code, msg);
@@ -129,6 +142,68 @@ private ResponseStatus handleBindException(BindException e) throws Exception {
return responseStatusFactory.newInstance(code, msg);
}
+ private String fieldSimpleName(String fieldName) {
+ int lastIndex = fieldName.lastIndexOf(".");
+ StringBuilder stringBuilder = new StringBuilder();
+ int length = fieldName.length();
+ for (int i = lastIndex + 1; i < length; i++) {
+ stringBuilder.append(fieldName.charAt(i));
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * 属性父类路径
+ *
+ * @param fieldName
+ * @return
+ */
+ private String fieldParentPath(String fieldName) {
+ int lastIndex = fieldName.lastIndexOf(".");
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < lastIndex; i++) {
+ stringBuilder.append(fieldName.charAt(i));
+ }
+ return stringBuilder.toString();
+ }
+
+ private String leafPropertyFieldName(String fieldName) {
+ int lastIndexOf = fieldName.lastIndexOf('.');
+ if (lastIndexOf == -1) {
+ return fieldName;
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ int len = fieldName.length();
+ for (int i = lastIndexOf + 1; i < len; i++) {
+ stringBuilder.append(fieldName.charAt(i));
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * 适配数组属性,包括数组、集合
+ *
+ * @param fieldName
+ * @return
+ */
+ private String adapterArrayProperty(String fieldName) {
+ //最后一个字符不是],则不是数组属性
+ if (fieldName.lastIndexOf(']') == -1) {
+ return fieldName;
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ int len = fieldName.length();
+ char c;
+ for (int i = 0; i < len; i++) {
+ c = fieldName.charAt(i);
+ if (c == '[') {
+ break;
+ }
+ stringBuilder.append(c);
+ }
+ return stringBuilder.toString();
+ }
+
/**
* 当前Controller方法
*