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切面,在切面中进行验证
  • 相关阅读:
    HDU 3681 Prison Break 越狱(状压DP,变形)
    POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
    ZOJ 3471 Most Powerful (状压DP,经典)
    POJ 2288 Islands and Bridges (状压DP,变形)
    HDU 3001 Travelling (状压DP,3进制)
    POJ 3311 Hie with the Pie (状压DP)
    POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
    FZU 2204 7
    POJ 3254 Corn Fields (状压DP,轮廓线DP)
    ZOJ 3494 BCD Code (数位DP,AC自动机)
  • 原文地址:https://www.cnblogs.com/sky-chen/p/11721402.html
Copyright © 2011-2022 走看看