Due to the circumstances of the projects we participated in, there were many behaviors that could not be realized with the standard standard dialect alone, so we decided to implement it ourselves. In the first place, Thymeleaf itself didn't have much opportunity to touch from the training when I was a newcomer, but rather I was more familiar with JSP, so I started studying from the beginning.
As I implemented it through trial and error and was able to reproduce the intended operation, it became more and more fun, so I will leave it as a memorandum.
The typical ones that are basically used are classified as follows.
name | Description |
---|---|
IProcessorDialect | Dialect that provides elements and attributes |
IExpressionObjectDialect | A dialect that provides an object that can be used in an EL expression in a tag attribute value |
IProcessorDialect registers a Processor and implements tags, and can be used with a description method such as th: text
.
IExpressionObjectDialect can add utilities that can be used in EL expressions, such as # strings
.
IProcessorDialect
A Dialect that can be described like an element or attribute. Since IProcessorDialect has an abstract class called AbstractProcessorDialect, we usually inherit and implement it. Create a Processor that implements the actual processing separately, and register it in the implementation class of AbstractProcessorDialect so that it works.
For example, if you create a date to format it as yyyy / mm / dd
, you can use it as follows.
■ Description on the template
<span thex:formatdate="${date}"></span>
■ Elements that are actually output
<span>2020/01/01</span>
Also, when I wrote the Dialect I created earlier inline in the script tag, I was addicted to it because the Dialect was not recognized.
<script th:inline="javascript">
var test = [# thex:formatdate="${date}" /] ;
console.log(test);
</script>
It seems that it will not be recognized on the template unless the description is set to be recognized inline in the implementation of AbstractProcessorDialect. Therefore, it is necessary to set the template mode according to the case where JavaScript or CSS is used.
@Override
public Set<IProcessor> getProcessors(String dialectPrefix) {
Set<IProcessor> proccessors = new HashSet<>();
proccessors.add(new SampleProcesssor(TemplateMode.HTML, dialectPrefix));
proccessors.add(new SampleProcesssor(TemplateMode.JAVASCRIPT, dialectPrefix));
proccessors.add(new SampleProcesssor(TemplateMode.CSS, dialectPrefix));
return proccessors;
}
IExpressionObjectDialect
As a trial, we will implement ʻIExpressionObjectDialectand create a utility that can be used in EL expressions as
# sample`.
Be careful not to duplicate the name you add as a utility with the one provided as standard.
First, we will implement Dialect to register Expression Object. Here, we will generate the name of the utility when using it in the EL expression and the class that actually performs the processing.
public class SampleDialect extends AbstractDialect implements IExpressionObjectDialect {
//Name constants when used in EL expressions
private static final String SAMPLE_DIALECT_NAME = "sample";
private static final Set<String> EXPRESSION_OBJECT_NAMES = Collections.singleton(SAMPLE_DIALECT_NAME);
public SampleDialect() {
super(SAMPLE_DIALECT_NAME);
}
@Override
public IExpressionObjectFactory getExpressionObjectFactory() {
return new IExpressionObjectFactory() {
@Override
public Set<String> getAllExpressionObjectNames() {
return EXPRESSION_OBJECT_NAMES;
}
@Override
public Object buildObject(IExpressionContext context, String expressionObjectName) {
if (SAMPLE_DIALECT_NAME.equals(expressionObjectName)) {
//Instantiation of a class that processes as a utility
return new Sample();
}
return null;
}
@Override
public boolean isCacheable(String expressionObjectName) {
return true;
}
};
}
}
Next, we will create a class that actually transfers the processing from the template side. This time, we will implement it with a simple process of passing a character string, formatting it, and displaying it on the screen.
public class Sample {
public String getSampleString(final String str) {
return "Sample string "" + str + "」";
}
}
You can actually use it in the EL expression as follows on HTML.
■ Description on the template
<span th:text="${#sample.getSampleString('sample')}"
■ Elements that are actually output
<span>Sample string "sample"</span>
We will set ViewResolver in the setting class so that it can operate on MVC. (For information on how to implement Java Config, click here](https://qiita.com/HiroyaEnd/items/17175e947911d84c1b3b#webmvcconfig)) Since you can register your own Dialect here, you can also register it and make it work on the template. (The setting method is basically the same for both IProcessorDialect and IExpressionObjectDialect)
//Constants used for encoding settings
public static final String CHARACTER_ENCODING = "UTF-8";
//A constant in the base directory path where the template is located
private static final String VIEW_LOCATION = "/WEB-INF/views/";
//Bean definition ThymeleafViewResolver
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(templateEngine());
thymeleafViewResolver.setCharacterEncoding(CHARACTER_ENCODING); //Set the response encoding
return thymeleafViewResolver;
}
//Define SpringTemplateEngine Bean
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.addDialect(new SampleDialect()); //Register your own Dialect
return templateEngine;
}
//Define TemplateResolver Bean
@Bean
public AbstractConfigurableTemplateResolver templateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix(VIEW_LOCATION); //Specifies the base directory where Thymeleaf templates are stored
templateResolver.setSuffix(".html"); //Set the Thymeleaf template extension
templateResolver.setTemplateMode(TemplateMode.HTML); //Set the template mode to interpret(The default value is HTML mode, but it is explicitly set)
templateResolver.setCharacterEncoding(CHARACTER_ENCODING); //Set the template file encoding
return templateResolver;
}
After the setting implementation is completed, you can operate it by creating a template file and transitioning it. The above settings are just samples, so I think you need to change them according to your environment.
When I actually used it, there were many points that I thought were easier to use than JSP. I found it attractive that it is highly extensible because you can easily add your own Dialect, and that it can be flexibly implemented by combining it with Standard Dialect. Personally, it was easier to extend than JSP's original tag.
Since Spring recommends Thymeleaf, there are likely to be many opportunities to come into contact with it in the future, so I would like to further increase my knowledge. (Preferably freemaker ...)
https://qiita.com/yoshikawaa/items/aba090f291f69185e6a5
https://macchinetta.github.io/server-guideline-thymeleaf/1.5.1.RELEASE/ja/ArchitectureInDetail/WebApplicationDetail/Thymeleaf.html#id21
Recommended Posts