diff --git a/changelog.md b/changelog.md
index 0eb502ab..82aef8b8 100644
--- a/changelog.md
+++ b/changelog.md
@@ -3,6 +3,7 @@
## 2.1.0
- 支持分布式限流(redis实现)
+- 可调整JSR-303校验顺序
## 2.0.0
diff --git a/doc/docs/_sidebar.md b/doc/docs/_sidebar.md
index 370a3a49..b4b85507 100644
--- a/doc/docs/_sidebar.md
+++ b/doc/docs/_sidebar.md
@@ -1,32 +1,32 @@
-* [首页](/?t=1567770151526)
+* [首页](/?t=1567997064207)
* 开发文档
- * [快速体验](files/10010_快速体验.md?t=1567770151530)
- * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1567770151558)
- * [新增接口](files/10020_新增接口.md?t=1567770151558)
- * [开发流程](files/10021_开发流程.md?t=1567770151558)
- * [业务参数校验](files/10030_业务参数校验.md?t=1567770151558)
- * [错误处理](files/10040_错误处理.md?t=1567770151558)
- * [编写文档](files/10041_编写文档.md?t=1567770151558)
- * [接口交互详解](files/10050_接口交互详解.md?t=1567770151558)
- * [easyopen支持](files/10070_easyopen支持.md?t=1567770151559)
- * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1567770151559)
- * [ISV管理](files/10085_ISV管理.md?t=1567770151559)
- * [自定义返回结果](files/10087_自定义返回结果.md?t=1567770151559)
- * [自定义过滤器](files/10088_自定义过滤器.md?t=1567770151559)
- * [路由授权](files/10090_路由授权.md?t=1567770151559)
- * [接口限流](files/10092_接口限流.md?t=1567770151559)
- * [监控日志](files/10093_监控日志.md?t=1567770151559)
- * [SDK开发](files/10095_SDK开发.md?t=1567770151559)
- * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1567770151559)
- * [应用授权](files/10097_应用授权.md?t=1567770151560)
- * [传统web开发](files/10100_传统web开发.md?t=1567770151560)
- * [文件上传](files/10104_文件上传.md?t=1567770151560)
- * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1567770151560)
- * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1567770151560)
- * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1567770151560)
+ * [快速体验](files/10010_快速体验.md?t=1567997064209)
+ * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1567997064227)
+ * [新增接口](files/10020_新增接口.md?t=1567997064227)
+ * [开发流程](files/10021_开发流程.md?t=1567997064227)
+ * [业务参数校验](files/10030_业务参数校验.md?t=1567997064227)
+ * [错误处理](files/10040_错误处理.md?t=1567997064227)
+ * [编写文档](files/10041_编写文档.md?t=1567997064227)
+ * [接口交互详解](files/10050_接口交互详解.md?t=1567997064227)
+ * [easyopen支持](files/10070_easyopen支持.md?t=1567997064227)
+ * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1567997064227)
+ * [ISV管理](files/10085_ISV管理.md?t=1567997064227)
+ * [自定义返回结果](files/10087_自定义返回结果.md?t=1567997064227)
+ * [自定义过滤器](files/10088_自定义过滤器.md?t=1567997064228)
+ * [路由授权](files/10090_路由授权.md?t=1567997064228)
+ * [接口限流](files/10092_接口限流.md?t=1567997064228)
+ * [监控日志](files/10093_监控日志.md?t=1567997064228)
+ * [SDK开发](files/10095_SDK开发.md?t=1567997064228)
+ * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1567997064228)
+ * [应用授权](files/10097_应用授权.md?t=1567997064228)
+ * [传统web开发](files/10100_传统web开发.md?t=1567997064228)
+ * [文件上传](files/10104_文件上传.md?t=1567997064228)
+ * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1567997064228)
+ * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1567997064228)
+ * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1567997064228)
* 原理分析
- * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1567770151560)
- * [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1567770151560)
- * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1567770151560)
- * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1567770151560)
- * [常见问题](files/90100_常见问题.md?t=1567770151560)
+ * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1567997064229)
+ * [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1567997064229)
+ * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1567997064229)
+ * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1567997064229)
+ * [常见问题](files/90100_常见问题.md?t=1567997064229)
diff --git a/doc/docs/files/10030_业务参数校验.md b/doc/docs/files/10030_业务参数校验.md
index 99599216..6ea1bce3 100644
--- a/doc/docs/files/10030_业务参数校验.md
+++ b/doc/docs/files/10030_业务参数校验.md
@@ -27,6 +27,21 @@ public class GoodsParam {
```
+- 校验顺序
+
+如果存在多个注解,可以指定groups来控制校验顺序,如下代码所示:
+
+```java
+@NotBlank(message = "NotBlank", groups = Group1.class)
+// 优先校验Group2
+// 可交换下面Group2,Group3,看下校验顺序
+@Length(min = 2, max = 20, message = "length must 10~20", groups = Group2.class)
+@Pattern(regexp = "[a-zA-Z]*", message = "name must letters", groups = Group3.class)
+private String name;
+```
+
+优先校验`@Length`,通过后再校验`@Pattern`
+
## 参数校验国际化
国际化的配置方式如下:
diff --git a/sop-common/sop-service-common/pom.xml b/sop-common/sop-service-common/pom.xml
index 9bb50bd3..83627a83 100644
--- a/sop-common/sop-service-common/pom.xml
+++ b/sop-common/sop-service-common/pom.xml
@@ -58,6 +58,24 @@
spring-boot-autoconfigure
true
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ javax.el
+ javax.el-api
+ 3.0.0
+ test
+
+
+ org.glassfish
+ javax.el
+ 3.0.0
+ test
+
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java
index 31ca519f..63d58761 100644
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java
+++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java
@@ -4,6 +4,7 @@ import com.gitee.sop.servercommon.bean.ServiceContext;
import com.gitee.sop.servercommon.exception.ServiceException;
import com.gitee.sop.servercommon.message.ServiceErrorEnum;
import com.gitee.sop.servercommon.message.ServiceErrorFactory;
+import com.gitee.sop.servercommon.param.validation.ValidationGroupSequence;
import org.springframework.util.CollectionUtils;
import javax.validation.ConstraintViolation;
@@ -18,8 +19,8 @@ import java.util.Set;
public class ServiceParamValidator implements ParamValidator {
private static final String LEFT_TOKEN = "{";
private static final String RIGHT_TOKEN = "}";
- public static final String EQ = "=";
- public static final String COMMA = ",";
+ private static final String EQ = "=";
+ private static final String COMMA = ",";
private static Object[] EMPTY_OBJ_ARRAY = {};
private static javax.validation.Validator validator;
@@ -34,7 +35,7 @@ public class ServiceParamValidator implements ParamValidator {
if (obj == null) {
return;
}
- Set> set = validator.validate(obj);
+ Set> set = validator.validate(obj, ValidationGroupSequence.class);
if (!CollectionUtils.isEmpty(set)) {
ConstraintViolation