The beginning of the world

Five years ago, Block B on the 1st floor of the Science and Technology Building.

Xiao Ming stared directly at the screen, his hands crackling on the keyboard.

Thinking does not exist, thinking will only slow down Xiao Ming's speed.

Good programmers don't need to think at all, just like they don't need to write documentation and comments.

"It's really a simple need," Xiao Ming felt a little boring, "There is no challenge."

Like countless web developers, what Xiaoming does today is the user registration function.

First define the corresponding user registration object:

public class UserRegister {

    /**
     * 名称
     */
    private String name;

    /**
     * 原始密码
     */
    private String password;

    /**
     * 确认密码
     */
    private String password2;

    /**
     * 性别
     */
    private String sex;

    // getter & setter & toString()
}

There are also simple restrictions on the format requirements document when registering:

(1) The name name must be between 1-32 digits

(2) The password must be between 6-32 digits

(3) password2 The confirmation password must be consistent with password

(4) Sex must be either BOY/GIRL.

"It's not difficult." The ruthless coding machine began to frantically tap the keyboard, and the basic verification method was written in a short while:

private void paramCheck(UserRegister userRegister) {
    //1. 名称
    String name = userRegister.getName();
    if(name == null) {
        throw new IllegalArgumentException("名称不可为空");
    }
    if(name.length() < 1 || name.length() > 32) {
        throw new IllegalArgumentException("名称长度必须介于 1-32 之间");
    }

    //2. 密码
    String password = userRegister.getPassword();
    if(password == null) {
        throw new IllegalArgumentException("密码不可为空");
    }
    if(password.length() < 6 || password.length() > 32) {
        throw new IllegalArgumentException("密码长度必须介于 6-32 之间");
    }
    //2.2 确认密码
    String password2 = userRegister.getPassword2();
    if(!password.equals(password2)) {
        throw new IllegalArgumentException("确认密码必须和密码保持一致");
    }

    //3. 性别
    String sex = userRegister.getSex();
    if(!SexEnum.BOY.getCode().equals(sex) && !SexEnum.GIRL.getCode().equals(sex)) {
        throw new IllegalArgumentException("性别必须指定为 GIRL/BOY");
    }
}

After finishing the work, Xiao Ming submitted the code and ran off the job early.

See Hibernate-Validator for the first time

"Xiao Ming, I briefly looked at your code today." The project manager said casually.

Xiao Ming stopped his work and looked at the project manager, meaning to let him continue.

"The whole is quite rigorous, that is, too much verification code has been written."

"Too many verification codes? What should I do if users fill in randomly without verifying data?" Xiao Ming didn't quite understand.

"If you have time to verify the code, you can learn about the hibernate-validator verification framework."

"Yes, I have time to check it out."

As he spoke, Xiao Ming felt 10,000 unwilling in his heart.

What dormant frame affects my speed of moving bricks.

Later, Xiao Ming reluctantly searched for hibernate-validator, and it looked pretty good.

This framework provides many built-in annotations to facilitate the development of daily verification and greatly improve the reusability of verification methods.

Therefore, Xiao Ming improved his verification method:

public class UserRegister {

    /**
     * 名称
     */
    @NotNull(message = "名称不可为空")
    @Length(min = 1, max = 32, message = "名称长度必须介于 1-32 之间")
    private String name;

    /**
     * 原始密码
     */
    @NotNull(message = "密码不可为空不可为空")
    @Length(min = 1, max = 32, message = "密码长度必须介于 6-32 之间")
    private String password;

    /**
     * 确认密码
     */
    @NotNull(message = "确认密码不可为空不可为空")
    @Length(min = 1, max = 32, message = "确认密码必须介于 6-32 之间")
    private String password2;

    /**
     * 性别
     */
    private String sex;

}

The calibration method is adjusted as follows:

private void paramCheck2(UserRegister userRegister) {
    //1. 名称
    ValidateUtil.validate(userRegister);

    //2.2 确认密码
    String password2 = userRegister.getPassword2();
    if(!userRegister.getPassword().equals(password2)) {
        throw new IllegalArgumentException("确认密码必须和密码保持一致");
    }

    //3. 性别
    String sex = userRegister.getSex();
    if(!SexEnum.BOY.getCode().equals(sex) && !SexEnum.GIRL.getCode().equals(sex)) {
        throw new IllegalArgumentException("性别必须指定为 GIRL/BOY");
    }
}

It's really refreshing a lot, ValidateUtil is based on a simple tool class:

public class ValidateUtil {

    /**
     * 使用hibernate的注解来进行验证
     */
    private  static Validator validator = Validation
            .byProvider(HibernateValidator.class)
            .configure().failFast(true)
            .buildValidatorFactory()
            .getValidator();

    public static <T> void validate(T t) {
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
        // 抛出检验异常
        if (constraintViolations.size() > 0) {
            final String msg = constraintViolations.iterator().next().getMessage();
            throw new IllegalArgumentException(msg);
        }
    }

}

But Xiaoming still feels dissatisfied, can the sex verification be further optimized?

The answer is yes, Xiao Ming found that hibernate-validator supports custom annotations.

This is a very powerful feature. The should provide users with more possibilities .

So Xiao Ming implemented a custom annotation:

@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyEnumRangesValidator.class)
public @interface MyEnumRanges {

    Class<? extends Enum> value();

    String message() default "";

}

The implementation of MyEnumRangesValidator is as follows:

