15

I have created 'for now' a simple and basic spring web application. I am used to have a deployment descriptor as a simple web.xml file, and then an application context as a xml file.

Though, now i wanted to try to create my entire spring web application using only java files. Therefore i have created my WebApplicationInitializer instead of the normal deployment descriptor, and my application context which uses the @Configuration annotation.

Deployment Descriptor

package dk.chakula.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
/**
 *
 * @author martin
 * @since 12-1-2012
 * @version 1.0
 */
public class Initializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext)
            throws ServletException {
        registerDispatcherServlet(servletContext);
    }

    private void registerDispatcherServlet(final ServletContext servletContext) {
        WebApplicationContext dispatcherContext = createContext(ChakulaWebConfigurationContext.class);
        DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
        Dynamic dispatcher = servletContext.addServlet("dispatcher", dispatcherServlet);
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

    private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(annotatedClasses);
        return context;
    }

} //End of class Initializer

Application context

package dk.chakula.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.tiles2.TilesConfigurer;
import org.springframework.web.servlet.view.tiles2.TilesView;

/**
 *
 * @author martin
 * @since 12-01-2013
 * @version 1.0
 */
@Configuration
@EnableWebMvc
@ComponentScan("dk.chakula.web")
public class ChakulaWebConfigurationContext {

    @Bean
    public TilesConfigurer setupTilesConfigurer() {
        TilesConfigurer configurer = new TilesConfigurer();
        String[] definitions = {"/layout/layout.xml"};
        configurer.setDefinitions(definitions);
        return configurer;
    }

    @Bean
    public UrlBasedViewResolver setupTilesViewResolver() {
        UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
        viewResolver.setViewClass(TilesView.class);
        return viewResolver;
    }

} //End of class ChakulaWebConfigurationContext

My problem is that I can't seem to find a way 'isolate' my mapping to resources folder which contains images, css javascript etc. When my application context is in java.

With the normal XML application context I used this tag to isolate the mapping to /resources/

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

How can I do this, so my web application can use my images, css etc.

Martin Rohwedder
  • 1,712
  • 4
  • 19
  • 34

3 Answers3

35

To be able to serve static resources in Spring MVC application you need two XML-tags: <mvc:resources/> and <mvc:default-servlet-handler/>. The same in the Java-based Spring configuration will be:

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    // equivalents for <mvc:resources/> tags
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }

    // equivalent for <mvc:default-servlet-handler/> tag
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    // ... other stuff ...
}

Note that since @EnableWebMvc annotation is used there's no need to extend directly WebMvcConfigurationSupport, and you should just extend WebMvcConfigurerAdapter. See JavaDoc for @EnableWebMvc for details.

Artem Shafranov
  • 2,655
  • 19
  • 19
  • saved my day I was extending both WebMvcConfigurationSupport and WebMvcConfigurerAdapter.my bad. – steveen zoleko Jan 16 '18 at 13:45
  • Well how do you server `/robots.txt`? By adding `configurer.enable()` that causes `Whitelabel Error Page` on all other `@RequestMapping` paths! `registry.addResourceHandler("/robots.txt").addResourceLocations("/static/robots.txt");` – Chloe May 04 '18 at 05:39
9

After using hours searching on the internet reading about Spring MVC 3 using only java files I fell over some articles which used an approach by extending from WebMvcConfigurationSupport class, and then overriding 2 methods - addResourceHandler( ResourceHandlerRegistry ) and ResourceHandlerMapping().

My new Application context now look like this.

package dk.chakula.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.tiles2.TilesConfigurer;
import org.springframework.web.servlet.view.tiles2.TilesView;

/**
 *
 * @author martin
 * @since 12-01-2013
 * @version 1.0
 */
@Configuration
@EnableWebMvc
@ComponentScan("dk.chakula.web")
public class ChakulaWebConfigurationContext extends WebMvcConfigurationSupport {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    @Override
    @Bean
    public HandlerMapping resourceHandlerMapping() {
        AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) super.resourceHandlerMapping();
        handlerMapping.setOrder(-1);
        return handlerMapping;
    }

    @Bean
    public TilesConfigurer setupTilesConfigurer() {
        TilesConfigurer configurer = new TilesConfigurer();
        String[] definitions = {"/layout/layout.xml"};
        configurer.setDefinitions(definitions);
        return configurer;
    }

    @Bean
    public UrlBasedViewResolver setupTilesViewResolver() {
        UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
        viewResolver.setViewClass(TilesView.class);
        return viewResolver;
    }

} //End of class ChakulaWebConfigurationContext

As I understood We had to override addResourceHandler, to add the location and the mapping of resources to the registry. Thereafter we needed a bean which returned an object of HandlerMapping. The order of this HandlerMapping should be set to -1, because as I could read from the spring documentation, then -1 means

HandlerMapping ordered at Integer.MAX_VALUE-1 to serve static resource requests.

My application can now load the css files and images into their views, and I wanted to enlighten you others with the answer so, people in the future could get benefit of this.

Martin Rohwedder
  • 1,712
  • 4
  • 19
  • 34
  • 3
    Somewhat a cumbersome way!.. Note that `@EnableWebMvc` already imported `WebMvcConfigurationSupport` to the configuration, so there's no need to use `@EnableWebMvc` annotation and to extend configuration class from `WebMvcConfigurationSupport` at the same time. See [JavaDoc for @EnableWebMvc](http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html) for details. – Artem Shafranov Jun 09 '13 at 19:46
4

Try this:

@Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
shubh
  • 253
  • 2
  • 3
  • 9