龙空技术网

自定义validation注解:解决动态多字段联动校验问题

JAVA前线 519

前言:

而今你们对“validationapi冲突”大约比较关注,小伙伴们都需要学习一些“validationapi冲突”的相关内容。那么小编同时在网络上搜集了一些有关“validationapi冲突””的相关文章,希望朋友们能喜欢,小伙伴们一起来了解一下吧!

欢迎大家关注今日头条号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考

1 文章概述

javax.validation是基于JSR-303标准定义的一组接口,目的是使开发者简洁地校验参数,hibernate-validator实现了这一组接口,可以作为工具独立引用。

<dependency>    <groupId>javax.validation</groupId>    <artifactId>validation-api</artifactId>    <version>1.1.0.Final</version></dependency><dependency>    <groupId>org.hibernate</groupId>    <artifactId>hibernate-validator</artifactId>    <version>6.0.18.Final</version></dependency>

如果是SpringBoot项目则无需显示引用上述依赖,因为SpringBoot已经将上述依赖进行了集成。

2 基本使用2.1 定义模型

import java.math.BigDecimal;import java.util.List;import javax.validation.constraints.DecimalMin;import javax.validation.constraints.Max;import javax.validation.constraints.Min;import javax.validation.constraints.NotBlank;import javax.validation.constraints.Size;import lombok.Data;@Datapublic class OrderModelA {    @Min(value = 1, message = "订单编号必须大于等于1")    @Max(value = 100, message = "订单编号必须小于等于100")    private Integer orderId;    @NotBlank(message = "订单名称不能为空")    private String orderName;    @Size(min = 1, max = 10)    private List<String> goodsList;    @DecimalMin(value = "1", message = "订单金额必须大于等于1")    private BigDecimal amount;}

2.2 定义接口

import javax.validation.Valid;import javax.validation.constraints.NotNull;import org.springframework.validation.annotation.Validated;import com.java.front.validation.model.OrderModelA;@Validatedpublic interface BizValidateService {    void bizMethodA(@Valid OrderModelA model, @NotNull String param);}

2.3 接口实现

import javax.validation.Valid;import javax.validation.constraints.NotNull;import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSON;import com.java.front.validation.model.OrderModelA;@Componentpublic class BizValidateServiceImpl implements BizValidateService {    @Override    public void bizMethodA(@Valid OrderModelA model, @NotNull String param) {        System.out.println("execute bizA model=" + JSON.toJSONString(model) + ",param=" + param);    }}

2.4 测试用例

@RunWith(SpringRunner.class)@SpringBootTestpublic class TestAuthApplication {    @Autowired    private BizValidateService bizValidateService;    @Test    public void testBizValidateA_correct() {        OrderModelA model = new OrderModelA();        model.setOrderId(1);        model.setOrderName("订单名称");        List<String> goodsList = new ArrayList<String>();        goodsList.add("goods1");        goodsList.add("goods2");        goodsList.add("goods3");        model.setGoodsList(goodsList);        model.setAmount(new BigDecimal("10"));        bizValidateService.bizMethodA(model, "param");    }    @Test    public void testBizValidateA_error() {        OrderModelA model = new OrderModelA();        model.setOrderId(0);        model.setOrderName("订单名称");        List<String> goodsList = new ArrayList<String>();        goodsList.add("goods1");        goodsList.add("goods2");        goodsList.add("goods3");        model.setGoodsList(goodsList);        model.setAmount(new BigDecimal("10"));        bizValidateService.bizMethodA(model, "param");    }}

2.5 报错信息

javax.validation.ConstraintViolationException: bizMethodA.model.orderId: 订单编号必须大于等于1	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:117)	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)	at com.java.front.validation.BizValidateServiceImpl$$EnhancerBySpringCGLIB$$42c25c43.bizMethodA(<generated>)	at com.java.front.TestAuthApplication.testBizValidateA_error(TestAuthApplication.java:62)

3 复杂应用

现在我们假设一种场景订单新增了type1、type2两个字段,这两个字段影响对于orderId值范围判断,也就是说orderId范围判断不再是静态的,而是受其它字段影响。

针对这种情况第一步我们可以构造type1、type2、orderId组合字段,第二步自定义校验器将组合字段拆开进行业务校验。

