Проверка группы SpringBoot и пользовательские аннотации проверки

Spring Boot

предисловие

  В ежедневном развитиипроверка параметровЭто очень важная ссылка, строгая проверка параметров снизит вероятность многих ошибок и повысит безопасность интерфейса. Написал статью раньшеУнифицированная проверка параметров SpringBootВ основном он вводит некоторые простые методы проверки. В этой статье представлены некоторые расширенные методы проверки. Например: в процессе написания интерфейса обязательно встретится, когда значение xxType равно A, нужно передать значение paraMA. Значение xxType равно B, и должно быть передано значение paramB. Для этого обычной практикой является добавление в контроллер различных суждений if. Очевидно, что такой код недостаточно элегантен, и эту проблему должны решить групповая проверка и проверка пользовательских параметров.

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

Интерфейс   Restful должен быть относительно обычным в наши дни, таким образом мы проверяем параметры часто используемой адресной строки.

/**
 * 获取电话号码信息
 */
@GetMapping("/phoneInfo/{phone}")
public ResultVo phoneInfo(@PathVariable("phone") String phone){
    // 验证电话号码是否有效
    String pattern = "^[1][3,4,5,7,8][0-9]{9}$";
    boolean isValid =  Pattern.matches(pattern, phone);
    if(isValid){
        // 执行相应逻辑
        return ResultVoUtil.success(phone);
    } else {
        // 返回错误信息
        return ResultVoUtil.error("手机号码无效");
    }
}

Очевидно, приведенный выше код недостаточно элегантен, поэтому мы можем добавить соответствующее регулярное выражение после параметраphone:正则表达式проверять. Это избавляет от необходимости писать проверочный код в контроллере.

/**
 * 获取电话号码信息
 */
@GetMapping("/phoneInfo/{phone:^[1][3,4,5,7,8][0-9]{9}$}")
public ResultVo phoneInfo(@PathVariable("phone") String phone){
    return ResultVoUtil.success(phone);
}

Хотя после такой обработки код становится более упорядоченным. Однако, если входящий номер мобильного телефона не соответствует правилам, 404 будет возвращен напрямую. Вместо запроса ошибки номера мобильного телефона. Сообщение об ошибке выглядит следующим образом:

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

   В качестве примера возьмем проверку номера мобильного телефона, хотяvalidationпри условии@PatternАннотации для использования регулярных выражений для проверки. Если вы изменяете одно за другим для использования во многих местах, после изменения регулярного выражения вам необходимо это сделать. Понятно, что для того, чтобы не заниматься полезной работой,自定义校验注解Ваш хороший помощник.

@Data
public class PhoneForm {

    /**
     * 电话号码
     */
    @Pattern(regexp = "^[1][3,4,5,7,8][0-9]{9}$" , message = "电话号码有误")
    private String phone;

}

   Чтобы реализовать пользовательскую аннотацию проверки, в основном нужно выполнить два шага. ОдинСама аннотация, дваКласс реализации логики проверки.

Аннотация проверки PhoneVerify

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
 
    String message() default "手机号码格式有误";

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

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

}

Класс реализации проверки PhoneValidator

public class PhoneValidator implements ConstraintValidator<Phone, Object> {

    @Override
    public boolean isValid(Object telephone, ConstraintValidatorContext constraintValidatorContext) {
        String pattern = "^1[3|4|5|7|8]\\d{9}$";
        return Pattern.matches(pattern, telephone.toString());
    }
}

Данные формы CustomForm

@Data
public class CustomForm {

    /**
     * 电话号码
     */
    @Phone
    private String phone;

}

тестовый интерфейс

@PostMapping("/customTest")
public ResultVo customTest(@RequestBody @Validated CustomForm form){
	return ResultVoUtil.success(form.getPhone());
}

смысл аннотаций

@Target({ElementType.FIELD})

