I have always wondered why so many Java developers use ".do" as the extension for their web controller (MVC) resources. Example: http://example.com/register.do
It doesn't even seem to be framework specific as I have seen it in Spring MVC and Struts projects.
Where did this ".do" extension practice come from. Why was this done instead of no extension?
I feel like I missed the Java world memo on this.
Personally I prefer no extension.
To my knowledge, this convention has been spread by Struts1. The user guide puts it like this:
5.4.2 Configure the ActionServlet Mapping
Note: The material in this section is not specific to Struts. The
configuration of servlet mappings is
defined in the Java Servlet
Specification. This section describes
the most common means of configuring a
application.
There are two common approaches to
defining the URLs that will be
processed by the controller servlet --
prefix matching and extension
matching. An appropriate mapping entry
for each approach will be described
below.
Prefix matching means that you want
all URLs that start (after the context
path part) with a particular value to
be passed to this servlet. Such an
entry might look like this:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/do/*</url-pattern>
</servlet-mapping>
which means that a request URI to
match the /logon path described
earlier might look like this:
http://www.mycompany.com/myapplication/do/logon
where /myapplication is the context
path under which your application is
deployed.
Extension mapping, on the other hand,
matches request URIs to the action
servlet based on the fact that the URI
ends with a period followed by a
defined set of characters. For
example, the JSP processing servlet is
mapped to the *.jsp pattern so that
it is called to process every JSP page
that is requested. To use the *.do
extension (which implies "do
something"), the mapping entry would
look like this:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
and a request URI to match the
/logon path described earlier might
look like this:
http://www.mycompany.com/myapplication/logon.do
WARNING - The framework will not operate correctly if you define more
than one <servlet-mapping> element
for the controller servlet.
WARNING - If you are using the new module support since version 1.1, you
should be aware that only extension
mapping is supported.
And I think this convention has been kept (sometimes to not change URLs even after replacing Struts1, sometimes just because people were happy with it).
It was common practice to map your struts servlet to *.do in web.xml to pass URLs to the struts servlet. For example:
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
There is really no reason except convention for this. If you use no extension you need to do some magic to handle images and other static content in a way that doesn't send them to your sevlet. Often this gets done at a load balancer of a fronting web server.
Related
There are two ways for servlet mapping.
The first is in web.xml:
<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>com.whatever.foo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>foo</servlet-name>
<url-pattern>/foo</url-pattern>
</servlet-mapping>
The second method uses the WebServlet annotation:
#WebServlet("/foo")
public class foo extends HttpServlet {
...
}
Which one is better? Where are the advantages of the first and the second way?
Provided that you're sure that you're using Tomcat 7 or newer, the webapp's web.xml has to be declared conform Servlet 3.0 spec in order to get Tomcat to scan and process the annotations. Otherwise Tomcat will still run in a fallback modus matching the Servlet version in web.xml. The support for servlet API annotations was only added in Servlet 3.0 (Tomcat 7).
So, the root declaration of your web.xml must look like below (make sure you remove any DOCTYPE from web.xml too, otherwise it will still be interpreted as Servlet 2.3!).
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
Further, there's a minor difference in the URL pattern. The URL pattern /notifications will let the servlet only listen on requests on exactly that path. It does not kick in on requests with an extra path like /notifications/list or something. The URL pattern /notifications/* will let the servlet listen on requests with extra path info as well.
The minimum #WebServlet annotation should thus look like this
#WebServlet("/notifications/*")
The rest of attributes are optional and thus not mandatory to get the servlet to function equally.
What is benefit of using java based config instead of web.xml for servlet 3.x?
It avoids repeating yourself, and making mistakes by doing so. The servlet class is, for example, com.foo.bar.SomeServlet. Using web.xml, you're forced to re-enter this class in web.xml:
<servlet-class>com.foo.bar.Someservlet</servlet-class>
But wait, you've made a typo and you'll only discover it at runtime.
Or you rename a servlet class, but you forget to rename it in the web.xml as well, and you only discover the mistake at deployment time.
Finally, they make our life easier. You're creating a servlet, and you obviously want to map it to some URL. So you just add an annotation. No need to go to another file to add the mapping, then go back to the class because you forgot its exact name, then go back to the file again. Everything regarding a servlet is in the servlet class. Same for a filter, listener, etc.
Annotations don't have all these problems.
I hope this helps you!
XML configuration :
advantages :
All mappings are in the same location, you have an overview of all of them in one single file.
disadvantages :
Needs a separate file in addition to the class files.
Annotation configuration :
advantages :
The mapping is described directly inside the relevant class.
disadvantages :
You have to open a particular class to see its mappings.
I am developing a java project.
I want to display an extention of any webpage as '.jsf' evenif it is 'jsp' or 'xhtml'.
What should I do?
Then just configure the FacesServlet accordingly?
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
If you actually meant "I want to block direct access to *.jsp and *.xhtml so that the visitor is forced to invoke them by *.jsf", then add a security constraint to web.xml on the desired url-patterns and an empty auth-constraint:
<security-constraint>
<display-name>Restrict direct access to JSP and XHTML files</display-name>
<web-resource-collection>
<web-resource-name>JSP and XHTML files</web-resource-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint />
</security-constraint>
Redirect all request to to the servlet that needs to handle the jsf requests
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>*</url-pattern>
</servlet-mapping>
STEPS (For new jsp project) :
In web.xml, change to *.jsf
Change to index.jsp
Create new welcome.jsp
In index.jsp page, include :
Run project and see extention in browser.
If this is for using JavaServer Faces, then the configuration of the JSF servlet enables the automatic mapping of .jsf to the underlying .xhtml or .jsp file.
I think you have it the wrong way round.
The user-agent will make requests to your servlet, with a given URI identifying the resource they wish to access. You decide what the correct URI for a given resource is, and how to respond to this request. So it's conceptually not a case of your webpage having an "address" that you want to display differently. Rather, it's a case of what URIs you want to use to map to which resources.
If you don't want to expose the extension, then you don't need URIs to have any extension at all, they're just strings. You will, however, need to think about how to resolve potential name clashes (as djna notes in the comment). I believe that this is configured for you at the Faces level, and actually BalusC's answer should have all the technical information necessary to do this.
I just wanted to point out the backwards nature of your thought processes, clearing this up will hopefully make it easier to grok the process in general. It's better that you understand it, than simply paste something into your web.xml that makes the problem go away (for now).
You should configure your server to process .jsf files as .jsp pages. How to actually do this depends on the server you are using - an information you haven't provided.
Disclaimer: I'm not familiar with either jsf or jsp, so I don't know what consequences this server modification will have on actual jsf pages.
The example documentation says that you simply need to place your files in war/ (or a subdirectory) and they should be accessible from the host (as long as they aren't JSPs or in WEB-INF). For example, if you place foo.css in war/ then you should be able to access it at http://localhost:8080/foo.css. However, this isn't working for me at all. NONE of my static files are accessible.
The docs on appengine-web.xml say that you can also specifically denote certain types as static. I've tried this as well and it makes no difference.
Am I missing something obvious?
UPDATE:
Turns out one of the mappings in my web.xml was a little too aggressive. The following was the culprit:
<servlet>
<servlet-name>Main</servlet-name>
<servlet-class>MainServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
It seems that it was grabbing everything that wasn't grabbed be one of the other rules, which I don't understand because there was no * on the end of the url-pattern. It also seems to be directly contradictory to the documentation that says:
Note: Static files, files that are served verbatim to users such as images, CSS or JavaScript, are handled separately from paths mentioned in the deployment descriptor. A request for a URL path that matches a path to a file in the WAR that's considered a static file will serve the file, regardless of servlet and filter mappings in the deployment descriptor. You can exclude files from those treated as static files using the appengine-web.xml file.
So, how can I have a rule that matches the base of my domain (eg. http://www.example.com/) and still allows the static files to filter through?
Try manually defining the static files in appengine-web.xml like
<static-files>
<include path="/favicon.ico" expiration="1d" />
<include path="/static/**" />
<include path="/**.css" />
</static-files>
This works for me even with servlets like
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
and
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
See Static Files and Resource Files
... It seems that it was grabbing everything that wasn't grabbed be one of the other rules, which I don't understand because there was no * on the end of the url-pattern. ...
[[Unfortunately, the term "default servlet" is overloaded to mean differnt things - leading to confusion. I'll try to be clear.]]
The url-pattern "/" is special (Rogue Wave calls this the "default mapping"). This defines the application's "default servlet", which is used when the URL request does not match other patterns (SRV.11.2 bullet 3 and SRV 11.1 item #4). Apparently, "/" is handled as if you specified "/*".
... It also seems to be directly contradictory to the documentation ...
Agreed, I think app engine has a bug so its not following the documentation you cited. Here's my theory of what is going on. Since there is a default servlet for your app (resulting from defining a servlet for url pattern "/"), the app stops using "default" "default servlet" provided by the container for apps that don't define their own "default servlet". The container's "default" "default servlet" is what provides the default behavior for serving up static files. I think this is consistent with how some containers behave.
I wonder what would happen if you tried specifying a servlet for a URL pattern that matches a static file. Would it serve the file (as indicated by the docs) or invoke the servlet (as indicated by this theory).
... So, how can I have a rule that matches the base of my domain (eg. http://www.example.com/) and still allows the static files to filter through? ...
If the theory is right, the solutions provided by jacob (adapted for google app engine) and zockman seem like they'd work - they map the static files to the container's "default" "default servlet".
The only other idea I have is to write your app's "default servlet" to examine the request to see if the request is for "/" or not. If so, handle it. If not, then (somehow) invoke the container's "default" "default servlet" to process the request (which will hopefully cache the file). Hopefully, once the static file has been served once, caching will bypass the servlet(s) in the future.
Sorry, I can't be more specific or provide code - I haven't work with Google app engine (yet!).
Ref:
JSR-000154 JavaTM Servlet 2.5 Specification
(Maintenance Release 2) - http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index2.html - sections SRV.11.2 and SRV.11.1
http://www2.roguewave.com/support/docs/hydraexpress/3.5.0/html/rwsfservletug/4-3.html#433 - Rogue Wave default servlet
http://tomcat.apache.org/tomcat-4.1-doc/catalina/funcspecs/fs-default.html - Tomcat default servlet
I realize that this is an really old question but I just ran into the same problem. I had put my css/*.css, js/*.css, and favicon.ico under /war/static/ and used the public_root directive in my appengine-web.xml to point to /static. This worked fine on my local dev server but did not when I uploaded the app. Getting rid of /static and moving everything up a level worked for me.
SDK v1.5.2 (Java) on Mac OSX 10.6.8 with Java SE 6 (MacOS X Default)
When using e.g tomcat for serving static files one has to specify the patterns like this:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
Maybe you could try to do the same?
I've mapped the Spring MVC dispatcher as a global front controller servlet on /*.
<servlet>
<servlet-name>home</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>home</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
However, this mapping stops the access to static files like CSS, JS, images etc which are all in the /res/ folder.
How can I access them anyway?
Map the controller servlet on a more specific url-pattern like /pages/*, put the static content in a specific folder like /static and create a Filter listening on /* which transparently continues the chain for any static content and dispatches requests to the controller servlet for other content.
In a nutshell:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
with the following in filter's doFilter():
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/static")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/pages" + path).forward(request, response);
}
No, this does not end up with /pages in browser address bar. It's fully transparent. You can if necessary make "/static" and/or "/pages" an init-param of the filter.
With Spring 3.0.4.RELEASE and higher you can use
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
As seen in Spring Reference.
What you do is add a welcome file in your web.xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
And then add this to your servlet mappings so that when someone goes to the root of your application, they get sent to index.html internally and then the mapping will internally send them to the servlet you map it to
<servlet-mapping>
<servlet-name>MainActions</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MainActions</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
End result: You visit /Application, but you are presented with /Application/MainActions servlet without disrupting any other root requests.
Get it? So your app still sits at a sub url, but automatically gets presented when the user goes to the root of your site. This allows you to have the /images/bob.img still go to the regular place, but '/' is your app.
If you use Tomcat, you can map resources to the default servlet:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
and access your resources with url http://{context path}/static/res/...
Also works with Jetty, not sure about other servlet containers.
Serving static content with appropriate suffix in multiple servlet-mapping definitions solved the security issue which is mentioned in one of the comments in one of the answers posted. Quoted below:
This was a security hole in Tomcat (WEB-INF and META-INF contents are accessible this way) and it has been fixed in 7.0.4 (and will be ported to 5.x and 6.x as well). – BalusC Nov 2 '10 at 22:44
which helped me a lot.
And here is how I solved it:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
I've run into this also and never found a great solution. I ended up mapping my servlet one level higher in the URL hierarchy:
<servlet-mapping>
<servlet-name>home</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
And now everything at the base context (and in your /res directory) can be served up by your container.
As of 3.0.4 you should be able to use mvc:resources in combination with mvc:default-servlet-handler as described in the spring documentation to achieve this.
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources
The reason for the collision seems to be because, by default, the context root, "/", is to be handled by org.apache.catalina.servlets.DefaultServlet. This servlet is intended to handle requests for static resources.
If you decide to bump it out of the way with your own servlet, with the intent of handling dynamic requests, that top-level servlet must also carry out any tasks accomplished by catalina's original "DefaultServlet" handler.
If you read through the tomcat docs, they make mention that True Apache (httpd) is better than Apache Tomcat for handling static content, since it is purpose built to do just that. My guess is because Tomcat by default uses org.apache.catalina.servlets.DefaultServlet to handle static requests. Since it's all wrapped up in a JVM, and Tomcat is intended to as a Servlet/JSP container, they probably didn't write that class as a super-optimized static content handler. It's there. It gets the job done. Good enough.
But that's the thing that handles static content and it lives at "/". So if you put anything else there, and that thing doesn't handle static requests, WHOOPS, there goes your static resources.
I've been searching high and low for the same answer and the answer I'm getting everywhere is "if you don't want it to do that, don't do that".
So long story short, your configuration is displacing the default static resource handler with something that isn't a static resource handler at all. You'll need to try a different configuration to get the results you're looking for (as will I).
'Static' files in App Engine aren't directly accessible by your app. You either need to upload them twice, or serve the static files yourself, rather than using a static handler.
The best way to handle this is using some kind of URL re-writing. In this way, you can have clean restful URLs, and NOT with any extensions i.e abc.com/welcom/register as opposed to abc.com/welcome/resister.html
I use Tuckey URL which is pretty cool.
It's got instructions on how to set up your web app.I have set it up with my Spring MVC web app. Of course, everything was fine until I wanted to use annotations for Spring 3 validations like #Email or #Null for domain objects.
When I add the Spring mvc directives:
< mvc:annotation-driven />
< mvc:default-servlet-handler />
.. it breaks the good ol Tuckey code. Apparently, < mvc:default-servlet-handler /> replaces Tuckey, which I'm still trying to solve.
I'd recommend trying to use a Filter instead of a default servlet whenever possible.
Other two possibilities:
Write a FileServlet yourself. You'll find plenty examples, it should just open the file by URL and write its contents into output stream. Then, use it to serve static file request.
Instantiate a FileServlet class used by Google App Engine and call service(request, response) on that FileServlet when you need to serve the static file at a given URL.
You can map /res/* to YourFileServlet or whatever to exclude it from DispatcherServlets' handling, or call it directly from DispatcherServlet.
And, I have to ask, what does Spring documentation say about this collision? I've never used it.
Add the folders which you don't want to trigger servlet processing to the <static-files> section of your appengine-web.xml file.
I just did this and looks like things are starting to work ok. Here's my structure:
/
/pages/<.jsp files>
/css
I added "/pages/**" and "/css/**" to the <static-files> section and I can now forward to a .jsp file from inside a servlet doGet without causing an infinite loop.
After trying the filter approach without success (it did for some reason not enter the doFilter() function) I changed my setup a bit and found a very simple solution for the root serving problem:
Instead of serving " / * "
in my main Servlet, I now only listen to dedicated language prefixes
"EN", "EN/ *", "DE", "DE/ *"
Static content gets served by the default Servlet and the empty root requests go to the index.jsp which calls up my main Servlet with the default language:
< jsp:include page="/EN/" />
(no other content on the index page.)
I found that using
<mvc:default-servlet-handler />
in the spring MVC servlet bean definition file works for me. It passes any request that isn't handled by a registered MVC controller on to the container's original default handler, which should serve it as static content. Just make sure you have no controller registered that handles everything, and it should work just fine. Not sure why #logixplayer suggests URL rewriting; you can achieve the effect he's looking for just adequately using Spring MVC alone.
I found a simpler solution with a dummy index file.
Create a Servlet (or use the one you wanted to respond to "/") which maps to "/index.html"
(Solutions mentioned here use the mapping via XML, I used the 3.0 version with annotation #WebServlet)
Then create a static (empty) file at the root of the static content named "index.html"
I was using Jetty, and what happened was that the server recognized the file instead of listing the directory but when asked for the resource, my Servlet took control instead. All other static content remained unaffected.
In Embedded Jetty I managed to achieve something similar by adding a mapping for the "css" directory in web.xml. Explicitly telling it to use DefaultServlet:
<servlet>
<servlet-name>DefaultServlet</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DefaultServlet</servlet-name>
<url-pattern>/css/*</url-pattern>
</servlet-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>
and if you want to use annotation based configuration use below code
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
With regard to Tomcat, a lot depends on the particular version. There was a bug fix
https://bz.apache.org/bugzilla/show_bug.cgi?id=50026
which means the servlet-mapping (other than for '/') for the default servlet behaves differently in Tomcat 6.0.29 (and earlier) compared with later versions.
In section "12.2 Specification of Mappings" of the Servlet Specification, it says:
A string containing only the ’/’ character indicates the "default" servlet of the
application.
So in theory, you could make your Servlet mapped to /* do:
getServletContext().getNamedDispatcher("/").forward(req,res);
... if you didn't want to handle it yourself.
However, in practice, it doesn't work.
In both Tomcat and Jetty, the call to getServletContext().getNamedDispatcher('/') returns null if there is a servlet mapped to '/*'
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 do (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?
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
Explicit (Path mappings)
Implicit (Extension mappings)
Default (/)
Please correct anything that I got wrong.
For reference, the "failed attempt #2" is perfectly correct in version of Tomcat >= to 6.0.29.
It was the result of a Tomcat bug that get fixed in version 6.0.29:
https://issues.apache.org/bugzilla/show_bug.cgi?id=50026
<!-- Correct for Tomcat >= 6.0.29 or other Servlet containers -->
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/some-static-content-folder/*</url-pattern>
</servlet-mapping>
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.