tags:

views:

4017

answers:

9

I am developing a webapp using Spring MVC 3 and have the DispatcherServlet catching all requests to '/' like so (web.xml):

  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

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

Now this works as advertised, however how can I handle static content? Previously, before using RESTful URLs, I would have caught all *.html for example and sent that to the DispatcherServlet, but now it's a different ball game.

I have a /static/ folder which includes /styles/, /js/, /images/ etc and I would like to exclude /static/* from the DispatcherServlet.

Now I could get static resources working when I did this:

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

But I want it to have nice URLs (the point of me using Spring MVC 3) not the landing page being www.domain.com/app/

I also don't want a solution coupled to tomcat or any other servlet container, and because this is (relatively) low traffic I don't need a webserver (like apache httpd) infront.

Is there a clean solution to this?

+5  A: 

I found a way around it using tuckey's urlrewritefilter. Please feel free to give a better answer if you have one!

In web.xml:

<filter>
 <filter-name>UrlRewriteFilter</filter-name>
 <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>

<filter-mapping>
 <filter-name>UrlRewriteFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

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

In urlrewrite.xml:

<urlrewrite default-match-type="wildcard">
<rule>
 <from>/</from>
 <to>/app/</to>
</rule>
<rule match-type="regex">
 <from>^([^\.]+)$</from>
 <to>/app/$1</to>
</rule>
<outbound-rule>
 <from>/app/**</from>
 <to>/$1</to>
</outbound-rule>

This means that any uri with a '.' in it (like style.css for example) won't be re-written.

hamo
+1  A: 

My way of solving this problem is placing all your actions with a specific prefix like "web" or "service" and configure that all url's with that prefix will be intercepted by the DispatcherServlet.

Teja Kantamneni
A: 

Sorry I don't have the answer: I have exactly the same problem (see my post here). Have you solution that's "better" than UrlRewriteFilter, or found any problems with the UrlRewriteFilter?

PUK
Nah, never came across another solution. Seems like it would be a common problem but there doesn't seem to be much mentioned about it. The whole rewriting of urls seems like a hack in this scenario, it just isn't elegent in my opinion.
hamo
Oh, also, I ended up changing the regex from rewriting urls with a '.' in them to rewriting any url with '/static/' in it (I place all my static content in one static directory). I did this because of the new json views etc.
hamo
OK, thanks for the information. If you follow the link to my forum post you'll see that I decided to use the "DefaultServlet". However, it's serving up raw content from /WEB-INF (not entirely sure why) so I'll looking again at the UrlRewriteFilter.It does seem hacky to me too. Seems like the sort of thing that you'd want to do to handle some legacy urls for transition, or SEO, but not something you'd need to do from scratch.Have you had any problems with UrlRewriteFilter? I ask because every solution I seem to find comes with its own problems!Thanks,PUK
PUK
Sorry for not responding, but no I haven't had any issues with urlrewriting (minus the gut feeling it doesn't seem right). As developers sometimes we have to let go things like that :)Best of luck,Cheers hamo
hamo
@hamo. No worries. The UrlRewriteFilter is looking good and I'm quite happy with it as a solution now. I think it might come in handy as the project grows too...
PUK
+1  A: 

If I understand your issue correctly, I think I have found a solution to your problem:

I had the same issue where raw output was shown with no css styles, javascripts or jquery files found.

I just added mappings to the "default" servlet. The following was added to the web.xml file:

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

This should filter out the javascript and css file requests from the DispatcherRequest object.

Again, not sure if this is what you are after, but it worked for me. I think "default" is the name of the default servlet within JBoss. Not too sure what it is for other servers.

I actually don't want to use the default servlet- that couples me to jboss/tomcat
hamo
+5  A: 

I've just been grappling with this issue in Spring MVC 3.0 and I initially went with the UrlRewriteFilter option. However I was not happy with this solution as it "didn't feel right" (I'm not the only one - see the link above to the Spring Forums where the word "hack" appears a few times).

So I came up with a similar solution to "Unknown (Google)" above but borrowed the idea of having all static content served from /static/ (taken from the Spring Roo version of the Pet Store app). The "default" servlet did not work for me but the Spring Webflow ResourceServlet did (also taken from Spring Roo generated app).

Web.xml:

<servlet>
    <servlet-name>mainDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

<servlet>
    <servlet-name>Resource Servlet</servlet-name>
    <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

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

<servlet-mapping>
    <servlet-name>Resource Servlet</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

The only change I made to JSPs was to add the /static/ path to URLs for CSS, JS and images. E.g. "${pageContext.request.contextPath}/static/css/screen.css".

for Maven users the dependency for "org.springframework.js.resource.ResourceServlet" is:

<dependency>
    <groupId>org.springframework.webflow</groupId>
    <artifactId>org.springframework.js</artifactId>
    <version>2.0.8.RELEASE</version>
</dependency>
nickdos
Not a bad solution nickdos- thank you! I still just don't "get it" as to why there isn't a resource servlet in core spring mvc (rather than having to add another dependency with web flow) or some other solution out of the box.Urlrewrite works fine for me so I'll stick with that for the time being! Cheers, Hamo
hamo
Looking back over the standard (non-Roo) version of the Spring Pet Clinic app, I noticed that the servlet definition for "default" is commented-out with the additional comment: "Uncomment this in containers (GlassFish) that do not declare this implicit definition out of the box". The explicit package declaration for default is org.apache.catalina.servlets.DefaultServlet. So this may be your "out of the box" resource servlet(?). I use Jetty for dev work and it seems Jetty does not provide an implicit default servlet (like Glassfish).
nickdos
A: 

After encountering and going through the same decision making process described here, I decided to go with the ResourceServlet proposal which works out quite nicely.

Note that you get more information on how to use webflow in your maven build process here: http://static.springsource.org/spring-webflow/docs/2.0.x/reference/html/ch01s05.html

If you use the standard Maven central repository the artifact is (in opposite to the above referred springsource bundle):

<dependency>
    <groupId>org.springframework.webflow</groupId>
    <artifactId>spring-js</artifactId>
    <version>2.0.9.RELEASE</version>
</dependency> 
ngeek
+1  A: 

The URLRewrite is sort of a "hack" if you want to call it that. What it comes down to is, you're re-inventing the wheel; as there are already existing solutions. Another thing to remember is Http Server = Static content & App server = dynamic content (this is how they were designed). By delegating the appropriate responsibilities to each server you maximize efficiency... but now-a-days this is probably only a concern in a performance critical environments and something like Tomcat would most likely work well in both roles most of the time; but it is still something to keep in mind none the less.

Stoney
A: 

I just add three rules before spring default rule (/**) to tuckey's urlrewritefilter (urlrewrite.xml) to solve the problem

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN" "http://tuckey.org/res/dtds/urlrewrite3.0.dtd"&gt;
    <urlrewrite default-match-type="wildcard">
     <rule>
      <from>/</from>
      <to>/app/welcome</to>
     </rule>
     <rule>
      <from>/scripts/**</from>
      <to>/scripts/$1</to>
     </rule>
     <rule>
      <from>/styles/**</from>
      <to>/styles/$1</to>
     </rule>
     <rule>
      <from>/images/**</from>
      <to>/images/$1</to>
     </rule>
     <rule>
      <from>/**</from>
      <to>/app/$1</to>
     </rule>
     <outbound-rule>
      <from>/app/**</from>
      <to>/$1</to>
     </outbound-rule> 
    </urlrewrite>
Pablo Cantero
+5  A: 

This problem is solved in spring 3.0.4.RELEASE where you can use <mvc:resources mapping="..." location="..."/> configuration element in your spring dispatcher configuration file.

Check Spring Documentation

rozky