View Full Version : How to avoid hard coding URL's in JSP pages
thuss
Jul 26th, 2005, 05:10 PM
I noticed that in Spring MVC I end up doing a lot of hard-coding of URL's in my JSP pages. So if in my servlet.xml I have a Spring bean named "/search.html" I then might have many different places in my JSP pages where I link to "/search.html".
This is not very elegant in that if I want to refactor and change the URL of the page to be /search/byname.html then I have to do a big search and replace and prey I got them all.
Is there a way instead to give a symbolic name to a Spring MVC bean that I can refer to in the JSP page and have Spring resolve the actual URL? That way if I change the location of a page, all links would continue to function properly?
For example Tapestry supports this as follows:
<a href="#" jwcid="search">foo</a>
which links to the "search" component. Tapestry then fills in the actual URL.
David Geary is also adding support for it to Shale for JSF ( http://jroller.com/page/dgeary?entry=img_src_http_jroller_com ).
Thoughts on how to do this in Spring MVC?
Thanks,
Todd
Colin Yates
Jul 27th, 2005, 04:55 AM
Excellent suggestion, and one I think should have been solved ages ago ;)
Although in truth, as long as you put some thought into your application navigation, the url's rarely change :)
maward
Jul 27th, 2005, 05:08 AM
I currently use the messages.properties file for storing URLs. This isn't perfect as there is still some duplication (SimpleUrlHandlerMapping etc.) of URLs - but at least I don't have them littered around in the template files.
I prefix all my URLs with either 'url.app.' for URLs that a related to the application (these are context-path relative) or 'url.ext.' for absolute URLs (external links).
Links then can look like this (using Freemarker):
<a href="<@myLib.appUrl 'loginPage'/>">Login Page</a>
This will look up loginPage by using the key url.app.loginPage in messages.properties and will add the context path onto the beginning.
<#macro appUrl(code)>
${httpResponse.encodeURL(req.contextPath + req.getMessage("url.app." + code))}<#t/>
</#macro>
The messages.properties file may have an entry looking like this:
url.app.loginPage = /auth/login.html
and that will eventually lead to a parsed template making this HTML (for an application installed with the context-path 'myApplicationContext'):
<a href="/myApplicationContext/auth/login.html">Login Page</a>
thuss
Jul 27th, 2005, 12:02 PM
Maward, good suggestion! How would you go about doing that for pages that require n number of parameters passed in as well?
-Todd
thuss
Jul 27th, 2005, 12:11 PM
yatesco, while URLs don't change much in practice we should still have the abiity to be able to refactor them easily without touching dozens of files. Tapestry handles this really well, in that when it interprets the HTML file to replace internal application page links it will actually generate an error if it can't resolve the link. Therefore you'll get errors in development telling you if a page link is bad.
In Spring MVC/JSP on the other hand unless a person actually clicks a link, or an automated test crawls the app, it is never validated making it much easier to accidentally get bad links to production.
Colin Yates
Jul 28th, 2005, 05:57 AM
yatesco, while URLs don't change much in practice we should still have the abiity to be able to refactor them easily without touching dozens of files.
Sorry. Can I have my hand back now :)
maward
Jul 28th, 2005, 06:04 AM
How would you go about doing that for pages that require n number of parameters
I must confess, I've been doing that very badly! I've been tacking the parameters onto the end - very messy, you end up with things like:
<a href="<@myLib.appUrl 'somePage'/>?id=${command.id}&another=${somevalue?url}">Some Page</a>
I'm going to change this situation so that the macro appUrl takes an optional second parameter mapping parameter names to values so that one could use:
<a href="<@myLib.appUrl key='somePage' params=["id":command.id, "another":somevalue?url]/>">Some Page</a>
I'm sure this could be made even nicer with some effort, so that strings are URL escaped automatically (without having to use ?url) and so on. I thought about the possibility of placeholders so that only the values need be supplied to the appUrl macro. In this case the messages.properties entries would look something like url.app.somePage = /blah.html?a=$$&b=$$ (supposing that $$ denotes a placeholder)
There are lots of possibilities, but using properties files seems the simplest place to start.
I have yet more duplication! I use an XML file to define the site navigation hierarchy. Currently that has URLs in it too. In the future I'm going to write a navigation manager that will be used in the templates and collaborating objects to fetch URLs defined in that XML file and will also write a subclass of SimpleUrlHandlerMapping that also uses the XML file.
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.