Apache FreeMarker — це шаблонізатор для генерації будь-якого виду текстового виведення від HTML до електронної пошти тощо. Spring Framework має вбудовану інтеграцію для використання Spring MVC з шаблонами FreeMarker.
Конфігурація подання
У наступному прикладі показано, як налаштувати FreeMarker як технологію подання:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
}
// Конфігуруємо FreeMarker...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/freemarker");
return configurer;
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.freeMarker()
}
// Конфігуруємо FreeMarker...
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("/WEB-INF/freemarker")
}
}
У наступному прикладі показано, як налаштувати те саме на XML:
<mvc:annotation-driven/>
<mvc:view-resolvers>
<mvc:freemarker/>
</mvc:view-resolvers>
<!-- Configuring FreeMarker... -->
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>
До того ж, можна оголосити бін FreeMarkerConfigurer для повного контролю над усіма властивостями, як показано в наступному прикладі:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>
Твої шаблони повинні зберігатися в директорії, вказаній FreeMarkerConfigurer, як показано в попередньому прикладі. Враховуючи попередню конфігурацію, якщо твій контролер повертає ім'я подання welcome, перетворювач шукає шаблон /WEB-INF/freemarker/welcome.ftl.
Конфігурація FreeMarker
Можна передати "Settings" і "SharedVariable" обробника FreeMarker безпосередньо до об'єкта Конфігурація обробника FreeMarker (який керується Spring), встановивши відповідні властивості біна в FreeMarkerConfigurer. Для якості freemarkerSettings потрібен об'єкт java.util.Properties, а для якості freemarkerVariables — java.util.Map. У цьому прикладі показано, як використовувати FreeMarkerConfigurer:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape"/>
</map>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
Подробиці про налаштування та змінні, які застосовуються до об'єкта Конфігурація, див. у документації FreeMarker.
Обробка форм
Spring передбачає бібліотеку тегів для використання в JSP, яка містить, серед іншого, елемент <spring:bind/>. Цей елемент насамперед дозволяє формам виводити на екран значення з базових об'єктів форми та відображати результати невдалих перевірок з Validator на вебрівні або бізнес-рівні. Spring також має підтримку тієї ж функціональності FreeMarker, з додатковими зручними макросами для генерації самих елементів введення форми.
Макроси прив'язки
Засоби підтримки стандартного набору макросів знаходяться у файлі spring- webmvc.jar для FreeMarker, тому вони завжди доступні для відповідного настроєного додатка.
Деякі макроси, визначені в бібліотеках шаблонізації в Spring, вважаються внутрішніми (приватними), але в визначеннях макросів такого обмеження немає, що робить все макроси видимими для коду, який робить виклик, і користувацьких шаблонів. Наступні розділи присвячені лише макросам, які необхідно викликати безпосередньо із шаблонів. Якщо тобі потрібно переглянути код макросу безпосередньо, файл називається spring.ftl і знаходиться в пакеті org.springframework.web.servlet.view.freemarker.
Просте прив'язування
У твоїх HTML-формах на базі шаблонів FreeMarker, які діють як подання форми для контролера Spring MVC, можна використовувати код, подібний до того, що представлений в наступному прикладі, для прив'язки до значень полів і виведення на екран повідомлень про помилки кожного поля введення аналогічно еквіваленту JSP. У цьому прикладі показано подання personForm:
<!-- Макроси FreeMarker повинні бути імпортовані в простір імен.
Ми рекомендуємо дотримуватись параметра "spring". -->
<#import "/spring.ftl" as spring/>
<html>
...
<form action="" method="POST">
Name:
<@spring.bind "personForm.name"/>
<input type="text"
name="${spring.status.expression}"
value="${spring.status.value?html}"/><br/>
<#list spring.status.errorMessages as error> <b>${error}</b> <br/> </#list>
<br />
...
<input type="submit" value="submit"/>
</form>
...
</html>
<@spring.bind> вимагає аргумент "path", який складається з імені твого об'єкта команди (це "command", якщо не змінити його в конфігурації контролера), за яким слідує точка та ім'я поля об'єкта команди, до якого ти хочеш здійснити прив'язку. Також можна використовувати вкладені поля, наприклад, command.address.street. Макрос bind передбачає логіку HTML-екранування за замовчуванням, встановлену параметром defaultHtmlEscape контексту ServletContext у web.xml.
Альтернативна форма макросу <@spring.bindEscaped> приймає другий аргумент, який явно вказує, чи слід використовувати HTML-екранування в повідомленнях про помилку визначення статусу чи значення. Залежно від необхідності можна встановити значення true або false. Додаткові макроси для роботи з формами полегшують використання HTML-екранування, і тобі варто використовувати ці макроси скрізь, де це можливо. Вони описані в наступному розділі.
Макроси введення
Додаткові допоміжні макроси для FreeMarker спрощують прив'язку та генерацію форм (включно з виведенням на екран помилок валідації). Немає необхідності використовувати ці макроси для створення полів введення форми: їх можна змішувати та поєднувати за допомогою простого HTML або прямих викликів макросів прив'язки Spring, про які ми розповідали раніше.
У цій таблиці доступних макросів наведено визначення шаблону FreeMarker Template (FTL) та список параметрів, які приймає кожен із них:
| макрос | Визначення FTL |
|---|---|
|
<@spring.message code/> |
|
<@spring.messageText code, text/> |
|
<@spring.url relativeUrl/> |
|
<@spring.formInput path, attributes, fieldType/> |
|
<@spring.formHiddenInput path, attributes/> |
|
<@spring.formPasswordInput path, attributes/> |
|
<@spring. formTextarea path, attributes/> |
|
<@spring.formSingleSelect path, options, attributes/> |
|
<@spring.formMultiSelect path, options, attributes/> |
|
<@spring.formRadioButtons path, options separator, attributes/> |
|
<@spring.formCheckboxes path, options, separator, attributes/> |
|
<@spring.formCheckbox path, attributes/> |
|
<@spring.showErrors separator, classOrStyle/> |
formHiddenInput та
formPasswordInput фактично немає потреби, тому що ти можеш використовувати звичайний макрос
formInput, якщо вкажеш
hidden або
password як значення параметра
fieldType.
Параметри будь-якого з вищезгаданих макросів мають зрозуміле значення:
path: ім'я поля для прив'язки (тобто. "command.name")options:Mapвсіх доступних значень, які можна обрати в полі введення. Ключі Map є значеннями, які передаються назад з форми і прив'язуються до об'єкта команди. Об'єкти Map, що зберігаються поряд із ключами, є мітками, що відображаються у формі для користувача, і можуть відрізнятися від відповідних значень, що повертаються формою. Зазвичай така Map надається контролером як довідкові дані. Ти можеш використовувати будь-яку реалізацію Map в залежності від логіки роботи. Для строго відсортованих Map можна використовувати SortedMap (наприклад, TreeMap) з відповідним Comparator, а для довільних Map, які повинні повертати значення в порядку вставки, використовуй LinkedHashMap або LinkedMap з commons-collections.separator: якщо кілька опцій доступні у вигляді окремих елементів (перемикачі або прапорці), цей параметр представляє послідовність символів, що використовуються для поділу кожного з них у списку (наприклад,<br>).attributes: додатковий рядок довільних тегів або тексту для включення в сам HTML-тег. Цей рядок буквально повторюється макросом. Наприклад, у поліtextareaможна передати атрибути (наприклад, 'rows="5" cols="60"') або інформацію про стиль, наприклад, 'style="border:1px solid silver"'.classOrStyle: для макросуshowErrors– ім'я класу CSS, який використовується в елементіspan,обгортаючи кожну помилку. Якщо інформація не надана (або значення порожнє), помилки обертаються в теги<b></b>.
У наступних розділах наведено приклади макросів.
Поля введення
Макро formInput приймає параметр path(command.name) та додатковий параметр attributes (який у наступному прикладі порожній). Цей макрос, як і інші макроси генерації форм, виконує неявну прив'язку Spring до параметра "path". Прив'язка залишається дійсною доти, доки не буде здійснено нову прив'язку, тому макросу showErrors не потрібно знову передавати параметр "шляху" — він працює з полем, для якого прив'язка була створена востаннє.
Макрос showErrors приймає параметр-розділювач (символи, які використовуються для розділення кількох помилок у даному полі), а також приймає другий параметр: цього разу — ім'я класу або атрибут стилю. Зверни увагу, що FreeMarker може встановити значення за замовчуванням для параметра "attributes". У наступному прикладі показано, як використовувати макроси formInput та showErrors:
<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>
У наступному прикладі показано виведення фрагменту форми з генерацією поля імені та виведенням помилки валідації після того, як форму було відправлено без значення в полі. Валідація відбувається через фреймворк Validation у Spring.
Створюваний HTML схожий на наступний приклад:
Name:
<input type="text" name="name" value="">
<br>
<b>required</b>
<br>
<br>
Макрос formTextarea працює так само, як і макрос formInput, і приймає той самий перелік параметрів. Зазвичай другий параметр (attributes) використовується для передачі інформації про стиль або атрибути rows і cols для textarea.
Поля вибору
Ти можеш використовувати чотири макроси для полів вибору, щоб генерувати звичайні вхідні дані вибору значень інтерфейсу користувача у своїх HTML-формах :
formSingleSelectformMultiSelectformRadioButtonsformCheckboxes
Кожен із чотирьох макросів приймає Map опцій, яка містить значення для поля форми та мітку, що відповідає цьому значенню. Значення та мітка можуть бути однаковими.
Наступний приклад стосується перемикачів у FTL. Базовий об'єкт форми задає для цього поля значення за замовчуванням "London", тому валідація не потрібна. Коли форма відображається, весь список міст для вибору надається як довідкові дані в моделі під ім'ям "cityMap". У наступному лістингу показаний приклад:
...
Town:
<@spring.formRadioButtons "command.address.town", cityMap, ""/><br><br>
У попередньому лістингу відображається рядок перемикачів, по одному для кожного значення cityMap, і використовується роздільник "". Жодних додаткових атрибутів не привласнюється (останнього параметра макросу немає). cityMap використовує ту саму String для кожної пари ключ-значення в Map. Ключі Map — це те, що форма фактично надсилає як параметри POST-запиту. Значення Map — це позначки, які бачить користувач. У попередньому прикладі, враховуючи список із трьох відомих міст і значення за замовчуванням у базовому об'єкті форми, HTML виглядає так:
Town:
<input type="radio" name="address.town" value="London">London</input>
<input type="radio" name="address.town" value="Paris" checked="checked">Paris</input>
<input type="radio" name="address.town" value="New York">New York</input>
Якщо твоя програма передбачає роботу з містами за внутрішніми кодами (наприклад), то можна створити Map кодів з відповідними ключами, як показано в наступному прикладі:
protected Map<String, ?> referenceData(HttpServletRequest request) throws Exception {
Map<String, String> cityMap = new LinkedHashMap<>();
cityMap.put("LDN", "London");
cityMap.put("PRS", "Paris");
cityMap.put("NYC", "New York");
Map<String, Object> model = new HashMap<>();
model.put("cityMap", cityMap);
return model;
}
protected fun referenceData(request: HttpServletRequest): Map<String, *> {
val cityMap = linkedMapOf(
"LDN" to "London",
"PRS" to "Paris",
"NYC" to "New York"
)
return hashMapOf("cityMap" to cityMap)
}
Тепер код виводить дані, де значеннями перемикача є відповідні коди, але користувач, як і раніше, бачить зручніші назви міст, як показано нижче:
Town:
<input type="radio" name="address.town" value="LDN">London</input>
<input type="radio" name="address.town" value="PRS" checked="checked">Paris</input>
<input type="radio" name="address.town" value="NYC">New York</input>
HTML-екранування
Використання за замовчуванням макросів форми, описаних раніше, призводить до створення HTML-елементів, які відповідають стандарту HTML 4.01 і використовують значення за замовчуванням для HTML-екранування, визначене у файлі web.xml, яке використовується засобами підтримки прив'язки Spring. Щоб зробити елементи сумісними з XHTML або перевизначити значення HTML-екранування за замовчуванням, можна вказати дві змінні у твоєму шаблоні (або у твоїй моделі, де їх бачать твої шаблони). Перевага їх зазначення в шаблонах полягає в тому, що їх можна змінити на інші значення пізніше під час обробки шаблону, щоб забезпечити різну логіку роботи для різних полів твоєї форми. Щоб перейти до режиму сумісності з XHTML для твоїх тегів, встанови значення true для моделі або контекстної змінної з ім'ям xhtmlCompliant, як показано в наступному прикладі:
<#-- для FreeMarker -->
<#assign xhtmlCompliant = true>
Після обробки цієї директиви всі елементи, створені макросами Spring, будуть сумісні зі стандартом XHTML.
Аналогічним чином можна встановити HTML-екранування для кожного поля, як показано в наступному прикладі:
<#-- until this point, default HTML escaping is used -->
<#assign htmlEscape = true>
<#-- next field will use HTML escaping -->
<@spring.formInput "command.name"/>
<#assign htmlEscape = false in spring>
<#-- all future fields will be bound with HTML-екранування off -->
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