Spring REST API and i18n - java

In my REST API I want to allow the user to set the locale using a lang parameter, i.e.
http://somehost/resource?param1=value1&lang=fr
If the lang parameter is not present in the URL then the Accept-Language header should be used and set as the Locale.
I'm using Spring's i18n features in my REST API. I have looked through the documentation and configured the necessary beans. If I send a request with the Accept-Language header it seems to work OK, when I call LocaleContextHolder.getLocale() it returns the locale I set in my header.
If I use the lang URL parameter it does not work.
How can I configure Spring to use the locale parameter too?
<bean id="localeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
<property name="interceptors">
<list>
<ref bean="localeInterceptor" />
</list>
</property>
</bean>
<bean id="sessionLocaleResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
<bean id="messages" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages</value>
</list>
</property>
</bean>

I have two suggestions to try out. First, are you certain that the LocaleChangeInterceptor is getting invoked? Most of the configurations I've seen have an id of handlerMapping for the HandlerMapping. The other suggestion is concerning another id, namely sessionLocaleResolver, I think it should be localeResolver. I'm not sure if Spring relies on those id values or the class types by default for wiring all of this together, but it is worth a shot.

Related

How to convert an xml config bean to java annotation bean ( spring boot )

I am new to java AOP. I am supposed to convert the following xml config to java annotation config in my spring boot application. May I know how exactly to convert this xml config to java annotation config:
I think none of the examples that I saw in stackoverflow match the pattern I am trying to convert.
<bean id="xyzRestTemplate"
class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="xyzClientHttpRequestFactory" />
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbDataMarshaller" />
<property name="unmarshaller" ref="jaxbDataMarshaller" />
</bean>
</list>
</property>
<property name="interceptors">
<list>
<bean class="com.example.XYZHeaderRequestInterceptor" />
</list>
</property>
</bean>
<bean id="jaxbDataMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPaths">
<list>
<value>com.a.b.c.d.v2</value>
</list>
</property> </bean>
When people talk about converting from XML they don't mean necessarily doing the same thing exactly. What makes Spring Boot attractive isn't just that a configuration is a java class.
You should convert this to use RestTemplate https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-resttemplate.html
Then you just build the RestTemplate using the builder to have the JaxB marshaller and the interceptor you want.
Rest Template - XML Indentation
A nice testcase that passes with XML and passes with #Configuration classes will prove you got it right.

Allow semicolon only for some specific url in Spring Security 5 i.e. StrictHttpFirewall?

We are using primefaces media component and it generates the url as /javax.faces.resource/dynamiccontent.properties;/ .pdf which contains semicolon(;).
Due to that, we are getting exception i.e. The request was rejected because the URL contained a potentially malicious String.
In Spring Security 5 update by default StrictHttpFirewall is enabled.
We can specify to allow semicolon by using setAllowSemicolon(true) in StrictHttpFirewall.
But this will be applicable for all URL.
Is there any way through which we can configure to allow semicolon only for specific URL?
As the answer above indicated I also added the following XML definition for a custom firewall that allows semi-colons.
<bean id="myHttpFirewall" class="org.springframework.security.web.firewall.StrictHttpFirewall">
<property name="allowSemicolon" value="true"/>
</bean>
<security:http-firewall ref="myHttpFirewall"/>
However byt itself this had no affect. To use that firewall in my application I had to add it to my FilterChainProxy as follows:
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<constructor-arg>
<list>
<security:filter-chain pattern="/**" filters="...."/>
</list>
</constructor-arg>
<property name="firewall" ref="myHttpFirewall"/>
</bean>
If you use xml configuration, Declare your bean:
<bean id="customStrictHttpFirewall"
class="org.springframework.security.web.firewall.StrictHttpFirewall">
<property name="allowSemicolon" value="true"/>
</bean>
then in security.xml ref:
<http-firewall ref="customStrictHttpFirewall"/>
if you use annotations, You can search for answers, like this!

Configuring locale switching with Spring MVC

