dubbo 参数验证
官网:https://dubbo.apache.org/zh/docs/advanced/parameter-validation/
参数验证
相关依赖
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.2.Final</version>
</dependency>
pojo 层:标注验证注解
@Data
public class ValidationParameter implements Serializable {
private static final long serialVersionUID = 7158911668568000392L;
@NotNull // 不允许为空
@Size(min = 1, max = 20) // 长度或大小范围
private String name;
@NotNull(groups = ValidationService.Save.class) // 保存时不允许为空,更新时允许为空 ,表示不更新该字段
@Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
private String email;
@Min(18) // 最小值
@Max(100) // 最大值
private int age;
@Past // 必须为一个过去的时间
private Date loginDate;
@Future // 必须为一个未来的时间
private Date expiryDate;
}
service 层:对pojo参数分组验证
public interface ValidationService { // 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class)
@interface Save{} //与方法同名接口,首字母大写,用于区分验证场景
//分组名也可以自定义,无大小写要求
//如:@NotNull(groups = ValidationService.Save.class),可选
void save(ValidationParameter parameter);
void update(ValidationParameter parameter);
}
servcie 层:定义分组验证顺序
@GroupSequence(value = {ValidationService.Save.class, ValidationService.Update.class})
public interface ValidationService {
@interface Save{}
void save(ValidationParameter parameter);
@interface Update{}
void update(ValidationParameter parameter);
}
service 层:对方法参数进行验证
public interface ValidationService {
void save(@NotNull ValidationParameter parameter); //参数不为空
void delete(@Min(1) int id); //验证基本类型参数
}
开启验证:如果不开启验证,不会检验参数
# 服务端开启验证
<dubbo:service id="validationService"
interface="org.apache.dubbo.examples.validation.api.ValidationService"
ref="validationService" validation="true" />
# 消费端开启验证
<dubbo:reference id="validationService"
interface="org.apache.dubbo.examples.validation.api.ValidationService"
validation="true" />
使用示例
************
服务端
application.yml
dubbo:
application:
name: dubbo-provider
#register-mode: instance
registry:
address: localhost:2181
protocol: zookeeper
group: dubbo
protocol:
name: dubbo
#port: 20880
Product:需实现seriable接口
@Data
public class Product implements Serializable {
private Integer id;
private String name;
private Integer num;
private Double price;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
ProductService
public interface ProductService {
Map<Integer,Product> save(Product product);
Product updatePrice(Product product);
void delete(Integer id);
}
ProductServiceImpl
@DubboService
public class ProductServiceImpl implements ProductService {
private Map<Integer,Product> map = new HashMap<>();
@Override
public Map<Integer,Product> save(Product product) {
map.put(product.getId(),product);
return map;
}
@Override
public Product updatePrice(Product product) {
Product object = map.get(product.getId());
object.setPrice(product.getPrice());
return map.get(product.getId());
}
@Override
public void delete(Integer id) {
map.remove(id);
}
}
************
消费端
application.yml
dubbo:
application:
name: dubbo-consumer
registry:
protocol: zookeeper
address: localhost:2181
group: dubbo
#register-mode: instance
protocol:
name: dubbo
#port: 20880
server:
port: 8081
Product:添加验证注解,在消费端验证
@Data
public class Product implements Serializable {
@NotNull
private Integer id;
@NotNull(groups = ProductService.Save.class)
private String name;
@NotNull(groups = ProductService.Save.class)
private Integer num;
@NotNull(groups = ProductService.UpdatePrice.class)
@DecimalMin(value = "1")
private Double price;
@Past(groups = ProductService.Save.class)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@Future(groups = ProductService.Save.class)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
ProductService:添加验证注解,对方法参数进行验证
public interface ProductService {
@GroupSequence(value = {UpdatePrice.class})
@interface Save{}
Map<Integer,Product> save(Product product);
@interface UpdatePrice{}
Product updatePrice(Product product);
void delete(Integer id);
}
HelloController
@RestController
public class HelloController {
@DubboReference(validation = "true")
private ProductService productService;
@RequestMapping("/save")
public Map<Integer,Product> save(Product product){
return productService.save(product);
}
@RequestMapping("/update")
public Product updatePrice(Product product){
return productService.updatePrice(product);
}
@RequestMapping("/delete")
public void save(@Min(1) @NotNull Integer id){
productService.delete(id);
}
}
************
使用测试
save:时间不满足验证要求,报错
java.lang.ClassNotFoundException: javax.validation.ValidationException
at org.apache.dubbo.validation.filter.ValidationFilter.invoke(ValidationFilter.java:88) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:313) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CallbackRegistrationInvoker.invoke(FilterChainBuilder.java:187) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invokeWithContext(AbstractClusterInvoker.java:364) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:332) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:99) ~[dubbo-3.0.5.jar:3.0.5]
...
save:所有参数均满足验证要求,可成功插入数据
update:更新数据时,price为空不满足验证规则报错
javax.validation.ValidationException: Failed to validate service: com.example.demo.service.ProductService, method: updatePrice, cause: [ConstraintViolationImpl{interpolatedMessage='不能为null', propertyPath=price, rootBeanClass=class com.example.demo.pojo.Product, messageTemplate='{javax.validation.constraints.NotNull.message}'}]
at org.apache.dubbo.validation.filter.ValidationFilter.invoke(ValidationFilter.java:96) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:313) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CallbackRegistrationInvoker.invoke(FilterChainBuilder.java:187) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invokeWithContext(AbstractClusterInvoker.java:364) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:332) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:99) ~[dubbo-3.0.5.jar:3.0.5]
...
update:更新数据时,price不为空可正常插入
delete:数据删除时,id最小为1,不满足报错
javax.validation.ValidationException: Failed to validate service: com.example.demo.service.ProductService, method: delete, cause: [ConstraintViolationImpl{interpolatedMessage='最小不能小于2', propertyPath=deleteArgument0, rootBeanClass=class com.example.demo.service.ProductService_DeleteParameter_java.lang.Integer, messageTemplate='{javax.validation.constraints.Min.message}'}]
at org.apache.dubbo.validation.filter.ValidationFilter.invoke(ValidationFilter.java:96) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CopyOfFilterChainNode.invoke(FilterChainBuilder.java:313) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder$CallbackRegistrationInvoker.invoke(FilterChainBuilder.java:187) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invokeWithContext(AbstractClusterInvoker.java:364) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:332) ~[dubbo-3.0.5.jar:3.0.5]
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:99) ~[dubbo-3.0.5.jar:3.0.5]
...
delete:数据删除时,id为1,可正常删除