Весенний загрузчик Реализуйте общий интерфейс параметр калибровки

Spring Boot Java задняя часть maven
Весенний загрузчик Реализуйте общий интерфейс параметр калибровки

Оригинальная ссылка:Woohoo.Магия шифров.Талант/Весна-сапог…

Обновленная версия «из коробки»:GitHub.com/ciphermagic…

Эта статья основана наSpring BootиJDK8написатьAOP, в сочетании с пользовательскими аннотациями для реализации общей проверки параметров интерфейса.

причина

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

public class AccountVO {
    private String name; // 姓名
    private Integer age; // 年龄
}

Предположим, есть такой бизнес: когда пользователи регистрируются, им нужно заполнить свое имя и возраст, а когда они входят в систему, им нужно заполнить только свои имена. Тогда явно неуместно добавлять правила проверки к классам сущностей.

Поэтому я всегда хотел реализовать проверку параметров на уровне методов, для одного и того же параметра сущности разные методы могут применять разные правила проверки, поэтому этот инструмент родился и давно используется в повседневной работе.

вводить

Рассмотрим способы использования:

@Service
public class TestImpl implements ITestService {

    @Override
    @Check({"name", "age"})
    public void testValid(AccountVO vo) {
        // ...
    }

}

из которых метод@CheckВ аннотации указан параметрAccountVOсерединаname,ageСвойство не может быть пустым. В дополнение к непустой проверке он также поддерживает определение размера, проверку на равенство и т. д.:

@Check({"id>=8", "name!=aaa", "title<10"})

Сообщение об ошибке по умолчанию возвращает поле, причину ошибки и вызываемый метод, например:

updateUserId must not null while calling testValid

id must >= 8 while calling testValid

name must != aaa while calling testValid

Также поддерживает пользовательскую информацию об ошибках:

@Check({"title<=8:标题字数不超过8个字,含标点符号"})
public void testValid(TestPO po) {
    // ...
}

Просто добавьте его после правил проверки:, за которым следует пользовательская информация, заменит сообщение об ошибке по умолчанию.

PS: Основной принцип заключается в том, чтобы получить значение поля в объекте параметра посредством отражения, а затем проверить его в соответствии с правилами. Поэтому в настоящее время поддерживаются только методы с одним параметром, и параметр не может быть базовым типом.

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

spring-bootкак пользоватьсяAOPНе повторять их здесь, в основном наAOPосновной код в .

Зависимости Maven

Кромеspring-bootВ дополнение к зависимостям необходимые сторонние зависимости не являются основными зависимостями и могут быть выбраны в соответствии с личными привычками:

<!-- 用于字符串校验 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.3.2</version>
</dependency>

<!-- 用于日志打印 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 参数校验 注解
 * Created by cipher on 2017/9/20.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
public @interface Check {

    // 字段校验规则,格式:字段名+校验规则+冒号+错误信息,例如:id<10:ID必须少于10
    String[] value();

}

основной код

Добавлено через фасетный перехват@CheckМетод аннотированного интерфейса выполняет проверку параметров перед выполнением метода.Если есть сообщение об ошибке, он возвращается напрямую:

@Around(value = "@com.cipher.checker.Check") // 这里要换成自定义注解的路径
public Object check(ProceedingJoinPoint point) throws Throwable {
    Object obj;
    // 参数校验
    String msg = doCheck(point);
    if (!StringUtils.isEmpty(msg)) {
        // 这里可以返回自己封装的返回类
        throw new IllegalArgumentException(msg);
    }
    obj = point.proceed();
    return obj;
}

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

/**
 * 参数校验
 *
 * @param point ProceedingJoinPoint
 * @return 错误信息
 */
private String doCheck(ProceedingJoinPoint point) {
    // 获取方法参数值
    Object[] arguments = point.getArgs();
    // 获取方法
    Method method = getMethod(point);
    String methodInfo = StringUtils.isEmpty(method.getName()) ? "" : " while calling " + method.getName();
    String msg = "";
    if (isCheck(method, arguments)) {
        Check annotation = method.getAnnotation(Check.class);
        String[] fields = annotation.value();
        Object vo = arguments[0];
        if (vo == null) {
            msg = "param can not be null";
        } else {
            for (String field : fields) {
                // 解析字段
                FieldInfo info = resolveField(field, methodInfo);
                // 获取字段的值
                Object value = ReflectionUtil.invokeGetter(vo, info.field);
                // 执行校验规则
                Boolean isValid = info.optEnum.fun.apply(value, info.operatorNum);
                msg = isValid ? msg : info.innerMsg;
            }
        }
    }
    return msg;
}

Вы можете видеть, что основная логика такова:

Разобрать поле -> получить значение поля -> выполнить правила проверки

Класс перечисления поддерживается внутри, и в нем указываются соответствующие операции проверки:

/**
 * 操作枚举
 */
enum Operator {
    /**
     * 大于
     */
    GREATER_THAN(">", CheckParamAspect::isGreaterThan),
    /**
     * 大于等于
     */
    GREATER_THAN_EQUAL(">=", CheckParamAspect::isGreaterThanEqual),
    /**
     * 小于
     */
    LESS_THAN("<", CheckParamAspect::isLessThan),
    /**
     * 小于等于
     */
    LESS_THAN_EQUAL("<=", CheckParamAspect::isLessThanEqual),
    /**
     * 不等于
     */
    NOT_EQUAL("!=", CheckParamAspect::isNotEqual),
    /**
     * 不为空
     */
    NOT_NULL("not null", CheckParamAspect::isNotNull);

    private String value;
    private BiFunction<Object, String, Boolean> fun;

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

Из-за недостатка места это не один из кодов, заинтересованные друзья могут получить весь исходный код:ciphermagic/java-learn/sandbox/checker

TODO

  • Пакет в независимый компонент в пути весеннего ботинка стартера
  • Поддержка проверки регулярного выражения

Наконец

Спасибо за чтение, друзья, которым это нравится, могут перейти кgithubUpvote, если у вас есть какие-либо вопросы или предложения, пожалуйста, оставьте сообщение ниже, с нетерпением жду вашего ответа.