欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

validation实现自定义注解

程序员文章站 2022-06-22 15:38:47
...

java接口使用入参时经常会判断一些参数的校验规则,使用validation的标签判断能拦截大部分不符合要求的参数,如:notnull max min ...

而有些业务需求的判断也可以通过自定义的标签来实现


下面实现request入参:判断多个参数需要有至少一个不为空


pom依赖的包:

                <dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.0.2.Final</version>
		</dependency>

		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>

 


自定义标签的实现:

package com.use;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;

import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SimultaneousNotNull.BindChecker.class)
@Documented
public @interface SimultaneousNotNull {
  //该组检查不为空的参数共有几个
  int checkCount();

  String message() default "参数不能同时为空!";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};


  public static class BindChecker implements ConstraintValidator<SimultaneousNotNull, String> {

    private static final ReentrantLock LOCK = new ReentrantLock();
    
    //全局统计打标签SimultaneousNotNull 的个数,用来跟checkCount判断是否可做最后一个判断
    private static AtomicInteger atomicInteger = new AtomicInteger(0);
    
    //标记打标签SimultaneousNotNull是否有一个入参有值,只要一个有值置为true,即满足条件
    private static AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    /**
     * @see javax.validation.ConstraintValidator#initialize(java.lang.annotation.Annotation)
     */
    public void initialize(SimultaneousNotNull constraintAnnotation) {}

    /**
     * @see javax.validation.ConstraintValidator#isValid(java.lang.Object,
     *      javax.validation.ConstraintValidatorContext)
     */
    public boolean isValid(String strValue, ConstraintValidatorContext context) {
      atomicInteger.getAndIncrement();
      Map<String, Object> attributes =
          ((ConstraintValidatorContextImpl) context).getConstraintDescriptor().getAttributes();
      String type = (String) attributes.get("type");
      String message = (String) attributes.get("message");
      int checkCount = Integer.parseInt(attributes.get("checkCount").toString());
      
      //同步加锁
      LOCK.lock();
      try {
        if (StringUtils.isNotBlank(strValue)) {
          atomicBoolean.set(true);
        }
        //last one
        if (atomicInteger.get() == checkCount && !atomicBoolean.get()) {
          return false;
        }
        return true;
      } finally {
        if (atomicInteger.get() == checkCount) {
          atomicBoolean.set(false);
          atomicInteger.set(0);
        }
        // 释放锁
        LOCK.unlock();
      }
    }


  }

}

 

request校验的实体

package com.use;

import javax.validation.constraints.NotNull;

public class BindCase{

  @SimultaneousNotNull(checkCount = 2)
  private String customer;
  
  @SimultaneousNotNull(checkCount = 2)
  private String id;
  
  @NotNull
  private String name;

  public String getCustomer() {
    return customer;
  }

  public void setCustomer(String customer) {
    this.customer = customer;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  
  
}

 

main方法

package com.use;

import java.util.Iterator;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.groups.Default;
public class Main {
  
  public static void main(String[] args) {
    BindCase case1 = new BindCase();
//    case1.setCustomer("1");

  Set<ConstraintViolation<BindCase>> constraintViolations =
      Validation.buildDefaultValidatorFactory().getValidator().validate(case1, Default.class);
  if (!constraintViolations.isEmpty()) {
      Iterator<ConstraintViolation<BindCase>> it = constraintViolations.iterator();
      StringBuilder sb = new StringBuilder();
      String msg;
      while (it.hasNext()) {
          sb.append(it.next().getMessage());
          sb.append(",");
      }
      msg = sb.substring(0, sb.lastIndexOf(",")).toString();
      System.err.println(msg);
      System.err.println("校验结束");
  }
  }
  

}

 

以上的业务逻辑实现主要是实现了javax.validation.ConstraintValidatorContext接口

如果有其它需求也可以参考实现自定义的校验标签