• Java中的参数验证(非Spring版)


    1. Java中的参数验证(非Spring版)

    1.1. 前言

    • 为什么我总遇到这种非正常问题,我们知道很多时候我们的参数校验都是放在controller层的传入参数进行校验,我们常用的校验方式就是引入下列的jar包,在参数中添加@Validated,并对Bean对象的参数做不同的注解处理就行,对Spring这种常用做法大家应该比较熟了
    • 但我现在遇到的需求,因为boss追求通用性,我们的controller入口只有一个,是通过传入参数中的不同tradeCode来区分调用哪个服务,这时我校验参数就得放到具体的每个服务方法上了,这样经过我的测试,加该注解已经不起作用了
        <!--jsr 303-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
    
        @PostMapping("/save/valid")
        public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
            userService.save(userDTO);
            return RspDTO.success();
        }
    
    @Data
    public class UserDTO implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        /*** 用户ID*/
        @NotNull(message = "用户id不能为空")
        private Long userId;
        
        /** 用户名*/
        @NotBlank(message = "用户名不能为空")
        @Length(max = 20, message = "用户名不能超过20个字符")
        @Pattern(regexp = "^[\u4E00-\u9FA5A-Za-z0-9\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
        private String username;
        
        /** 手机号*/
        @NotBlank(message = "手机号不能为空")
        @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
        private String mobile;
    
        /**性别*/
        private String sex;
    
        /** 邮箱*/
        @NotBlank(message = "联系邮箱不能为空")
        @Email(message = "邮箱格式不对")
        private String email;
    
        /** 密码*/
        private String password;
    
        /*** 创建时间 */
        @Future(message = "时间必须是将来时间")
        private Date createTime;
    
    }
    

    1.2. 方案

    • 不能用它的注解,但我们可以用它的方法,下面我写了一个用Java代码验证参数的例子,抛砖引玉,并不能直接用在自己的系统哦,想要使用请结合自己系统封装方法,我打算做成注解的形式,利用spring aop切我的服务层,实现的效果就和controller层类似了

    1.2.1. 主方法

    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.Validator;
    import javax.validation.ValidatorFactory;
    import java.util.Date;
    import java.util.Set;
    import java.util.stream.Stream;
    
    /**
     * @author laoliangliang
     * @date 2019/10/22 15:19
     */
    public class ValidLearn {
        public static void main(String[] args) {
            ValidLearn learn = new ValidLearn();
            learn.testValid(new Order().setIdcard("33062119981012361X").setName("  ").setCreateDate(new Date()));
        }
    
        public void testValid(@Validated Order order) {
            ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
            Validator validator = validatorFactory.getValidator();
            //分组Insert.class则id为空不检验
            Set<ConstraintViolation<Order>> validate = validator.validate(order, Insert.class);
            Stream.of(validate).forEach(action -> {
                for (ConstraintViolation<Order> orderConstraintViolation : action) {
                    String message = orderConstraintViolation.getMessage();
                    System.out.println(message);
                }
            });
        }
    }
    

    1.2.2. 实体类

    /**
     * @author laoliangliang
     * @date 2019/10/21 16:44
     */
    @Data
    @Accessors(chain = true)
    public class Order {
    
        @NotNull(message = "id不能为空",groups = Update.class)
        private Long id;
    
        @NotEmpty(message = "name is not null",groups = Insert.class)
        private String name;
    
        @Future(message = "必须之后的时间")
        private Date createDate;
    
        @IdCardValid(message = "idcard 不合法")
        private String idcard;
    }
    
    • 以上两个代码就可以做到检验实体类对象注解,并打印校验不通过的消息了,可以改造成存在校验错误消息则抛出异常
    • 代码还涉及了一些细节,比如group分组和自定义注解

    1.2.3. group分组

    import javax.validation.groups.Default;
    
    /**
     * @author laoliangliang
     * @date 2019/10/22 16:32
     */
    public interface Update extends Default {
    }
    
    import javax.validation.groups.Default;
    
    /**
     * @author laoliangliang
     * @date 2019/10/22 16:32
     */
    public interface Insert extends Default {
    }
    
    
    • 我例子代码中用到了Insert.class,表示做插入动作时,存在这个分组的注解才会起作用,因此我id不传,id不为空的注解也不会起作用

    1.2.4. 自定义注解

    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * @author laoliangliang
     * @date 2019/10/22 15:55
     */
    public class IdCardValidator implements ConstraintValidator<IdCardValid, Object> {
    
        private Pattern pattern = Pattern.compile("^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])" +
                "\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$");
        @Override
        public void initialize(IdCardValid idCardValid) {
        }
    
        @Override
        public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
            Matcher matcher = pattern.matcher(o.toString());
            return matcher.matches();
        }
    }
    
    /**
     * @author laoliangliang
     * @date 2019/10/22 15:53
     */
    @Documented
    @Target({ElementType.PARAMETER,ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = IdCardValidator.class)
    public @interface IdCardValid {
    
        String message() default "身份证不合法";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
    • 这里我以验证身份证号为例,写了个自定义注解,实现ConstraintValidator接口,在isValid方法中实现自定义逻辑即可使用注解

    1.3. 总结

    • 此篇举了Validation用Java代码实现验证的例子,应对service层参数验证,实际应用到自己代码可以自己写个自定义注解,实现aop切面,在切面中进行验证
  • 相关阅读:
    fastadmin自定义列表下拉框筛选
    printf输出16进制和对齐, fprintf的运用
    微信小程序代码提交发布之后,必须删除原来的小程序才会更新到最新的代码
    win 内存优化
    CRT工具 直连AMZ主机
    解决Jumpserver邮件不发送
    NxShell
    Photoshop 2022 破解版下载
    IDA Pro7.7破解版下载
    MAC下调用已打开浏览器的方法
  • 原文地址:https://www.cnblogs.com/sky-chen/p/11721402.html
Copyright © 2020-2023  润新知