Аннотация    указывает, где можно использовать текущую пользовательскую аннотацию, здесь она позволяет ему использовать только атрибуты. Но его также можно использовать в других местах, таких как методы, конструкторы и т. д.

  • TYPE — класс, интерфейс (включая типы аннотаций) или перечисление
  • FIELD — Поле (включая константы перечисления)
  • МЕТОД - Метод
  • ПАРАМЕТР - параметр
  • КОНСТРУКТОР - Конструктор
  • LOCAL_VARIABLE - локальная переменная
  • Annotionation_Type - Типы аннотации
  • Пакет - пакет
  • TYPE_PARAMETER — параметр типа
  • TYPE_USE - тип использования
@Retention(RetentionPolicy.RUNTIME)

   указывает, что текущая аннотация сохраняется до времени выполнения. Существует три политики хранения:

  • ИСТОЧНИК — аннотации хранятся только в исходных файлах, когда файлы Java компилируются в файлы классов, аннотации отбрасываются.
  • Класс - аннотации хранятся в файле класса, но отбрасываются, когда JVM загружает файл класса, который является течением по умолчанию.
  • ВРЕМЯ ВЫПОЛНЕНИЯ. Аннотации не только сохраняются в файле класса, но и продолжают существовать после того, как JVM загрузит файл класса.
@Constraint(validatedBy = PhoneValidator.class)

   указывает, какой класс проверки использует текущая аннотация для проверки.

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

UserForm

@Data
public class UserForm {

    /**
     * id
     */
    @Null(message = "新增时id必须为空", groups = {Insert.class})
    @NotNull(message = "更新时id不能为空", groups = {Update.class})
    private String id;

    /**
     * 类型
     */
    @NotEmpty(message = "姓名不能为空" , groups = {Insert.class})
    private String name;

    /**
     * 年龄
     */
    @NotEmpty(message = "年龄不能为空" , groups = {Insert.class})
    private String age;
    
}

Вставить группу

public interface Insert {
}

Обновить группировку

public interface Update {
}

тестовый интерфейс

/**
 * 添加用户
 */
@PostMapping("/addUser")
public ResultVo addUser(@RequestBody @Validated({Insert.class}) UserForm form){
  	// 选择对应的分组进行校验
    return ResultVoUtil.success(form);
}

/**
 * 更新用户
 */
@PostMapping("/updateUser")
public ResultVo updateUser(@RequestBody @Validated({Update.class}) UserForm form){
    // 选择对应的分组进行校验
    return ResultVoUtil.success(form);
}

Результаты теста

добавить тест

обновить тест

Последовательная проверка@GroupSequence

существует@GroupSequenceВы можете указать порядок групповой проверки. Например@GroupSequence({Insert.class, Update.class, UserForm.class})Первое исполнениеInsertпроверить, затем выполнитьUpdateчек. еслиInsertГруппировка, если проверка не удалась, она не будет обработанаUpdateгрупповая проверка.

@Data
@GroupSequence({Insert.class, Update.class, UserForm.class})
public class UserForm {

    /**
     * id
     */
    @Null(message = "新增时id必须为空", groups = {Insert.class})
    @NotNull(message = "更新时id不能为空", groups = {Update.class})
    private String id;

    /**
     * 类型
     */
    @NotEmpty(message = "姓名不能为空" , groups = {Insert.class})
    private String name;

    /**
     * 年龄
     */
    @NotEmpty(message = "年龄不能为空" , groups = {Insert.class})
    private String age;

}
тестовый интерфейс
/**
* 编辑用户
*/
@PostMapping("/editUser")
public ResultVo editUser(@RequestBody @Validated UserForm form){
	return ResultVoUtil.success(form);
}
Результаты теста

Ха-ха-ха, результат теста на самом деле мертвый цикл, если вы ошибаетесь, маленький партнер может попробовать. Вышеприведенный пример является лишь демонстрацией, на практике или не делать этого, нужно проверять по конкретной логике.

Проверка пользовательской группы

   Как упоминалось ранее, когда значение xxType равно A, необходимо передать значение paraMA. Значение xxType равно B, и в таком сценарии необходимо передать значение paramB. Это невозможно, используя только контрольную сумму блока и последовательность блоков. Нужно использовать@GroupSequenceProviderПросто сделай это.

