Win a copy of Fixing your Scrum this week in the Agile forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Rob Spoor
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Tim Holloway
  • Piet Souris
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Frits Walraven
  • Himai Minh

URL containing Locale with Spring MVC

 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi everyone!

I'm new to the forum, and I'd be pleased If anyoune could help me with an issue I'm having since I moved my application from Struts to SpringMVC.

I have a Home controller with two methods, one handles the requests for

www.myapp/
www.myapp/home/

and the other one handles requests for:

www.myapp/{locale}/
www.myapp/{locale}/home/

As I want to use one only method for both requests, I'm using an interceptor in order to add the "/en/" to the request in case there is no locale on it (example www.myapp/ --> www.myapp/en/"), but does not seem to work.

Is there a better solution for doing this?? How can I modify the request to use just one "@RequestMapping" method?

Thank you very much.

Mike Zuir

Controller:

Interceptor:
 
Bartender
Posts: 1682
7
Android Mac OS X IntelliJ IDE Spring Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi and welcome to the ranch. The reason you are struggling with this is the locale does not belong in the URL like you have it

Typically locale specific language is put in properties files following a naming convention eg appProperties_en.properties or appProperties_de.properties. You use a Spring MessageSource which will load the correct one and resolve the correct message based on the users locale. The locale is negotiated in a number of different ways:

1) Accept Header - perhaps the easiest let the browser tell you
2) Cookie
3) Session - makes sense if this is something stored in a user preferences for example
4)LocaleChangeInterceptor - looks for a parameter on the request e.g. http://www.sf.net/home.view?siteLanguage=nl

See this link for more info
http://docs.spring.io/spring/docs/4.0.0.RELEASE/spring-framework-reference/htmlsingle/#mvc-localeresolver
 
Mike Zuir Auza
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Bill.

First of all, thank you for the reply, I really appreciate any help with this problem I'm having. However, this is not the answer I was looking for, as it is not a locale problem, so let's just talk about URLs.

My application handles three URLs, which go to the same controller:

www.myapplication.com/home --> For english users
www.myapplication.com/es/home --> For spanish users
www.myapplication.com/fr/home --> For french users

The thing is, that I need two different methods with different request mappings at the controller class, to deal with the "/home" and "/es/home", and that is what I'm trying to avoid.

I thought that changing the request path on an interceptor I could transform :

"www.myapplication.com/home"
on
"www.myapplication.com/en/home"

And once it's been processed by the Controller, restore to it's initial state.

Do you know if it's possible to do it?? Or is any other way for doing it since PathVariable can not be optional?

Thank you very much
 
Bill Gorder
Bartender
Posts: 1682
7
Android Mac OS X IntelliJ IDE Spring Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yup you can not have optional path parameters. If you do it the way you are trying to you will have to have two separate handler methods like you do now that call the same service, one would pass in the locale. What I was trying to tell you is you are going against the standard. How many sites have you visited that have locales as part of the URL path? Rather than going against the grain pick one of the accepted approaches for doing this sort of thing like what was specified in the link I gave. If you are set on URL based Locale negotiation than use option 4 and set it as a request parameter instead.


Your XML would look something like this (assuming you are using a recent version of Spring)



Now you would have a WEB-INF/messages.properties with fall back properties in case locale is not specified. You would also have one for each language you want to support

/WEB-INF/message.properties
/WEB-INF/message_en.properties
/WEB-INF/message_de.properties
etc etc.

Now if I get a request for http://my-app/home it will resolve it from message.properties
if I get a request from http://my-app/home?lang=en
it will resolve from message_en.properties

You do not need to do anything special Spring takes care of it.

If you want to get the locale you can get it from the localContextHolder


or alternatively grab it off the request in your controller

 
Bill Gorder
Bartender
Posts: 1682
7
Android Mac OS X IntelliJ IDE Spring Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The part I did not mention is now you only maintain one home page not 3 and everything locale specific is reference through properties. Spring will put the right words in the right places depending on the users locale.
 
Mike Zuir Auza
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bill Gorder wrote:Yup you can not have optional path parameters. If you do it the way you are trying to you will have to have two separate handler methods like you do now that call the same service, one would pass in the locale. What I was trying to tell you is you are going against the standard. How many sites have you visited that have locales as part of the URL path? Rather than going against the grain pick one of the accepted approaches for doing this sort of thing like what was specified in the link I gave. If you are set on URL based Locale negotiation than use option 4 and set it as a request parameter instead.



If you take a look at the Apple.com website, you will see that depending on the language you select, you are redirected to the url containing that language identifier:

when you accede the main site, you go to:
http://www.apple.com/ <-- United states
http://www.apple.com/ne/ <-- Niger
http://www.apple.com/de/ <-- Germany

When you select an option from the menu, the url mantains the same structure:

http://www.apple.com/ipod/ <-- United states
http://www.apple.com/ne/ipod/ <-- Niger
http://www.apple.com/de/ipod/ <-- Germany

And so on...

I don't actually use the URL to deal with locales, I have a session parameter for that, and I already have my .properties files for each language.

Thank you anyways, Bill.

Mikel González.

 
Bill Gorder
Bartender
Posts: 1682
7
Android Mac OS X IntelliJ IDE Spring Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well how about that, I stand corrected

Ok I still think it is not the norm. But you have a few options with your current approach, since path params cannot have optional parameters

1) have the 2 controller methods for every one like you do now
2) Create a custom MethodArgumentResolver that works the same way as @PathVariable but accepts optional parameters, and defaults to en when not present. You could model this after theirs and register it in your configuration. You would create a new annotation like @OptionalPathParameter and use it instead of @PathVariable.
3)Since you have a session param for your locale you maybe don't care what the path param is so maybe something like this would work



It will match either in that case, you don't have easy access to the path parameter(you could pass in an HttpServletRequest and parse it out of the requestUri) but from the sounds of it you have that worked out elsewhere.

 
Mike Zuir Auza
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for answering again, Bill. About your answers, I must say that

Bill Gorder wrote:
1) have the 2 controller methods for every one like you do now
2) Create a custom MethodArgumentResolver that works the same way as @PathVariable but accepts optional parameters, and defaults to en when not present. You could model this after theirs and register it in your configuration. You would create a new annotation like @OptionalPathParameter and use it instead of @PathVariable.
3)Since you have a session param for your locale you maybe don't care what the path param is so maybe something like this would work




1.- Is not valid as I'ts what I'm trying to avoid
3.- Is not valid either, as I don't want anyone acceding the application typing myapp/"whatever"/home, I need to validate that the url only contains the language identifiers I will deal with.
2.- Looks great, but I've found an easier solution, implementing a filter:

xeb.xml

UrlFilter.java

This way I only need to implement a @RequestMapping method at the controller:

WelcomeController.java

Thank you very much for your help.

Mike.
 
Bill Gorder
Bartender
Posts: 1682
7
Android Mac OS X IntelliJ IDE Spring Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I thought about adding the filter option, but I was trying to stay in the Spring world. Your solution looks good to me. Glad you got it resolved, and thanks for posting back with what worked for you!
 
Bill Gorder
Bartender
Posts: 1682
7
Android Mac OS X IntelliJ IDE Spring Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

3.- Is not valid either, as I don't want anyone acceding the application typing myapp/"whatever"/home, I need to validate that the url only contains the language identifiers I will deal with.



Just for the sake of completeness since this thread documents so many approaches, you can also use regex which I did not mention earlier



With this code you would get a 404 if you did not do /ipod/ES/home, /ipod/UK/home, /ipod/PT/home, or ipod/home

If you wanted the lang you could do this:

 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic