kayahr
kayahr

Reputation: 22020

How to use default-servlet-handler

I want to configure Spring MVC to serve dynamic files mixed with static files, like this (URL => File):

/iAmDynamic.html   => /WEB-INF/views/iAmDynamic.html.ftl
/iAmAlsoDynamic.js => /WEB-INF/views/iAmAlsoDynamic.js.ftl
/iAmStatiHtml      => /iAmStatic.html

The DispatchServlet is mapped to /, annotation-based MVC configuration is enabled and I have a view controller like this (Simplified):

@Controller
public class ViewController
{
    @RequestMapping("*.html")
    public String handleHtml(final HttpServletRequest request)
    {
         return request.getServletPath();
    }

    @RequestMapping("*.js")
    public String handleJavaScript(final HttpServletRequest request)
    {
        return request.getServletPath();
    }
}

The spring config looks like this:

<context:component-scan base-package="myPackage" />

<mvc:default-servlet-handler />

<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath" value="/WEB-INF/views/" />
</bean>

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
  <property name="cache" value="true" />
  <property name="prefix" value="" />
  <property name="suffix" value=".ftl" />
</bean>

Unfortunately it doesn't work. When this <mvc:default-servlet-handler /> is active then I can only access the iAmStatic.html file. When I disable the default-servlet-handler then only the dynamic stuff works. But I want both at once and that's exactly what this default-servlet-handler should do, or not? Where is the error here?

Upvotes: 7

Views: 19829

Answers (3)

Aniket Thakur
Aniket Thakur

Reputation: 68935

You need to define two important configurations

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

<mvc:annotation-driven/> will enable your default infrastructure beans where as <mvc:default-servlet-handler /> will configure a handler for serving static resources by forwarding to the Servlet container's default Servlet.

Also don't forget the mvc name space i.e xmlns:mvc="http://www.springframework.org/schema/mvc"

My complete config file (using TilesViewResolver) looks like below

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/mvc 
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven/>

    <!-- 
      Configures a handler for serving static resources by forwarding to the 
      Servlet container's default Servlet. 
    -->
    <mvc:default-servlet-handler />

    <mvc:view-controller path="/" view-name="welcome"/>
    <mvc:view-controller path="/home" view-name="welcome"/>

    <bean class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles.xml</value>
            </list>
        </property>
    </bean> 

    <bean class="org.springframework.web.servlet.view.tiles3.TilesViewResolver">
        <property name="order" value="1"/>
    </bean> 

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="2"/>
        <property name="prefix" value="/WEB-INF/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

Also if you have multiple HandlerMapping considering ordering them. For one for which you don't provide order explicitly Spring treats it with lowest precedence.

Upvotes: 1

aces.
aces.

Reputation: 4122

I had similar problem, none of the requests were getting mapped to the Spring Controllers: I discovered I was missing this in spring config xml:

<mvc:annotation-driven/>

It seems with , this is necessary. From documentation, the purpose of doing this is:

Configures the annotation-driven Spring MVC Controller programming model

I will also let DefaultServlet handle static content requests.

So your spring config should look like:

<context:component-scan base-package="myPackage" />
<!-- Define location and mapping of static content -->
<mvc:resources location="/static/" mapping="/static/**"/>

<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath" value="/WEB-INF/views/" />
</bean>

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
  <property name="cache" value="true" />
  <property name="prefix" value="" />
  <property name="suffix" value=".ftl" />
</bean>

Hope this helps!

Upvotes: 4

gutch
gutch

Reputation: 7139

I think that the view name you are returning from the ViewController is invalid. I expect that request.getServletPath() returns a blank string for all URLs, because the path to your servlet is probably / and the Java documentation says that getServletPath() returns a blank string for that path. Therefore the FreeMarker view resolver is probably ignoring the view name because it wouldn't know what to show.

However using a controller class with @RequestMapping is probably not the ideal way to go about this task anyway. Spring includes a ContentNegotiatingViewResolver which automatically determines the correct view depending on the content type. This overview of ContentNegotiatingViewResolver explains how to set it up.

Upvotes: 0

Related Questions