Сравнение версий
Ключ
- Эта строка добавлена.
- Эта строка удалена.
- Изменено форматирование.
2. Краткий обзор
Чтобы внедрить динамический контент на наши страницы, нам нужно использовать синтаксис, который понимает FreeMarker :
${…}
в шаблоне будет заменено в сгенерированном выводе фактическим Основные правила
Метка в шаблоне
Метка в шаблоне обозначается ${…}. Метка заменяется значением выражения внутри фигурных скобок
— мы называем этоинтерполяцией —
несколько примеров: . Примеры: ${1 + 2
}
и, ${variableName}
Теги
Теги FTL похожи на теги HTML (но
содержат#
или @
содержат # или @ ), и FreeMarker интерпретирует их, например, <#if…></#if>
Комментарии
Комментарии в FreeMarker начинаются
с<#–
и заканчиваются с <#– и заканчиваются -->
??
оператор, чтобы проверить, Свойства страницы | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
В работе | Комментарий | |
3. Тег включения
Директива включения
FTL позволяет нам следовать принципу DRY в нашем приложении. Мы определим повторяющийся контент в файле и повторно используем его в разных шаблонах FreeMarker с одним включенным
тегом.
Один из таких вариантов использования — когда мы хотим включить раздел меню на многие страницы. Во-первых, мы определим раздел меню внутри файла — назовем его menu.ftl
— со следующим содержимым:
<a href="#dashboard">Dashboard</a>
<a href="#newEndpoint">Add new endpoint</a>
И на нашу HTML-страницу давайте включим созданный файл menu.ftl
:
<!DOCTYPE html>
<html>
<body>
<#include 'fragments/menu.ftl'>
<h6>Dashboard page</h6>
</body>
</html>
И мы также можем включить FTL в наши фрагменты, и это здорово.
4. Обработка существования ценности
FTL будет рассматривать любое нулевое
значение как отсутствующее значение. Таким образом, нам нужно быть особенно осторожными и добавить логику для обработки null
внутри нашего шаблона.
|
Операторы
Оператор | Описание |
---|---|
?? | Проверить существует ли атрибут или вложенное свойство |
? |
Итак, мы проверили атрибут на null,
но этого не всегда достаточно. Давайте теперь определим значение по умолчанию в качестве запасного варианта для этого отсутствующего значения. Для этого нам понадобится !
оператор ставится после имени переменной:
${attribute!'default value'}
Используя круглые скобки, мы можем обернуть многие вложенные атрибуты.
Например, чтобы проверить,c | Преобразовать логическое значение в удобочитаемую строку |
! | Значение по умолчанию, если атрибут не существует |
() | Проверить существует ли атрибут и имеет ли он вложенное свойство с другим вложенным свойством |
${(attribute.nestedProperty.nestedProperty)??}
Наконец, собрав все вместе, мы можем встроить их среди статического контента:
<p>TestingПример
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>Testing is student property exists: ${student???c}</ |
<p>Using
p> <p>Using default value for missing student: ${student!'John Doe'}</ |
<p>Wrapping
p> <p>Wrapping student nested properties: ${(student.address.street)???c}</ |
И, если бы student
был null
, мы бы увидели:
p> |
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>Testing is student property exists: |
<p>Using
false</p> <p>Using default value for missing student: John |
<p>Wrapping
Doe</p> <p>Wrapping student nested properties: |
false</ |
Обратите внимание на дополнительную директиву ?c , используемую после
??
. Мы сделали это, чтобы преобразовать логическое значение в удобочитаемую строку.
5. Тег «если-иначе»
p> |
Тег «Условие»
Управляющие структуры присутствуют во FreeMarker, и традиционный if-else
, вероятно, вам знаком:<#if condition>Блок кода | ||
---|---|---|
| ||
<#if condition> <!-- block to execute if condition is true --> |
<#elseif condition2>
<#elseif condition2> <!-- block to execute if condition2 is the first true condition --> |
<#elseif condition3>
<#elseif condition3> <!-- block to execute if condition3 is the first true condition --> |
<#else>
<#else> <!-- block to execute if no condition is true --> |
</ |
Хотя ветки elseif
и else
необязательны, условия должны разрешаться в логическое значение.
Чтобы помочь нам с нашими оценками, мы, вероятно, будем использовать один из:
x == y
, чтобы проверить, равен лиx
y
x != y
, чтобы вернутьtrue
, только еслиx
отличается отy
x lt y
означает, чтоx
должен быть строго меньшеy
— мы также можем использовать<
вместоlt
x gt y
оценивается какtrue
, только еслиx
строго большеy
— мы можем использовать>
вместоgt
x lte y
проверяет , меньше лиx или равно
y
– альтернативойlte
является<=
x gte y
проверяет, больше лиx
или равноy
– альтернативаgte
>=Икс??
проверить существованиеx
sequence?seqContains(x)
проверяет наличиеx
внутри последовательности
Очень важно помнить, что FreeMarker рассматривает >= и > как закрывающие символы для тега FTL. Решение состоит в том, чтобы заключить их использование в круглые скобки или вместо этого использовать gte
или gt
.
Собираем все вместе по следующему шаблону:
<#if#if> |
Пример
Блок кода | ||||
---|---|---|---|---|
| ||||
<#if status??> |
<p>${status.reason}</ |
<#else>
p> <#else> |
<p>Missing status!</ |
</#if>
В итоге получаем HTML-код:
p>
</#if> |
Блок кода | ||||
---|---|---|---|---|
| ||||
<!-- When status attribute exists --> |
<p>404
<p>404 Not |
Found</p> <!-- When status attribute is missing --> |
<p>Missing
<p>Missing status!</ |
p> |
Контейнеры подпеременных
Во FreeMarker у нас есть три типа контейнеров для подпеременных:
- Хэши — - это последовательность пар ключ-значение — ключ должен быть уникальным внутри хеша, и у нас нет порядка
Последовательности
— - Последовательности - это списки, в которых у нас есть индекс, связанный с каждым значением — примечательным фактом является то, что подпеременные могут быть разных типов.
- Коллекции — - это особый случай последовательностей, где мы не можем получить доступ к размеру или получить значения по индексу — мы все же можем перебирать их с помощью тега списка ! <#list>
Повторение элементов
Мы можем перебирать контейнер Перебор контейнера двумя основными способами. В первом случае мы перебираем каждое значение, и для каждого из них выполняется логика:
<#list
Блок кода | ||||
---|---|---|---|---|
| ||||
<#--Перебираем каждое значение, и для каждого из них выполняется логика--> <#list sequence as |
item> <!-- do something with ${item} --> |
</ |
#list> <#--Или, когда мы хотим повторить |
Hash |
, получая доступ как к ключу, так и к |
значению --> <#list hash as key, |
value> <!-- do something with ${key} and ${value} --> |
</ |
Вторая форма более мощная, потому что она также позволяет нам определить логику, которая должна происходить на различных этапах итерации:
<#list sequence>#list> |
Блок кода | ||||
---|---|---|---|---|
| ||||
<#-- Позволяет определить логику, которая должна происходить на различных этапах итерации. Элемент представляет собой имя зацикленной переменной, но можно переименовать его по своему усмотрению --> <#list sequence> <!-- one-time logic if the sequence is not empty --> |
<#items as |
item> <!-- logic repeated for every item in sequence --> |
</ |
#items> <!-- one-time logic if the sequence is not empty --> |
<#else>
<#else> <!-- one-time logic if the sequence is empty --> |
</ |
Элемент представляет собой имя зацикленной переменной, но мы можем переименовать его по своему усмотрению .
Ветка else не
является обязательной.
Для практического примера хорошо определите шаблон, в котором мы перечисляем некоторые статусы:
<#list statuses><ul>
<#items as status>
#list> |
Пример
Блок кода | ||||
---|---|---|---|---|
| ||||
<#list statuses> <ul> <#items as status> |
<li>${status}</ |
li> </ |
#items> </ |
<#else>
ul> <#else> |
<p>No statuses |
available</p> </ |
Это вернет нам следующий HTML-код, когда наш
#list> |
<li>200 OK</li>
<li>404 Not Found</li>
<li>500
Блок кода | ||||
---|---|---|---|---|
| ||||
<ul> <li>200 OK</li> <li>404 Not Found</li> <li>500 Internal Server |
Error</li> </ |
6.2.
ul> |
Обработка предметов
Хэш позволяет нам выполнять две простые функции: keys
keys для извлечения только содержащихся ключей и values
values для извлечения только значений.
Последовательность более сложная; мы можем можно сгруппировать наиболее полезные функции:
фрагмент
chunk исоединение
join, чтобы получить подпоследовательность или объединить две последовательностиreverse
reverse ,sort
sort иsortBy
sortBy для изменения порядка элементовfirst
first иlast
last извлекут первый или последний элемент соответственноsize
size представляет количество элементов в последовательностиseqContains
seqContains ,seqIndexOf
seqIndexOf илиseqLastIndexOf
seqLastIndexOf для поиска элемента
Обработка типов
FreeMarker поставляется с огромным количеством разнообразных функций (встроенных), доступных для работы с объектами. Давайте посмотрим на некоторые часто используемые функции.
7.1.Обработка строк
url
и urlPath
- url и urlPath будут экранировать строку URL-адресом, за исключением того,
- что urlPath
- не будет экранировать косую черту /
jString
- jString ,
jsString
и jsonString
- jsString и jsonString будут применять правила экранирования для Java, Javascript и JSON соответственно .
capFirst
- capFirst ,
uncapFirst
- uncapFirst ,
upperCase
- upperCase ,
lowerCase
и capitalize
- lowerCase и capitalize полезны для изменения регистра
- строки, как следует из их названий.
boolean
- boolean ,
date
- date ,
time
- time ,
datetime
и number
— - datetime и number - это функции для преобразования строки в другие типы.
Давайте теперь воспользуемся некоторыми из этих функций:
<p>$Пример
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>${'http://myurl.com/?search=Hello World'?urlPath}</ |
<p>$
p> <p>${'Using " in text'?jsString}</ |
<p>$
p> <p>${'my value?upperCase}</ |
<p>$
p> <p>${'2019-01-12'?date('yyyy-MM-dd')}</ |
И вывод для шаблона выше будет:
<p>http%3Ap> |
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>http%3A//myurl.com/ |
<p>MY VALUE</p>
<p>Using
%3Fsearch%3DHello%20World</p> <p>MY VALUE</p> <p>Using \" in |
<p>12
text</p> <p>12.01. |
2019</ |
При использовании функции даты
мы также передаем шаблон для анализа объекта String. FreeMarker использует локальный формат, если не указано иное , например, в строковой
функции, доступной для объектов даты.
7.2. Обработка номеров
round
, пол
и потолок
p> |
Обработка чисел
- round , min и max могут помочь с округлением чисел
abs
- abs вернет абсолютное значение числа
string
- string преобразует число в строку. Мы также можем передать четыре предопределенных числовых формата:
компьютер
, валюта
, число
или процент
или - компьютер , валюта , число или процент или определить свой собственный формат,
- например ["0.###"]
Сделаем цепочку из нескольких математических операций:
<p>$Пример
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>${(7.3?round + 3.4?ceiling + 0.1234)?string('0.##')}</ |
<!
p> <#-- (7 + 4 + 0.1234) with 2 decimals --> |
И, как и ожидалось, результирующее значение равно 11,12.
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>11.12</p> |
Обработка даты
- .now
- представляет текущую дату и время
date
- date ,
time
и datetime
- time и datetime могут возвращать разделы даты и времени объекта даты и времени.
строка
преобразует - строка преобразует дату и время в строки
- - можно передать желаемый формат или использовать предопределенный
Теперь мы собираемся получить текущее время и отформатировать вывод в строку, содержащую только часы и минуты:
<p>$Блок кода | ||||
---|---|---|---|---|
| ||||
<p>${.now?time?string('HH:mm')}</ |
Результирующий HTML будет:
<p>15:39</p>
8. Обработка исключений
Мы увидим дваp> |
Блок кода | ||||
---|---|---|---|---|
| ||||
<p>15:39</p> |
Обработка исключений
Два способа обработки исключений для шаблона FreeMarker.Первый способ — использовать
Использовать теги попытки
recover, чтобы определить, что мы должны попытаться выполнить, и блок кода, который должен выполниться в случае ошибки.
Синтаксис:
<#attempt>Блок кода language xml title Шаблон <#attempt> <!-- block to try -->
<#recover>
<#recover> <!-- block to execute in case of exception -->
</
#attempt>
Теги
попытки
и восстановления
attempt и recover являются обязательными. В случае ошибки он откатывает предпринятый блок и выполняет только код в разделе
восстановления
.Помня об этом синтаксисе, давайте определим наш шаблон как:
<p>Preparing to evaluate</p>
<#attempt>
<p>Attribute is ${attributeWithPossibleValue??}</p>
<#recover>
<p>Attribute is missing</p>
</#attempt>
<p>Done with the evaluation</p>
Когда attributeWithPossibleValue
отсутствует, мы увидим:
<p>Preparing to evaluate</p>
<p>Attribute is missing</p>
<p>Done with the evaluation</p>
И вывод, когда attributeWithPossibleValue
существует:
<p>Preparing to evaluate</p>
<p>Attribute is 200 OK</p>
<p>Done with the evaluation</p>
Второй способ — настроить recover.
- Настроить FreeMarker, что должно происходить в случае исключений.
С Spring Boot мы легко настраиваем это через файл свойств; вот некоторые доступные конфигурации:
spring.freemarker.setting.template_exception_handler=rethrow
повторно выдает исключениеspring.freemarker.setting.template_exception_handler=debug
выводит клиенту информацию о трассировке стека, а затем повторно выдает исключение.spring.freemarker.setting.template_exception_handler=html_debug
выводит клиенту информацию о трассировке стека, форматируя ее так, чтобы она обычно хорошо читалась в браузере, а затем повторно выдает исключение.spring.freemarker.setting.template_exception_handler=ignore
пропускает ошибочные инструкции, позволяя шаблону продолжить выполнение.spring.freemarker.setting.template_exception_handler = по умолчанию
9. Методы вызова
Иногда мы хотим вызывать методы Java из наших шаблонов FreeMarker. Сейчас мы посмотрим, как это сделать.
9.1. Статические члены
Чтобы начать доступ к статическим членам, мы можем либо обновить нашу глобальную конфигурацию FreeMarker, либо добавить в модель атрибут типа S taticModels
под именем атрибута statics
:
model.addAttribute("statics", new DefaultObjectWrapperBuilder(new Version("2.3.28"))
.build().getStaticModels());
Доступ к статическим элементам прост.
Сначала мы импортируем статические элементы нашего класса, используя тег assign, затем выбираем имя и, наконец, путь к классам Java.
Вот как мы импортируем класс Math
в наш шаблон, показываем значение статического поля PI
и используем статический метод pow :
<#assign MathUtils=statics['java.lang.Math']>
<p>PI value: ${MathUtils.PI}</p>
<p>2*10 is: ${MathUtils.pow(2, 10)}</p>
Результирующий HTML:
<p>PI value: 3.142</p>
<p>2*10 is: 1,024</p>
9.2. Члены бина
Доступ к членам компонента очень прост: используйте точку (.) , и все!
В нашем следующем примере мы добавим в нашу модель объект Random :
model.addAttribute("random", new Random());
В нашем шаблоне FreeMarker сгенерируем случайное число:
<p>Random value: ${random.nextInt()}</p>
Это приведет к выводу, подобному:
<p>Random value: 1,329,970,768</p>
9.3. Пользовательские методы
Первым шагом для добавления пользовательского метода является наличие класса, который реализует интерфейс TemplateMethodModelEx
FreeMarker и определяет нашу логику внутри метода exec :
public class LastCharMethod implements TemplateMethodModelEx {
public Object exec(List arguments) throws TemplateModelException {
if (arguments.size() != 1 || StringUtils.isEmpty(arguments.get(0)))
throw new TemplateModelException("Wrong arguments!");
String argument = arguments.get(0).toString();
return argument.charAt(argument.length() - 1);
}
}
Мы добавим экземпляр нашего нового класса в качестве атрибута модели:
model.addAttribute("lastChar", new LastCharMethod());
Следующим шагом будет использование нашего нового метода внутри нашего шаблона:
<p>Last char example: ${lastChar('mystring')}</p>
Наконец, в результате получается:
<p>Last char example: g</p>
Оглавление |
---|