参数校验

在 Dubbo 中进行参数校验

特性说明

参数验证功能是基于 JSR303 实现的,用户只需标识 JSR303 标准的验证 annotation,并通过声明 filter 来实现验证。

Maven 依赖

1. <dependency>
2. <groupId>javax.validation</groupId>
3. <artifactId>validation-api</artifactId>
4. <version>1.0.0.GA</version>
5. </dependency>
6. <dependency>
7. <groupId>org.hibernate</groupId>
8. <artifactId>hibernate-validator</artifactId>
9. <version>4.2.0.Final</version>
10. </dependency>

使用场景

服务端在向外提供接口服务时,解决各种接口参数校验问题。

参考用例 https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-validation

使用方式

参数标注示例

1. import java.io.Serializable;
2. import java.util.Date;

4. import javax.validation.constraints.Future;
5. import javax.validation.constraints.Max;
6. import javax.validation.constraints.Min;
7. import javax.validation.constraints.NotNull;
8. import javax.validation.constraints.Past;
9. import javax.validation.constraints.Pattern;
10. import javax.validation.constraints.Size;

12. public class ValidationParameter implements Serializable {
13. private static final long serialVersionUID = 7158911668568000392L;

15. @NotNull // 不允许为空
16. @Size(min = 1, max = 20) // 长度或大小范围
17. private String name;

19. @NotNull(groups = ValidationService.Save.class) // 保存时不允许为空,更新时允许为空 ,表示不更新该字段
20. @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
21. private String email;

23. @Min(18) // 最小值
24. @Max(100) // 最大值
25. private int age;

27. @Past // 必须为一个过去的时间
28. private Date loginDate;

30. @Future // 必须为一个未来的时间
31. private Date expiryDate;

33. public String getName() {
34. return name;
35. }

37. public void setName(String name) {
38. this.name = name;
39. }

41. public String getEmail() {
42. return email;
43. }

45. public void setEmail(String email) {
46. this.email = email;
47. }

49. public int getAge() {
50. return age;
51. }

53. public void setAge(int age) {
54. this.age = age;
55. }

57. public Date getLoginDate() {
58. return loginDate;
59. }

61. public void setLoginDate(Date loginDate) {
62. this.loginDate = loginDate;
63. }

65. public Date getExpiryDate() {
66. return expiryDate;
67. }

69. public void setExpiryDate(Date expiryDate) {
70. this.expiryDate = expiryDate;
71. }
72. }

分组验证示例

1. public interface ValidationService { // 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class)
2. @interface Save{} // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选
3. void save(ValidationParameter parameter);
4. void update(ValidationParameter parameter);
5. }

关联验证示例

1. import javax.validation.GroupSequence;

3. public interface ValidationService {
4. @GroupSequence(Update.class) // 同时验证Update组规则
5. @interface Save{}
6. void save(ValidationParameter parameter);

8. @interface Update{}
9. void update(ValidationParameter parameter);
10. }

参数验证示例

1. import javax.validation.constraints.Min;
2. import javax.validation.constraints.NotNull;

4. public interface ValidationService {
5. void save(@NotNull ValidationParameter parameter); // 验证参数不为空
6. void delete(@Min(1) int id); // 直接对基本类型参数验证
7. }

在客户端验证参数

1. <dubbo:reference id="validationService" interface="org.apache.dubbo.examples.validation.api.ValidationService" validation="true" />

在服务器端验证参数

1. <dubbo:service interface="org.apache.dubbo.examples.validation.api.ValidationService" ref="validationService" validation="true" />

Dubbo 默认支持 hibernate-validator 版本 <=6.x,若使用 hibernate-validator 7.x 版本,请将 validation 参数声明为 jvalidationNew

验证异常信息

1. import javax.validation.ConstraintViolationException;
2. import javax.validation.ConstraintViolationException;

4. import org.springframework.context.support.ClassPathXmlApplicationContext;

6. import org.apache.dubbo.examples.validation.api.ValidationParameter;
7. import org.apache.dubbo.examples.validation.api.ValidationService;
8. import org.apache.dubbo.rpc.RpcException;

10. public class ValidationConsumer {
11. public static void main(String[] args) throws Exception {
12. String config = ValidationConsumer.class.getPackage().getName().replace('.', '/') + "/validation-consumer.xml";
13. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
14. context.start();
15. ValidationService validationService = (ValidationService)context.getBean("validationService");
16. // Error
17. try {
18. parameter = new ValidationParameter();
19. validationService.save(parameter);
20. System.out.println("Validation ERROR");
21. } catch (RpcException e) { // 抛出的是RpcException
22. ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); // 里面嵌了一个ConstraintViolationException
23. Set<ConstraintViolation<?>> violations = ve.getConstraintViolations(); // 可以拿到一个验证错误详细信息的集合
24. System.out.println(violations);
25. }
26. }
27. }

验证方式可扩展,扩展方式参见开发者手册中的 验证扩展

最后修改 September 13, 2024: Refactor website structure (#2860) (1a4b998f54b)