First of all I have to say, that I am an absolute beginner in developing Spring Application. What I try to do is to switch the locale from 'en' to 'de'. For this I found the configuration below witch I put in my mvc-dispatcher-servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="Messages" />
</bean>
<!-- Localization Start -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language" />
</bean>
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
<property name="interceptors">
<list>
<ref bean="localeChangeInterceptor" />
</list>
</property>
</bean>
After that I expect that I can change the locale by adding '?language=de' behind a existing URL. So the request 'http://localhost:8080/?language=de' should switch the locale. This didn’t work. The website is shown in the defined default language
My property files are located in /src/main/resources. The names are “Messages_en.propperties” and “Messages_de.propperties”. If I switch the default language to “de”, the correct language file is loaded and the website is shown in german.
Has someone an idea what’s wrong in my configuration?
I believe you have to register the LocaleChangeInterceptor with an interceptor in Spring
<!-- Declare the Interceptor -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="locale" />
</mvc:interceptors>
The LocaleChangeInterceptor is configured to look for the parameter name 'locale' to indicate a change of the user's locale, and is registered as an interceptor using the Spring MVC Namespace. For example, adding 'locale=es' to a URL would change the locale to Spanish.

How to obtain the current language in a controller?

Here is my locale configuration
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
When I try to call locale in a controller using
#RequestMapping(value = "customers/customer-{idCustomer:[0-9]+}/detail", method = RequestMethod.GET)
public ModelAndView detail(Map<String, Object> map, #PathVariable Integer idCustomer, Locale locale) {
logger.info(locale.toString());
logger.info(request.getLocale().toString());
...
}
It returns different values. But when I switch a language on a site using GET param in URL ?lang=en, it change nothing in mentioned controller's calls. i18n works fine, it loads a labels from correct file. But I want to obtain changed language in my controllers. I want to obtain choosed language independently on opened page (with/without request param lang in URL).
You can use LocaleContextHolder class that Spring provides for this purpose. From documentation:
Used as a central holder for the current Locale in Spring, wherever
necessary: for example, in MessageSourceAccessor. DispatcherServlet
automatically exposes its current Locale here. Other applications can
expose theirs too, to make classes like MessageSourceAccessor
automatically use that Locale.
Then in your controller just call:
LocaleContextHolder.getLocale();
to retrieve the locale using Spring.
LocaleContextHolder.getLocale() javadoc.

how to set header no cache in spring mvc 3 by annotation

how to set header no cache in spring mvc 3 by annotation? not is
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
There is no such option. You can use an interceptor:
<mvc:annotation-driven/>
<mvc:interceptors>
<bean id="webContentInterceptor"
class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="0"/>
<property name="useExpiresHeader" value="true"/>
<property name="useCacheControlHeader" value="true"/>
<property name="useCacheControlNoStore" value="true"/>
</bean>
</mvc:interceptors>
(taken from here)
On one hand it is logical not to have such annotation. Annotations on spring-mvc methods are primarily to let the container decide which method to invoke (limiting it by a request header, request url, or method). Controlling the response does not fall into this category.
On the other hand - yes, it will be handy to have these, because when controllers are unit-tested it is not relevant to test http header stuff (or is it?). And there are #ResponseBody and #ResponseStatus, which do specify some response properties.
To override the settings for certain controller mappings use the cacheMappings properties object on the WebContentInterceptor
<bean id="webContentInterceptor"
class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="2100" />
<property name="useExpiresHeader" value="true" />
<property name="useCacheControlHeader" value="true" />
<property name="useCacheControlNoStore" value="true" />
<property name="cacheMappings">
<props>
<prop key="/myUncachedController">0</prop>
</props>
</property>
I know this is old but this might be helpful to some.
If you wanted to add a lot more logic to when you cache and when you don't you can also write a custom interceptor.
For example if you wanted to disable caching in the response only when the browser is IE or only from specific urls you can do that as well by extending the HandlerInterceptor interface.
By doing that you can have a lot of control over exactly what happens. It's not as easy as just setting the header for everything at once or just typing in the changes to the response in each controller but it is also not that hard and is a better long term solution in my opinion. It is also a good thing to know how to do in spring generally.
This is a pretty good tutorial for it:
http://www.mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example/

Categories