Проверка параметров, форматирование, диапазоны параметров и обработка пользовательских правил проверки в Spring

Spring

использовать фон

В настоящее время в проекте проверка параметров выполняется на внешнем интерфейсе, в то время как внутренний интерфейс имеет дело только с бизнес-логикой, но этот метод не является разумным, обход страницы для выполнения http-запросов напрямую, будут системные исключения и риск грязных данных, поэтому рекомендуемое использованиеBean Validationна основеJSR 303 - Bean ValidationПлатформа проверки параметров выполняет проверку параметров, проверку формата и проверку дополнительного диапазона параметров во внутреннем интерфейсе, что позволяет не только избежать большинства системных исключений, вызванных отсутствующими параметрами, но и на этапе совместной отладки интерфейса. Повысьте эффективность совместного исследования и сократите время, затрачиваемое студентами переднего и заднего плана на устранение проблем во время совместного исследования.

Hibernate ValidatorЯвляется эталонной реализацией Bean Validation. Hibernate Validator обеспечивает реализацию всех встроенных ограничений спецификации JSR 303 и теперь обновлен доBean Validation 2.0 / JSR - 380, в дополнение к некоторым дополнительным ограничениям.Hibernate не является ORM для Hibernate

Например, ограничение (ограничение, ограничение) в Bean Validation, аннотация Bean Validation находится под javax.validation.constraints

ограничение ограничение
@Null Аннотированный элемент должен быть нулевым
@NotNull Аннотированный элемент не должен быть нулевым
@AssertTrue Аннотированный элемент должен быть истинным
@AssertFalse Аннотированный элемент должен быть ложным
@Min(value) Аннотированный элемент должен быть числом, значение которого должно быть больше или равно указанному минимальному значению.
@Max(value) Аннотированный элемент должен быть числом, значение которого должно быть меньше или равно указанному максимальному значению.
@DecimalMin(value) Аннотированный элемент должен быть числом, значение которого должно быть больше или равно указанному минимальному значению.
@DecimalMax(value) Аннотированный элемент должен быть числом, значение которого должно быть меньше или равно указанному максимальному значению.
@Size(max, min) Размер аннотируемого элемента должен быть в пределах указанного диапазона.
@Digits (integer, fraction) Аннотируемый элемент должен быть числом, и его значение должно быть в допустимом диапазоне.
@Past Аннотированный элемент должен быть датой в прошлом
@Future Аннотированный элемент должен быть датой в будущем
@Pattern(value) Аннотированный элемент должен соответствовать указанному регулярному выражению.

Дополнительное ограничение Hibernate Validator / Hibernate Validator — лучшая реализация JSR-303, спецификация обновлена ​​до JSR

ограничение ограничение
@Email Аннотированный элемент должен быть адресом электронной почты.
@Length Размер аннотированной строки должен быть в пределах указанного диапазона.
@NotEmpty Аннотированная строка должна быть непустой.
@Range Аннотируемый элемент должен находиться в соответствующей области

инструкции

Bean Validation встроен после JDK 1.6+, имя пакета — javax.validation.constraints.

Hibernate Validator должен представить пакет jar с именем org.hibernate.validator.constraints.

POM.xml

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.1.Final</version> 
</dependency>

класс сущности

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import java.util.Date;

public class ValidationDemo {
    private String id;

    @Length(min = 2, max = 6, message = "用户名长度要求在{min}-{max}之间")
    @NotNull(message = "用户名不可为空")
    private String userName;

    @Email(message = "邮箱格式错误")
    private String email;

    @Past(message = "出生日期错误")
    private Date birthDay;

    @Min(value = 18, message = "年龄错误")
    @Max(value = 80, message = "年龄错误")
    private Integer age;

    @Range(min = 0, max = 1, message = "性别选择错误")
    private Integer sex;
}

Сравнительный @Valid и Validated, в соответствии с фактическим спросом необходимо выбрать

@Valid: нет функции группировки, ее можно использовать для методов, конструкторов, параметров метода и свойств членов (полей).Если проверяемый класс pojo также содержит объекты, подлежащие проверке, вам необходимо аннотировать @ на объекте, чтобы быть проверено действительным, чтобы проверить свойства члена в объекте, который нужно проверить

@Validated : предоставляет функцию группировки, которую можно использовать для типов, методов и параметров методов в соответствии с различными группами во время проверки параметров. Но не для свойств члена (поля).

Controller

-- @Valid 表示对该实体进行校验
-- BindingResult 则保存对参数的校验结果
@RequestMapping(value = "validation", method = RequestMethod.POST)
public JsonResult validation(@Valid @RequestBody ValidationDemo demo, BindingResult result) {
    JsonResult jsonResult = new JsonResult();
    if (result.hasErrors()) {
        result.getAllErrors().forEach(err -> {
            jsonResult.setCode(ApiConstants.JsonResult.FAIL);
            jsonResult.setMsg(err.getDefaultMessage());
        });
    }
    return jsonResult;
}

RequestBody

{
  "age": 19,
  "birthDay": "2019-04-14T09:05:39.604Z",
  "email": "string",
  "id": "string",
  "sex": 0,
  "userName": "string"
}

Response

{
  "code": 1,
  "msg": "邮箱格式错误",
  "total": 0,
  "totalpage": 0
}
Видно, что проверка параметров вступила в силу, так как электронная почта не соответствует правилам проверки @Email. Конкретные правила проверки см. в реализации @Email EmailValidator.java.

В сообщении об ошибке userName есть {min} - {max}?

RequestBody

{
  "age": 19,
  "birthDay": "2019-04-14T09:05:39.604Z",
  "email": "string",
  "id": "string",
  "sex": 0,
  "userName": ""
}

Response

{
  "code": 1,
  "msg": "用户名长度要求在2-6之间",
  "total": 0,
  "totalpage": 0
}

Hibernate Validator получает значения свойств min и max, определенных в @length через выражения EL

В приведенном выше Контроллере необходимо добавить BindingResult в параметры интерфейса для получения результата проверки.Каждому BindingResult соответствует @Valid один к одному.Если @Valid несколько, то для сохранения проверки требуется один BindResult результат результат теста

Расширенное использование, единая обработка результатов проверки и возврат к внешнему интерфейсу

В ResponseEntityExceptionHandler (строка 162) вызывается MethodArgumentNotValidException, если проверка не пройдена.

MethodArgumentNotValidException 描述:

Exception to be thrown when validation on an argument annotated with {@code @Valid} fails.

当使用@Valid注解的参数验证失败是抛出异常

Итак, обработайте MethodArgumentNotValidException в BaseController.

Controller

-- 对接口进行简化,通过异常捕获的方式对校验结果返回给前端
@RequestMapping(value = "validation", method = RequestMethod.POST)
public JsonResult validation(@Valid @RequestBody ValidationDemo demo) {
    return null;
}

BaseController

if (e instanceof MethodArgumentNotValidException) {
    res.setCode(ApiConstants.JsonResult.FAIL);
    res.setMsg(JSONArray.toJSONString(((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList())));
}

Response

{
  "code": 1,
  "msg": "[\"年龄错误\",\"邮箱格式错误\"]",
  "total": 0,
  "totalpage": 0
}

Проверка пакетов

В реальном использовании возможно, что у нас есть несколько правил проверки для атрибута.В настоящее время нам нужно использовать групповую проверку.

Модернизированный объект

public class ValidationDemo {
    private String id;

    @Length(min = 2, max = 6, message = "用户名长度要求在{min}-{max}之间")
    @NotNull(message = "用户名不可为空")
    private String userName;

    // 表示分组为Adult时使用该校验规则
    @Email(message = "邮箱格式错误")
    @NotBlank(message = "邮箱不可为空", groups = {ValidationDemo.Adult.class})
    private String email;

    @Past(message = "出生日期错误")
    private Date birthDay;

    @Min(value = 18, message = "年龄错误")
    @Max(value = 80, message = "年龄错误")
    private Integer age;

    @Range(min = 0, max = 1, message = "性别选择错误")
    private Integer sex;

    // 添加两个分组
    public interface Adult {
    }

    public interface Minor {
    }
}

пройти тест

// 这里将分组设置为Minor,目的是不校验邮箱字段
@RequestMapping(value = "validation", method = RequestMethod.POST)
public JsonResult validation(@Validated({ValidationDemo.Adult.class}) @RequestBody ValidationDemo demo) {
    return null;
}

RequestBody:
{
  "age": 0,
  "birthDay": "2019-04-14T10:39:08.501Z",
  "email": "",
  "id": "string",
  "sex": 0,
  "userName": "string"
}
Response:
{
  "code": 1,
  "msg": "[\"邮箱不可为空\"]",
  "total": 0,
  "totalpage": 0
}

Что, если в интерфейсе используется второстепенная группировка?

RequestBody:
{
  "age": 0,
  "birthDay": "2019-04-14T10:39:08.501Z",
  "email": "",
  "id": "string",
  "sex": 0,
  "userName": "string"
}
Response:
{
  "code": 0,
  "data": [
    {}
  ],
  "extra": "string",
  "msg": "string",
  "result": {},
  "total": 0,
  "totalpage": 0
}
Подсказки о том, что почтовый ящик не может быть пустым, нет, видно, что групповая проверка вступила в силу.

пользовательские правила проверки

Например, создайте собственную проверку формата даты

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = {DateFormatByPatternValidator.class})
public @interface DateFormatByPattern {
    String pattern() default "yyyy-MM-dd HH:mm";

    //默认错误消息
    String message() default "日期格式错误";

    //分组
    Class<?>[] groups() default {};

    //负载
    Class<? extends Payload>[] payload() default {};
}

При этом создайте соответствующий валидатор

public class DateFormatByPatternValidator implements ConstraintValidator<DateFormatByPattern, String> {

    private DateFormatByPattern dateFormatByPattern;

    @Override
    public void initialize(DateFormatByPattern constraintAnnotation) {
        dateFormatByPattern = constraintAnnotation;
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        //假如参数为空的话,返回true,如果要对参数值进行非空校验的话,通过@NotNull来校验,这样与日期格式校验解耦
        if (StringUtils.isNotBlank(value)) {
            String pattern = dateFormatByPattern.pattern();
            SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
            try {
                dateFormat.parse(value);
            } catch (ParseException e) {
                return false;
            }
        }
        return true;
    }
}

Модернизированный объект

//使用自定义规则校验前端参数
@DateFormatByPattern(pattern = "yyyy-MM-dd")
//因为同时用到了分组校验,所以在stringDate上添加@Valid,使校验生效
@Valid
private String stringDate;

пройти тест

RequestBody:
{
  "age": 0,
  "birthDay": "2019-04-15T08:23:21.683Z",
  "email": "",
  "id": "string",
  "sex": 0,
  "stringDate": "string",
  "userName": "string"
}
Response:
{
  "code": 1,
  "msg": "[\"日期格式错误\",\"邮箱不可为空\",\"年龄错误\"]",
  "total": 0,
  "totalpage": 0
}
Видно, что пользовательская проверка вступила в силу.

Справочная документация

Проверка пользовательской аннотации Hibernate Validation

Пользовательские аннотации валидатора

Интегрированная проверка компонентов SpringMVC 1.0 (JSR-303)

Проверка параметров через Hibernate-Validation