Using Pretty URLs with Spring and Annotations

Update June 15th, 2010: This page is no longer relevant. Spring 3 provides a much cleaner annotation driven method for nice URLs. This page is likely only relevant to you if you are using legacy Spring 2 or 2.5.

I’m currently working on a Java Web App with Spring. If you aren’t familiar with the Spring Framework, especially with the annotation support, then you’ve never had the pleasure of developing a web app in Java (but you may have experienced the pain). In another post, I will explain why this is so amazing, but for now lets just assume you know.

If you notice on blogs or other sites they have something called “pretty urls”. Essentially if you had a blog, this lets you have /post/welcome-to-my-site/ instead of /post/?id=33. Using the Spring Framework and the hot new annotation support in 2.5.1, you can easily achieve that.

Specify your url on your method like so:

public static final String URL_POST = "/post/*/";

@RequestMapping(URL_POST)
public String showPost(HttpServletRequest req) {
...
}

Now all we need to do is pull out the part of the URL that has whats in the star. I’ve created the following class to assist in this manner:

public class UrlUtils {
public static String[] breakUri(final String uri, final String expectedUrl) {
Pattern p = Pattern.compile(expectedUrl.replace("*", "(.*?)"));
Matcher m = p.matcher(uri);
if (m.find()) {
String[] ret = new String[m.groupCount()];
for (int i=0; i<ret.length; i++) {
ret[i] = m.group(i+1);
}
return ret;
}
else {
return null;
}
}
}
view raw UrlUtils.java This Gist brought to you by GitHub.

So equipped with this class, you only have to do the following:

String[] parts = UrlUtils.breakUri(req.getRemoteUri(), URL_POST);
if (parts == null) {
    // Do code to show an archive or whatever you want when the * part is missing
}
else {
    // parts[0] will have what you want.
}

Note: This will also (sort of) work if you have a url like: "/post/*/*/" (the array will have a length of 2). However, if you get "/post/welcome/" as the URL from the user, breakUri() will return null, in which case you might want to check for "/post/*/".

Now, this code isn’t very complex but it does allow you to deal with pretty urls without the hassle of building the regex yourself (something you may sometimes have to do!)

Finally, I’ve put a request into the fine folks that develop the Spring Framework to include this type of functionality out of the box so your method could be something like:

@RequestMapping(POST_URL)
public String showPost(RequestParts parts) {
    if (!parts.hasParts()) {
        // show general page
    }
    else {
        // Show specific page (parts.get(0))
    }
}

Please go vote for that feature at Spring’s issue tracking database.