• 自定义注解实现入参校验


    一、需求背景

    对于一些业务场景,接口字段很多,且对字段格式有特殊要求、或者各个字段之间有级联关系,为了写出优雅的代码,避免接口字段校验逻辑对业务主体逻辑的侵入,考虑使用注解方式去校验字段,当然也支持自定义注解。

    二、实现方案

    使用Spring Validation注解实现对接口入参的校验。

    接下来展示,使用自定义注解校验入参某几个字段之间的校验,例如入参的“省、市、区”的级联校验

    三、编码实现

    3.1 项目结构

    3.2 自定义注解

    1. package com.saferycom.validate;
    2. import javax.validation.Constraint;
    3. import javax.validation.Payload;
    4. import java.lang.annotation.*;
    5. /**
    6. * @author LH
    7. */
    8. @Documented
    9. @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
    10. @Retention(RetentionPolicy.RUNTIME)
    11. @Constraint(validatedBy = PccMatchValidator.class)
    12. public @interface PccMatch {
    13. // 省
    14. String prov();
    15. // 市
    16. String city();
    17. // 区
    18. String country();
    19. // 默认错误消息
    20. String message() default "Invalid value for MyConstraint";
    21. // 分组
    22. Class[] groups() default {};
    23. // 负载
    24. Classextends Payload>[] payload() default {};
    25. }

    3.3 自定义校验器

    1. package com.saferycom.validate;
    2. import org.springframework.beans.BeanWrapperImpl;
    3. import javax.validation.ConstraintValidator;
    4. import javax.validation.ConstraintValidatorContext;
    5. /**
    6. * @author LH
    7. */
    8. public class PccMatchValidator implements ConstraintValidator {
    9. private String prov;
    10. private String city;
    11. private String country;
    12. @Override
    13. public void initialize(PccMatch args) {
    14. // 初始化逻辑
    15. this.prov = args.prov();
    16. this.city = args.city();
    17. this.country = args.country();
    18. }
    19. @Override
    20. public boolean isValid(Object obj, ConstraintValidatorContext context) {
    21. // 结构体为空的默认返回true
    22. if (obj == null) {
    23. return true;
    24. }
    25. BeanWrapperImpl beanWrapper = new BeanWrapperImpl(obj);
    26. String province = (String) beanWrapper.getPropertyValue(this.prov);
    27. String city1 = (String) beanWrapper.getPropertyValue(this.city);
    28. String country1 = (String) beanWrapper.getPropertyValue(this.country);
    29. // todo 这里可以添加具体的验证逻辑,这里简单示例
    30. if ("31000".equals(province) && "31100".equals(city1) && "31101".equals(country1)) {
    31. return true;
    32. }
    33. return false;
    34. }
    35. }

    3.4 定义一个接口的入参,对需要校验的字段打上自定义注解

    1. package com.saferycom.validate;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Builder;
    4. import lombok.Data;
    5. import lombok.NoArgsConstructor;
    6. import javax.validation.Valid;
    7. /**
    8. * @author LH
    9. */
    10. @Data
    11. @Builder
    12. @AllArgsConstructor
    13. @NoArgsConstructor
    14. @Valid
    15. @PccMatch(prov = "prov", city = "city", country = "country", message = "省市区级联校验失败")
    16. public class RegisterAddress {
    17. private String id;
    18. private String prov;
    19. private String city;
    20. private String country;
    21. }

    3.5 定义一个接口,进行测试

    1. package com.saferycom.validate;
    2. import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
    3. import org.springframework.web.bind.annotation.PostMapping;
    4. import org.springframework.web.bind.annotation.RequestBody;
    5. import org.springframework.web.bind.annotation.RequestMapping;
    6. import org.springframework.web.bind.annotation.RestController;
    7. import javax.annotation.Resource;
    8. import javax.validation.ConstraintViolation;
    9. import java.util.Set;
    10. /**
    11. * @author LH
    12. */
    13. @RestController
    14. @RequestMapping("/test")
    15. public class ValidateTestController {
    16. @Resource
    17. private LocalValidatorFactoryBean localValidatorFactoryBean;
    18. @PostMapping("/validate")
    19. public String validateTest(@RequestBody RegisterAddress address) {
    20. Set> violations = localValidatorFactoryBean.getValidator().validate(address);
    21. return "ok";
    22. }
    23. }

    3.5 启动服务,使用ApiPost调用接口查看校验情况

     断点测试,查看校验结果

    如上图,我们拿到的校验结果。 

    四、总结

    以上,就是使用自定义注解实现接口入参校验,后续,我们校验完成之后,可以考虑抛出异常,然后对抛出的异常进行统一收集处理,然后统一返回给接口调用者,这里的操作我们放到下期进行展示。

    期待一下吧,一起学习,一起进步。

  • 相关阅读:
    匠心新品:大彩科技超薄7寸WIFI线控器发布,热泵、温控器、智能家电首选!
    Python的math.sqrt()和math.pow()的使用
    leetcode(力扣) 54. 螺旋矩阵 (边界控制思路)
    数据结构:顺序表
    浅析GC-垃圾回收
    vie的刷新机制
    Docker 中的端口
    java学习--day23(线程池)
    Kubernetes集群中配置Ingress支持HTTPS访问(一):cfssl
    重载与重写有什么区别?
  • 原文地址:https://blog.csdn.net/weixin_42324005/article/details/140054265