Spring and character encoding in properties files - spring

I know, that there were many questions about the encoding in properties files, but I couldn't find answer which would help me, so I'm asking one more time.
So I have a Spring 4 based project with Java Config and with Thymeleaf as the templating engine.
I want to specify some labels in properties file, and read values of properties in the .html files using Thymeleaf's directive #{property.name}.
I already set up enconding in Character encoding Filter, I also set up encoding in messageSource (I'm using ReloadableResourceBundleMessageSource). I also added property to pom.xml:
UTF-8
And honestly, I'm out of ideas what I could do wrong.
What I didn't do from things which I have found in stackoverflow answers:
I didn't configured ant/maven native2ascii plugin, as I tried to change my characters (like ó or ł) to ascii counterparts, and almost all characters was still replaced by '??' signs.
I have also didn't configured maven-resource-plugin as I'm not sure why should I use it if all .properties files are available ?
EDIT
MessageSource definition:
#Bean(name = "messageSource")
public ReloadableResourceBundleMessageSource getMessageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasenames("/i18n/messages");
resource.setDefaultEncoding("UTF-8");
return resource;
}
WebApp initialization:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
FilterRegistration.Dynamic fr = servletContext.addFilter("encodingFilter",
new CharacterEncodingFilter());
fr.setInitParameter("encoding", "UTF-8");
fr.setInitParameter("forceEncoding", "true");
fr.addMappingForUrlPatterns(null, true, "/*");
}
Maven properties definition
UTF-8
(other properties)
Reference in HTML file (in anchor tag):
th:href="#{about.html}" th:text="#{navigation.about}"
Properties files are: webapp/i18n/message_en_EN.properties, webapp/i18n/message_pl_PL.properties (both are saved in UTF-8 encoding by Intellij)

Ok so the problem was lying in Thymeleaf.
I was using ServletContextTemplateResolver and ThymeleafViewResolvere, and I had to set encoding in those two objects:
#Bean(name="templateResolver")
public ServletContextTemplateResolver getServletContextTemplateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/somepath/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCacheable(false);
return templateResolver;
}
#Bean(name="viewResolver")
public ThymeleafViewResolver getThymeleafViewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(getTemplateEngine());
viewResolver.setOrder(1);
viewResolver.setCharacterEncoding("UTF-8");
return viewResolver;
}

Related

Thymeleaf - return rendered template to String

I was using this solution as an example:
Can I render Thymeleaf templates manually from a String?
but after processing template I am getting not rendered template:
my template (plans/test.html):
<!doctype html>
<html lang="pl">
<div th:text="${loki}"></div>
</html>
Java code that should renderd the template:
#RestController
public class PlansPageRestController {
#Autowired
TemplateEngine myTemplateEngine;
#RequestMapping(value = {"/public/plans"}, method = RequestMethod.POST, produces = "application/json")
public Map<String,String> getPlans(#RequestParam Map<String, String> requestParams) {
Context ctx = new Context();
ctx.setVariable("loki", "Some test value");
String htmlTemplate = myTemplateEngine.process("plans/test.html", ctx);
Map<String,String> result = new HashMap<>();
result.put("html", htmlTemplate );
result.put("result", "success" );
return result;
}
}
but as a result I am getting content of plans/test.html so:
<!doctype html>
<html lang="pl">
<div th:text="${loki}"></div>
</html>
I am working with spring boot 3.0.0 and regarding to pom I am using thymeleaf:
<artifactId>thymeleaf-spring6</artifactId>
<version>3.1.0.RELEASE</version>
Can anyone help me in finding what I am doing wrong?
my thymeleaf configuration:
#Configuration
public class ThymeleafConfiguration implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#Bean
public TemplateEngine myTemplateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.setTemplateResolver(templateResolver());
engine.setDialect(new LayoutDialect());
return engine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/templates/");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
resolver.setCacheTTLMs(0L);
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
The reason your standard Thymeleaf expression is not being evaluated is because you have replaced the Thymeleaf "standard" dialect with the layout dialect:
engine.setDialect(new LayoutDialect());
(I should say "the Spring dialect", given you are using Spring-Thymeleaf.)
If you need to use the layout dialect, then you can add it to the engine - and still keep the standard dialect as well:
engine.addDialect(new LayoutDialect());
Or, you may not need the layout dialect at all (you do not use it in the sample HTML file in the question, but maybe you use it elsewhere). If that is the case, you can remove this line of code.
Just to add: The default Spring Boot settings should work without you needing to define any ThymeleafConfiguration class. But, again, there may be other places where you need to use a custom configuration (e.g. the UTF-8 encoding).

