SPEL Настолько сладкие особенности не используются, не осмеливаться забавно веселиться?

Java задняя часть
SPEL Настолько сладкие особенности не используются, не осмеливаться забавно веселиться?

Эта статья включена в репозиторий Github.GitHub.com/silently952…

Публичный аккаунт WeChat: бета изучает Java

предисловие

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

Мы исследовали языки выражений OGNL и SpEL (их больше, чем эти два), и выбрали SpEL, потому что сам наш проект зависит от Spring.

Введение в SpEL и обзор функций

SpEL — это мощный язык выражений, предоставляемый Spring.Он также используется в качестве краеугольного модуля Spring и используется во многих модулях Spring.Хотя SpEL является краеугольным камнем Spring, он полностью независим от Spring. Основные возможности, предоставляемые SpEL:

  • буквальное выражение
  • Булевы и реляционные операторы
  • регулярное выражение
  • выражение класса
  • Доступ к свойствам, массивам, спискам, картам
  • Вызов метода
  • оператор отношения
  • параметр
  • вызвать конструктор
  • ссылка на бин
  • Построить массив
  • Встроенные списки, встроенные карты
  • Тернарный оператор
  • Переменная
  • определяемая пользователем функция
  • ансамблевая проекция
  • Фильтрация коллекции
  • выражение шаблона

Язык выражений SpEL для начинающих.

Следующий код использует API SpEL для анализа выражения текстовой строки Hello World.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();

интерфейсExpressionParserОтвечает за синтаксический анализ строк выражений, одинарные кавычки необходимы для представления строк в выражениях.

SpEL поддерживает множество функций, таких как вызов методов, доступ к свойствам и вызов конструкторов.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();

SpEL также поддерживает использование стандартной нотации «.», т. е. установку вложенных свойств prop1.prop2.prop3 и значений свойств

ExpressionParser parser = new SpelExpressionParser();

// invokes getBytes().length
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
int length = (Integer) exp.getValue();

также можно использоватьpublic <T> T getValue(Class<T> desiredResultType)Для получения результата, возвращающего указанный тип, принудительное преобразование типа не требуется.Если фактический результат не может быть преобразован в указанный тип, будет выдано исключениеEvaluationException

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);

Чаще всего SpEL используется для предоставления проанализированной строки выражения для конкретного экземпляра объекта (называемого корневым объектом).Этот метод также используется в нашем проекте, устанавливая данные json, переданные из разных каналов, в качестве корневого объекта и затем укажите строковое выражение для анализа каждого стандартного поля

GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name");

EvaluationContext context = new StandardEvaluationContext(tesla);
String name = (String) exp.getValue(context);

EvalacingContext Интерфейс

интерфейсEvaluationContextЕсть готовая реализацияStandardEvaluationContext;Используйте отражение для управления объектами и кэширования экземпляров метода, поля и конструктора java.lang.reflect для повышения производительности при оценке выражений для разрешения свойств, методов и облегчения выполнения преобразований типов.

StandardEvaluationContextв состоянии пройтиsetRootObject()Или передайте корневой объект конструктору, чтобы установить корневой объект, вы также можете использоватьsetVariable()Установить переменные,registerFunction()для регистрации метода; мы также можем настроитьConstructorResolvers, MethodResolvers, PropertyAccessorдля расширения функциональности SpEL.

Конфигурация парсера

можно сделать с помощьюorg.springframework.expression.spel.SpelParserConfigurationДля уточнения функции парсера конфигурации, например: если значение позиции индекса массива или коллекции, указанной в выражении, равно null, пусть он автоматически создает элемент; если индекс превышает текущий размер массива, он автоматически расширяется

class Demo {
    public List<String> list;
}

// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true,true);

ExpressionParser parser = new SpelExpressionParser(config);

Expression expression = parser.parseExpression("list[3]");

Demo demo = new Demo();

Object o = expression.getValue(demo);

ссылка на язык

буквальное выражение

Типы, которые поддерживают литеральные выражения, — это строки, даты, числа (целые, вещественные, шестнадцатеричные), логические значения и null. Строки разделяются одинарными кавычками. Сама одинарная кавычка представлена ​​в строке двумя символами одинарной кавычки. В приведенном ниже списке показано простое использование литералов. Поддержка чисел с использованием знака минус, знака экспоненты и десятичной точки

ExpressionParser parser = new SpelExpressionParser();

// evals to "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();

double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();

// evals to 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();

boolean trueValue = (Boolean) parser.parseExpression("true").getValue();

Object nullValue = parser.parseExpression("null").getValue();

Properties, Arrays, Lists, Maps

Использовать ссылки на атрибуты очень просто: просто используйте.Представляет значения вложенных свойств.

// evals to 1856
int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context);

String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);

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

ExpressionParser parser = new SpelExpressionParser();

// Inventions Array
StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla);

// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(
        teslaContext, String.class);

// Members List
StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee);

// evaluates to "Nikola Tesla"
String name = parser.parseExpression("Members[0].Name").getValue(
        societyContext, String.class);

// List and Array navigation
// evaluates to "Wireless communication"
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(
        societyContext, String.class);

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

// Officer's Dictionary

Inventor pupin = parser.parseExpression("Officers['president']").getValue(
        societyContext, Inventor.class);

// evaluates to "Idvor"
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(
        societyContext, String.class);

// setting values
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(
        societyContext, "Croatia");

метод вызова

Вызовы методов по-прежнему поддерживаются в выражениях.

// string literal, evaluates to "bc"
String c = parser.parseExpression("'abc'.substring(2, 3)").getValue(String.class);

// evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
        societyContext, Boolean.class);

метод, используемый здесьisMemberЭто метод в корневом объекте. Если корневой объект не существует, этот метод сообщит об ошибке

оператор

Реляционные операторы: «равно», «не равно», «меньше», «меньше или равно», «больше» и «больше или равно» используются так же, как и в обычном Java.

// evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);

// evaluates to false
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);

В дополнение к стандартным реляционным операторам SpEL поддерживаетinstanceofи регулярные выраженияmatchesработать.

boolean falseValue = parser.parseExpression(
        "'xyz' instanceof T(int)").getValue(Boolean.class);

// evaluates to true
boolean trueValue = parser.parseExpression(
        "'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);

Логический оператор: поддерживаемый логический операторand, or, not.

/ -- AND --

// evaluates to false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);

// evaluates to true
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

// -- OR --

// evaluates to true
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);

// evaluates to true
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

// -- NOT --

// evaluates to false
boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);

// -- AND and NOT --
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);

#this и #root переменные

Переменная #this всегда определена и ссылается на текущий исполняемый объект. Переменная #root указывает на объект корневого контекста.

// create an array of integers
List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));

// create parser and set variable primes as the array of integers
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("primes",primes);

// all prime numbers > 10 from the list (using selection ?{...})
// evaluates to [11, 13, 17]
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
        "#primes.?[#this>10]").getValue(context);

функция

Иногда вам может понадобиться настроить некоторые служебные функции для использования в выражениях, вы можете использоватьStandardEvaluationContext.registerFunctionМетоды регистрируют функции, а затем вызывают функции в выражениях.

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();

context.registerFunction("reverseString",
    StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class }));  //注册函数reverseString

String helloWorldReversed = parser.parseExpression(
    "#reverseString('hello')").getValue(context, String.class);

ссылка на бин

Если контекст синтаксического анализа был настроен, синтаксический анализатор компонента может использовать из выражения@Класс символического компонента поиска, использование&Найдите объект FactoryBean

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());

// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("@something").getValue(context);

SpEL уже предоставляет по умолчаниюBeanFactoryResolver, нет необходимости реализовывать это вручную

установить выбор

Выбор — это мощная функция языка выражений, которую можно использовать для установки условий фильтрации и возврата подмножества, соответствующего условиям, подобно фильтру в потоке; при выборе используется синтаксис?[selectionExpression].

Список фильтров

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(Arrays.asList(1, 7, 0, 3, 4, 9));
Object subList = parser.parseExpression("#root.?[#this>5]").getValue(context);  //[7, 9]

фильтровать пример карты

ExpressionParser parser = new SpelExpressionParser();
Map<String,Integer> root = new HashMap<>();
root.put("3",3);
root.put("6",6);
root.put("8",8);
StandardEvaluationContext context = new StandardEvaluationContext(root);
Object subMap = parser.parseExpression("#root.?[#this.value>5]").getValue(context); //{6=6, 8=8}

Помимо возврата всех выбранных элементов, его также можно использовать для получения первого или последнего значения. Синтаксис для получения выбора, соответствующего первой записи:^[...]И чтобы получить последнее совпадение, синтаксис выбора$[...]

ансамблевая проекция

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

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(Arrays.asList(
        new User("Silently9521"),
        new User("Silently9522"), 
        new User("Silently9527")));
Object nameList = parser.parseExpression("#root.![#this.name]").getValue(context);//[Silently9521, Silently9522, Silently9527]

Обратитесь к официальной документации:docs.spring.IO/spring-без оперативной памяти…


Пишите до конца (обратите внимание, не потеряйтесь)

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

Наконец,Проституция нехороша, творить нелегко, я надеюсь, что мои друзья могутНравится Комментарий ПодписатьсяСанлян, потому что это все источники мотивации, которыми я могу поделиться🙏


Я написал упрощенную версию springmvc с нуля, а также написал подробную документацию, надеясь помочь партнерам глубже понять основные принципы springmvc, нуждающиеся друзья могут обратить внимание на общедоступный номер: бета-версия JAVA, ответьте源码Просто