[ACCEPTED]-How to access static resources when mapping a global front controller servlet on /*-resources

Accepted answer
Score: 75

Map the controller servlet on a more specific 10 url-pattern like /pages/*, put the static content in a specific 9 folder like /static and create a Filter listening on 8 /* which transparently continues the chain 7 for any static content and dispatches requests 6 to the controller servlet for other content.

In 5 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 4 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 3 address bar. It's fully transparent. You 2 can if necessary make "/static" and/or "/pages" an init-param of the 1 filter.

Score: 43

With Spring 3.0.4.RELEASE and higher you can use

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

As seen in Spring Reference.

0

Score: 21

What you do is add a welcome file in your 14 web.xml

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

And then add this to your servlet 13 mappings so that when someone goes to the 12 root of your application, they get sent 11 to index.html internally and then the mapping 10 will internally send them to the servlet 9 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 8 you are presented with /Application/MainActions 7 servlet without disrupting any other root 6 requests.

Get it? So your app still sits 5 at a sub url, but automatically gets presented 4 when the user goes to the root of your site. This 3 allows you to have the /images/bob.img still 2 go to the regular place, but '/' is your 1 app.

Score: 17

If you use Tomcat, you can map resources 4 to the default servlet:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

and access your resources 3 with url http://{context path}/static/res/...

Also 2 works with Jetty, not sure about other servlet 1 containers.

Score: 17

Serving static content with appropriate 10 suffix in multiple servlet-mapping definitions 9 solved the security issue which is mentioned 8 in one of the comments in one of the answers 7 posted. Quoted below:

This was a security 6 hole in Tomcat (WEB-INF and META-INF contents 5 are accessible this way) and it has been 4 fixed in 7.0.4 (and will be ported to 5.x 3 and 6.x as well). – BalusC Nov 2 '10 at 2 22:44

which helped me a lot. And here is 1 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>
Score: 12

I've run into this also and never found 5 a great solution. I ended up mapping my 4 servlet one level higher in the URL hierarchy:

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

And 3 now everything at the base context (and 2 in your /res directory) can be served up 1 by your container.

Score: 9

As of 3.0.4 you should be able to use mvc:resources in 2 combination with mvc:default-servlet-handler as described in the spring 1 documentation to achieve this.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources

Score: 6

The reason for the collision seems to be 35 because, by default, the context root, "/", is 34 to be handled by org.apache.catalina.servlets.DefaultServlet. This 33 servlet is intended to handle requests for 32 static resources.

If you decide to bump it 31 out of the way with your own servlet, with 30 the intent of handling dynamic requests, that 29 top-level servlet must also carry out any 28 tasks accomplished by catalina's original 27 "DefaultServlet" handler.

If you read through 26 the tomcat docs, they make mention that 25 True Apache (httpd) is better than Apache 24 Tomcat for handling static content, since 23 it is purpose built to do just that. My 22 guess is because Tomcat by default uses 21 org.apache.catalina.servlets.DefaultServlet 20 to handle static requests. Since it's all 19 wrapped up in a JVM, and Tomcat is intended 18 to as a Servlet/JSP container, they probably 17 didn't write that class as a super-optimized 16 static content handler. It's there. It gets 15 the job done. Good enough.

But that's the 14 thing that handles static content and it 13 lives at "/". So if you put anything else 12 there, and that thing doesn't handle static 11 requests, WHOOPS, there goes your static 10 resources.

I've been searching high and 9 low for the same answer and the answer I'm 8 getting everywhere is "if you don't want 7 it to do that, don't do that".

So long story 6 short, your configuration is displacing 5 the default static resource handler with 4 something that isn't a static resource handler 3 at all. You'll need to try a different configuration 2 to get the results you're looking for (as 1 will I).

Score: 3

'Static' files in App Engine aren't directly 4 accessible by your app. You either need 3 to upload them twice, or serve the static 2 files yourself, rather than using a static 1 handler.

Score: 2

The best way to handle this is using some 12 kind of URL re-writing. In this way, you 11 can have clean restful URLs, and NOT with 10 any extensions i.e abc.com/welcom/register 9 as opposed to abc.com/welcome/resister.html

I 8 use Tuckey URL which is pretty cool.

It's got instructions 7 on how to set up your web app.I have set 6 it up with my Spring MVC web app. Of course, everything 5 was fine until I wanted to use annotations 4 for Spring 3 validations like @Email or @Null for domain 3 objects.

When I add the Spring mvc directives:

< mvc:annotation-driven  /> 
< mvc:default-servlet-handler />

.. it 2 breaks the good ol Tuckey code. Apparently, < mvc:default-servlet-handler /> replaces 1 Tuckey, which I'm still trying to solve.

Score: 1

I'd recommend trying to use a Filter instead 15 of a default servlet whenever possible.

Other 14 two possibilities:

Write a FileServlet yourself. You'll 13 find plenty examples, it should just open 12 the file by URL and write its contents into 11 output stream. Then, use it to serve static 10 file request.

Instantiate a FileServlet class 9 used by Google App Engine and call service(request, response) on 8 that FileServlet when you need to serve 7 the static file at a given URL.

You can map 6 /res/* to YourFileServlet or whatever to 5 exclude it from DispatcherServlets' handling, or 4 call it directly from DispatcherServlet.

And, I 3 have to ask, what does Spring documentation 2 say about this collision? I've never used 1 it.

Score: 1

Add the folders which you don't want to 8 trigger servlet processing to the <static-files> section 7 of your appengine-web.xml file.

I just did 6 this and looks like things are starting 5 to work ok. Here's my structure:

/

/pages/<.jsp 4 files>

/css

I added "/pages/**" and "/css/**" to 3 the <static-files> section and I can now forward to a 2 .jsp file from inside a servlet doGet without 1 causing an infinite loop.

Score: 1

After trying the filter approach without 11 success (it did for some reason not enter 10 the doFilter() function) I changed my setup 9 a bit and found a very simple solution for 8 the root serving problem:

Instead of serving 7 " / * " in my main Servlet, I now only listen 6 to dedicated language prefixes "EN", "EN/ *", "DE", "DE/ *"

Static 5 content gets served by the default Servlet 4 and the empty root requests go to the index.jsp 3 which calls up my main Servlet with the 2 default language:

< jsp:include page="/EN/" /> (no 1 other content on the index page.)

Score: 1

I found that using

<mvc:default-servlet-handler />

in the spring MVC servlet 10 bean definition file works for me. It passes 9 any request that isn't handled by a registered 8 MVC controller on to the container's original 7 default handler, which should serve it as 6 static content. Just make sure you have 5 no controller registered that handles everything, and 4 it should work just fine. Not sure why 3 @logixplayer suggests URL rewriting; you 2 can achieve the effect he's looking for 1 just adequately using Spring MVC alone.

Score: 1

I found a simpler solution with a dummy 12 index file.

Create a Servlet (or use the 11 one you wanted to respond to "/") which 10 maps to "/index.html" (Solutions mentioned 9 here use the mapping via XML, I used the 8 3.0 version with annotation @WebServlet) Then 7 create a static (empty) file at the root 6 of the static content named "index.html"

I 5 was using Jetty, and what happened was that 4 the server recognized the file instead of 3 listing the directory but when asked for 2 the resource, my Servlet took control instead. All 1 other static content remained unaffected.

Score: 0

In Embedded Jetty I managed to achieve something 3 similar by adding a mapping for the "css" directory 2 in web.xml. Explicitly telling it to use 1 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>
Score: 0
<?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 1 configuration use below code

@Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
Score: 0

With regard to Tomcat, a lot depends on 5 the particular version. There was a bug 4 fix https://bz.apache.org/bugzilla/show_bug.cgi?id=50026 which means the servlet-mapping (other 3 than for '/') for the default servlet behaves 2 differently in Tomcat 6.0.29 (and earlier) compared 1 with later versions.

More Related questions