public class MyEnumRangesValidator implements
        ConstraintValidator<MyEnumRanges, String> {

    private MyEnumRanges myEnumRanges;

    @Override
    public void initialize(MyEnumRanges constraintAnnotation) {
        this.myEnumRanges = constraintAnnotation;
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return getEnumValues(myEnumRanges.value()).contains(value);
    }

    /**
     * 获取枚举值对应的信息
     *
     * @param enumClass 枚举类
     * @return 枚举说明
     * @since 0.0.9
     */
    private List<String> getEnumValues(Class<? extends Enum> enumClass) {
        Enum[] enums = enumClass.getEnumConstants();

        return ArrayUtil.toList(enums, new IHandler<Enum, String>() {
            @Override
            public String handle(Enum anEnum) {
                return anEnum.toString();
            }
        });
    }

}

Restrict the current field value must be within the specified enumeration range, all future enumeration ranges involved, use this annotation to get it.

Then add @MyEnumRanges to the sex field:

@NotNull(message = "性别不可为空")
@MyEnumRanges(message = "性别必须在 BOY/GIRL 范围内", value = SexEnum.class)
private String sex;

In this way, the verification method can be simplified as follows:

private void paramCheck3(UserRegister userRegister) {
    //1. 名称
    ValidateUtil.validate(userRegister);
    //2.2 确认密码
    String password2 = userRegister.getPassword2();
    if(!userRegister.getPassword().equals(password2)) {
        throw new IllegalArgumentException("确认密码必须和密码保持一致");
    }
}

Xiao Ming smiled with satisfaction.

But his smile only lasted for a while, because he found an unsatisfactory place.

Can the code for confirming the password be removed?

It seems impossible to use the hibernate-validator framework directly.

Inadequacies of the framework

All this made Xiaoming very painful, he found that the framework itself did have many shortcomings.

Scenarios that hibernate-validator cannot satisfy

The most popular hibernate-validator framework for java today, but some scenarios cannot be satisfied.

for example:

  1. Verify that the new password and the confirmed password are the same. (The relationship between different attributes under the same object)
  2. When an attribute value satisfies a certain condition, the parameter verification of other values is performed.
  3. Multiple attribute values, at least one cannot be null

In fact, hibernate-validator will be weaker when dealing with the relationship between multiple fields.

This project combines the original advantages to strengthen the function of this point.

validation-api is too complex

The validation-api provides a wealth of feature definitions, but it also brings a problem.

Realization is particularly complicated.

However, in actual use, we often do not need such a complicated implementation.

valid-api provides a set of apis that are much simplified for users to implement by themselves.

Customization lacks flexibility

In the use of hibernate-validator, the implementation of custom constraints is based on annotations, which is not flexible enough for single attribute verification.

In this project, attribute verification constraints and annotation constraints are distinguished to facilitate reuse and expansion.

Procedural programming vs annotation programming

The core of hibernate-validator supports annotation programming and bean-based validation.

One problem is that it is not flexible for attribute verification. Sometimes, for bean verification, you still have to write your own judgment.

This project supports fluent-api for procedural programming, as well as annotation programming.

Give consideration to flexibility and convenience as much as possible.

The birth of the valid tool

So Xiaoming spent a long time writing a verification tool, hoping to make up for the shortcomings of the above tools.

Open source address: https://github.com/houbb/valid

characteristic

  • Support fluent-validation
  • Support jsr-303 annotations, support all hibenrate-validator common annotations
  • Support i18n
  • Support user-defined strategy
  • Support user-defined annotations
  • Support verification for attributes
  • Support procedural programming and annotation programming
  • Supports specifying the conditions for validating verification

Quick start

Introduced by maven

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>valid-jsr</artifactId>
    <version>0.2.2</version>
</dependency>

coding

Use of tools:

User user = new User();
user.sex("what").password("old").password2("new");

ValidHelper.failOverThrow(user);

The error is as follows:

ValidRuntimeException will be thrown, the information of the exception is as follows:

name: 值 <null> 不是预期值,password: 值 <old> 不是预期值,sex: 值 <what> 不是预期值

The definition of User is as follows:

public class User {

    /**
     * 名称
     */
    @HasNotNull({"nickName"})
    private String name;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 原始密码
     */
    @AllEquals("password2")
    private String password;

    /**
     * 新密码
     */
    private String password2;

    /**
     * 性别
     */
    @Ranges({"boy", "girl"})
    private String sex;

    /**
     * 失败类型枚举
     */
    @EnumRanges(FailTypeEnum.class)
    private String failType;

    //Getter and Setter
}

The introduction of built-in annotations is as follows:

annotationinstruction
@AllEqualsThe current field and the specified field value must all be equal
@HasNotNullAt least one of the current field and the specified field value is not null
@EnumRangesThe current field value must be within the enumeration property range
@RangesThe current field value must be within the specified attribute range

When Xiaoming designed the verification tool, he made a little improvement to address the shortcomings of hibernater.

You can make connections between fields to provide more powerful functions.

Each annotation has a corresponding procedural method, allowing you to switch freely between annotation and procedural methods.

Built-in @Condition annotation effective conditions, making annotation effective more flexible.

Xiao Ming looked up and looked at the clock on the wall. The night was too deep. It is better to see it after hearing it. If you are interested, you can feel it for yourself:

Open source address: https://github.com/houbb/valid

summary

This open source tool is the product of not wanting to write too many verification methods in daily work. It is still in the early stage and there are still many areas for improvement.

However, I hope you like it.

I am an old horse, and I look forward to seeing you again next time.

在这里插入图片描述


老马啸西风
191 声望34 粉丝