自定义验证器,保证同一个类中的两个属性不同时为空。以Person类为例,用户post时至少需要输入一种姓名,无论是中文名还是英文名
@interface
package com.skye.utils;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* @author skye
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//指定注解的实现类
@Constraint(validatedBy = ValuesValidNotNullImpl.class)
public @interface ValuesNotBothNull {
String message() default "At least one name is required";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@target
指定注解的作用目标
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
本例中因为要处理类的多个属性,所以注解作用在类上
@Retention
指定注解的作用时效
RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
本例中Validator一定要保留至运行时期
@Documented
说明该注解将被包含在javadoc中
我觉得这个无所谓吧,加了也不影响什么
@Constraint
指定注解的实现类
实现类负责具体的验证逻辑
变量
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
一定要有
实现类
package com.skye.utils;
import com.skye.entity.Person;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Slf4j
public class ValuesValidNotNullImpl implements ConstraintValidator<ValuesNotBothNull, Person> {
@Override
public void initialize(ValuesNotBothNull constraintAnnotation) {
log.info("init validator-------");
}
@Override
public boolean isValid(Person person, ConstraintValidatorContext constraintValidatorContext) {
if (person.getChineseName() != null && !person.getChineseName().equalsIgnoreCase("")){
log.info("has chineseName");
return true;
}else if (person.getEnglishName() != null && !person.getEnglishName().equalsIgnoreCase("")){
log.info("has EnglishName");
return true;
}else{
log.info("No Name");
return false;
}
}
}
Init
重写方法,接收到待验证对象时触发,详见控制台
isValid
True:验证通过
False:验证失败
Person
package com.skye.entity;
import com.skye.utils.ValuesNotBothNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ValuesNotBothNull
public class Person {
private String ChineseName;
private String EnglishName;
}
与常见的@NotEmpty等验证不同,这是写在类上的
Controller
package com.skye.controller;
import com.skye.entity.Person;
import com.skye.entity.User;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
@Slf4j
public class PersonController {
@PostMapping("/person")
public void person(@Valid Person person,BindingResult bindingResult){
if (bindingResult.hasErrors()){
log.info("person is illegal");
}else{
log.info("person={} is legal",person);
}
log.info("-----------------------------");
}
}
我的bindingResult不为空,但是defaultmessage为空,所以我没输出message
控制台
中英文名字都有
Validator init方法被call
只有中文名没有英文名
只有英文名没有中文名
既没有中文名也没有英文名
实现目标