1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/admin_yu-yx-validator

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

yx-validator

2020-01-16 19:03:05 Четверг

Разработка среды: jdk1.8, maven3.5.0, spring boot 2.0.2.RELEASE

Как элегантно реализовать проверку параметров интерфейса в Spring Boot проекте?

В процессе разработки Java-приложений, многие проекты не выполняют проверку параметров интерфейсов или используют простые методы проверки с помощью if-выражений. Это связано с несколькими причинами:

  • Отсутствие популярных и подходящих схем проверки API-параметров;
  • Невозможность применения существующих схем к конкретному проекту;
  • Низкие требования к проверке параметров в проектах, развёрнутых во внутренней сети;
  • Передача задачи проверки параметров на фронтэнд.

AOP + аннотации для реализации проверки параметров метода

Hibernate Validator — это фреймворк для проверки данных в Hibernate, который является эталонной реализацией Bean Validation. Он широко используется и может быть применён для создания собственной системы проверки параметров. Однако при использовании Hibernate Validator для разных методов могут потребоваться разные правила проверки, что приводит к необходимости создания нескольких классов сущностей или групп, а иногда даже к отсутствию параметров у некоторых интерфейсов. Поэтому использование Hibernate Validator может вызвать определённые трудности.

На основе этого опыта я разработал собственную систему проверки параметров интерфейса на основе AOP и аннотаций.

Реализация

Для проверки параметров используются аннотации @CheckParam или @CheckParams. Вот пример использования этих аннотаций:

@RestController
@RequestMapping("/paramCheck")
public class ParamCheckController {

    @CheckParam(value = Check.NotEmpty, argName = "userName", msg = "Ты большой дядя, это обязательный параметр!")
    @PostMapping("/singleCheckNotEmpty")
    public Object singleCheckNotNull(String userName) {
        return 1;
    }

    @CheckParam(value = Check.DateTime, argName = "dateTime", msg = "msg можно не указывать, есть стандартное сообщение")
    @PostMapping("/singleCheckDateTime")
    public Object singleCheckDateTime(String dateTime) {
        return 1;
    }
    
    @CheckParams({
        @CheckParam(value = Check.NotNull, argName = "userId", msg = "Ты большой дядя, этот параметр обязателен!"),
        @CheckParam(value = Check.NotEmpty, argName = "userName"),
        @CheckParam(value = Check.NotEmpty, argName = "dept.deptName", msg = "Проверка атрибутов сущности"),
        @CheckParam(value = Check.Past, argName = "dept.createTime"),
        @CheckParam(value = Check.lt, argName = "dept.employees", express = "2") // Проверка размера коллекции
    })
    @PostMapping("/entityMultiCheck")
    public Object entityMultiCheck(Integer userId, String userName, @RequestBody DeptEntity dept) {
        return 1;
    }}

Конкретная реализация

  • В теле метода используются аннотации @CheckParam или @CheckParams для указания параметров, подлежащих проверке.
  • Затем с помощью AOP происходит внедрение, где извлекаются настроенные правила проверки и соответствующие значения аргументов.
  • Вызывается инструмент CheckUtil для выполнения проверки.

Вот перечисление Check, которое содержит различные типы проверок:

public enum Check {

    Null("Параметр должен быть null", CheckUtil::isNull),

    NotNull("Параметр не должен быть null", CheckUtil::isNotNull),

    Empty("Параметр должен быть пустым", CheckUtil::isEmpty),
    
    NotEmpty("Параметр не должен быть пустым", CheckUtil::isNotEmpty),
    
    True("Параметр должен быть true", CheckUtil::isTrue),

    False("Параметр должен быть false", CheckUtil::isFalse),

    Date("Параметр должен представлять собой дату в формате yyyy-MM-dd", CheckUtil::isDate),

    DateTime("Параметр должен представлять собой дату и время в формате yyyy-MM-dd HH:mm:ss", CheckUtil::isDateTime),

    Past("Параметр должен представлять прошедшую дату", CheckUtil::isPast),

    Future("Параметр должен представлять будущую дату", CheckUtil::isFuture),
    
    Today("Параметр должен представлять сегодняшнюю дату", CheckUtil::isToday),
    
    Enum("Параметр должен принадлежать перечислению", CheckUtil::inEnum),
    
    Email("Параметр должен быть адресом электронной почты", CheckUtil::isEmail),

    Range("Параметр должен находиться в допустимом диапазоне", CheckUtil::inRange),

    NotIn("Параметр должен не находиться в указанном диапазоне", CheckUtil::outRange),
    
    Length("Длина параметра должна находиться в заданном диапазоне", CheckUtil::inLength),
    
    gt("Параметр должен быть больше указанного значения", CheckUtil::isGreaterThan),
    
    lt("Параметр должен быть меньше указанного значения", CheckUtil::isLessThan),
    
    ge("Параметр должен быть больше или равен указанному значению", CheckUtil::isGreaterThanEqual),
    
