diff --git a/commons/common-util/pom.xml b/commons/common-util/pom.xml index d6d10b4ec741ef86f5729815c633c825a625e6e9..211d183b4c06654aa1cf3fae7f2f53a049dfd511 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 0000000000000000000000000000000000000000..16678339eedf6cb3cfbe5144d6dd453fd83c2e93 --- /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 0b6f76696535ae4ca12a27974ec6c30bf041e5e4..9853a2cffffa8a77a48a652bcfab33791fb9c42b 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 2eaa27841d604c6c7f728fe82db86b9e4db2c177..72cecf0e5792254b8bcc642784a51a52105bc893 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 6e3aefeafc2b3a228a8135db4af0f13e53bcd6be..64ac0bbdcf57cbed91f5c67e5011edd678a5de31 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 a8959fc8356d451eb77f82a529271cae31e113fc..fab9a82443a98e2ba72293105c0e369b57aeb098 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 0000000000000000000000000000000000000000..332c11bd60426b9b8d0c98a6ed7e7580fc103827 --- /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 5aefdc319c76b203b9e6a9b316ec6bde99cdc37a..e29d5aee8a89511c76a650e51d5206e1e7618d6b 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) {