How to switch between externalized messages in Spring with thymeleaf?

Spring + thymeleaf
I want to display the message from Messages_pl.properties or Messages_en.properties depending on the need. And here's my problem as I don't know what to do when I want to view a message from the second file ( Messages_pl.properties is taken into account by default).
To access resource bundles by using specified basename I added the bean below to my #Configuration class:
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("Messages");
return messageSource;
}
Messages_pl.properties:
welcome.message=siemanko
Messages_en.properties:
welcome.message=hello
The fragment of my html file where I use this property:
<h1 th:text="#{message.welcome}"></h1>
Result: siemanko
what should I do to get the result as hello?
You can define on the same file Messages.properties the following :
welcome.message.pl=siemanko
welcome.message.en=hello
Then you can can a local resolver to make your project capable of determining the locale which is currently being used :
#Bean
public LocaleResolver localeResolver() {
return new CookieLocaleResolver();
}
Then add an interceptor of your language :
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
After that its simple to switch between languages , you just have to change the value of parameter lang on your link :
localhost:8080/your_page?lang=pl // will show siemanko on your page
localhost:8080/your_page?lang=en // will show hello on your page

Display messages with thymeleaf in Spring Boot

I'm tryting to add externalized messages from a properties file in a thymeleaf html template. I have a file messages_es.properties located in i18n/messages with this inside:
estimado=Estimado:
In my html template i have the following
<div th:text="#{estimado}">Estimado placeholder</div>
but then, the html I get is the following:
<div>??estimado_es??</div>
Is anyone able to help me?
This is the configuration i have added in order to make this work:
#Bean
#Qualifier("custom")
public ITemplateResolver thymeleafTemplateResolver(){
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Bean
public SpringTemplateEngine thymeleafTemplateEngine(#Qualifier("custom") ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.setTemplateEngineMessageSource(messageSource());
return templateEngine;
}
#Bean
#Description("Spring Message Resolver")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
return messageSource;
}
In my application.yml file:
spring.messages.basename: i18n/messages
first of all you should add classpath: as prefix to your base name.
secondly if you have baseName set toi18n/messages app will look for i18n/messages_es.properties
if i understand correctly your file path is i18n/messages/messages_es.properties
so you need to set baseName to: classpath:i18n/messages/messages

What is the difference between SpringResourceTemplateResolver and ClassLoaderTemplateResolver?

I'm trying to cofigure my project. I have two variants of tempalteResolver.
if i use this one:
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
return templateResolver;
}
i get an error that my template can't resolve the thymeleaf syntax th even when i add xmlns:th="http://www.thymeleaf.org"
and when i use the following code:
#Bean
public ClassLoaderTemplateResolver templateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(false);
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
i get an error that there is no templates under this path (/WEB-INF/templates).
Full path to my templates is src\main\webapp\WEB-INF\templates\
What is the best template resolver to be used and why?
Thanks!
You should be using SpringResourceTemplateResolver for web projects (using SpringMvc controllers), and ClassLoaderTemplateResolver for command line projects, or when you need to generate html for non-web applications (such as sending html email or something like that).
First error occured becouse spring security somehow didn't connect to a project and my
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
modelAndView.addObject("auth", auth);
Send nulls.
And second error i dunno why occured.

Several template locations for Thymeleaf in Spring Boot

Currently Spring Boot allow one value for the Thymeleaf templates location with the spring.thymeleaf.prefix property.
The default value is classpath:/templates/.
I want to have another location for the thymeleaf templates (but keep the default one), outside the jar, for example:
spring.thymeleaf.prefix = classpath:/templates/, file:/resources/templates
Do i have to define another template resolver for the new location i want ?
Define the setting in the application.properties file
spring.thymeleaf.templateResolverOrder=1
Now in your custom Bean which creates ITemplateResolver set order to 0 along with prefix and suffix. This way spring boot will listen to both places
Setting order to 0 is important
An example of bean creation can be
#Bean
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("mails/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(TemplateMode.HTML);
emailTemplateResolver.setCharacterEncoding("UTF-8");
emailTemplateResolver.setOrder(0);
emailTemplateResolver.setCheckExistence(true);
return emailTemplateResolver;
}
MyExample
In order to define multiple template locations, you must define Spring beans implementing ITemplateResolver.
#Bean
public SpringResourceTemplateResolver firstTemplateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/templatelocation/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(0);
templateResolver.setCheckExistence(true);
return templateResolver;
}
#Bean
public ClassLoaderTemplateResolver secondTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/templatelocation/other/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(1);
templateResolver.setCheckExistence(true);
return templateResolver;
}
You can also check out the blog post detailing the usage.

Resources