    le("Параметр должен быть меньше или равен указанному значению", CheckUtil::isLessThanEqual),
    
    ne("Параметр должен отличаться от указанного значения", CheckUtil::isNotEqual),
    
    Equal("Параметр должен совпадать с указанным значением", CheckUtil::isEqual),
    
    Pattern("Параметр должен соответствовать указанному регулярному выражению", CheckUtil::isPattern);

    public String msg;
    public BiFunction<Object, String, Boolean> fun;

    Check(String msg, BiFunction<Object, String, Boolean> fun) {
        this.msg = msg;
        this.fun = fun;
    }
}

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

Интеграция

  • Измените Application, добавив @SpringBootApplication(scanBasePackages = {"com.yuxue"}), чтобы все аннотации были просканированы.
  • Добавьте зависимости в maven-проект или добавьте jar-зависимость.
<dependency>
    <groupId>com.yuxue</groupId>
    <artifactId>yx-validator</artifactId>
    <version>1.0.0</version>
</dependency>

Пример использования

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.yuxue.entity.DeptEntity;
import com.yuxue.entity.EmployeeEntity;
import com.yuxue.validator.annotation.CheckParam;
import
``` ```
com.yuxue.validator.annotation.CheckParams;
import com.yuxue.validator.enumtype.Check;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;

@Api(tags = {"check"}, description = "Параметр проверки")
@RestController
@RequestMapping("/paramCheck")
public class ParamCheckController {
    @ApiImplicitParam(name = "userId", value = "", dataType = "Integer", paramType="query")
    @CheckParam(value = Check.NotNull, argName = "userId")
    @PostMapping("/singleCheckNotNull")
    public Object singleCheckNotNull(Integer userId) {
        System.err.println(userId);
        return 1;
    }

    @ApiImplicitParam(name = "userName", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.NotEmpty, argName = "userName", msg = "Ты большой дядя, это обязательный параметр!")
    @PostMapping("/singleCheckNotEmpty")
    public Object singleCheckNotNull(String userName) {
        System.err.println(userName);
        return 1;
    }

    @ApiImplicitParam(name = "bl", value = "", dataType = "Boolean", paramType="query")
    @CheckParam(value = Check.True, argName = "bl")
    @PostMapping("/singleCheckTrue")
    public Object singleCheckTrue(Boolean bl) {
        System.err.println(bl);
        return 1;
    }

    @ApiImplicitParam(name = "date", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Date, argName = "date")
    @PostMapping("/singleCheckDate")
    public Object singleCheckDate(String date) {
        System.err.println(date);
        return 1;
    }

    @ApiImplicitParam(name = "dateTime", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.DateTime, argName = "dateTime")
    @PostMapping("/singleCheckDateTime")
    public Object singleCheckDateTime(String dateTime) {
        System.err.println(dateTime);
        return 1;
    }

    @ApiImplicitParam(name = "date", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Past, argName = "date")
    @PostMapping("/singleCheckPast")
    public Object singleCheckPast(String date) {
        System.err.println(date);
        return 1;
    }

    @ApiImplicitParam(name = "dateTime", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Future, argName = "dateTime", msg = "Параметр должен быть будущей датой или временем и соответствовать формату yyyy-MM-dd HH:mm:ss.")
    @PostMapping("/singleCheckFuture")
    public Object singleCheckFuture(String dateTime) {
        System.err.println(dateTime);
        return 1;
    }

    @ApiImplicitParam(name = "date", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Today, argName = "date")
    @PostMapping("/singleCheckToday")
    public Object singleCheckToday(String date) {
        System.err.println(date);
        return 1;
    }

    @ApiImplicitParam(name = "gender", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Enum, argName = "gender", express="мужчина, женщина, евнух")
    @PostMapping("/singleCheckStringEnum")
    public Object singleCheckStringEnum(String gender) {
        System.err.println(gender);
        return 1;
    }

    @ApiImplicitParam(name = "gender", value = "", dataType = "Integer", paramType="query")
    @CheckParam(value = Check.Enum, argName = "gender", express="0,1")
    @PostMapping("/singleCheckIntegerEnum")
    public Object singleCheckIntegerEnum(Integer gender) {
        System.err.println(gender);
        return 1;
    }

    @ApiImplicitParam(name = "password", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Length, argName = "password", express="6,18", msg="Длина пароля должна быть от 6 до 18 символов!")
    @PostMapping("/singleCheckStringLength")
    public Object singleCheckStringLength(String password) {
        System.err.println(password);
        return 1;
    }

