前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中的参数验证(非Spring版)

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

作者头像
老梁
修改2019-10-25 12:00:59
2.4K0
修改2019-10-25 12:00:59
举报

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

1.1. 前言

  • 为什么我总遇到这种非正常问题,我们知道很多时候我们的参数校验都是放在controller层的传入参数进行校验,我们常用的校验方式就是引入下列的jar包,在参数中添加@Validated,并对Bean对象的参数做不同的注解处理就行,对Spring这种常用做法大家应该比较熟了
  • 但我现在遇到的需求,因为boss追求通用性,我们的controller入口只有一个,是通过传入参数中的不同tradeCode来区分调用哪个服务,这时我校验参数就得放到具体的每个服务方法上了,这样经过我的测试,加该注解已经不起作用了
代码语言:txt
复制
    <!--jsr 303-->
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
代码语言:txt
复制
    @PostMapping("/save/valid")
    public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
        userService.save(userDTO);
        return RspDTO.success();
    }
代码语言:txt
复制
@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. 主方法

代码语言:txt
复制
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. 实体类

代码语言:txt
复制
/**
 * @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分组

代码语言:txt
复制
import javax.validation.groups.Default;

/**
 * @author laoliangliang
 * @date 2019/10/22 16:32
 */
public interface Update extends Default {
}
代码语言:txt
复制
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. 自定义注解

代码语言:txt
复制
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();
    }
}
代码语言:txt
复制
/**
 * @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切面,在切面中进行验证
老梁讲Java
老梁讲Java

欢迎关注公众号,一起学习进步

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Java中的参数验证(非Spring版)
    • 1.1. 前言
      • 1.2. 方案
        • 1.2.1. 主方法
        • 1.2.2. 实体类
        • 1.2.3. group分组
        • 1.2.4. 自定义注解
      • 1.3. 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档