индивидуальная форма группы

@Data
@GroupSequenceProvider(value = CustomSequenceProvider.class)
public class CustomGroupForm {

    /**
     * 类型
     */
    @Pattern(regexp = "[A|B]" , message = "类型不必须为 A|B")
    private String type;

    /**
     * 参数A
     */
    @NotEmpty(message = "参数A不能为空" , groups = {WhenTypeIsA.class})
    private String paramA;

    /**
     * 参数B
     */
    @NotEmpty(message = "参数B不能为空", groups = {WhenTypeIsB.class})
    private String paramB;

    /**
     * 分组A
     */
    public interface WhenTypeIsA {

    }

    /**
     * 分组B
     */
    public interface WhenTypeIsB {

    }

}

CustomSequenceProvider

public class CustomSequenceProvider implements DefaultGroupSequenceProvider<CustomGroupForm> {

    @Override
    public List<Class<?>> getValidationGroups(CustomGroupForm form) {
        List<Class<?>> defaultGroupSequence = new ArrayList<>();

        defaultGroupSequence.add(CustomGroupForm.class);

        if (form != null && "A".equals(form.getType())) {
            defaultGroupSequence.add(CustomGroupForm.WhenTypeIsA.class);
        }

        if (form != null && "B".equals(form.getType())) {
            defaultGroupSequence.add(CustomGroupForm.WhenTypeIsB.class);
        }

        return defaultGroupSequence;
    }
}

тестовый интерфейс

/**
 * 自定义分组
 */
@PostMapping("/customGroup")
public ResultVo customGroup(@RequestBody @Validated CustomGroupForm form){
    return ResultVoUtil.success(form);
}

Результаты теста

Тип Тип это

Тип Б

Резюме

  GroupSequenceАннотация представляет собой стандартную аннотацию проверки подлинности компонента. Как и прежде, он позволяет вам статически переопределить порядок группы проверки класса по умолчанию. тем не мениеGroupSequenceProviderЭто позволяет динамически определять порядок группы проверки.

замечание

SpringBoot 2.3.x удаленvalidationЗависимости необходимо импортировать вручную.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Суммировать

  Некоторый личный опыт, ненулевая оценка параметров, это должно быть первым шагом проверки, в дополнение к ненулевой проверке нам также необходимо сделать следующее:

  • Обычные параметры - необходимо уточнить длину поля. Если данные будут храниться в базе данных, длина зависит от базы данных, в противном случае она определяется в зависимости от бизнеса.
  • Параметры типа. Лучше всего использовать регулярные выражения для строгой проверки типов, которые могут появиться. НапримерtypeЗначение равно [0 | 1 | 2].
  • Параметры списка (списка) — нужно не только проверять, квалифицированы ли параметры в списке, но и ограничивать размер списка. Скажи 100.
  • Такие параметры, как дата, электронная почта, сумма и URL-адрес, должны быть проверены с использованием соответствующего регулярного выражения.
  • Параметр аутентичность - это в основном для различныхIdНапримерuserId,merchantIdДля таких параметров проверка подлинности требуется, чтобы определить, содержит ли система, и соответствует ли соответствующее состояние нормально.

   Чем строже проверка параметров, тем лучше Строгие правила проверки позволяют не только снизить вероятность ошибок интерфейса, но и избежать появления грязных данных, тем самым обеспечивая безопасность и стабильность работы системы.

Неправильная информация для напоминания должна быть дружелюбной, чтобы потом старший брат не жаловался на нее.

Обзор последнего номера

конец

  Если вы считаете, что это полезно для вас, вы можете прокомментировать и поставить лайк, или вы можете перейти на мою домашнюю страницу, чтобы увидеть, может быть, есть статья, которая вам нравится, вы также можете просто подписаться на нее, спасибо.

  Я другой технарь, каждый день я делаю небольшие успехи и живу другой жизнью. Увидимся в следующий раз!