views:

11633

answers:

4

I'm trying to write a web application using SpringMVC. Normally I'd just map some made-up file extension to Spring's front controller and live happily, but this time I'm going for REST-like URLs, with no file-name extensions.

Mapping everything under my context path to the front controller (let's call it "app") means I should take care of static files also, something I'd rather not to (why reinvent yet another weel?), so some combination with tomcat's default servlet (let's call it "tomcat") appears to be the way to go.

I got the thing to work doing something like

<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>*.ext</url-pattern>
</servlet-mapping>

and repeating the latter for each one of the file extensions of my static content. I'm just wondering why the following setups, which to me are equivalent to the one above, don't work.

<!-- failed attempt #1 -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>*.ext</url-pattern>
</servlet-mapping>

<!-- failed attempt #2 -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>/some-static-content-folder/*</url-pattern>
</servlet-mapping>

Can anyone shed some light?

A: 

I don't think that / and /* count as valid url-patterns.

According to Section 10 of the Servlet 2.2 specification:

Specification of Mappings
In the Web Application Deployment Descriptor, the following syntax is used to define mappings:
• A string beginning with a ‘/’ character and ending with a ‘/*’ postfix is used as a path mapping.
• A string beginning with a ‘*.’ prefix is used as an extension mapping.
• All other strings are used as exact matches only

Strings like / and /* match neither category 1 or category 2, so they are used as exact matches.

Sounds like at the very least, you need to use a mapping like /somepath/*.

(I know that version 2.2 of the specification is pretty old, but Sun makes it really hard to find a link-able format of the latest specs!)

matt b
A: 

I've never tried to map a servlet like this, but I would argue that /* does technically both start with / and end with /*, even though the same character is used for both matches.

Adam Crume
+6  A: 

I think I may know what is going on.

In your working web.xml you have set your servlet to be the default servlet (/ by itself is the default servlet called if there are no other matches), it will answer any request that doesn't match another mapping.

In Failed 1 your /* mapping does appear to be a valid path mapping. With the /* mapping in web.xml it answers all requests except other path mappings. According to the specification extension mappings are implicit mappings that are overwritten by explicit mappings. That's why the extension mapping failed. Everything was explicitly mapped to app.

In Failed 2, App is responsible for everything, except content that matches the static content mapping. To show what is happening in the quick test I set up. Here is an example. /some-static-content-folder/ contains test.png

Trying to access test.png I tried:

/some-static-content-folder/test.png

and the file was not found. However trying

/some-static-content-folder/some-static-content-folder/test.png

it comes up. So it seems that the Tomcat default servlet (6.0.16 at least) drops the servlet mapping and will try to find the file by using the remaining path. According to this post Servlet for serving static content Jetty gives the behavior you and I were expecting.

Is there some reason you can't do something like map a root directory for your rest calls. Something like app mapped to /rest_root/* than you are responsible for anything that goes on in the rest_root folder, but anywhere else should be handled by Tomcat, unless you make another explicit mapping. I suggest setting your rest servlet to a path mapping, because it declares the intent better. Using / or /* don't seem appropriate, since you have to map out the exceptions. Using SO as an example, my rest mappings would be something like

/users/* for the user servlet

/posts/* for the posts servlet

Mapping order

  1. Explicit (Path mappings)
  2. Implicit (Extension mappings)
  3. Default (/)

Please correct anything that I got wrong.

Philip T.
Explanation for "Failed attempt #1" is dead on target. Still can't figure the other one.
agnul
If /* is already mapped to "app" servlet, what do you gain from mapping "/" as well?
matt b
There is no gain from mapping out / if you use /*, since it won't ever get called. The disadvantage to /*, is that you will need to handle everything, where with / you can still setup extension mappings.
Philip T.
Ok, trying to wrap my mind around your explanation for case #2. As for your question, no, there's no particular reason for not creating a /rest_root/* mapping, just personal preference. Sounds simpler than fighting with default and extension mappings tough :-)
agnul
I am editing this one more time. I almost had #2 right now, after coming across another post, I know what is going on.
Philip T.