FreeMarker

Apache FreeMarker (英語) は、HTML からメールなどへのあらゆる種類のテキスト出力を生成するためのテンプレートエンジンです。Spring Framework には、Spring MVC と FreeMarker テンプレートを使用するための組み込みの統合機能があります。

構成を表示

次の例は、FreeMarker をビューテクノロジーとして設定する方法を示しています。

  • Java

  • Kotlin

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.freeMarker();
	}

	// Configure 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()
	}

	// Configure FreeMarker...

	@Bean
	fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
		setTemplateLoaderPath("/WEB-INF/freemarker")
	}
}

次の例は、XML で同じものを構成する方法を示しています。

<mvc:annotation-driven/>

<mvc:view-resolvers>
	<mvc:freemarker/>
</mvc:view-resolvers>

<!-- Configure FreeMarker... -->
<mvc:freemarker-configurer>
	<mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>

または、次の例に示すように、すべてのプロパティを完全に制御するために FreeMarkerConfigurer Bean を宣言することもできます。

<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 の設定

FreeMarkerConfigurer Bean で適切な Bean プロパティを設定することにより、FreeMarker の「設定」と "SharedVariables" を FreeMarker Configuration オブジェクト(Spring によって管理される)に直接渡すことができます。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"/>

Configuration オブジェクトに適用される設定と変数の詳細については、FreeMarker のドキュメントを参照してください。

フォーム処理

Spring は、特に <spring:bind/> 要素を含む JSP で使用するタグライブラリを提供します。この要素により、フォームは主にフォームバッキングオブジェクトの値を表示し、Web またはビジネス層の Validator からの検証の失敗の結果を表示できます。Spring は、FreeMarker と同じ機能をサポートしていますが、フォーム入力要素自体を生成するための追加の便利なマクロがあります。

バインドマクロ

マクロの標準セットは、FreeMarker の spring-webmvc.jar ファイル内で維持されるため、適切に構成されたアプリケーションで常に使用可能です。

Spring テンプレートライブラリで定義されているマクロの一部は内部(プライベート)と見なされますが、マクロ定義にはそのようなスコープは存在せず、呼び出し元のコードとユーザーテンプレートにすべてのマクロが表示されます。次のセクションでは、テンプレート内から直接呼び出す必要があるマクロのみに焦点を当てます。マクロコードを直接表示する場合、ファイルは spring.ftl と呼ばれ、org.springframework.web.servlet.view.freemarker パッケージに含まれています。

簡単なバインド

Spring MVC コントローラーのフォームビューとして機能する FreeMarker テンプレートに基づく HTML フォームでは、次の例のようなコードを使用して、フィールド値にバインドし、JSP の同等の方法と同様の方法で各入力フィールドのエラーメッセージを表示できます。次の例は、personForm ビューを示しています。

<!-- FreeMarker macros have to be imported into a namespace.
	We strongly recommend sticking to '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 マクロは、web.xml の ServletContext パラメーター defaultHtmlEscape で指定されたデフォルトの HTML エスケープ動作を想定しています。

<@spring.bindEscaped> と呼ばれるマクロの代替形式は、ステータスエラーメッセージまたは値で HTML エスケープを使用するかどうかを明示的に指定する 2 番目の引数を取ります。必要に応じて、true または false に設定できます。追加のフォーム処理マクロにより、HTML エスケープの使用が簡単になります。これらのマクロは可能な限り使用する必要があります。それらについては次のセクションで説明します。

入力マクロ

FreeMarker 用の追加の便利なマクロは、バインディングとフォーム生成(検証エラー表示を含む)の両方を簡素化します。これらのマクロを使用してフォーム入力フィールドを生成する必要はありません。これらを単純な HTML と組み合わせたり、以前に強調した Spring バインドマクロへの直接呼び出しを組み合わせたりすることができます。

次の使用可能なマクロの表は、FreeMarker テンプレート(FTL)定義とそれぞれが取るパラメーターリストを示しています。

表 1: マクロ定義の表
マクロ FTL 定義

message (output a string from a resource bundle based on the code parameter)

<@spring.message code/>

messageText (output a string from a resource bundle based on the code parameter, falling back to the value of the default parameter)

<@spring.messageText code, text/>

url (prefix a relative URL with the application’s context root)

<@spring.url relativeUrl/>

formInput (standard input field for gathering user input)

<@spring.formInput path, attributes, fieldType/>

formHiddenInput (hidden input field for submitting non-user input)

<@spring.formHiddenInput path, attributes/>

formPasswordInput (standard input field for gathering passwords. Note that no value is ever populated in fields of this type.)

<@spring.formPasswordInput path, attributes/>

formTextarea (large text field for gathering long, freeform text input)

<@spring.formTextarea path, attributes/>

formSingleSelect (drop down box of options that let a single required value be selected)

<@spring.formSingleSelect path, options, attributes/>

formMultiSelect (a list box of options that let the user select 0 or more values)

<@spring.formMultiSelect path, options, attributes/>

formRadioButtons (a set of radio buttons that let a single selection be made from the available choices)

