Commit b4d7bec9 authored by liaozan's avatar liaozan 🏀

Support dubbo-rpc parameter validation

parent a3f1fd8f
......@@ -82,6 +82,11 @@
<artifactId>apm-toolkit-trace</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
......
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<ConstraintViolation<?>> 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
......@@ -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<String> 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<String> 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<ConstraintViolation<?>> 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);
......
......@@ -268,16 +268,6 @@
<artifactId>commons-pool2</artifactId>
<version>${commons-pool2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
......
......@@ -19,8 +19,8 @@
<artifactId>apollo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
......@@ -42,6 +42,10 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-filter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring</artifactId>
......
......@@ -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,11 +44,18 @@ 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);
......
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
......@@ -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) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment