Spring boot - cannot set default Locale - java

I am now developing Spring Boot application (only rest controllers). Each request to my server contains language tag. I would like to send response in specific language according to this tag. Controllers extract those tags from request and provide to service layer as a Locale instance. I have created properties file under src/main/resources, like this:
https://i.stack.imgur.com/fsXPG.jpg.
My problem is with default language. Regardless of provided Locale, messages returned from properties file are always from AppResources_pl.properties. I think that, problem is with default locale. For now i tryied two different ways and still don't know how to set default properties file to english.
First:
ResourceBundle myResources = ResourceBundle.getBundle("AppResources", currentLocale);
String message = myResources.getString("label.error");
Second:
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.forLanguageTag("en-US"));
return slr;
}
#Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("AppResources");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
and in service:
messageSource.getMessage("label.error", null, locale)
Both way returning message but always from AppResources_pl.properties. How can i set AppResources.properties as a default properties file when provided locale is not found under *.properties files?

I found that in MessageSourceAccessor default locale is null, so used system locale. This issue appeared in the last versions because about 6 months ago I used provided in original comment configuration with LocaleResolver and it's worked fine.
Solved issue in following line return new MessageSourceAccessor(messageSource, Locale.US); (directly passed Locale)
#Bean(name = "messageSource")
public ReloadableResourceBundleMessageSource getMessageSource() {
final ReloadableResourceBundleMessageSource res = new ReloadableResourceBundleMessageSource();
res.setDefaultEncoding("UTF-8");
res.setFallbackToSystemLocale(false); // will force to use specified locale even if locale for current env is different
res.addBasenames("classpath:messages/validation", "classpath:messages/messages", "classpath:messages/titles");
return res;
}
#Bean
public MessageSourceAccessor getMessageSourceAccessor(final MessageSource messageSource) {
return new MessageSourceAccessor(messageSource, Locale.US);
}

You can try below:
/*
* Create MessageSource bean
*/
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new
ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:AppResources");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
/*
* Create LocaleResolver Bean
*/
#Bean
public LocaleResolver localeResolver(){
CookieLocaleResolver resolver = new CookieLocaleResolver();
resolver.setDefaultLocale(new Locale("en")); // your default locale
return resolver;
}

Related

How to use TWO SpringResourceTemplateResolver Beans?

Since Thymeleaf 3, Thymeleaf prefers the use of SpringResourceTemplateResolver (https://www.thymeleaf.org/doc/articles/thymeleaf3migration.html). So I decided to go from ClassLoaderTemplateResolver to SpringResourceTemplateResolver:
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
registry.setOrder(1);
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(0);
resolver.setCheckExistence(true);
return resolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver2() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("/templates-2/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(1);
resolver.setCheckExistence(true);
return resolver;
}
}
Unfortunately, when implementig like this, I'll get an error:
Error resolving template [index], template might not exist or might not be accessible by any of the configured Template Resolvers.
To be honest, I've simple replaced ClassLoaderTemplateResolver with SpringResourceTemplateResolver in the hope, this will work. It doesn't. But searching for a working solution dealing with two template locations, all I find are outdated samples using ClassLoaderTemplateResolvers.
Trying to implement the code snippet provided by Thymeleaf as shown here https://www.thymeleaf.org/doc/articles/thymeleaf3migration.html won't work either when using two template directories, besides the fact, that this code itself uses the deprecated WebMvcConfigurerAdapter.
Is there any example how to configure a Spring Boot application using Thymeleaf having two or more template locations which isn't completely outdated?
So after a while and many many tryouts I've finally got the templates working. Since there isn't any decent answer to my question flying round the internet, I will post my solution for others:
#Configuration
public class ThymeleafConfig implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(#Autowired ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("classpath:/templates-1/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(1);
templateResolver.setCheckExistence(true); /* FYI: necessary to chain TemplateResolvers */
templateResolver.setCacheable(false); /* FYI: during development -> false, so that we can see changes we make */
return templateResolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver2() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("classpath:/templates-2/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(2);
templateResolver.setCheckExistence(true); /* FYI: necessary to chain TemplateResolvers */
templateResolver.setCacheable(false); /* FYI: during development -> false, so that we can see changes we make */
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
/* SpringTemplateEngine automatically applies SpringStandardDialect and
enables Spring's own MessageSource message resolution mechanisms. */
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(this.templateResolver());
templateEngine.addTemplateResolver(this.templateResolver2());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(this.templateEngine());
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setCache(false); /* FYI: during development -> false */
viewResolver.setOrder(1);
return viewResolver;
}
}
I hope this will help others to save time and nerves^^.
If you are using Spring Boot, you can add an extra resolver on top of the default one like this:
First, add this to application.properties:
# This ensures that the default HTML template resolver of Thymeleaf has priority over our custom SVG resolver
spring.thymeleaf.template-resolver-order=0
Then add the extra resolver in a #Configuration class:
#Configuration
public class MyApplicationConfiguration {
#Bean
public ITemplateResolver svgTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/svg/");
resolver.setSuffix(".svg");
resolver.setTemplateMode("XML");
return resolver;
}
}
There is no need to manually define SpringTemplateEngine and ViewResolver beans.
You can disable caching during development using spring.thymeleaf.cache=false.

Spring Boot / Docker: Thymeleaf template not found for html mail

I have a problem with finding a thymeleaf template on docker. I'm familiar with the leading slash problem in ordinary controllers. However I'd now like to use thymeleaf to render email bodies.
My code looks like this:
#Component
public class HtmlEmailDocumenter implements Documenter {
#Autowired
SpringTemplateEngine thymeleafTemplateEngine;
// more dependencies
#Override
public void accept(Documentable documentable){
Context thymeleafContext = new Context();
thymeleafContext.setVariable("doc", documentable);
String template = "mail/default";
String htmlBody = thymeleafTemplateEngine.process(template, thymeleafContext);
// send the email...
}
}
The template in question is under /src/main/resources/templates/mail/default.html. I have alternatively tried using "mail/default.html" in the source code. Doesn't work either in docker.
Any hints welcome.
I am doing something similar in non-Boot Spring application by defining the template engine template and resolver as follows:
#Bean
public ResourceBundleMessageSource emailMessageSource() {
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("templates/email/mailMessages");
return messageSource;
}
#Bean
public TemplateEngine emailTemplateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine;
}
private ITemplateResolver htmlTemplateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setOrder(Integer.valueOf(2));
templateResolver.setPrefix("/templates/email/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCacheable(false);
return templateResolver;
}
I then refer to an email message template using just the name of the template within the /templates/email directory without extension.

How to make a redirect including the name of the project in the url in Spring MVC?

I'm new to spring, but not in the world of frameworks. What I have noticed is that the addresses are handled with the name of the project, and then the specified routes.
What happens is that when I am trying to call a controller action from a view, I do the following:
<td class="cell1"><span style="color:#696969;font-family:Arial;font-size:15px;line-height:16px;">Eliminar</span></td>
Therefore, the controller is as follows:
#PostMapping("/{idUser}/delete")
public String deleteUser(#PathVariable (value = "idUser") Integer cedula, Model model){
Usuario usuario = this.usuarioService.find(cedula);
usuario.setEstaOculto(true);
this.usuarioService.update(usuario);
model.addAttribute("mensaje", "Usuario eliminado correctamente");
return "redirect:/user/";
}
Sure, and the following should happen:
http://localhost:8084/trabajaya/user/423423/delete
But the redirection is bad for me, since it "eats" the name "trabajaya", which is the name of the project, and leaves it as follows.
http://localhost:8084/user/423423/delete
Of course, the ideal is to name the gasdfvgsdfd subpath to the part of the html that requires it, but it is not ideal, since I am working on AWS and in this it changes the name of the project.
In case it is enecsario, I leave the configuration of the routes and the resources, although I don't think it helps a lot
#Configuration
#EnableWebMvc
//BUSQUEDA DE TODAS LAS CLASES Y PAQUETES DERIVADOS DE com.howtodoinjava.demo.spring
#ComponentScan(basePackages = {"edu.co.ucatolica.trabajaya"})
#EnableJpaRepositories
#Import(HibernateConfig.class)
public class WebMvcConfig implements WebMvcConfigurer {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
//AQUI BUSCA LAS VISTAS
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages");
return source;
}
#Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/");
}
}
How do I correct this?
Thank you.
I was really drowning in a glass of water, it is pure basic HTML, I have not used HTML for a while and I had forgotten how to use it.
Simply by adding the following:
<td class="cell1"><span style="color:#696969;font-family:Arial;font-size:15px;line-height:16px;">Eliminar</span></td>
OR:
<td class="cell1"><span style="color:#696969;font-family:Arial;font-size:15px;line-height:16px;">Eliminar</span></td>
It is already corrected and redirected to the corresponding route and the controller answers the call.
Now, if you want to redirect a link to another controller it is as follows:
<td class="cell1"><span style="color:#696969;font-family:Arial;font-size:15px;line-height:16px;">Modificar</span></td>
Thanks from #Istiaque Hossain for his answer

