JSR380验证框架
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
demo
@Size(min=10,max=200 ,message="描述需要控制在10到200字符")
@Min(value=18,message="年龄不能小于18")
@Max(value=150,message="年龄不能大于150")
list<@NotBlank String> roles; public Optional<@Past localdate> getDateOfBirth(){return Optional.of(dateofBirth)
}
常用的验证注解
- @NotNull 论证注解的属性值不是空的。
- @AssertTrue 验证注解的属性值是否为真。
- @Size 验证注解的属性值的大小介于属性min和max之间;可应用于string,collection,map和数组属性。
- @Min 验证注解属性的值不小于值属性的值
- @Max 验证被注解的属性的值不大于值属性的值
- @Email 验证注解的属性是一个有效的电子邮件地址。
- @Pattern 验证注解的属性是否匹配正则表达式
- @NotEmpty 验证属性不是空或空;可以应用于string,collection,map或array值。
- @NotBlank 只能应用于文本值,并验证该属性不是空的或空白的。
- @Positive 和 @PositiveOrZero 适用于数值,并验证它们是严格意义上的正数,或包括0在内的正数
- @Negative 和 @NegativeOrZero 适用于数值,并脸证它们是严格意上的负值,或包括0在内的负值。
- @Past 和 @PastOrPresent 验证一个日期值是在过去或过去(包括现在),可应用于日期类型,包括在JAVA中新增的日期类型。
- @Futuren 和 @FutureOrPresent 验证一个日期值是在未来,或者说是在未来,包括现在。
基础使用
domain
@Data
public class UserDto implements Serializable {@NotNull@NotBlank@Size(min = 4, max = 50, message = "用户名长度必须在4到50个字符之间")private String username;@NotNull@NotBlank@Size(min = 4, max = 50, message = "用户密码长度必须在4到50个字符之间")private String password;@NotNull@NotBlank@Size(min = 4, max = 50, message = "用户密码长度必须在4到50个字符之间")private String matchingPassword;@NotNull@NotBlank@Email
//正则验证邮箱格式 @Pattern(regexp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")private String email;@NotNull@NotBlank@Size(min = 4, max = 50, message = "姓名长度必须在4到50个字符之间")private String name;
}
controller
@RestController
@RequestMapping("/authorize")
public class AuthorizeResource {//需要加@Valid使验证生效@PostMapping("/register")public UserDto register(@Valid @RequestBody UserDto userDto) {return userDto;}}
结果
{"username": "zhangsan","password": "qwerty12345T!","matchingPassword": "12345678","email": "zs@local.top","name": "张三李四"
}
{"timestamp": "2024-03-06T08:39:48.102+00:00","status": 400,"error": "Bad Request","trace": " rejected value [张三李四111111111111111111111111111111111111111111111111111111111111111111]; codes [Size.userDto.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userDto.name,name]; arguments []; default message [name],50,4]; default message [姓名长度必须在4到50个字符之间]] \r\n\tat ","message": "Validation failed for object='userDto'. Error count: 1","errors": [{"codes": ["Size.userDto.name","Size.name","Size.java.lang.String","Size"],"arguments": [{"codes": ["userDto.name","name"],"arguments": null,"defaultMessage": "name","code": "name"},50,4],"defaultMessage": "姓名长度必须在4到50个字符之间","objectName": "userDto","field": "name","rejectedValue": "张三李四111111111111111111111111111111111111111111111111111111111111111111","bindingFailure": false,"code": "Size"}],"path": "/authorize/register"
}
自定义验证规则
demo1 邮箱验证
1、定义注解
@Target({ TYPE, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = EmailValidator.class) //指定验证器类
@Documented
public @interface ValidEmail {String message() default "{ValidEmail.email}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
2、验证器
实现ConstraintValidator
接口
public class EmailValidator implements ConstraintValidator<ValidEmail, String> {private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";@Overridepublic void initialize(final ValidEmail constraintAnnotation) {}@Overridepublic boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {return validateEmail(s);}private boolean validateEmail(String s) {Pattern pattern = Pattern.compile(EMAIL_PATTERN);Matcher matcher = pattern.matcher(s);return matcher.matches();}
}
3、加上注解
@NotNull@NotBlank@ValidEmail(message = "邮箱格式不正确")
// @Email
// @Pattern(regexp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")private String email;
结果
{"timestamp": "2024-03-06T08:54:06.189+00:00","status": 400,"error": "Bad Request","trace": "codes [userDto.email,email]; arguments []; default message [email]]; default message [邮箱格式不正确]] \r\n\tat ","message": "Validation failed for object='userDto'. Error count: 1","errors": [{"codes": ["ValidEmail.userDto.email","ValidEmail.email","ValidEmail.java.lang.String","ValidEmail"],"arguments": [{"codes": ["userDto.email","email"],"arguments": null,"defaultMessage": "email","code": "email"}],"defaultMessage": "邮箱格式不正确","objectName": "userDto","field": "email","rejectedValue": "zs@local","bindingFailure": false,"code": "ValidEmail"}],"path": "/authorize/register"
}
密码的验证规则
- 密码的验证比较复杂,使用passay框架进行验证
- 封装验证逻辑在注解中,有效的剥离验证逻辑和业务逻辑
- 对于2个以上属性的复合验证,可以写一个应用于类的注解
<dependency><groupId>org.passay</groupId><artifactId>passay</artifactId><version>1.6.0</version>
</dependency>
注解
@Documented
@Constraint(validatedBy = PasswordConstraintValidator.class)
@Target({ TYPE, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface ValidPassword {String message() default "Invalid Password";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}
验证器
public class PasswordConstraintValidator implements ConstraintValidator<ValidPassword, String> {@Overridepublic void initialize(ValidPassword constraintAnnotation) {}@Overridepublic boolean isValid(String password, ConstraintValidatorContext constraintValidatorContext) {PasswordValidator validator = new PasswordValidator(List.of(// 长度规则:8 - 30 位new LengthRule(8, 30),// 至少有一个大写字母new CharacterRule(EnglishCharacterData.UpperCase, 1),// 至少有一个小写字母new CharacterRule(EnglishCharacterData.LowerCase, 1),// 至少有一个数字new CharacterRule(EnglishCharacterData.Digit, 1),// 至少有一个特殊字符new CharacterRule(EnglishCharacterData.Special, 1),// 不允许连续 3 个字母,按字母表顺序// alphabetical is of the form 'abcde', numerical is '34567', qwery is 'asdfg'// the false parameter indicates that wrapped sequences are allowed; e.g. 'xyzabc'new IllegalSequenceRule(EnglishSequenceData.Alphabetical, 5, false),// 不允许 3 个连续数字new IllegalSequenceRule(EnglishSequenceData.Numerical, 5, false),// 不允许 QWERTY 键盘上的三个连续相邻的按键所代表的字符new IllegalSequenceRule(EnglishSequenceData.USQwerty, 5, false),// 不允许包含空格new WhitespaceRule()));RuleResult validate = validator.validate(new PasswordData(password));if (validate.isValid()) {return true;}return false;}
}
domain
@Data
public class UserDto implements Serializable {@NotNull@NotBlank@Size(min = 4, max = 50, message = "用户名长度必须在4到50个字符之间")private String username;@NotNull@ValidPasswordprivate String password;@NotNull@ValidPasswordprivate String matchingPassword;@NotNull@NotBlank@ValidEmail(message = "邮箱格式不正确")// @Email// @Pattern(regexp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")private String email;@NotNull@NotBlank@Size(min = 4, max = 50, message = "姓名长度必须在4到50个字符之间")private String name;
}
结果
{"timestamp": "2024-03-06T09:23:38.543+00:00","status": 400,"error": "Bad Request","trace": "","message": "Validation failed for object='userDto'. Error count: 3","errors": [{"codes": ["ValidPassword.userDto.password","ValidPassword.password","ValidPassword.java.lang.String","ValidPassword"],"arguments": [{"codes": ["userDto.password","password"],"arguments": null,"defaultMessage": "password","code": "password"}],"defaultMessage": "Invalid Password","objectName": "userDto","field": "password","rejectedValue": "qwerty12345T!","bindingFailure": false,"code": "ValidPassword"},{"codes": ["ValidEmail.userDto.email","ValidEmail.email","ValidEmail.java.lang.String","ValidEmail"],"arguments": [{"codes": ["userDto.email","email"],"arguments": null,"defaultMessage": "email","code": "email"}],"defaultMessage": "邮箱格式不正确","objectName": "userDto","field": "email","rejectedValue": "zs@local","bindingFailure": false,"code": "ValidEmail"},{"codes": ["ValidPassword.userDto.matchingPassword","ValidPassword.matchingPassword","ValidPassword.java.lang.String","ValidPassword"],"arguments": [{"codes": ["userDto.matchingPassword","matchingPassword"],"arguments": null,"defaultMessage": "matchingPassword","code": "matchingPassword"}],"defaultMessage": "Invalid Password","objectName": "userDto","field": "matchingPassword","rejectedValue": "12345678","bindingFailure": false,"code": "ValidPassword"}],"path": "/authorize/register"
}
密码是否一致验证
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = PasswordMatchesValidator.class)
public @interface PasswordMatches {String message() default "{javax.validation.constraints.NotNull.message}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, UserDto> {@Overridepublic void initialize(PasswordMatches constraintAnnotation) {}@Overridepublic boolean isValid(UserDto userDto, ConstraintValidatorContext constraintValidatorContext) {return Objects.equals(userDto.getPassword(), userDto.getMatchingPassword());}
}
@PasswordMatches(message = "密码不一致")
@Data
public class UserDto implements Serializable {@NotNull@NotBlank@Size(min = 4, max = 50, message = "用户名长度必须在4到50个字符之间")private String username;@NotNull@ValidPasswordprivate String password;@NotNull
// @ValidPasswordprivate String matchingPassword;@NotNull@NotBlank@ValidEmail(message = "邮箱格式不正确")
// @Email
// @Pattern(regexp = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")private String email;@NotNull@NotBlank@Size(min = 4, max = 50, message = "姓名长度必须在4到50个字符之间")private String name;
}
passay 异常的国际化
- 创建一个消息解析器
- 配置验证器使用消息解析器
- 在对应的注解中写消息的键值
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {private final MessageSource messageSource;/*** 配置 Passay 使用 Spring 的 MessageSource* @return*/@Beanpublic MessageResolver messageResolver(){return new SpringMessageResolver(messageSource);}/*** 配置 Java Validation 使用国际化的消息资源* @return*/@Beanpublic LocalValidatorFactoryBean getValidator(){LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();factoryBean.setValidationMessageSource(messageSource);return factoryBean;}
}
@RequiredArgsConstructor
public class PasswordConstraintValidator implements ConstraintValidator<ValidPassword, String> {private final SpringMessageResolver springMessageResolver;@Overridepublic void initialize(ValidPassword constraintAnnotation) {}@Overridepublic boolean isValid(String password, ConstraintValidatorContext context) {PasswordValidator validator = new PasswordValidator(springMessageResolver,List.of(// 长度规则:8 - 30 位new LengthRule(8, 30),// 至少有一个大写字母new CharacterRule(EnglishCharacterData.UpperCase, 1),// 至少有一个小写字母new CharacterRule(EnglishCharacterData.LowerCase, 1),// 至少有一个数字new CharacterRule(EnglishCharacterData.Digit, 1),// 至少有一个特殊字符new CharacterRule(EnglishCharacterData.Special, 1),// 不允许连续 3 个字母,按字母表顺序// alphabetical is of the form 'abcde', numerical is '34567', qwery is 'asdfg'// the false parameter indicates that wrapped sequences are allowed; e.g. 'xyzabc'new IllegalSequenceRule(EnglishSequenceData.Alphabetical, 5, false),// 不允许 3 个连续数字new IllegalSequenceRule(EnglishSequenceData.Numerical, 5, false),// 不允许 QWERTY 键盘上的三个连续相邻的按键所代表的字符new IllegalSequenceRule(EnglishSequenceData.USQwerty, 5, false),// 不允许包含空格new WhitespaceRule()));RuleResult validate = validator.validate(new PasswordData(password));if (validate.isValid()) {return true;}context.disableDefaultConstraintViolation();context.buildConstraintViolationWithTemplate(String.join(",", validator.getMessages(validate))).addConstraintViolation();return false;}
}
配置文件
messages.properties
# Passay properties
HISTORY_VIOLATION=Password matches one of {0} previous passwords.
ILLEGAL_WORD=Password contains the dictionary word '{0}'.
ILLEGAL_WORD_REVERSED=Password contains the reversed dictionary word '{0}'.
ILLEGAL_DIGEST_WORD=Password contains a dictionary word.
ILLEGAL_DIGEST_WORD_REVERSED=Password contains a reversed dictionary word.
ILLEGAL_MATCH=Password matches the illegal pattern '{0}'.
ALLOWED_MATCH=Password must match pattern '{0}'.
ILLEGAL_CHAR=Password {1} the illegal character '{0}'.
ALLOWED_CHAR=Password {1} the illegal character '{0}'.
ILLEGAL_QWERTY_SEQUENCE=Password contains the illegal QWERTY sequence '{0}'.
ILLEGAL_ALPHABETICAL_SEQUENCE=Password contains the illegal alphabetical sequence '{0}'.
ILLEGAL_NUMERICAL_SEQUENCE=Password contains the illegal numerical sequence '{0}'.
ILLEGAL_USERNAME=Password {1} the user id '{0}'.
ILLEGAL_USERNAME_REVERSED=Password {1} the user id '{0}' in reverse.
ILLEGAL_WHITESPACE=Password {1} a whitespace character.
ILLEGAL_NUMBER_RANGE=Password {1} the number '{0}'.
ILLEGAL_REPEATED_CHARS=Password contains {2} sequences of {0} or more repeated characters, but only {1} allowed: {3}.
INSUFFICIENT_UPPERCASE=Password must contain {0} or more uppercase characters.
INSUFFICIENT_LOWERCASE=Password must contain {0} or more lowercase characters.
INSUFFICIENT_ALPHABETICAL=Password must contain {0} or more alphabetical characters.
INSUFFICIENT_DIGIT=Password must contain {0} or more digit characters.
INSUFFICIENT_SPECIAL=Password must contain {0} or more special characters.
INSUFFICIENT_CHARACTERISTICS=Password matches {0} of {2} character rules, but {1} are required.
INSUFFICIENT_COMPLEXITY=Password meets {1} complexity rules, but {2} are required.
INSUFFICIENT_COMPLEXITY_RULES=No rules have been configured for a password of length {0}.
SOURCE_VIOLATION=Password cannot be the same as your {0} password.
TOO_LONG=Password must be no more than {1} characters in length.
TOO_SHORT=Password must be {0} or more characters in length.
TOO_MANY_OCCURRENCES=Password contains {1} occurrences of the character '{0}', but at most {2} are allowed.jakarta.validation.constraints.AssertFalse.message = must be false
jakarta.validation.constraints.AssertTrue.message = must be true
jakarta.validation.constraints.DecimalMax.message = must be less than ${inclusive == true ? 'or equal to ' : ''}{value}
jakarta.validation.constraints.DecimalMin.message = must be greater than ${inclusive == true ? 'or equal to ' : ''}{value}
jakarta.validation.constraints.Digits.message = numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)
jakarta.validation.constraints.Email.message = must be a well-formed email address
jakarta.validation.constraints.Future.message = must be a future date
jakarta.validation.constraints.FutureOrPresent.message = must be a date in the present or in the future
jakarta.validation.constraints.Max.message = must be less than or equal to {value}
jakarta.validation.constraints.Min.message = must be greater than or equal to {value}
jakarta.validation.constraints.Negative.message = must be less than 0
jakarta.validation.constraints.NegativeOrZero.message = must be less than or equal to 0
jakarta.validation.constraints.NotBlank.message = must not be blank
jakarta.validation.constraints.NotEmpty.message = must not be empty
jakarta.validation.constraints.NotNull.message = must not be null
jakarta.validation.constraints.Null.message = must be null
jakarta.validation.constraints.Past.message = must be a past date
jakarta.validation.constraints.PastOrPresent.message = must be a date in the past or in the present
jakarta.validation.constraints.Pattern.message = must match "{regexp}"
jakarta.validation.constraints.Positive.message = must be greater than 0
jakarta.validation.constraints.PositiveOrZero.message = must be greater than or equal to 0
jakarta.validation.constraints.Size.message = size must be between {min} and {max}org.hibernate.validator.constraints.CreditCardNumber.message = invalid credit card number
org.hibernate.validator.constraints.Currency.message = invalid currency (must be one of {value})
org.hibernate.validator.constraints.EAN.message = invalid {type} barcode
org.hibernate.validator.constraints.Email.message = not a well-formed email address
org.hibernate.validator.constraints.ISBN.message = invalid ISBN
org.hibernate.validator.constraints.Length.message = length must be between {min} and {max}
org.hibernate.validator.constraints.CodePointLength.message = length must be between {min} and {max}
org.hibernate.validator.constraints.LuhnCheck.message = the check digit for ${validatedValue} is invalid, Luhn Modulo 10 checksum failed
org.hibernate.validator.constraints.Mod10Check.message = the check digit for ${validatedValue} is invalid, Modulo 10 checksum failed
org.hibernate.validator.constraints.Mod11Check.message = the check digit for ${validatedValue} is invalid, Modulo 11 checksum failed
org.hibernate.validator.constraints.ModCheck.message = the check digit for ${validatedValue} is invalid, {modType} checksum failed
org.hibernate.validator.constraints.Normalized.message = must be normalized
org.hibernate.validator.constraints.NotBlank.message = may not be empty
org.hibernate.validator.constraints.NotEmpty.message = may not be empty
org.hibernate.validator.constraints.ParametersScriptAssert.message = script expression "{script}" didn't evaluate to true
org.hibernate.validator.constraints.Range.message = must be between {min} and {max}
org.hibernate.validator.constraints.ScriptAssert.message = script expression "{script}" didn't evaluate to true
org.hibernate.validator.constraints.UniqueElements.message = must only contain unique elements
org.hibernate.validator.constraints.URL.message = must be a valid URLorg.hibernate.validator.constraints.br.CNPJ.message = invalid Brazilian corporate taxpayer registry number (CNPJ)
org.hibernate.validator.constraints.br.CPF.message = invalid Brazilian individual taxpayer registry number (CPF)
org.hibernate.validator.constraints.br.TituloEleitoral.message = invalid Brazilian Voter ID card numberorg.hibernate.validator.constraints.pl.REGON.message = invalid Polish Taxpayer Identification Number (REGON)
org.hibernate.validator.constraints.pl.NIP.message = invalid VAT Identification Number (NIP)
org.hibernate.validator.constraints.pl.PESEL.message = invalid Polish National Identification Number (PESEL)org.hibernate.validator.constraints.time.DurationMax.message = must be shorter than${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}
org.hibernate.validator.constraints.time.DurationMin.message = must be longer than${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}ValidEmail.email=Invalid Email
PasswordMatches.userDto=Passwords do not match
login.page.title=Login
login.page.logout.msg=You have logged out.
login.page.bad-credential=Username or password is wrong
login.page.form.username=Username
login.page.form.password=Password
login.page.form.submit=Login
index.page.menu.sign-out=Sign Out
login.page.form.remember-me=Remember me
messages_zh_CN.properties
# Passay 属性
HISTORY_VIOLATION=密码和您最近用过的 {0} 个密码之一重复。
ILLEGAL_WORD=密码包含了黑名单字典中的词 {0}。
ILLEGAL_WORD_REVERSED=密码包含了保留字典中的词 {0}。
ILLEGAL_DIGEST_WORD=密码包含了字典中的词。
ILLEGAL_DIGEST_WORD_REVERSED=密码包含了保留字典中的词。
ILLEGAL_MATCH=密码匹配了非法结构 {0}。
ALLOWED_MATCH=密码必须要匹配结构 {0}。
ILLEGAL_CHAR=密码 {1} 非法字符 {0}。
ALLOWED_CHAR=密码 {1} 非法字符 {0}。
ILLEGAL_QWERTY_SEQUENCE=密码包含非法的QWERTY序列 {0}。
ILLEGAL_ALPHABETICAL_SEQUENCE=密码包含非法的字母序列 {0}。
ILLEGAL_NUMERICAL_SEQUENCE=密码包含非法的数字序列 {0}。
ILLEGAL_USERNAME=密码 {1} 用户 id {0}。
ILLEGAL_USERNAME_REVERSED=密码 {1} 倒序的用户 id {0}。
ILLEGAL_WHITESPACE=密码 {1} 空格。
ILLEGAL_NUMBER_RANGE=密码 {1} 数字 {0}.
ILLEGAL_REPEATED_CHARS=密码中包含 {2} 序列 {0} 的一个或多个重复字符, 但仅允许 {1} 个: {3}。
INSUFFICIENT_UPPERCASE=密码中必须包含至少 {0} 个大写字母。
INSUFFICIENT_LOWERCASE=密码中必须包含至少 {0} 个小写字母。
INSUFFICIENT_ALPHABETICAL=密码中必须包含至少 {0} 个字母。
INSUFFICIENT_DIGIT=密码中必须包含至少 {0} 个数字。
INSUFFICIENT_SPECIAL=密码中必须包含至少 {0} 个特殊字符。
INSUFFICIENT_CHARACTERISTICS=密码匹配了 {0} of {2} 字符规则, 但只允许 {1} 个。
INSUFFICIENT_COMPLEXITY=密码符合了 {1} 个复杂规则, 但需要符合 {2} 个。
INSUFFICIENT_COMPLEXITY_RULES=对于密码长度 {0},没有配置规则。
SOURCE_VIOLATION=密码不能和之前的 {0} 个历史密码相同。
TOO_LONG=密码长度不能超过 {1} 个字符。
TOO_SHORT=密码长度不能少于 {0} 个字符。
TOO_MANY_OCCURRENCES=密码包含 {1} 个 {0}, 但是至多只允许 {2} 个。jakarta.validation.constraints.AssertFalse.message = 只能为false
jakarta.validation.constraints.AssertTrue.message = 只能为true
jakarta.validation.constraints.DecimalMax.message = 必须小于或等于{value}
jakarta.validation.constraints.DecimalMin.message = 必须大于或等于{value}
jakarta.validation.constraints.Digits.message = 数字的值超出了允许范围(只允许在{integer}位整数和{fraction}位小数范围内)
jakarta.validation.constraints.Email.message = 不是一个合法的电子邮件地址
jakarta.validation.constraints.Future.message = 需要是一个将来的时间
jakarta.validation.constraints.FutureOrPresent.message = 需要是一个将来或现在的时间
jakarta.validation.constraints.Max.message = 最大不能超过{value}
jakarta.validation.constraints.Min.message = 最小不能小于{value}
jakarta.validation.constraints.Negative.message = 必须是负数
jakarta.validation.constraints.NegativeOrZero.message = 必须是负数或零
jakarta.validation.constraints.NotBlank.message = 不能为空
jakarta.validation.constraints.NotEmpty.message = 不能为空
jakarta.validation.constraints.NotNull.message = 不能为null
jakarta.validation.constraints.Null.message = 必须为null
jakarta.validation.constraints.Past.message = 需要是一个过去的时间
jakarta.validation.constraints.PastOrPresent.message = 需要是一个过去或现在的时间
jakarta.validation.constraints.Pattern.message = 需要匹配正则表达式"{regexp}"
jakarta.validation.constraints.Positive.message = 必须是正数
jakarta.validation.constraints.PositiveOrZero.message = 必须是正数或零
jakarta.validation.constraints.Size.message = 个数必须在{min}和{max}之间org.hibernate.validator.constraints.CreditCardNumber.message = 不合法的信用卡号码
org.hibernate.validator.constraints.Currency.message = 不合法的货币 (必须是{value}其中之一)
org.hibernate.validator.constraints.EAN.message = 不合法的{type}条形码
org.hibernate.validator.constraints.Email.message = 不是一个合法的电子邮件地址
org.hibernate.validator.constraints.Length.message = 长度需要在{min}和{max}之间
org.hibernate.validator.constraints.CodePointLength.message = 长度需要在{min}和{max}之间
org.hibernate.validator.constraints.LuhnCheck.message = ${validatedValue}的校验码不合法, Luhn模10校验和不匹配
org.hibernate.validator.constraints.Mod10Check.message = ${validatedValue}的校验码不合法, 模10校验和不匹配
org.hibernate.validator.constraints.Mod11Check.message = ${validatedValue}的校验码不合法, 模11校验和不匹配
org.hibernate.validator.constraints.ModCheck.message = ${validatedValue}的校验码不合法, {modType}校验和不匹配
org.hibernate.validator.constraints.NotBlank.message = 不能为空
org.hibernate.validator.constraints.NotEmpty.message = 不能为空
org.hibernate.validator.constraints.ParametersScriptAssert.message = 执行脚本表达式"{script}"没有返回期望结果
org.hibernate.validator.constraints.Range.message = 需要在{min}和{max}之间
org.hibernate.validator.constraints.ScriptAssert.message = 执行脚本表达式"{script}"没有返回期望结果
org.hibernate.validator.constraints.URL.message = 需要是一个合法的URLorg.hibernate.validator.constraints.time.DurationMax.message = 必须小于${inclusive == true ? '或等于' : ''}${days == 0 ? '' : days += '天'}${hours == 0 ? '' : hours += '小时'}${minutes == 0 ? '' : minutes += '分钟'}${seconds == 0 ? '' : seconds += '秒'}${millis == 0 ? '' : millis += '毫秒'}${nanos == 0 ? '' : nanos += '纳秒'}
org.hibernate.validator.constraints.time.DurationMin.message = 必须大于${inclusive == true ? '或等于' : ''}${days == 0 ? '' : days += '天'}${hours == 0 ? '' : hours += '小时'}${minutes == 0 ? '' : minutes += '分钟'}${seconds == 0 ? '' : seconds += '秒'}${millis == 0 ? '' : millis += '毫秒'}${nanos == 0 ? '' : nanos += '纳秒'}ValidEmail.email=非法电子邮件地址
PasswordMatches.userDto=密码输入不一致login.page.title=登录
login.page.logout.msg=您已退出登录
login.page.bad-credential=用户名或密码不正确
login.page.form.username=用户名
login.page.form.password=密码
login.page.form.submit=登录
index.page.menu.sign-out=退出登录
login.page.form.remember-me=记住我
相关文章:

JSR380验证框架
依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>demo Size(min10,max200 ,message"描述需要控制在10到200字符") Min(valu…...

百度paddleocr GPU版部署
显卡:NVIDIA GeForce RTX 4070,Nvidia驱动程序版本:537.13 Nvidia驱动程序能支持的最高cuda版本:12.2.138 Python:python3.10.11。试过python3.12,安装paddleocr失败,找不到相关模块。 飞桨版本…...
node.js 常用命令
Node.js的常用命令包括多种类型,从运行JavaScript文件到管理Node.js的模块和包。以下是一些主要的Node.js常用命令: 运行JavaScript文件: node filename.js 这个命令会调用Node.js程序来运行指定的JavaScript文件。 查看文件和目录…...
Easypoi实现导出Excel(简单高效)
今天做报表导出,网上找了很多导出的方法,最后总结发现以下方法是最简便,更易维护的导出方法,下面来分享给大家。 1、首先引入相关依赖 <!--EasyPoi 报表--><dependency><groupId>cn.afterturn</groupId>…...
python之pathlib库使用介绍
pathlib 是 Python 标准库中用于处理文件路径的模块。它提供了一种面向对象的方式来操作文件和目录路径,简化了路径操作的编码和跨平台的兼容性。下面是 pathlib 库的基本介绍和使用方法: 1.导入 pathlib 模块 from pathlib import Path 2.创建路径对…...

Java:设计模式
文章目录 参考简介工厂模式简单工厂模式工厂方法模式抽象工厂模式总结 单例模式预加载懒加载线程安全问题 策略模式 参考 知乎 简介 总体来说设计模式分为三类共23种。 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模…...

【链表】Leetcode 19. 删除链表的倒数第 N 个结点【中等】
删除链表的倒数第 N 个结点 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5] 解题思路 1、使用快慢指针找到要删除节点的前一个节点。2、删…...
亚马逊认证考试系列 - 知识点 - 安全组简介
AWS安全组是一种虚拟防火墙,用于控制实例进出网络流量。安全组是一个实例级别的防火墙,可以定义哪些流量可以进入或离开特定的EC2实例。 功能:安全组可以用于限制特定类型的流量,如HTTP或SSH,允许特定IP地址范围的流量…...
同向双指针合集(力扣)
283. 移动零 代码 class Solution { public:void moveZeroes(vector<int>& nums) {int n nums.size();int l 0, r 0;while(r < n){if(nums[r]){swap(nums[l],nums[r]);l;}r;}} };209. 长度最小的子数组 代码 class Solution { public:int minSubArrayLen(i…...

G - Find a way
题目分析 1.双重bfs,遍历两个起点求最短路再计算总和即可 2.唯一的坑点在于对于一个KFC,两人中可能有一个到不了,所以还要对到不了的点距离做处理 #include <bits/stdc.h> using namespace std; using ll long long; const int N 220;struct pos…...

AJAX 02 案例、Bootstrap框架
AJAX 学习 AJAX 2 综合案例黑马 API01 图书管理Bootstrap 官网Bootstrap 弹框图书管理-渲染列表图书管理-添加图书图书管理-删除图书图书管理 - 编辑图书 02 图片上传03 更换图片04 个人信息设置信息渲染头像修改补充知识点:label扩大表单的范围 AJAX 2 综合案例 黑…...

SinoDB客户端工具dbaccess
类似Oracle的客户端工具sqlplus,Mysql的客户端工具mysql,SinoDB数据库也有自带的命令行客户端工具dbaccess。 dbaccess 识别用户输入,将用户输入的 SQL 语句打包发送给 SinoDB 数据库服务器执行,然后接收服务器的执行结果…...
postman学习
一、如何学习postman工具 1、下载和安装 Postman: 首先,从 Postman 官方网站(https://www.postman.com)下载并安装 Postman 应用程序。 2、了解基本概念: 在开始学习之前,了解一些基本概念,…...

【Linux】初识进程
目录 操作系统是什么 设计操作系统的目的 操作系统的定位 如何理解管理 管理的本质 管理的例子 计算机的管理概念图 操作系统管理逻辑的六字真言 系统调用和库函数的概念 进程 进程的概念 什么是PCB? PCB的主要内容 如何查看进程? 通过系统…...

有关Theano和PyTensor库
根据Github里面的介绍,PyTensor是源于Theano, Theano目前应该已经不再开发了,更新都是很多年前。 因此PyTensor在背景介绍中说 PyTensor is a fork of Aesara, which is a fork of Theano. Theano和PyTensor都是计算相关的库,可以…...

用 Open-Sora 高效创作视频,让创意触手可及
近年来,视频内容以爆炸式增长席卷了我们的生活。从短视频平台到直播带货,视频正成为人们获取信息和娱乐的主要方式。然而,传统视频制作流程往往耗时费力,对于普通用户来说门槛较高。 为了降低视频创作门槛,让更多人享…...

Git版本管理工具
前言: 本文记录学习使用 Git 版本管理工具的学习笔记,通过阅读参考链接中的博文和实际操作,快速的上手使用 Git 工具。 本文参考了引用链接博文里的内容。 引用: Git使用教程-配置管理 git reset详解-CSDN博客 3、Git使用不完全指南&am…...

微信小程序选择器picker的使用(省市区)
index.wxml picker中的 moderegion模式,这里同element中的select不同的是,不需要自己在绑定数据原,默认就包含了省市区的整体数据 <view class"section"><view class"section__title">省市区选择器</vie…...

std::shared_ptr与std::make_unique在类函数中的使用
在最近学习cartographer算法的时候,发现源码中大量的使用了std::shared_ptr与std::make_unique,对于这些东西之前不是很了解,为了更好的理解源代码,因此简单学习了一下这块内容的使用,在这里简单记个笔记。 std::shar…...

flutter 局部view更新,dialog更新进度,dialog更新
局部更新有好几种方法,本次使用的是 StatefulBuilder 定义 customState去更新对话框内容 import package:flutter/cupertino.dart; import package:flutter/material.dart;class ProgressDialog {final BuildContext context;BuildContext? dialogContext;double _…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...