Spring Validation數(shù)據(jù)校驗(yàn)詳解
Spring Validation數(shù)據(jù)校驗(yàn)
Spring Validation是SpringFramework提供的一種輕量級的數(shù)據(jù)驗(yàn)證框架,用于Java對象進(jìn)行校驗(yàn)。
Spring Validation(Spring的數(shù)據(jù)驗(yàn)證組件)其實(shí)是一個(gè)抽象層,它為數(shù)據(jù)驗(yàn)證提供了統(tǒng)一的接口和基本的校驗(yàn)功能。
Spring Validation默認(rèn)使用了Hibernate Validator作為其具體的實(shí)現(xiàn),但是也可以通過適配器與其他數(shù)據(jù)驗(yàn)證框架(如Apache Commons Validator)一起工作。
Spring Validation的主要功能包括:
1、提供了一套注解,用于對Java對象進(jìn)行校驗(yàn);
2、支持嵌套校驗(yàn),用于對一個(gè)對象中的屬性進(jìn)行遞歸校驗(yàn);
3、支持分組校驗(yàn),用于根據(jù)不同的校驗(yàn)場景,使用不同的校驗(yàn)規(guī)則;
4、支持國際化,可以根據(jù)不同的語言環(huán)境,使用不同的校驗(yàn)提示消息。
5、支持自定義注解和校驗(yàn)器,滿足各種復(fù)雜的校驗(yàn)需求。
Spring提供的數(shù)據(jù)校驗(yàn)方式:
- 實(shí)現(xiàn)org.springframework.validation.Validator接口,調(diào)用接口實(shí)現(xiàn)類;
- 通過 注解 方式進(jìn)行數(shù)據(jù)校驗(yàn)(按照Bean Validation方式);
- 基于 方法(函數(shù)) 實(shí)現(xiàn)數(shù)據(jù)校驗(yàn);
- 自定義校驗(yàn)
依賴引入:
如果springboot版本小于2.3.x,spring-boot-web-starter會自動引入hibernate-validator。
如果spring-boot版本為2.3.x,則需要手動引入依賴,如:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>1、Validator接口方式
@Data
public class Person {
private String name;
private int age;
}
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
/**
* @description 實(shí)現(xiàn)接口{@link org.springframework.validation.Validator}
*/
public class PersonValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Person.class.equals(clazz);
}
@Override
public void validate(Object obj, Errors errors) {
//設(shè)置name為空時(shí),報(bào)錯(cuò):name.empty
ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
//傳入對象,強(qiáng)轉(zhuǎn)為實(shí)體類Person對象
Person p = (Person) obj;
if (p.getAge() < 0) { //設(shè)置age屬性小于零時(shí)報(bào)錯(cuò)
errors.rejectValue("age", "error (age < 0)");
} else if (p.getAge() > 110) {//設(shè)置age屬性大于110報(bào)錯(cuò)
errors.rejectValue("age", "error (age > 110) too old !!");
}
}
}
/**
* 測試
*
*/
@Slf4j
class IomsApplicationTests {
public static void main(String[] args) {
Person person = new Person();
// person.setName("高啟強(qiáng)");
// person.setAge(29);
//創(chuàng)建person對象的DataBinder
DataBinder binder = new DataBinder(person);
//設(shè)置校驗(yàn)
binder.setValidator(new PersonValidator());
//校驗(yàn)(當(dāng)person屬性值為空時(shí),校驗(yàn)不通過)
binder.validate();
//輸出校驗(yàn)結(jié)果
BindingResult bindingResult = binder.getBindingResult();
System.out.println(bindingResult.getAllErrors());
}
}2、基于注解方式(Bean Validation)
使用Bean Validation校驗(yàn)方式,需要將Bean Validation需要的javax.validation.ValidatorFactory和javax.validation.Validator注入到容器中。
Spring默認(rèn)有一個(gè)實(shí)現(xiàn)類LocalValidatorFactoryBean,它實(shí)現(xiàn)了Bean Validator中的接口和org.springframework.validation.Validator接口。
在springboot2.2.2中已自動注入,源碼如下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
/**
* 基于方法的校驗(yàn)方式
*/
@Bean
@ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
@Lazy Validator validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
processor.setProxyTargetClass(proxyTargetClass);
processor.setValidator(validator);
return processor;
}
}
Spring Validation常用的注解
@NotNull:檢查是否為null,不能為null。@NotBlank:檢查字符串是否為null或空字符串。@NotEmpty:檢查字符串、集合或數(shù)組是否為null或空。@Min:檢查數(shù)字是否大于等于指定值。@Max:檢查數(shù)字是否小于等于指定值。@DecimalMin:檢查數(shù)字是否大于等于指定值。@DecimalMax:檢查數(shù)字是否小于等于指定值。@Size:檢查字符串、集合或數(shù)組的長度是否在指定范圍內(nèi)。@Digits:檢查數(shù)字是否符合指定的精度和小數(shù)位數(shù)。@Past:檢查日期是否在當(dāng)前時(shí)間之前。@Future:檢查日期是否在當(dāng)前時(shí)間之后。@Pattern:檢查字符串是否匹配指定的正則表達(dá)式。@Email:檢查是否為有效的電子郵件地址。@Length:檢查字符串的長度是否在指定范圍內(nèi)。@Range:檢查數(shù)字是否在指定范圍內(nèi)。@Positive:檢查數(shù)字是否為正數(shù)。@PositiveOrZero:檢查數(shù)字是否為非負(fù)數(shù)。@Negative:檢查數(shù)字是否為負(fù)數(shù)。@NegativeOrZero:檢查數(shù)字是否為非正數(shù)。@AssertTrue:檢查是否為true。@AssertFalse:檢查是否為false。@NotNull(message = “{user.name.notnull}”):使用國際化消息提示。@NotBlank(message = “{user.name.notblank}”):使用國際化消息提示。@NotEmpty(message = “{user.name.notempty}”):使用國際化消息提示。@Email(message = “{user.email.format}”):使用國際化消息提示。@Valid:用于嵌套校驗(yàn),可以對一個(gè)對象中的屬性進(jìn)行遞歸校驗(yàn)。@ConvertGroup:用于分組校驗(yàn),可以指定校驗(yàn)的分組,根據(jù)不同的分組執(zhí)行不同的校驗(yàn)規(guī)則。@GroupSequence:用于定義校驗(yàn)分組的順序,指定不同分組的執(zhí)行順序。
手動校驗(yàn):通過"校驗(yàn)器+注解校驗(yàn)"
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
@Data
public class User {
@NotEmpty //不可為空
private String name;
@Min(0) //最小值
@Max(110) //最大值
private int age;
}
使用java原生的jakarta.validation.Validator校驗(yàn)器
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* 使用java原生的jakarta.validation.Validator校驗(yàn)
*
*/
@Service
public class JavaService {
@Autowired //自動裝配Validator對象
private Validator validator;
//校驗(yàn)方法
public boolean validator(User user){
//校驗(yàn)后的結(jié)果存放進(jìn)Set集合
Set<ConstraintViolation<User>> set = validator.validate(user);
//若沒有校驗(yàn)到錯(cuò)誤,集合為空,返回true。
return set.isEmpty();
}
}
使用spring提供的 org.springframework.validation.Validator校驗(yàn)器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindException;
import org.springframework.validation.Validator;
/**
* 使用spring提供的validate校驗(yàn)方法
*/
@Service
public class SpringService {
@Autowired
private Validator validator;
public boolean validator2(User user){
BindException bindException = new BindException(user,user.getName());
validator.validate(user,bindException); //調(diào)用校驗(yàn)方法進(jìn)行校驗(yàn)
System.out.println(bindException.getAllErrors()); //輸出所有錯(cuò)誤信息
return bindException.hasErrors(); //若沒有異常,返回false
}
}
一、基本使用:
對于Web服務(wù)來說,為防止非法參數(shù)對業(yè)務(wù)造成影響,在Controller層一定要做好參數(shù)校驗(yàn)。大部分情況下,請求參數(shù)分為如下兩種形式:
- 1、POST、PUT請求,使用@RequestBody傳遞參數(shù);
- 2、GET請求,使用@RequestParam、@PathVariable傳遞參數(shù);
①、使用@RequestBody傳遞參數(shù),后端使用DTO(Data Transfer Object 數(shù)據(jù)傳輸對象)進(jìn)行接受,只要給DTO對象加上@Validated注解就能進(jìn)行自動參數(shù)校驗(yàn)。當(dāng)校驗(yàn)失敗時(shí),會拋出MethodArgumentNotValidException異常,Spring 默認(rèn)會將其轉(zhuǎn)為400(Bad Request)請求。
@Data
@ApiModel("健康度統(tǒng)計(jì)")
public class HealthyStatistic {
@Pattern(message = "線路id只能為1-20位數(shù)字", regexp = RegexConstants.ID)
private String lineId;
@Pattern(message = "站點(diǎn)id只能為1-20位數(shù)字", regexp = RegexConstants.ID)
private String stationId;
@Pattern(message = "子系統(tǒng)id只能為1-20位數(shù)字", regexp = RegexConstants.ID)
private String subsystemId;
@EnumValue(message = "月份只能位1-12", intValues = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})
private Integer month;
}/**
* 在方法參數(shù)上聲明校驗(yàn)注解@Validated或者@Valid
*/
@PostMapping("/statistic")
public BaseResp healthyStatistic(@Validated @RequestBody HealthyStatistic healthyStatistic) {
return BaseResp.getSuccessResult();
}②、使用@RequestParam、@PathVariable傳遞參數(shù),必須在Controller類上標(biāo)注@Validated注解,
校驗(yàn)失敗會拋出ConstraintViolationException異常。
/**
* 類上標(biāo)注@Validated注解
*/
@RestController
@RequestMapping("${zte.usp.app-name}/alarm/diagnose")
@Validated
public class AlarmDiagnoseController {
@GetMapping("/get/{userId}")
public BaseResp getAlarmDiagnose(@PathVariable("userId") @Min(10000000000000000L) Long userId, @RequestParam("alarmId") @NotEmpty String alarmId) {
return IomsBaseResp.getSuccessResult(responseEntity.getData());
}
}二、分組校驗(yàn):
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@FieldNameConstants
public class Manufacturer extends Entity {
@NotBlank(message = "廠商id不能為空", groups = UpdateGroup.class)
private String id;
private String sn;
private String name;
private Integer dockingGatewayId;
public interface UpdateGroup {
}
}@PostMapping("update")
public BaseResp updateManufacturer(@Validated({Manufacturer.UpdateGroup.class, Default.class}) @RequestBody Manufacturer manufacturer) {
return manufacturerService.updateManufacturer(manufacturer);
}三、嵌套校驗(yàn):
/**
* Job屬性 嵌套校驗(yàn)使用@Valid注解
*/
@Data
public class UserDTO {
@Min(value = 10000000000000000L, groups = Update.class)
private Long userId;
@NotNull(groups = {Save.class, Update.class})
@Length(min = 2, max = 10, groups = {Save.class, Update.class})
private String userName;
@NotNull(groups = {Save.class, Update.class})
@Valid
private Job job;
@Data
public static class Job {
@Min(value = 1, groups = Update.class)
private Long jobId;
@NotNull(groups = {Save.class, Update.class})
@Length(min = 2, max = 10, groups = {Save.class, Update.class})
private String jobName;
@NotNull(groups = {Save.class, Update.class})
@Length(min = 2, max = 10, groups = {Save.class, Update.class})
private String position;
}
public interface Save {
}
public interface Update {
}
}
四、多字段聯(lián)合校驗(yàn):
Hibernate Validator提供了非標(biāo)準(zhǔn)的@GroupSequenceProvider注解。
根據(jù)當(dāng)前對象實(shí)例的狀態(tài),動態(tài)來決定加載哪些校驗(yàn)組進(jìn)入默認(rèn)校驗(yàn)組。
為了實(shí)現(xiàn)多字段聯(lián)合校驗(yàn),需要借助Hibernate Validator提供的DefaultGroupSequenceProvider接口。
/**
* 該接口定義了:動態(tài)Group序列的協(xié)定
* 要想它生效,需要在T上標(biāo)注@GroupSequenceProvider注解并且指定此類為處理類
* 如果`Default`組對T進(jìn)行驗(yàn)證,則實(shí)際驗(yàn)證的實(shí)例將傳遞給此類以確定默認(rèn)組序列
*/
public interface DefaultGroupSequenceProvider<T> {
/**
* 合格方法是給T返回默認(rèn)的組(多個(gè))。因?yàn)槟J(rèn)的組是Default
* 入?yún) object允許在驗(yàn)證值狀態(tài)的函數(shù)中動態(tài)組合默認(rèn)組序列。(非常強(qiáng)大)
* object是待校驗(yàn)的Bean。它可以為null哦~(Validator#validateValue的時(shí)候可以為null)
* 返回值表示默認(rèn)組序列的List。它的效果同@GroupSequence定義組序列,尤其是列表List必須包含類型T
*/
List<Class<?>> getValidationGroups(T object);
}
實(shí)現(xiàn)步驟:
1、實(shí)現(xiàn)DefaultGroupSequenceProvider接口
public class PersonGroupSequenceProvider implements DefaultGroupSequenceProvider<Person> {
@Override
public List<Class<?>> getValidationGroups(Person bean) {
List<Class<?>> defaultGroupSequence = new ArrayList<>();
defaultGroupSequence.add(Person.class); // 這一步不能省,否則Default分組都不會執(zhí)行了,會拋錯(cuò)的
if (bean != null) { // 這塊判空請務(wù)必要做
Integer age = bean.getAge();
if (age < 30) {
defaultGroupSequence.add(Person.AgeLt30Group.class);
} else if (age >= 30 && age < 40) {
defaultGroupSequence.add(Person.Age30And40Group.class);
}
}
return defaultGroupSequence;
}
}
2、在待校驗(yàn)的Bean上使用@GroupSequenceProvider注解指定處理器,并定義好校驗(yàn)邏輯(?;罘纸M)
@GroupSequenceProvider(PersonGroupSequenceProvider.class)
@Getter
@Setter
@ToString
public class Person {
@NotNull
private String name;
@NotNull
@Range(min = 10, max = 40)
private Integer age;
@NotNull(groups = {AgeLt30Group.class, Age30And40Group.class})
@Size(min = 1, max = 2, groups = AgeLt30Group.class)
@Size(min = 3, max = 5, groups = Age30And40Group.class)
private List<String> hobbies;
/**
* 定義專屬的業(yè)務(wù)邏輯分組
*/
public interface AgeLt30Group{
}
public interface Age30And40Group{
}
}
五、@GroupSequence(JSR提供),具有控制校驗(yàn)組順序及短路能力
public class User {
@NotEmpty(message = "firstname may be empty")
private String firstname;
@NotEmpty(message = "middlename may be empty", groups = Default.class)
private String middlename;
@NotEmpty(message = "lastname may be empty", groups = GroupA.class)
private String lastname;
@NotEmpty(message = "country may be empty", groups = GroupB.class)
private String country;
public interface GroupA {
}
public interface GroupB {
}
// 組序列
@GroupSequence({Default.class, GroupA.class, GroupB.class})
public interface Group {
}
}
3、基于方法的校驗(yàn)(MethodValidationPostProcessor)
@Data
public class User {
@NotNull
private String name;
@Min(0)
@Max(129)
private int age;
//手機(jī)號格式 1開頭 第二位是(3、4、6、7、9)其一,后面是9位數(shù)字
@Pattern(regexp = "^1(3|4|6|7|9)\\d{9}$", message = "手機(jī)號碼格式錯(cuò)誤")
@NotBlank(message = "手機(jī)號碼不能為空")
private String phone;
}
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
@Service
@Validated
public class MethodValidService {
/**
* 校驗(yàn)Service層方法參數(shù)
*
* @param user
* @return
*/
public String validParams(@Valid @NotNull User user) {
return user.toString();
}
}源碼解析:
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
private Class<? extends Annotation> validatedAnnotationType = Validated.class;
@Nullable
private Validator validator;
......
/**
* 生成切點(diǎn)AnnotationMatchingPointcut
*/
@Override
public void afterPropertiesSet() {
Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
}
/**
* 生成切面AOP advice
*/
protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
}
}public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {
@Nullable
protected Advisor advisor;
protected boolean beforeExistingAdvisors = false;
private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<>(256);
public void setBeforeExistingAdvisors(boolean beforeExistingAdvisors) {
this.beforeExistingAdvisors = beforeExistingAdvisors;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
/**
* 通過ProxyFactory返回代理對象
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
protected boolean isEligible(Object bean, String beanName) {
return isEligible(bean.getClass());
}
protected boolean isEligible(Class<?> targetClass) {
Boolean eligible = this.eligibleBeans.get(targetClass);
if (eligible != null) {
return eligible;
}
if (this.advisor == null) {
return false;
}
eligible = AopUtils.canApply(this.advisor, targetClass);
this.eligibleBeans.put(targetClass, eligible);
return eligible;
}
protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
proxyFactory.setTarget(bean);
return proxyFactory;
}
protected void customizeProxyFactory(ProxyFactory proxyFactory) {
}
}
public class MethodValidationInterceptor implements MethodInterceptor {
private final Validator validator;
......
@Override
@SuppressWarnings("unchecked")
public Object invoke(MethodInvocation invocation) throws Throwable {
// Avoid Validator invocation on FactoryBean.getObjectType/isSingleton
if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
return invocation.proceed();
}
Class<?>[] groups = determineValidationGroups(invocation);
// Standard Bean Validation 1.1 API
ExecutableValidator execVal = this.validator.forExecutables();
Method methodToValidate = invocation.getMethod();
Set<ConstraintViolation<Object>> result;
try {
result = execVal.validateParameters(
invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
catch (IllegalArgumentException ex) {
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
// Let's try to find the bridged method on the implementation class...
methodToValidate = BridgeMethodResolver.findBridgedMethod(
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
result = execVal.validateParameters(
invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
Object returnValue = invocation.proceed();
result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
return returnValue;
}
......
}
4、自定義校驗(yàn)
自定義注解,編寫校驗(yàn)器實(shí)現(xiàn)ConstraintValidator
/**
* 自定義校驗(yàn)規(guī)則的注解,并指定校驗(yàn)器
*
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EnumValueValidator.class})
public @interface EnumValue {
// 默認(rèn)錯(cuò)誤消息
String message() default "必須為指定值";
// 字符串類型
String[] strValues() default {};
// 整型
int[] intValues() default {};
// 枚舉類
Class<?> enumClass() default Class.class;
// 分組
Class<?>[] groups() default {};
// 負(fù)載
Class<? extends Payload>[] payload() default {};
// 指定多個(gè)時(shí)使用
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
@interface List {
EnumValue[] value();
}
}import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 枚舉值校驗(yàn)器
*
*/
@Slf4j
public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {
private String[] strValues;
private int[] intValues;
private List<Object> objValues = new ArrayList<>();
@Override
public void initialize(EnumValue constraintAnnotation) {
strValues = constraintAnnotation.strValues();
intValues = constraintAnnotation.intValues();
Class<?> enumClass = constraintAnnotation.enumClass();
if (!Objects.isNull(enumClass) && Enum.class.isAssignableFrom(enumClass)) {
try {
Method method = enumClass.getMethod("getId");
Object[] enumConstants = enumClass.getEnumConstants();
for (Object constant : enumConstants) {
objValues.add(method.invoke(constant));
}
} catch (Exception e) {
log.error("使用自定義枚舉類型校驗(yàn)的時(shí)候枚舉必須用id來進(jìn)行范圍校驗(yàn)", e);
}
}
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
if (Objects.isNull(value)) {
return true;
}
if (objValues.size() > 0) {
if (objValues.contains(value)) {
return true;
}
} else if (value instanceof String) {
for (String s : strValues) {
if (s.equals(value)) {
return true;
}
}
} else if (value instanceof Integer) {
for (Integer s : intValues) {
if (s == value) {
return true;
}
}
}
return false;
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot利用validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)完整指南
- Spring Validation中9個(gè)數(shù)據(jù)校驗(yàn)工具使用指南
- SpringValidation數(shù)據(jù)校驗(yàn)之約束注解與分組校驗(yàn)方式
- 使用Spring Validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的代碼詳解
- Spring?Validation實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的示例
- SpringBoot?Validation快速實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的示例代碼
- spring boot輸入數(shù)據(jù)校驗(yàn)(validation)的實(shí)現(xiàn)過程
- Spring4下validation數(shù)據(jù)校驗(yàn)無效(maven)的解決
相關(guān)文章
spring boot配合前端實(shí)現(xiàn)跨域請求訪問
本篇文章主要介紹了spring boot配合前端實(shí)現(xiàn)跨域請求訪問,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
Java Flink窗口觸發(fā)器Trigger的用法詳解
Trigger(窗口觸發(fā)器)決定了窗口(由 WindowAssigner 產(chǎn)生)什么時(shí)候調(diào)用窗口處理函數(shù)。可以根據(jù)指定的時(shí)間或數(shù)據(jù)元素條件來決定什么時(shí)候觸發(fā)。本文將詳細(xì)講講其用法,需要的可以參考一下2022-07-07
JavaWeb實(shí)戰(zhàn)之用Servlet+JDBC實(shí)現(xiàn)用戶登錄與注冊
這篇文章主要介紹了JavaWeb實(shí)戰(zhàn)之用Servlet+JDBC實(shí)現(xiàn)用戶登錄與注冊,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很大的幫助,需要的朋友可以參考下2021-04-04
Java啟動參數(shù)從基礎(chǔ)配置到高級調(diào)優(yōu)(最新整理)
文章系統(tǒng)講解Java啟動參數(shù)分類、內(nèi)存管理配置、GC調(diào)優(yōu)策略及生產(chǎn)環(huán)境實(shí)踐,重點(diǎn)涵蓋標(biāo)準(zhǔn)/非標(biāo)準(zhǔn)參數(shù)、堆/元空間/直接內(nèi)存設(shè)置、G1/Parallel等回收器選擇,并提供壓縮指針、容器化部署等優(yōu)化建議,感興趣的朋友跟隨小編一起看看吧2025-08-08
Java中StringBuilder類常用方法總結(jié)
這篇文章主要介紹了Java中StringBuilder類常用方法的相關(guān)資料,StringBuilder類是Java中用于頻繁修改字符串的可變字符串緩沖區(qū)類,它提供了多種方法進(jìn)行字符串操作,如添加、插入、刪除、替換字符等,需要的朋友可以參考下2024-12-12
Java中wait與sleep的區(qū)別講解(wait有參及無參區(qū)別)
這篇文章主要介紹了Java中wait與sleep的講解(wait有參及無參區(qū)別),通過代碼介紹了wait()?與wait(?long?timeout?)?區(qū)別,wait(0)?與?sleep(0)區(qū)別,需要的朋友可以參考下2022-04-04

