Add the language in the url / fr /, / en /, etc internationalization spring boot mvc - spring-boot

I followed this tutorial
https://www.baeldung.com/spring-boot-internationalization
I managed to get it to work: when I put the following url www.example.com/?lang=en I have the English version that is displayed.
However, I want to "convert" it so that the lang is directly in the example url www.example.com/en/ or www.example.com/fr/.
So i have this
#Configuration
public class Locale implements WebMvcConfigurer {
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
return slr;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
localeInterceptor.setParamName("lang");
return localeInterceptor;
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
I was thinking of using a filter, which will redirect to www.example.com/en/ or / fr / and if it can't find the language, configure the controller that if / {language} is null then it ignores it.
However, I do not know if my approach is good and especially I do not know how to retrieve the information of the language in the filter.
Could you help me ?
thank you

Related

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

Camel REST and Spring Security Java Configuration

I'm trying to set up Camel REST to use basic auth with a simple username/password from my application.properties and can't for the life of me seem to configure Camel Spring Security to do that. I'm trying to follow the Spring Security component documentation which seems to be missing the example of configuring the required beans. I found the missing example here under 'Controlling access to Camel routes' but this only shows the xml configuration.
How do I set up the required SpringSecurityAuthorizationPolicy bean? It needs an AuthenticationManager and an AccessDecisionManager and it also seems to require that I set its SpringSecurityAccessPolicy which I have no idea how to do.
I haven't gotten to test these yet, because I can't get my beans set up, but my rest route looks like:
rest("/ingest")
.post("/json").consumes("application/json")
.route()
.process(authProcessor)
.policy(authPolicy) // this is the bean I don't know how to configure
.to("direct:ingest")
.endRest();
and my AuthProcessor (taken from the camel component doc) looks like:
#Component
public class AuthProcessor implements Processor {
public void process(Exchange exchange) {
String userpass = new String(Base64.decodeBase64(exchange.getIn().getHeader("Authorization", String.class)));
String[] tokens = userpass.split(":");
// create an Authentication object
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(tokens[0], tokens[1]);
// wrap it in a Subject
Subject subject = new Subject();
subject.getPrincipals().add(authToken);
// place the Subject in the In message
exchange.getIn().setHeader(Exchange.AUTHENTICATION, subject);
}
}
and here's my broken bean configuration for what it's worth:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public SpringSecurityAuthorizationPolicy springSecurityAuthorizationPolicy(
AuthenticationManager authenticationManager, AccessDecisionManager accessDecisionManager) {
SpringSecurityAuthorizationPolicy policy = new SpringSecurityAuthorizationPolicy();
SpringSecurityAccessPolicy springSecurityAccessPolicy = new SpringSecurityAccessPolicy();
policy.setAuthenticationManager(authenticationManager);
policy.setAccessDecisionManager(accessDecisionManager);
policy.setSpringSecurityAccessPolicy(????);
return policy;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("pass").roles("USER");
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AccessDecisionManager accessDecisionManager() {
AffirmativeBased affirmativeBased = new AffirmativeBased(ImmutableList.of(
new RoleVoter()
));
affirmativeBased.setAllowIfAllAbstainDecisions(true);
return affirmativeBased;
}
}
I've been banging my head against the wall trying to understand this so an example of how to do this would be amazing. It looks like the xml configuration for what I want to do (in the second link) is simple enough but I can't seem to replicate it in Java configuration.
I know it's an old topic, but I ran into similar questions. I managed to get it working. Not by overriding the accessDecisionManager() method within the WebSecurityConfigurerAdapter class, but by constructing a new instance while building my SpringSecurityAuthorizationPolicy:
#Bean
public Policy adminPolicy(AuthenticationManager authenticationManager) {
RoleVoter roleVoter = new RoleVoter();
SpringSecurityAuthorizationPolicy policy = new SpringSecurityAuthorizationPolicy();
policy.setAuthenticationManager(authenticationManager);
policy.setAccessDecisionManager(new UnanimousBased(List.of(roleVoter)));
policy.setSpringSecurityAccessPolicy(new SpringSecurityAccessPolicy(roleVoter.getRolePrefix() + "<ROLE_NAME>");
return policy;
}

Spring Boot Controller Locale Not Changing with Parameter

I'm having some trouble with using Spring Boot with Kotlin to handle locale. I created these settings in my application.properties file:
spring.messages.basename=messages/messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8
Then created an autowired instance of MessageSource in my controller:
#Autowired
lateinit var messageSource: MessageSource
When put a locale in the url as a parameter, the parameter doesn't seem to get picked up when I call LocaleContextHolder.getLocale(), so it is always en_US. Though, I can manually pick it up using #RequestParam(value="locale") locale: Locale as a parameter to my controller function and use it from there in the controller function, but not in other functions. I thought that spring boot LocaleContextHolder was supposed to hold the current locale based on the request URL automatically for the whole session.
I read an older article that mentioned using a LocaleChangeInterceptor bean as well as beans for MessageSource and LocaleResolver in your main class, but another article said Spring Boot doesn't require that. I tried it anyway with no difference. These are the functions I used:
#Bean
open fun localeResolver(): LocaleResolver {
val slr = SessionLocaleResolver()
slr.setDefaultLocale(Locale.US)
return slr
}
#Bean
open fun localeChangeInterceptor(): LocaleChangeInterceptor {
val localeChangeInterceptor = LocaleChangeInterceptor()
localeChangeInterceptor.paramName = "locale"
return localeChangeInterceptor
}
#Bean
open fun messageSource(): ResourceBundleMessageSource {
val source = ResourceBundleMessageSource()
source.setBasenames("messages/messages")
source.setDefaultEncoding("UTF-8")
return source
}
Any suggestions on what to try next other than capturing the locale manually and making it a parameter in every function that gets called by the controller? Thanks!
OK, looks like the missing piece was implementing a WebMvcConfigurerAdapter, setting up a SessionLocaleResolver bean, and overriding the addInterceptors function to manually add my LocaleChangeInterceptor. I used a separate Configuration class to do this.
#Configuration
open class CustomWebMvcConfigurerAdapter : WebMvcConfigurerAdapter() {
//internationalization beans
#Bean
open fun localeResolver(): LocaleResolver {
val slr = SessionLocaleResolver()
slr.setDefaultLocale(Locale.US)
return slr
}
#Bean
open fun localeChangeInterceptor(): LocaleChangeInterceptor {
val localeChangeInterceptor = LocaleChangeInterceptor()
localeChangeInterceptor.paramName = "locale"
return localeChangeInterceptor
}
override fun addInterceptors(registry: InterceptorRegistry?) {
registry?.addInterceptor(localeChangeInterceptor())
super.addInterceptors(registry)
}
}
I guess I misunderstood, thinking that Spring Boot handled the LocaleChangeInterceptor on it's own if you created the proper bean, but I guess you have to still override a WebMvcConfigurerAdapter and force the interceptor in there. If I've missed something and someone has a cleaner solution, I'd be happy to give you the accepted answer since what I'm doing here just feels like a messy workaround.

Spring MVC VersionResourceResolver / ContentVersionStrategy not working correctly in JSP

I have a Spring MVC (4.3.0) application and have registered a VersionResourceResolver with added ContentVersionStrategy with the ResourceHandlerRegistry. I have the ResourceUrlEncodingFilter enabled.
#Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
boolean devMode = this.env.acceptsProfiles("local");
//boolean useResourceCache = !devMode;
Integer cachePeriod = devMode ? 0 : (60 * 60 * 24 * 365); //If dev clear cache else 1 year
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/")
.setCachePeriod(cachePeriod)
.resourceChain(false)
.addResolver(new VersionResourceResolver()
.addContentVersionStrategy("/**"))
.addTransformer(new AppCacheManifestTransformer());
}
When I access anything in /resources (JS, Images, CSS, etc) on a JSP page using the c:url or spring:url tags, the "versioned" URL does not show up (meaning: no hash code in the URL). Example:
<link href="<c:url value="/resources/css/views/login.css" />" rel="stylesheet">
Produces: /myapp/resources/css/views/login.css as the URL string when inspecting the page.
But, if I use a ResourceURLProvider in my Controller, I do see the hash code in the URL:
#Autowired
private ResourceUrlProvider mvcResourceUrlProvider;
#RequestMapping(value = { "/" }, method = RequestMethod.GET)
public String projectBaseRedirect() {
logger.debug("js = '" + this.mvcResourceUrlProvider.getForLookupPath("/resources/js/views/overview.js") + "'");
logger.debug("css = '" + this.mvcResourceUrlProvider.getForLookupPath("/resources/css/views/overview-page.css") + "'");
return "redirect:/admin/overview";
}
The log messages produce this:
2016-07-09 11:47:19 DEBUG AdminLoginController:35 - js = '/resources/js/views/overview-36d1ff98d627d92a72d579eca49dbd8a.js'
2016-07-09 11:47:19 DEBUG AdminLoginController:36 - css = '/resources/css/views/overview-page-d47f10e5bcf0fdd67bd8057479b523f0.css'
Why is this working in the controller but not on my JSP pages?
I am also using Spring Security (4.1.0)...
As it is missing in your example it is maybe missing in your project as well. You need a resource provider for the template engine you're using. In case of JSP, register a filter:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
return new ResourceUrlEncodingFilter();
}
}
Or use a filter registration bean with that filter:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public FilterRegistrationBean filterRegistrationBean() {
final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new ResourceUrlEncodingFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
Rossen's comment on Michael's answer was exactly the missing glue I needed. After I put this code in the class that extends AbstractAnnotationConfigDispatcherServletInitializer, it worked perfectly with the other code from my original post!
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
FilterRegistration.Dynamic fr = servletContext.addFilter("resourceUrlEncodingFilter",
new ResourceUrlEncodingFilter());
fr.setInitParameter("encoding", "UTF-8");
fr.setInitParameter("forceEncoding", "true");
fr.addMappingForUrlPatterns(null, true, "/*");
}

LocalContextHandler usage

I am very new to LocalContexHandler. I have read about it. From what I understood it is used to retrieve locale information in a java application.
I am passing the locale from the url as follows:
url?lang = fr
When I am trying to retrieve the locale in java application as follows:
Locale locale = LocaleContextHolder.getLocale();
It is giving null value. Can someone help me understand it's usage or is there any other alternative for the same?
If you want to pass locale in URL you must register LocaleChangeInterceptor interceptor and create LocaleResolver bean. For example SessionLocaleResolver stores chosen locale in session. Then LocaleContextHolder#getLocale will return not-null value. Take a look in Spring documentation to section Using locales. Below you can see basic Java configuration for you example.
If you want just use LocaleContextHolder you have to call LocaleContextHolder#setLocale from your code before calling LocaleContextHolder#getLocale. It's just simple holder class that stores LocaleContext in ThreadLocal variable.
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// Rest of Web MVC configuration omitted
#Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(localeChangeInterceptor());
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale("fr");
return sessionLocaleResolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
}

Resources