zoukankan      html  css  js  c++  java
  • 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切面,在切面中进行验证
  • 相关阅读:
    初认识AngularJS
    (imcomplete) UVa 10127 Ones
    UVa 10061 How many zero's and how many digits?
    UVa 11728 Alternate Task
    UVa 11490 Just Another Problem
    UVa 10673 Play with Floor and Ceil
    JSON对象和字符串的收发(JS客户端用typeof()进行判断非常重要)
    HTML.ActionLink 和 Url.Action 的区别
    EASYUI TREE得到当前节点数据的GETDATA方法
    jqueery easyui tree把已选中的节点数据拼成json或者数组(非常重要)
  • 原文地址:https://www.cnblogs.com/sky-chen/p/11721402.html
Copyright © 2011-2022 走看看