
Всем привет, я Мисти.
Несколько дней назад я написал «SpringBoot, как унифицированный формат возвращается бэкэндом? Вот как это делают старые птицы! «Результаты чтения были хорошими, но слишком много владельцев воспроизводятся, и сегодня мы продолжим. Во-вторых, поговорим о том, как интегрировать параметры в проверку SprinBoot Validator и проверку параметров навыков более высокого порядка (пользовательская проверка, проверка группировки) .
Эта статья опирается на код предыдущей статьи, и в проект добавлена глобальная проверка исключений. (Репозиторий кода находится в конце статьи)
Во-первых, давайте посмотрим, что такое валидатор параметров Validator и зачем нам нужна валидация параметров?
Зачем нужна проверка параметров?
При ежедневной разработке интерфейса, чтобы предотвратить влияние незаконных параметров на бизнес, часто необходимо проверять параметры интерфейса, например, при входе в систему нужно проверять, не пусты ли логин и пароль, а при создании пользователя, вам необходимо подтвердить электронную почту и мобильный телефон.Точен ли формат номера. Проверять параметры интерфейса по одному коду слишком громоздко, а читабельность кода крайне плохая.
Платформа Validator предназначена для решения проблемы, заключающейся в том, что разработчики пишут меньше кода во время разработки, и повышения эффективности разработки; Validator специально используется для проверки параметров интерфейса, таких как общая необходимая проверка, проверка формата электронной почты, а имя пользователя должно находиться между 6 и 12. ждать...
Среда проверки Validator соответствует спецификации проверки JSR-303 (спецификация проверки параметров), JSR
Java Specification Requestsаббревиатура от.
Далее давайте посмотрим, как интегрировать инфраструктуру проверки параметров в SpringbBoot.
Встроенная проверка параметров в SpringBoot
Первым шагом является введение зависимостей
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Примечание: от
springboot-2.3В начале пакет проверки был разделен наstarterкомпоненты, поэтому вам нужно ввести проверку и веб, а такжеspringboot-2.3В предыдущих версиях нужно было только ввести веб-зависимости.
Второй шаг — определить класс сущностей для параметризации.
@Data
public class ValidVO {
private String id;
@Length(min = 6,max = 12,message = "appId长度必须位于6到12之间")
private String appId;
@NotBlank(message = "名字为必填项")
private String name;
@Email(message = "请填写正确的邮箱地址")
private String email;
private String sex;
@NotEmpty(message = "级别不能为空")
private String level;
}
В реальной разработке необходимо установить соответствующие бизнес-подсказки для полей, которые необходимо проверить, то есть атрибут сообщения.
Общие аннотации ограничений следующие:
| аннотация | Функция |
|---|---|
| @AssertFalse | Может быть нулевым, должно быть ложным, если не нулевым |
| @AssertTrue | Может быть нулевым, должно быть истинным, если не нулевым |
| @DecimalMax | Параметр не может превышать максимальное значение |
| @DecimalMin | Параметр не может превышать минимальное значение |
| @Digits | Параметр должен быть числом, а количество целых цифр и количество знаков после запятой должны быть в пределах указанного диапазона. |
| @Future | Дата должна быть в будущем от текущей даты |
| @Past | Дата должна быть в прошлом от текущей даты |
| @Max | Максимум не должен превышать это максимальное значение |
| @Min | Максимум не должен быть меньше этого минимума |
| @NotNull | не может быть нулевым, может быть пустым |
| @Null | должен быть нулевым |
| @Pattern | Должен удовлетворять указанному регулярному выражению |
| @Size | Значение size() коллекций, массивов, карт и т. д. должно находиться в пределах указанного диапазона. |
| Должен быть в формате электронной почты | |
| @Length | Длина должна быть в пределах указанного диапазона |
| @NotBlank | Строка не может быть нулевой, и строка не может равняться "" после функции trim(). |
| @NotEmpty | Не может быть нулевым, size() наборов, массивов, карт и т. д. не может быть 0; string trim() может быть равен "" |
| @Range | Значение должно быть в пределах указанного диапазона |
| @URL | Должен быть URL |
Примечание. Эта таблица представляет собой простое описание функции аннотации и не описывает атрибуты каждой аннотации; подробности см. в исходном коде.
Третий шаг — определить класс проверки для тестирования.
@RestController
@Slf4j
@Validated
public class ValidController {
@ApiOperation("RequestBody校验")
@PostMapping("/valid/test1")
public String test1(@Validated @RequestBody ValidVO validVO){
log.info("validEntity is {}", validVO);
return "test1 valid success";
}
@ApiOperation("Form校验")
@PostMapping(value = "/valid/test2")
public String test2(@Validated ValidVO validVO){
log.info("validEntity is {}", validVO);
return "test2 valid success";
}
@ApiOperation("单参数校验")
@PostMapping(value = "/valid/test3")
public String test3(@Email String email){
log.info("email is {}", email);
return "email valid success";
}
}
Здесь мы сначала определяем три метода использования test1, test2, test3, test1.@RequestBodyAnnotation используется для приема данных json, отправленных внешним интерфейсом, test2 имитирует отправку формы, а test3 имитирует отправку одного параметра.Обратите внимание, что при использовании проверки с одним параметром вам необходимо добавить аннотацию @Validated к контроллеру, иначе она не вступит в силу..
Четвертый шаг, испытайте эффект
- Вызовите метод test1, подсказка
org.springframework.web.bind.MethodArgumentNotValidExceptionаномальный
POST http://localhost:8080/valid/test1
Content-Type: application/json
{
"id": 1,
"level": "12",
"email": "47693899",
"appId": "ab1c"
}
{
"status": 500,
"message": "Validation failed for argument [0] in public java.lang.String com.jianzh5.blog.valid.ValidController.test1(com.jianzh5.blog.valid.ValidVO) with 3 errors: [Field error in object 'validVO' on field 'email': rejected value [47693899]; codes [Email.validVO.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [validVO.email,email]; arguments []; default message [email],[Ljavax.validation.constraints.Pattern$Flag;@26139123,.*]; default message [不是一个合法的电子邮件地址]]...",
"data": null,
"timestamp": 1628239624332
}
- Вызовите метод test2, подсказка
org.springframework.validation.BindExceptionаномальный
POST http://localhost:8080/valid/test2
Content-Type: application/x-www-form-urlencoded
id=1&level=12&email=476938977&appId=ab1c
{
"status": 500,
"message": "org.springframework.validation.BeanPropertyBindingResult: 3 errors\nField error in object 'validVO' on field 'name': rejected value [null]; codes [NotBlank.validVO.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [validVO.name,name]; arguments []; default message [name]]; default message [名字为必填项]...",
"data": null,
"timestamp": 1628239301951
}
- Вызовите метод test3, подсказка
javax.validation.ConstraintViolationExceptionаномальный
POST http://localhost:8080/valid/test3
Content-Type: application/x-www-form-urlencoded
email=476938977
{
"status": 500,
"message": "test3.email: 不是一个合法的电子邮件地址",
"data": null,
"timestamp": 1628239281022
}
присоединившисьValidatorПлатформа проверки может помочь нам автоматизировать проверку параметров.
Добавить исключение параметра в глобальный обработчик исключений
Хотя мы определили глобальный перехватчик исключений ранее и увидели, что перехватчик действует, ноValidatorСообщение об ошибке, возвращаемое фреймворком проверки, слишком раздутое и неудобное для чтения. Чтобы упростить подсказку внешнего интерфейса, нам нужно ее упростить.
непосредственно изменять ранее определенныеRestExceptionHandler, который отдельно перехватывает три исключения для проверки параметров:javax.validation.ConstraintViolationException,org.springframework.validation.BindException,org.springframework.web.bind.MethodArgumentNotValidException, код показан ниже:
@ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
public ResponseEntity<ResultData<String>> handleValidatedException(Exception e) {
ResultData<String> resp = null;
if (e instanceof MethodArgumentNotValidException) {
// BeanValidation exception
MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),
ex.getBindingResult().getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("; "))
);
} else if (e instanceof ConstraintViolationException) {
// BeanValidation GET simple param
ConstraintViolationException ex = (ConstraintViolationException) e;
resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),
ex.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; "))
);
} else if (e instanceof BindException) {
// BeanValidation GET object param
BindException ex = (BindException) e;
resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),
ex.getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining("; "))
);
}
return new ResponseEntity<>(resp,HttpStatus.BAD_REQUEST);
}
Эффект опыта
POST http://localhost:8080/valid/test1
Content-Type: application/json
{
"id": 1,
"level": "12",
"email": "47693899",
"appId": "ab1c"
}
{
"status": 400,
"message": "名字为必填项; 不是一个合法的电子邮件地址; appId长度必须位于6到12之间",
"data": null,
"timestamp": 1628435116680
}
Вы чувствуете себя более свежим?
Проверка пользовательских параметров
Хотя аннотаций, предоставляемых Spring Validation, в основном достаточно, перед лицом сложных определений нам все равно нужно определить наши собственные аннотации для достижения автоматической проверки.
Например, атрибут секса в приведенном выше классе сущностей позволяет интерфейсу передавать только два значения перечисления M и F. Как это реализовать?
Первый шаг — создать пользовательскую аннотацию.
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Repeatable(EnumString.List.class)
@Documented
@Constraint(validatedBy = EnumStringValidator.class)//标明由哪个类执行校验逻辑
public @interface EnumString {
String message() default "value not in enum values.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return date must in this value array
*/
String[] value();
/**
* Defines several {@link EnumString} annotations on the same element.
*
* @see EnumString
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@interface List {
EnumString[] value();
}
}
Второй шаг — настроить логику проверки
public class EnumStringValidator implements ConstraintValidator<EnumString, String> {
private List<String> enumStringList;
@Override
public void initialize(EnumString constraintAnnotation) {
enumStringList = Arrays.asList(constraintAnnotation.value());
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if(value == null){
return true;
}
return enumStringList.contains(value);
}
}
Третий шаг — добавление аннотаций к полям
@ApiModelProperty(value = "性别")
@EnumString(value = {"F","M"}, message="性别只允许为F或M")
private String sex;
Четвертый шаг, испытайте эффект
POST http://localhost:8080/valid/test2
Content-Type: application/x-www-form-urlencoded
id=1&name=javadaily&level=12&email=476938977@qq.com&appId=ab1cdddd&sex=N
{
"status": 400,
"message": "性别只允许为F或M",
"data": null,
"timestamp": 1628435243723
}
Проверка пакетов
При добавлении объекта ВО некоторые поля обязательны, а при обновлении не обязательны. как указано вышеValidVOСвойства id и appId используются при добавлении операций.Не требуется, так и во время операций редактированияНеобходимый, имя при добавлении операцииНеобходимый, как бы вы справились с этим сценарием?
В реальной разработке я видел, как многие студенты создавали два объекта VO,ValidCreateVO,ValidEditVOЧтобы справиться с такого рода сценой, это действительно может дать эффект, но это вызовет раздувание класса, и ветераны-разработчики очень легко будут смеяться над этим.

фактическиValidatorПлатформа проверки приняла во внимание этот сценарий и предоставила решение, котороеПроверка пакетов, но многие студенты этого не знают. Для использования проверки блоков требуется всего три шага:
Шаг 1: Определите интерфейс пакета
public interface ValidGroup extends Default {
interface Crud extends ValidGroup{
interface Create extends Crud{
}
interface Update extends Crud{
}
interface Query extends Crud{
}
interface Delete extends Crud{
}
}
}
Здесь мы определяем интерфейс группировки ValidGroup, чтобы позволить ему наследоватьjavax.validation.groups.Default, а затем определите несколько различных типов операций в интерфейсе группировки: «Создать», «Обновить», «Запросить», «Удалить». Что касается того, зачем нам нужно наследовать Default, мы поговорим об этом позже.
Второй шаг — назначить группы параметрам в модели.
@Data
@ApiModel(value = "参数校验类")
public class ValidVO {
@ApiModelProperty("ID")
@Null(groups = ValidGroup.Crud.Create.class)
@NotNull(groups = ValidGroup.Crud.Update.class, message = "应用ID不能为空")
private String id;
@Null(groups = ValidGroup.Crud.Create.class)
@NotNull(groups = ValidGroup.Crud.Update.class, message = "应用ID不能为空")
@ApiModelProperty(value = "应用ID",example = "cloud")
private String appId;
@ApiModelProperty(value = "名字")
@NotBlank(groups = ValidGroup.Crud.Create.class,message = "名字为必填项")
private String name;
@ApiModelProperty(value = "邮箱")
@Email(message = "请填写正取的邮箱地址")
privte String email;
...
}
Укажите группировку для параметра и используйте группировку по умолчанию, если группировка не указана.
Третий шаг — назначить группы методам, требующим проверки параметров.
@RestController
@Api("参数校验")
@Slf4j
@Validated
public class ValidController {
@ApiOperation("新增")
@PostMapping(value = "/valid/add")
public String add(@Validated(value = ValidGroup.Crud.Create.class) ValidVO validVO){
log.info("validEntity is {}", validVO);
return "test3 valid success";
}
@ApiOperation("更新")
@PostMapping(value = "/valid/update")
public String update(@Validated(value = ValidGroup.Crud.Update.class) ValidVO validVO){
log.info("validEntity is {}", validVO);
return "test4 valid success";
}
}
Здесь мы проходимvalueприписыватьadd()а такжеupdate()Методы задают группы Create и Update соответственно.
Четвертый шаг, испытайте эффект
POST http://localhost:8080/valid/add
Content-Type: application/x-www-form-urlencoded
name=javadaily&level=12&email=476938977@qq.com&sex=F
Мы не передавали параметры id и appId в Create, и проверка прошла.
Когда мы вызываем метод обновления с теми же параметрами, он выдает ошибку проверки параметра.
{
"status": 400,
"message": "ID不能为空; 应用ID不能为空",
"data": null,
"timestamp": 1628492514313
}
Так как электронная почта принадлежит к группе по умолчанию, и наш групповой интерфейсValidGroupунаследовалDefaultгруппировка, поэтому также можно выполнить проверку параметров в поле электронной почты. Такие как:
POST http://localhost:8080/valid/add
Content-Type: application/x-www-form-urlencoded
name=javadaily&level=12&email=476938977&sex=F
{
"status": 400,
"message": "请填写正取的邮箱地址",
"data": null,
"timestamp": 1628492637305
}
Конечно, если ваша ValidGroup не наследует группу Default, вам нужно добавить ее в атрибут code@Validated(value = {ValidGroup.Crud.Create.class, Default.class}позволитьemailПроверка поля вступает в силу.
резюме
Проверка параметров очень часто используется в фактической разработке, но многие студенты до сих пор остаются только в простом использовании, таком как групповая проверка и проверка пользовательских параметров.Эти два высокоуровневых навыка используются не очень часто.Множественные ВО используются для принятия создания и Сценарии обновлений. Старые птицы легко презирают и высмеивают. Надеюсь, вы справитесь с ними.
Наконец, я Мисти Джем, архитектор, который пишет код, и программист, который работает в области архитектуры. Я с нетерпением жду вашей переадресации и внимания. Конечно, вы также можете добавить мой личный WeChat.jianzh5, давайте поговорим о технологии!
Исходный код старой серии птиц был загружен на GitHub, и вам необходимо ответить на ключевое слово в общедоступной учетной записи [JAVA Daily Knowledge Record]0923 Получать