ResourceBundleMessageSource properties not working

So, I was using JDK 8 with Sprint Boot 2.0.3 before and now I moved to JDK 11 and Spring Boot 2.1.1. And I had the TemplateEngine Bean which processed the thymeleaf templates for the email and it was working fine with the below configuration of ReloadableResourceBundleMessageSource
ReloadableResourceBundleMessageSource messageSourceThymeleafConfiguration = new ReloadableResourceBundleMessageSource();
messageSourceThymeleafConfiguration.setBasename("classpath*:i18n/messages");
messageSourceThymeleafConfiguration.setDefaultEncoding("UTF-8");
And now that I have moved to JDK 11 and Spring Boot 2.1.1 it has stopped working all of a sudden and in the emails instead of the locale based translations from the properties file the property keys are being displayed. For example:
??email.greeting_en??
??email.text1_en??
I even tried to replace the ReloadableResourceBundleMessageSource bean with ResourceBundleMessageSource and try it and it still doesn't work. I tried to meddle with the base name string by using classpath:i18n/messages, i18n/messages still doesn't seem to work.
Any help would be highly appreciated.
Edit: This is how my entire Configuration related to this looks
#Configuration
public class MailServiceThymeleafConfiguration {
#Bean
public TemplateEngine templateEngineThymeleafConfiguration() {
SpringTemplateEngine templateEngineThymeleafConfiguration = new SpringTemplateEngine();
templateEngineThymeleafConfiguration.setTemplateResolver(emailTemplateResolver());
templateEngineThymeleafConfiguration.setMessageSource(messageSourceThymeleafConfiguration());
return templateEngineThymeleafConfiguration;
}
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("mails/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding("UTF-8");
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
#Bean
public MessageSource messageSourceThymeleafConfiguration() {
ReloadableResourceBundleMessageSource messageSourceThymeleafConfiguration = new ReloadableResourceBundleMessageSource();
messageSourceThymeleafConfiguration.setBasename("classpath*:i18n/messages");
messageSourceThymeleafConfiguration.setDefaultEncoding("UTF-8");
return messageSourceThymeleafConfiguration;
}
}

Spring Boot content-negotiation configuration

I have difficulties configuring content-negotiation with spring-boot.
I would like to keep most of the default spring-boot configuration.
I followed the following https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc/
not so recent tutorial. At the moment when I send a request for application/json or txt/html the view doesn't seem to get resolved, but when I turn on #EnableWebMvc it does seem to get resolved.
Below is my current configuration.
#Configuration // according to the spring-boot docs this should be enough with spring-boot
//#EnableWebMvc If I enable this content-negotiation seems to work without any configuration, but I loose the default spring-boot configuration
public class MvcConfiguration implements WebMvcConfigurer {
#Bean(name = "jsonViewResolver")
public ViewResolver getJsonViewResolver() {
return new JsonViewResolver();
}
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// Simple strategy: only path extension is taken into account
configurer.favorPathExtension(true)
.defaultContentType(MediaType.TEXT_HTML)
.mediaType("html", MediaType.TEXT_HTML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
#Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = newContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
return resolver;
}
}
You are not registering your resolvers in your content negotiation manager.
please try with the following modification:
#Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager){
ContentNegotiatingViewResolver resolver = newContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
List<ViewResolver> resolvers = new ArrayList<>();
ViewResolver aViewResolver = getJsonViewResolver();
resolvers.add(aViewResolver);
resolver.setViewResolvers(resolvers);
return resolver;
}

Categories

Resources