<@spring.formRadioButtons path, options separator, attributes/>

formCheckboxes (a set of checkboxes that let 0 or more values be selected)

<@spring.formCheckboxes path, options, separator, attributes/>

formCheckbox (a single checkbox)

<@spring.formCheckbox path, attributes/>

showErrors (simplify display of validation errors for the bound field)

<@spring.showErrors separator, classOrStyle/>

In FreeMarker templates, formHiddenInput and formPasswordInput are not actually required, as you can use the normal formInput macro, specifying hidden or password as the value for the fieldType parameter.

The parameters to any of the above macros have consistent meanings:

  • path: The name of the field to bind to (for example, "command.name")

  • options: A Map of all the available values that can be selected from in the input field. The keys to the map represent the values that are POSTed back from the form and bound to the command object. Map objects stored against the keys are the labels displayed on the form to the user and may be different from the corresponding values posted back by the form. Usually, such a map is supplied as reference data by the controller. You can use any Map implementation, depending on required behavior. For strictly sorted maps, you can use a SortedMap (such as a TreeMap) with a suitable Comparator and, for arbitrary Maps that should return values in insertion order, use a LinkedHashMap or a LinkedMap from commons-collections.

  • separator: Where multiple options are available as discreet elements (radio buttons or checkboxes), the sequence of characters used to separate each one in the list (such as <br>).

  • attributes: An additional string of arbitrary tags or text to be included within the HTML tag itself. This string is echoed literally by the macro. For example, in a textarea field, you may supply attributes (such as 'rows="5" cols="60"'), or you could pass style information such as 'style="border:1px solid silver"'.

  • classOrStyle: For the showErrors macro, the name of the CSS class that the span element that wraps each error uses. If no information is supplied (or the value is empty), the errors are wrapped in <b></b> tags.

The following sections outline examples of the macros.

Input Fields

The formInput macro takes the path parameter (command.name) and an additional attributes parameter (which is empty in the upcoming example). The macro, along with all other form generation macros, performs an implicit Spring bind on the path parameter. The binding remains valid until a new bind occurs, so the showErrors macro does not need to pass the path parameter again — it operates on the field for which a binding was last created.

The showErrors macro takes a separator parameter (the characters that are used to separate multiple errors on a given field) and also accepts a second parameter — this time, a class name or style attribute. Note that FreeMarker can specify default values for the attributes parameter. The following example shows how to use the formInput and showErrors macros:

<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>

The next example shows the output of the form fragment, generating the name field and displaying a validation error after the form was submitted with no value in the field. Validation occurs through Spring’s Validation framework.

The generated HTML resembles the following example:

Name:
<input type="text" name="name" value="">
<br>
	<b>required</b>
<br>
<br>

The formTextarea macro works the same way as the formInput macro and accepts the same parameter list. Commonly, the second parameter (attributes) is used to pass style information or rows and cols attributes for the textarea.

Selection Fields

You can use four selection field macros to generate common UI value selection inputs in your HTML forms:

  • formSingleSelect

  • formMultiSelect

  • formRadioButtons

  • formCheckboxes

4 つのマクロはそれぞれ、フォームフィールドの値とその値に対応するラベルを含む Map のオプションを受け入れます。値とラベルは同じにすることができます。

次の例は、FTL のラジオボタンです。フォームバックオブジェクトはこのフィールドにデフォルト値「ロンドン」を指定するため、検証は必要ありません。フォームがレンダリングされると、選択する都市のリスト全体が、モデル内の参照データとして "cityMap" という名前で提供されます。次のリストに例を示します。

...
Town:
<@spring.formRadioButtons "command.address.town", cityMap, ""/><br><br>

上記のリストは、cityMap の各値に 1 つずつラジオボタンの行をレンダリングし、"" のセパレータを使用しています。追加の属性は提供されません(マクロの最後のパラメーターが欠落しています)。cityMap は、マップ内の各キーと値のペアに同じ String を使用します。マップのキーは、フォームが POST リクエストパラメーターとして実際に送信するものです。マップ値は、ユーザーに表示されるラベルです。前の例では、3 つのよく知られた都市のリストと、フォームバッキングオブジェクトのデフォルト値を指定すると、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>

アプリケーションが(たとえば)内部コードで都市を処理することを期待している場合、次の例に示すように、適切なキーを使用してコードのマップを作成できます。

  • Java

  • Kotlin

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 4.01 に準拠し、Spring のバインドサポートで使用される web.xml ファイルで定義された HTML エスケープのデフォルト値を使用する HTML 要素が生成されます。要素を XHTML 準拠にするか、デフォルトの HTML エスケープ値をオーバーライドするには、テンプレート(またはテンプレートに表示されるモデル)で 2 つの変数を指定できます。テンプレートで指定することの利点は、後でテンプレート処理で異なる値に変更して、フォームの異なるフィールドに異なる動作を提供できることです。

タグの XHTML 準拠に切り替えるには、次の例に示すように、xhtmlCompliant という名前のモデルまたはコンテキスト変数に true の値を指定します。

<#-- for 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 escaping off -->