Simple Implementation of Spring Verification of validator and JSR 303

  • 2021-11-29 23:58:58
  • OfStack

Directory Spring Verification (validator, JSR-303) What is the JSR-303 specification combined with Spring MVC entity class add validation annotation controller validation annotation add Java Hibernate Validator JSR-303 validation integration use annotation instruction

Implementation of Spring Verification (validator, JSR-303)

What is the JSR-303 specification

JSR 303 is a sub-specification of Java EE 6, which is called Bean Validation. The official reference implementation is hibernate Validator, which has nothing to do with Hibernate ORM. JSR 303 is used to validate the values of the fields in Java Bean.

Combined with Spring MVC

Spring-mvc. xml configuration:


    <!--JSR-303-->
    <mvc:annotation-driven validator="validator"/>
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
        <property name="validationMessageSource" ref="messageSource"/>
    </bean>
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="validatemessage"/>
        <property name="useCodeAsDefaultMessage" value="false"/>
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="cacheSeconds" value="60"/>
    </bean>
    <bean  id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
        <property name="conversionService">
            <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
        </property>
        <property name="validator" ref="validator"/>
    </bean>

Entity class adds validation annotations

Post some codes here and know how to annotate them:


import com.lemontree.common.utils.AjaxResult;
import com.lemontree.common.utils.StringUtil;
import com.lemontree.common.utils.email.EmailUtils;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.Date;
public class User {
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.id
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    private Integer id;
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.user_name
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    @NotEmpty(message = " User name cannot be empty ")
    private String userName;
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.password
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    @NotEmpty(message = " Password cannot be empty ")
    private String password;
    }

Controller validation annotation addition

Follow the @ Validated annotation before the entity class, followed by BindingResult:


    @RequestMapping(value = "/login.htm", method = RequestMethod.POST)
    public @ResponseBody AjaxResult login(@Validated User user, BindingResult bindingResult,
                                          HttpServletRequest request, HttpServletResponse response) {
        if (bindingResult.hasErrors()){
            List<FieldError> errorses = bindingResult.getFieldErrors();
            if (CollectionUtils.isNotEmpty(errorses)){
                errorses.forEach(item->{
                    System.out.println(item.getDefaultMessage());
                });
            }
        }
      }

Java Hibernate Validator JSR-303 Verification

JSR-303 is a sub-specification of JAVA EE 6, called Bean Validation, and Hibernate Validator is the reference implementation of Bean Validation.

The actual use is to add constraints to the field through annotations, and then verify whether the field conforms to the specification. If it does not conform, an exception will be thrown, so as to reduce the code for verifying data and ensure that the obtained data conform to the specification. It can also be used together with Spring framework

Integration

Official documents

https://mvnrepository.com/artifact/org.hibernate/hibernate-validator

https://mvnrepository.com/artifact/javax.validation/validation-api


        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.10.Final</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.el</artifactId>
            <version>3.0.1-b09</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>

Use

Verification object


public class JsrTest {
    @NotNull(message = "id Cannot be empty !")
    @Min(value = 1, message = "Id Only greater than or equal to 1")
    Integer id;
    @NotNull(message = " Name cannot be empty !")
    String name;
    public void validateParams() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();// Get 1 Verifier 
        Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(this);// Validation data , Get the error set 
        Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
        if (iterator.hasNext()) {
            String errorMessage = iterator.next().getMessage();// Get an error message 
            throw new ValidationException(errorMessage);
        }
    }
    public static void main(String args[]) {
        JsrTest req = new JsrTest();
        req.id = 1;
        req.validateParams();
    }
}

Constraints are declared by adding annotations to attributes as above

Check attribute

The above is to verify the whole object, or you can verify a field separately:


validator.validateProperty(object, "name");

Packet check


public class JsrTest {
    @NotNull(message = "id Cannot be empty !", groups = {ValidationGroup.class})
    @Min(value = 1, message = "Id Only greater than or equal to 1")
    Integer id;
    @NotNull(message = " Name cannot be empty !", groups = {ValidationGroup.class})
    String name;
    @DecimalMin(value = "1.1")
    double price;
    int date;
    public static void validateParams(JsrTest jsrTest) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(jsrTest, ValidationGroup.class);
        Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
        if (iterator.hasNext()) {
            String errorMessage = iterator.next().getMessage();
            throw new ValidationException(errorMessage);
        }
    }
    public static void main(String args[]) {
        JsrTest req = new JsrTest();
        validateParams(req);
    }    
    public interface ValidationGroup {
    }
}

