views:

2536

answers:

10

Hi i have a problem i want to send all my request to one spring servlet

<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>

but this mapping stops the access to static files like images etc i have put them all in /res/....... folder

please help me how can i make this work i am using this on google app engine.

A: 

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.

alamar
A: 

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.

Gandalf
I would really like to see a better solution to this. It sucks to be stuck with a /app/ prefix everywhere.
pjesi
+1  A: 

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.

av
This is on App Engine, as the original asker said, not in Tomcat or Jetty.
Nick Johnson
+1  A: 

'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.

Nick Johnson
A: 

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).

Bill
A: 

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.

casey
A: 

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.

MStodd
+1  A: 

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 nut:

<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():

String uri = ((HttpServletRequest) request).getRequestURI();
if (uri.startsWith("/static")) {
    chain.doFilter(request, response); // Goes to default servlet.
} else {
    request.getRequestDispatcher("/pages" + uri).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.

BalusC
Perhaps I'm missing something, but what do have the doGet in your controller do? In mine, if I have the RequestDispatcher forward to '/pages/default.jsp' after I've updated the request model by setting attributes on it, I get an infinite loop.
MStodd
@MStodd: Just don't forward back to the controller, it has already done its job. Hide the views away somewhere in `/WEB-INF`, e.g. `/WEB-INF/pages/default.jsp`. For more hints see [this](http://stackoverflow.com/questions/2523430/hidden-features-of-jsp-servlet/2525995#2525995) and [this](http://stackoverflow.com/questions/3541077/design-patterns-web-based-applications/3542297#3542297) answer.
BalusC
Awesome! I think I moved my jsps out of there trying to solve this a different way earlier, and didn't move them back in.
MStodd
A: 

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. http://www.tuckey.org/urlrewrite/ its 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....can anyone help me ..... I need to use this cuz I want to use out of the box Annotation validations.....if you guys do not want to use annotation validations..Tuckey is a very good way to go...

logixplayer