3.1 定义注解

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import javax.validation.Constraint;import javax.validation.Payload;@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })@Constraint(validatedBy = TypeAndOrderIdValidator.class)public @interface TypeAndOrderIdValid {    String message() default "不满足业务条件";    Class<?>[] groups() default {};    Class<? extends Payload>[] payload() default {};}

3.2 定义校验器

import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import com.java.front.validation.model.OrderModelB;public class TypeAndOrderIdValidator implements ConstraintValidator<TypeAndOrderIdValid, String> {    @Override    public boolean isValid(String value, ConstraintValidatorContext context) {        String[] array = value.split(OrderModelB.JOINT);        int type1 = Integer.parseInt(array[0]);        int type2 = Integer.parseInt(array[1]);        int orderId = Integer.parseInt(array[2]);        if (type1 == 1 && type2 == 2) {            return orderId > 20;        }        return true;    }}

3.3 定义模型

import java.math.BigDecimal;import java.util.List;import javax.validation.constraints.DecimalMin;import javax.validation.constraints.Max;import javax.validation.constraints.Min;import javax.validation.constraints.NotBlank;import javax.validation.constraints.Size;import com.alibaba.fastjson.annotation.JSONField;import com.java.front.server.validation.extend.TypeAndOrderIdValid;import lombok.Data;@Datapublic class OrderModelB {    public static final String JOINT = "_";    @Min(value = 1, message = "订单编号必须大于等于1")    @Max(value = 100, message = "订单编号必须小于等于100")    private Integer orderId;    @NotBlank(message = "订单名称不能为空")    private String orderName;    @Size(min = 1, max = 10)    private List<String> goodsList;    @DecimalMin(value = "1", message = "订单金额必须大于等于1")    private BigDecimal amount;    private int type1;    private int type2;    @JSONField(serialize = false)    private String typeAndOrderIdComposite;    @TypeAndOrderIdValid    public String getTypeAndOrderIdComposite() {        return getType1() + JOINT + getType2() + JOINT + getOrderId();    }}

3.4 定义接口

import javax.validation.Valid;import javax.validation.constraints.NotNull;import org.springframework.validation.annotation.Validated;import com.java.front.validation.model.OrderModelB;@Validatedpublic interface BizValidateService {    void bizMethodB(@Valid OrderModelB model, @NotNull String param);}

3.5 接口实现

import javax.validation.Valid;import javax.validation.constraints.NotNull;import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSON;import com.java.front.server.validation.model.OrderModelB;@Componentpublic class BizValidateServiceImpl implements BizValidateService {    @Override    public void bizMethodB(@Valid OrderModelB model, @NotNull String param) {        System.out.println("execute bizB model=" + JSON.toJSONString(model) + ",param=" + param);    }}

3.6 测试用例

@RunWith(SpringRunner.class)@SpringBootTestpublic class TestAuthApplication {    @Autowired    private BizValidateService bizValidateService;    @Test    public void testBizValidateB_correct() {        OrderModelB model = new OrderModelB();        model.setOrderId(30);        model.setOrderName("订单名称");        List<String> goodsList = new ArrayList<String>();        goodsList.add("goods1");        goodsList.add("goods2");        goodsList.add("goods3");        model.setGoodsList(goodsList);        model.setAmount(new BigDecimal("10"));        model.setType1(1);        model.setType2(2);        bizValidateService.bizMethodB(model, "param");    }    @Test    public void testBizValidateB_error() {        OrderModelB model = new OrderModelB();        model.setOrderId(1);        model.setOrderName("订单名称");        List<String> goodsList = new ArrayList<String>();        goodsList.add("goods1");        goodsList.add("goods2");        goodsList.add("goods3");        model.setGoodsList(goodsList);        model.setAmount(new BigDecimal("10"));        model.setType1(1);        model.setType2(2);        bizValidateService.bizMethodB(model, "param");    }}

3.7 错误信息

javax.validation.ConstraintViolationException: bizMethodB.model.typeAndOrderIdComposite: 不满足业务条件	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:117)	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)	at com.java.front.validation.BizValidateServiceImpl$$EnhancerBySpringCGLIB$$7c26a7cb.bizMethodB(<generated>)	at com.java.front.server.TestAuthApplication.testBizValidateB_error(TestAuthApplication.java:94)

4 文章总结

本文第一章节介绍了validation基本概念,第二章节介绍了validation基本应用,第三章节介绍了通过自定义注解动态校验字段,希望本文对大家有所帮助。

欢迎大家关注今日头条号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考

标签: #validationapi冲突