The calss specified by packet check must be 1 interface, and multiple interfaces can be specified

Custom constraint

Normally, the annotations provided by the framework can already meet the normal verification requirements, but we can also customize the annotations to meet our requirements

Our example here is that the annotated string cannot contain the specified characters


@Target(FIELD)      // Meta-annotation , Define the annotation to be used on the field 
@Retention(RUNTIME) // Define the life cycle of annotations 
@Constraint(validatedBy = CustomValidator.class)// Validator indicating the annotation 
@Documented         // Indicates that the annotation will be added to the JavaDoc Medium 
public @interface CustomConstraints {
    String message() default " Default exception message";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {}; // This property can be used to mark the severity level of the error , But not by API Used by oneself 
    String value() default " ";
}

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
 *  Need to implement ConstraintValidator Interface 
 *  The first of generic 1 Parameters are custom annotations , No. 1 2 The type of field annotated by the parameter annotation 
 */
public class CustomValidator implements ConstraintValidator<CustomConstraints, String> {
    private String value;
    /**
     *  Initialization call , Get the specified by the annotation value
     *
     * @param constraintAnnotation
     */
    @Override
    public void initialize(CustomConstraints constraintAnnotation) {
        value = constraintAnnotation.value();
    }
    /**
     * @param value    The value of the field annotated 
     * @param context
     * @return true  Pass verification ,false  Failed to validate 
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value != null && value.contains(this.value)) {
            context.disableDefaultConstraintViolation();// Disable default messages 
            context.buildConstraintViolationWithTemplate(" Newly added error message ").addConstraintViolation();
            return false;
        }
        return true;
    }
}

Then you can use it like other annotations 1

Encapsulation

Or extract the code for verifying parameters and write a method separately


    public static void validateParams(Object object) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();// Get 1 Verifier 
        Set<ConstraintViolation<Object>> violationSet = validator.validate(object);// Validation data , Get the error set 
        Iterator<ConstraintViolation<Object>> iterator = violationSet.iterator();
        if (iterator.hasNext()) {
            String errorMessage = iterator.next().getMessage();// Get an error message 
            throw new ValidationException(errorMessage);
        }
    }

Of course, you can return 1 boolean value without throwing an exception here. How to encapsulate it depends on the actual requirements

Used in conjunction with Spring


import com.lemontree.common.utils.AjaxResult;
import com.lemontree.common.utils.StringUtil;
import com.lemontree.common.utils.email.EmailUtils;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.Date;
public class User {
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.id
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    private Integer id;
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.user_name
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    @NotEmpty(message = " User name cannot be empty ")
    private String userName;
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.password
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    @NotEmpty(message = " Password cannot be empty ")
    private String password;
    }
0

@ Valid will validate the parameters after adding this annotation. If BindingResult is not followed, an exception will be thrown directly if the validation fails. If BindingResult parameter is added, an exception will not be thrown directly, but the exception information will be stored in BindingResult for developers to handle by themselves

If you want to use grouping, you can do this


import com.lemontree.common.utils.AjaxResult;
import com.lemontree.common.utils.StringUtil;
import com.lemontree.common.utils.email.EmailUtils;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.Date;
public class User {
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.id
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    private Integer id;
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.user_name
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    @NotEmpty(message = " User name cannot be empty ")
    private String userName;
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.password
     *
     * @mbg.generated Thu Mar 16 13:27:38 CST 2017
     */
    @NotEmpty(message = " Password cannot be empty ")
    private String password;
    }
1

@ Validated If you don't use grouping, its function and @ Valid1

Notes and instructions for use

Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是1个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是1个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是1个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是1个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是1个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是1个过去的日期
@PastOrPresent 被注释的元素必须是过去或现在的日期
@Future 被注释的元素必须是1个将来的日期
@FutureOrPresent 被注释的元素必须是将来或现在的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
@Digits(integer =, fraction =) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证
@NotBlank 字符串不能是Null还有被Trim的长度要大于0
@NotEmpty 不能为null,且长度大于0
@Negative 被注释的元素必须是负数
@NegativeOrZero 被注释的元素必须是负数或0
@Positive 必须是正数
@PositiveOrZero 必须是正数或0

Related articles: