1. 应用层如何使用
package com.ken.business.protocol.input;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ken.business.protocol.vaildhandler.BirthdayVaildHandler;
import com.ken.common.web.vaild.annotation.KenVaild;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.*;
import java.util.Date;
@Data
@KenVaild(message = "年龄和生日不匹配", handler = BirthdayVaildHandler.class)
public class StudentInput {
@NotNull(message = "姓名不能为空")
private String name;
@Min(value = 1, message = "年龄不能小于1岁")
@Max(value = 20, message = "年龄不能大于20岁")
private Integer age;
@Email
@NotNull(message = "邮箱不能为空")
private String email;
@NotNull(message = "性别不能为空")
private Integer sex;
@Past(message = "生日范围不正确")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
private Date birthday;
}
package com.ken.business.protocol.vaildhandler;
import com.ken.business.protocol.input.StudentInput;
import com.ken.common.web.vaild.annotation.KenVaild;
import com.ken.common.web.vaild.handler.KenVaildHandler;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
@Component
public class BirthdayVaildHandler implements KenVaildHandler<StudentInput> {
@Override
public boolean vaild(KenVaild kenVaild, StudentInput data) {
System.out.println("自定义的校验触发!");
Integer age = data.getAge();
Date birthday = data.getBirthday();
if (age == null || birthday == null) return true;
//当前时间
Date now = new Date();
//日历对象
Calendar calender = Calendar.getInstance();
calender.setTime(now);
int nowYear = calender.get(Calendar.YEAR);
calender.setTime(birthday);
int birthdayYear = calender.get(Calendar.YEAR);
if (nowYear - birthdayYear == age)
return true;
return false;
}
}
2. 架构层涉及到的类
2.1 自定义的参数校验注解
package com.ken.common.web.vaild.annotation;
import com.ken.common.web.vaild.constraint.KenVaildConstraint;
import com.ken.common.web.vaild.handler.KenVaildHandler;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义的参数校验注解
*/
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
//当前自定义的参数校验注解 对应的校验类型
@Constraint(validatedBy = KenVaildConstraint.class)
public @interface KenVaild {
/**
* 校验失败后的提示
* @return
*/
String message() default "校验失败";
/**
* 校验的分组
* @return
*/
Class<?>[] groups() default {};
/**
* 校验的负载
* @return
*/
Class<? extends Payload>[] payload() default {};
/**
* 实际的校验处理器的Class对象
* @return
*/
Class<? extends KenVaildHandler> handler();
}
2.2 当前自定义的参数校验注解,对应的校验类型
package com.ken.common.web.vaild.constraint;
import com.ken.common.web.utils.ApplicationContextUtils;
import com.ken.common.web.vaild.annotation.KenVaild;
import com.ken.common.web.vaild.handler.KenVaildHandler;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Optional;
/**
* 自定义的参数校验类
*/
public class KenVaildConstraint implements ConstraintValidator<KenVaild, Object> {
private KenVaild kenVaild;
@Override
public void initialize(KenVaild kenVaild) {
this.kenVaild = kenVaild;
}
/**
* 实际的校验方法
* true表示校验通过
* false 表示不通过
* @param value
* @param context
* @return
*/
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
//判断非空
if (value != null) {
Class<? extends KenVaildHandler> handler = kenVaild.handler();
//交给KenVaildHandler处理该数据
KenVaildHandler kenVaildHandler = ApplicationContextUtils.getBean(handler);
return Optional
.ofNullable(kenVaildHandler)
.map(kenVaildHandler1 -> {
return kenVaildHandler.vaild(kenVaild, value);
}).orElse(false);
}
//如果校验数据为null,则直接通过校验
return true;
}
}
其中涉及到的ApplicationContextUtils的封装:
package com.ken.common.web.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* Spring容器的工具方法 - 手动从Spring容器中获取Bean对象
*/
@Component
public class ApplicationContextUtils {
@Autowired
private ApplicationContext applicationContext;
/**
* 静态的容器对象
*/
private static ApplicationContext staticApplicationContext;
/**
* 初始化方法
*/
@PostConstruct
public void init(){
ApplicationContextUtils.staticApplicationContext = applicationContext;
}
/**
* 根据class类型获取Spring容器中的对象
* @param cls
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> cls){
if (staticApplicationContext != null) {
return staticApplicationContext.getBean(cls);
}
return null;
}
}
2.3 拓展自定义的校验规则的接口
package com.ken.common.web.vaild.handler;
import com.ken.common.web.vaild.annotation.KenVaild;
/**
* 拓展接口 - 主要让开发者实现该接口,拓展自定义的校验规则
*/
public interface KenVaildHandler<T> {
/**
* 实际的校验方法
* @param data
* @return
*/
boolean vaild(KenVaild kenVaild, T data);
}
3. 自定义校验器的流程图
参考的工程:https://gitee.com/wlkken/ken_framework_pom
参考课程:https://www.bilibili.com/video/BV1hQ4y1z78B?p=20