种一棵树最好的时间是10年前,其次就是现在,加油!
                                                                                   --by蜡笔小柯南

你是否还在Controller里写满if(userName == null)这样的判空代码?每次新增参数都要复制粘贴一堆校验逻辑?不仅繁琐,而且极易出错!本文将带你使用Spring Validation一站式解决参数校验难题,用注解代替繁琐逻辑,让代码更简洁、更健壮!

依赖导入

在pom文件中导入validation的依赖,添加依赖坐标

        <!-- validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>3.2.2</version>
        </dependency>

自定义参数校验工具类

创建名为BeanValidator的工具类,定义validateObject 校验方法

/** 
 * 商品实体类
 * 
 * @author 蜡笔小鑫星
 */
public class BeanValidator {

    private static Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(true)
            .buildValidatorFactory().getValidator();


    public static void validateObject(Object object, Class<?>... groups) {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
        if (constraintViolations.stream().findFirst().isPresent()) {
            throw new ValidationException(constraintViolations.stream().findFirst().get().getMessage());
        }
    }
}
  • Validation.byProvider(HibernateValidator.class):使用HibernateValidator作为验证提供者,用于验证Java Bean的约束

  • configure:用于对ValidatorFactory进行配置,可以设置不同的参数来调整验证行为

  • failFast:配置是否快速失败,可配置为true或fasle

    • true:配置为true,则在验证参数的过程中,碰到第一个不满足约束的就立即停止,不再向后继续验证
    • false:配置为false,则会收集所有不满足约束的错误信息,而不是在第一个约束不满足时就停止
  • buildValidatorFactory().getValidator():构建ValidatorFactory实例,获取Validator对象,Validator是执行验证操作的核心接口

validateObject方法中,调用validator.validate(object, groups)去校验参数,返回一个Set集合。如果有参数校验没有通过,那么Set集合中保存的就是未通过校验的参数数据;如果参数校验全部通过,那么Set集合中的元素个数就是0。

数据校验

在类的字段上,添加对应的注解,以及校验不通过时的错误信息

/** 
 * 商品实体类
 * 
 * @author 蜡笔小鑫星
 */
public class Goods {
    
    @NotBlank(message = "商品名称不能为空")
    private String goodsName;
    
    @NotNull(message = "商品数量不能为空")
    private Integer goodsCount;
    
    @NotNull(message = "商品价格不能为空")
    @DecimalMin(value = "0.0", inclusive = false, message = "商品价格必须大于0")
    private BigDecimal price;

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public Integer getGoodsCount() {
        return goodsCount;
    }

    public void setGoodsCount(Integer goodsCount) {
        this.goodsCount = goodsCount;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

调用BeanValidator.validateObject()方法,完成参数校验

/**
 * 单元测试类
 *
 * @author 蜡笔小鑫星
 */
@SpringBootTest
class ApplicationTests {

    @Test
    public void testValidator() {
        Goods goods = new Goods();
        goods.setGoodsName("商品1");
        goods.setGoodsCount(10);
        try {
            BeanValidator.validateObject(goods);
        } catch (ValidationException e) {
            System.out.println(e.getMessage());
        }
    }
}

try-catch中捕获了 ValidationException 异常,打印了异常的message信息。

这里我们以商品价格为例,设置了商品名称、商品数量,没有设置商品价格属性,所以验证完成后输出:商品价格不能为空。

两种校验方式的对比

普通if方式

构建Controller,使用if的方式进行入参校验

/**
 * @author 蜡笔小鑫星
 */
@RestController
@RequestMapping("/goods")
public class GoodsController {

    @PostMapping("/validate")
    public void goods(@RequestBody Goods goods) {
        String goodsName = goods.getGoodsName();
        if (goodsName == null) {
            System.out.println("商品名称不能为空");
            return;
        }
        Integer goodsCount = goods.getGoodsCount();
        if (goodsCount == null) {
            System.out.println("商品数量不能为空");
            return;
        }
        BigDecimal price = goods.getPrice();
        if (price == null) {
            System.out.println("商品价格不能为空");
            return;
        }
        BigDecimal zero = new BigDecimal("0.0");
        if (price.compareTo(zero) <= 0) {
            System.out.println("商品价格必须大于0");
            return;
        }
        System.out.println("模拟其他业务逻辑处理...");
    }
}

可见,非常多的if代码,这还只是校验3个参数的情况下,如果需要校验的参数更多,那么会有更多的if块,代码也会越来越臃肿。

当入参不满足条件时,控制台打印错误信息。

如:入参为以下数据

{
  "goodsName": "玫瑰花",
  "goodsCount": 1,
  "price": "-2"
}

则输出:商品价格必须大于0

校验工具类方式

改造Controller层代码,使用BeanValidator工具类的方式

/**
 * @author 蜡笔小鑫星
 */
@RestController
@RequestMapping("/goods")
public class GoodsController {

    @PostMapping("/validate")
    public void goods(@RequestBody Goods goods) {
        try {
            BeanValidator.validateObject(goods);
        }catch (ValidationException e) {
            System.out.println(e.getMessage());
            return;
        }
        System.out.println("模拟其他业务逻辑处理...");
    }
}

我们捕获了异常,把异常信息进行了打印。

使用以下数据进行验证:

{
  "goodsName": "",
  "goodsCount": 1,
  "price": "3"
}

控制台打印输出:商品名称不能为空

可以看到,使用工具类的方式,大大减少了if代码,只需调用BeanValidator.validateObject(goods)就能搞定,如果后续需要新增校验其他字段,只需在Goods类中需要校验的字段上,添加对应的注解即可。


结语

只要再涉及到参数校验,再也不用写一堆if去判断,只需要在需要校验的属性上添加注解,调用工具类方法校验即可。

现在,你已经掌握了用Spring Validation取代繁琐if-else的精髓。想象一下,当你的代码中不再充斥着重复的判空逻辑,这种清爽感是多么令人愉悦!



如果你有任何疑问或经验分享,可以在评论区留言哦~~

不管在任何时候,我希望你永远不要害怕挑战,不要畏惧失败。每一个错误都是向成功迈出的一步,每一个挑战都是成长的机会,因为每一次的努力,都会使我们离梦想更近一点。只要你行动起来,任何时候都不算晚。最后,把座右铭送给大家:种一棵树最好的时间是10年前,其次就是现在,加油!共勉 💪。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