Micronaut で Thymeleaf Dialectを追加する方法

2 min read読了の目安(約2600字

以下の環境で作成

  • Micronaut: 2.1.0
  • Kotlin: 1.4.10

Dialectを作る

公式サイトで紹介されているDialectをそのまま使用する。

https://www.thymeleaf.org/doc/articles/sayhelloextendingthymeleaf5minutes.html
<p hello:sayto="World">Hi ya!</p>

↓に変換するDialect

<p>Hello World!</p>
HelloDialect
import org.thymeleaf.context.ITemplateContext
import org.thymeleaf.engine.AttributeName
import org.thymeleaf.model.IProcessableElementTag
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor
import org.thymeleaf.processor.element.IElementTagStructureHandler
import org.thymeleaf.templatemode.TemplateMode
import org.unbescape.html.HtmlEscape

class SayToAttributeTagProcessor(dialectPrefix: String) : AbstractAttributeTagProcessor(
    TemplateMode.HTML,
    dialectPrefix,
    null,
    false,
    ATTR_NAME,
    true,
    PRECEDENCE,
    true
) {
    companion object {
        private const val ATTR_NAME = "sayto"
        private const val PRECEDENCE = 10000
    }

    override fun doProcess(
        context: ITemplateContext?,
        tag: IProcessableElementTag?,
        attributeName: AttributeName?,
        attributeValue: String?,
        structureHandler: IElementTagStructureHandler?) {
        structureHandler?.setBody(
            "Hello, " + HtmlEscape.escapeHtml5(attributeValue) + "!", false)
    }
}
import org.thymeleaf.dialect.AbstractProcessorDialect

class HelloDialect : AbstractProcessorDialect(
    "Hello Dialect", "hello", 1000
) {
    override fun getProcessors(dialectPrefix: String): Set<SayToAttributeTagProcessor> =
        setOf(SayToAttributeTagProcessor(dialectPrefix))
}

TemplateEngineにDialectを追加する

io.micronaut.views.thymeleaf.ThymeleafFactoryでDIコンテナに登録されているTemplateEngineにDialectを追加する。
追加にはBeanCreatedEventListenerを使用する。

import io.micronaut.context.event.BeanCreatedEvent
import io.micronaut.context.event.BeanCreatedEventListener
import org.thymeleaf.TemplateEngine
import javax.inject.Singleton

@Singleton
class TemplateEngineInitializer : BeanCreatedEventListener<TemplateEngine> {
    override fun onCreated(event: BeanCreatedEvent<TemplateEngine>): TemplateEngine {
        val engine = event.bean
        engine.addDialect(HelloDialect()) // ここでDialectを追加
        return engine
    }
}

HTMLの用意

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <p hello:sayto="World">Hi ya!</p>
</body>
</html>

動作確認

追加したDialectにより hello:sayto が置き換わっていることがわかる。

$ curl localhost:8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
<p>Hello, World!</p>
</body>
</html>%