From b4d7bec992d9d7065cac70a4ef6c2dfa5a61ef6f Mon Sep 17 00:00:00 2001
From: liaozan <378024053@qq.com>
Date: Tue, 4 Jul 2023 03:47:00 +0800
Subject: [PATCH] Support dubbo-rpc parameter validation
---
commons/common-util/pom.xml | 5 +++
.../support/ValidationMessageBuilder.java | 41 +++++++++++++++++++
.../web/exception/GlobalExceptionHandler.java | 38 +++--------------
pom.xml | 10 -----
starters/dubbo-spring-boot-starter/pom.xml | 8 +++-
.../dubbo/filter/DubboExceptionFilter.java | 25 ++++++++---
.../DubboValidationInitializer.java | 26 ++++++++++++
.../DubboConfigLoadedEventListener.java | 2 +
8 files changed, 106 insertions(+), 49 deletions(-)
create mode 100644 commons/common-util/src/main/java/com/schbrain/common/util/support/ValidationMessageBuilder.java
create mode 100644 starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/initializer/DubboValidationInitializer.java
diff --git a/commons/common-util/pom.xml b/commons/common-util/pom.xml
index d6d10b4..211d183 100644
--- a/commons/common-util/pom.xml
+++ b/commons/common-util/pom.xml
@@ -82,6 +82,11 @@
apm-toolkit-trace
true
+
+ org.hibernate.validator
+ hibernate-validator
+ true
+
com.baomidou
mybatis-plus-extension
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/support/ValidationMessageBuilder.java b/commons/common-util/src/main/java/com/schbrain/common/util/support/ValidationMessageBuilder.java
new file mode 100644
index 0000000..1667833
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/support/ValidationMessageBuilder.java
@@ -0,0 +1,41 @@
+package com.schbrain.common.util.support;
+
+import org.hibernate.validator.internal.engine.path.PathImpl;
+import org.springframework.validation.*;
+
+import javax.validation.ConstraintViolation;
+import java.util.*;
+
+/**
+ * @author liaozan
+ * @since 2023-07-04
+ */
+public class ValidationMessageBuilder {
+
+ public static String buildBindingErrorMsg(BindingResult bindingResult) {
+ String prefix = "参数验证失败: ";
+ StringJoiner joiner = new StringJoiner(", ");
+ for (ObjectError error : bindingResult.getAllErrors()) {
+ String errorMessage = Optional.ofNullable(error.getDefaultMessage()).orElse("验证失败");
+ String source;
+ if (error instanceof FieldError) {
+ source = ((FieldError) error).getField();
+ } else {
+ source = error.getObjectName();
+ }
+ joiner.add(source + " " + errorMessage);
+ }
+ return prefix + joiner;
+ }
+
+ public static String buildConstraintViolationErrorMsg(Set> constraintViolations) {
+ String prefix = "参数验证失败: ";
+ StringJoiner joiner = new StringJoiner(", ");
+ for (ConstraintViolation> violation : constraintViolations) {
+ PathImpl propertyPath = (PathImpl) violation.getPropertyPath();
+ joiner.add(propertyPath.asString() + " " + violation.getMessage());
+ }
+ return prefix + joiner;
+ }
+
+}
\ No newline at end of file
diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/exception/GlobalExceptionHandler.java b/commons/web-common/src/main/java/com/schbrain/common/web/exception/GlobalExceptionHandler.java
index 0b6f766..9853a2c 100644
--- a/commons/web-common/src/main/java/com/schbrain/common/web/exception/GlobalExceptionHandler.java
+++ b/commons/web-common/src/main/java/com/schbrain/common/web/exception/GlobalExceptionHandler.java
@@ -4,14 +4,14 @@ import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import com.schbrain.common.constants.ResponseActionConstants;
import com.schbrain.common.exception.BaseException;
+import com.schbrain.common.util.support.ValidationMessageBuilder;
import com.schbrain.common.web.result.ResponseDTO;
import lombok.extern.slf4j.Slf4j;
-import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.ClassUtils;
-import org.springframework.validation.*;
+import org.springframework.validation.BindException;
import org.springframework.web.*;
import org.springframework.web.bind.*;
import org.springframework.web.bind.annotation.*;
@@ -20,10 +20,10 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
-import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLException;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
import static com.schbrain.common.constants.ResponseCodeConstants.*;
@@ -178,14 +178,14 @@ public class GlobalExceptionHandler {
/************************************* Parameter Binding Exception Handing *************************************/
@ExceptionHandler(BindException.class)
public ResponseDTO handleBindException(BindException ex) {
- String errorMsg = buildBindingErrorMsg(ex.getBindingResult());
+ String errorMsg = ValidationMessageBuilder.buildBindingErrorMsg(ex.getBindingResult());
log.error(errorMsg);
return buildResponse(ex, PARAM_INVALID, errorMsg);
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseDTO handleConstraintViolationException(ConstraintViolationException ex) {
- String errorMsg = buildBindingErrorMsg(ex.getConstraintViolations());
+ String errorMsg = ValidationMessageBuilder.buildConstraintViolationErrorMsg(ex.getConstraintViolations());
log.error(errorMsg);
return buildResponse(ex, PARAM_INVALID, errorMsg);
}
@@ -218,32 +218,6 @@ public class GlobalExceptionHandler {
return null;
}
- private String buildBindingErrorMsg(BindingResult bindingResult) {
- String prefix = "参数验证失败: ";
- StringJoiner joiner = new StringJoiner(", ");
- for (ObjectError error : bindingResult.getAllErrors()) {
- String errorMessage = Optional.ofNullable(error.getDefaultMessage()).orElse("验证失败");
- String source;
- if (error instanceof FieldError) {
- source = ((FieldError) error).getField();
- } else {
- source = error.getObjectName();
- }
- joiner.add(source + " " + errorMessage);
- }
- return prefix + joiner;
- }
-
- private String buildBindingErrorMsg(Set> constraintViolations) {
- String prefix = "参数验证失败: ";
- StringJoiner joiner = new StringJoiner(", ");
- for (ConstraintViolation> violation : constraintViolations) {
- PathImpl propertyPath = (PathImpl) violation.getPropertyPath();
- joiner.add(propertyPath.asString() + " " + violation.getMessage());
- }
- return prefix + joiner;
- }
-
private void logError(Throwable throwable) {
String exMsg = ExceptionUtil.getMessage(throwable);
log.error(exMsg, throwable);
diff --git a/pom.xml b/pom.xml
index 2eaa278..72cecf0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -268,16 +268,6 @@
commons-pool2
${commons-pool2.version}
-
- org.apache.dubbo
- dubbo
- ${dubbo.version}
-
-
- org.apache.dubbo
- dubbo-spring-boot-starter
- ${dubbo.version}
-
org.apache.dubbo
dubbo-common
diff --git a/starters/dubbo-spring-boot-starter/pom.xml b/starters/dubbo-spring-boot-starter/pom.xml
index 6e3aefe..64ac0bb 100644
--- a/starters/dubbo-spring-boot-starter/pom.xml
+++ b/starters/dubbo-spring-boot-starter/pom.xml
@@ -19,8 +19,8 @@
apollo-spring-boot-starter
- org.springframework.boot
- spring-boot-starter-validation
+ org.hibernate.validator
+ hibernate-validator
org.apache.zookeeper
@@ -42,6 +42,10 @@
org.apache.dubbo
dubbo-common
+
+ org.apache.dubbo
+ dubbo-filter-validation
+
org.apache.dubbo
dubbo-config-spring
diff --git a/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/filter/DubboExceptionFilter.java b/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/filter/DubboExceptionFilter.java
index a8959fc..fab9a82 100644
--- a/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/filter/DubboExceptionFilter.java
+++ b/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/filter/DubboExceptionFilter.java
@@ -2,6 +2,8 @@ package com.schbrain.framework.autoconfigure.dubbo.filter;
import cn.hutool.core.exceptions.ExceptionUtil;
import com.schbrain.common.exception.BaseException;
+import com.schbrain.common.exception.ParamInvalidException;
+import com.schbrain.common.util.support.ValidationMessageBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
@@ -9,6 +11,7 @@ import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.filter.ExceptionFilter;
import org.apache.dubbo.rpc.service.GenericService;
+import javax.validation.ConstraintViolationException;
import java.util.Arrays;
/**
@@ -26,8 +29,13 @@ public class DubboExceptionFilter extends ExceptionFilter {
}
Throwable cause = ExceptionUtil.getRootCause(appResponse.getException());
+
+ if (cause instanceof ConstraintViolationException) {
+ cause = createParamInvalidException(invocation, (ConstraintViolationException) cause);
+ }
+
appResponse.setException(cause);
- logErrorDetail(invoker, cause);
+ logErrorDetail(invocation, cause);
if (cause instanceof BaseException) {
return;
@@ -36,15 +44,22 @@ public class DubboExceptionFilter extends ExceptionFilter {
super.onResponse(appResponse, invoker, invocation);
}
- private void logErrorDetail(Invoker> invoker, Throwable exception) {
+ protected ParamInvalidException createParamInvalidException(Invocation invocation, ConstraintViolationException cause) {
+ String serviceName = invocation.getInvoker().getInterface().getSimpleName();
+ String methodName = invocation.getMethodName();
+ String errorMsg = ValidationMessageBuilder.buildConstraintViolationErrorMsg(cause.getConstraintViolations());
+ return new ParamInvalidException(String.format("%s.%s %s", serviceName, methodName, errorMsg));
+ }
+
+ protected void logErrorDetail(Invocation invocation, Throwable exception) {
RpcServiceContext context = RpcContext.getCurrentServiceContext();
+ String serviceName = invocation.getInvoker().getInterface().getSimpleName();
+ String methodName = invocation.getMethodName();
String arguments = Arrays.toString(context.getArguments());
- String serviceName = invoker.getInterface().getSimpleName();
- String methodName = context.getMethodName();
String remoteHost = context.getRemoteHost();
String remoteApplication = context.getRemoteApplicationName();
String errorMessage = ExceptionUtil.getMessage(exception);
log.error("Catch rpc exception: {}, client: {}@{}, target: {}#{}, args: {}", errorMessage, remoteApplication, remoteHost, serviceName, methodName, arguments, exception);
}
-}
+}
\ No newline at end of file
diff --git a/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/initializer/DubboValidationInitializer.java b/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/initializer/DubboValidationInitializer.java
new file mode 100644
index 0000000..332c11b
--- /dev/null
+++ b/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/initializer/DubboValidationInitializer.java
@@ -0,0 +1,26 @@
+package com.schbrain.framework.autoconfigure.dubbo.initializer;
+
+import com.schbrain.common.util.properties.OrderedMapPropertySource;
+import org.springframework.util.ClassUtils;
+
+/**
+ * 暂时以编程的方式配置参数校验。待所有服务都升级到指定版本时,再通过配置开启
+ *
+ * @author liaozan
+ * @since 2023-07-04
+ */
+public class DubboValidationInitializer {
+
+ private static final String VALIDATION_FILTER_CLASS_NAME = "org.apache.dubbo.validation.filter.ValidationFilter";
+
+ private static final String PROVIDER_VALIDATION_PROPERTY = "dubbo.provider.validation";
+
+ public static void initialize(OrderedMapPropertySource propertySource) {
+ if (ClassUtils.isPresent(VALIDATION_FILTER_CLASS_NAME, DubboValidationInitializer.class.getClassLoader())) {
+ if (!propertySource.containsProperty(PROVIDER_VALIDATION_PROPERTY)) {
+ propertySource.addProperty(PROVIDER_VALIDATION_PROPERTY, Boolean.TRUE.toString());
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/listener/DubboConfigLoadedEventListener.java b/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/listener/DubboConfigLoadedEventListener.java
index 5aefdc3..e29d5ae 100644
--- a/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/listener/DubboConfigLoadedEventListener.java
+++ b/starters/dubbo-spring-boot-starter/src/main/java/com/schbrain/framework/autoconfigure/dubbo/listener/DubboConfigLoadedEventListener.java
@@ -3,6 +3,7 @@ package com.schbrain.framework.autoconfigure.dubbo.listener;
import com.schbrain.common.util.properties.OrderedMapPropertySource;
import com.schbrain.framework.autoconfigure.apollo.event.ConfigLoadedEvent;
import com.schbrain.framework.autoconfigure.apollo.event.listener.GenericConfigLoadedEventListener;
+import com.schbrain.framework.autoconfigure.dubbo.initializer.DubboValidationInitializer;
import com.schbrain.framework.autoconfigure.dubbo.properties.DubboProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
@@ -29,6 +30,7 @@ public class DubboConfigLoadedEventListener extends GenericConfigLoadedEventList
@Override
protected void onConfigLoaded(ConfigLoadedEvent event, DubboProperties properties) {
addRequiredProperties(event.getSpringApplication(), event.getPropertySource());
+ DubboValidationInitializer.initialize(event.getPropertySource());
}
private void addRequiredProperties(SpringApplication application, OrderedMapPropertySource propertySource) {
--
GitLab