    @ApiImplicitParam(name = "password", value = "", dataType = "String", paramType="query")
    @CheckParams({
        @CheckParam(value = Check.ge, argName = "password", express = "6"),
``` Вот перевод текста на русский язык:

    @CheckParam(value = Check.le, argName = "password", express = "18")
    })
    @PostMapping("/singleCheckStringLength1")
    public Object singleCheckStringLength1(String password) {
        System.err.println(password);
        return 1;
    }

    @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query")
    @CheckParam(value = Check.Range, argName = "age", express="18,50")
    @PostMapping("/singleCheckIntegerRange")
    public Object singleCheckIntegerRange(Integer age) {
        System.err.println(age);
        return 1;
    }

    @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query")
    @CheckParams({
        @CheckParam(value = Check.ge, argName = "age", express="18"),
        @CheckParam(value = Check.le, argName = "age", express="50")
    })
    @PostMapping("/singleCheckIntegerRange1")
    public Object singleCheckIntegerRange1(Integer age) {
        System.err.println(age);
        return 1;
    }

    @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query")
    @CheckParam(value = Check.NotIn, argName = "age", express="18,50")
    @PostMapping("/singleCheckIntegerNotIn")
    public Object singleCheckIntegerNotIn(Integer age) {
        System.err.println(age);
        return 1;
    }

    @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query")
    @CheckParams({
        @CheckParam(value = Check.lt, argName = "age", express="18"),
        @CheckParam(value = Check.gt, argName = "age", express="50")
    })
    @PostMapping("/singleCheckIntegerNotIn1")
    public Object singleCheckIntegerNotIn1(Integer age) {
        System.err.println(age);
        return 1;
    }

    @ApiImplicitParam(name = "email", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Email, argName = "email", msg="你大爷的,输入个邮箱啊!")
    @PostMapping("/singleCheckEmail")
    public Object singleCheckEmail(String email) {
        System.err.println(email);
        return 1;
    }

    @ApiImplicitParam(name = "age", value = "", dataType = "Integer", paramType="query")
    @CheckParam(value = Check.ge, argName = "age", express="18", msg = "必须大于等于18岁") // gt、lt、le、ne、Equal不再举例; 具体看注释
    @PostMapping("/singleCheckIntegerGe")
    public Object singleCheckIntegerGe(Integer age) {
        System.err.println(age);
        return 1;
    }

    @ApiImplicitParam(name = "pattern", value = "", dataType = "String", paramType="query")
    @CheckParam(value = Check.Pattern, argName = "pattern", express="^[\u0021-\u007E]{4,16}$")
    @PostMapping("/singleCheckPattern")
    public Object singleCheckPattern(String pattern) {
        System.err.println(pattern);
        return 1;
    }

    @ApiImplicitParams({
        @ApiImplicitParam(name = "userId", dataType = "Integer", paramType="query"),
        @ApiImplicitParam(name = "userName", dataType = "String", paramType="query")
    })
    @CheckParams({
        @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"),
        @CheckParam(value = Check.NotNull, argName = "userName")
    })
    @PostMapping("/multiCheckNotNull")
    public Object multiCheckNotNull(Integer userId, String userName) {
        System.err.println(userId);
        System.err.println(userName);
        return 1;
    }

    @ApiImplicitParams({
        @ApiImplicitParam(name = "userId", dataType = "Integer", paramType="query"),
        @ApiImplicitParam(name = "userName", dataType = "String", paramType="query"),
        @ApiImplicitParam(name = "employee", dataType = "entity", paramType="body")
    })
    @CheckParams({
        @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"),
        @CheckParam(value = Check.NotEmpty, argName = "userName"),
        @CheckParam(value = Check.NotEmpty, argName = "employee.name")
    })
    @PostMapping("/entityCheckNotNull")
    public Object entityCheckNotNull(Integer userId, String userName, @RequestBody EmployeeEntity employee) {
        System.err.println(userId); ```
System.err.println(userName);
System.err.println(employee.getName());
return 1;
}

@ApiImplicitParams({
    @ApiImplicitParam(name = "userId", dataType = "Integer", paramType="query"),
    @ApiImplicitParam(name = "userName", dataType = "String", paramType="query"),
    @ApiImplicitParam(name = "dept", dataType = "entity", paramType="body")
})

@CheckParams({
    @CheckParam(value = Check.NotNull, argName = "userId", msg = "你大爷的,这个是必填参数!"),
    @CheckParam(value = Check.NotEmpty, argName = "userName"),
    @CheckParam(value = Check.NotEmpty, argName = "dept.deptName"),
    @CheckParam(value = Check.Past, argName = "dept.createTime"),
    @CheckParam(value = Check.lt, argName = "dept.employees", express = "2") // 对集合的size判断
})
@PostMapping("/entityMultiCheck")
public Object entityMultiCheck(Integer userId, String userName, @RequestBody DeptEntity dept) {
    System.err.println(userId);
    System.err.println(userName);
    System.err.println(dept.getDeptName());
    return 1;
}

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Спринг бут + мэйвен проект, элегантная реализация проверки параметров интерфейса. Развернуть Свернуть
BSD-3-Clause
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/admin_yu-yx-validator.git
git@api.gitlife.ru:oschina-mirror/admin_yu-yx-validator.git
oschina-mirror
admin_yu-yx-validator
admin_yu-yx-validator
master