I'll be using Freemarker as my presentation technology rather than JSP this time. There are a few reasons for that but not least is me wanting to try out Freemarker and see how it compares vs JSP in a Spring MVC project.
This article is far from complete - just a dump of config for now. I'll add more explanations what the code is doing in due course.
First up... the web.xml
Web.xml Java config
Spring provides an interface that provides for creating the servlet context. Simply implementing that interface is all that is needed to be able to run your Spring MVC application without a web.xml file.That interface is "WebApplicationInitializer".
So I have created a class that does just that:
public class YhjInitializer implements WebApplicationInitializer{
@Override public void onStartup(ServletContext servletContext) throwsServletException {
ctx.register(MvcConfiguration.class); //this is another of my classes that I'll show in the next section of this article
ctx.setServletContext(servletContext);
DispatcherServlet springServlet = new DispatcherServlet(ctx);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", springServlet);
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
There are several interfaces that can be implemented that cause slightly different behaviour, for example there is another interface that causes a security filter to be added to the filter chain.
Dependencies
Of course you need to include the required dependencies in your Maven build file (pom.xml). I'll update this list later.In this example I'm using:
- Spring: 3.2
- Freemarker: 2.3.20
Replacing application-context.xml and servlet-context.xml
So we've replaced web.xml with Java config. Now to handle the Spring specific stuff.I've put my config in a file called MvcConfiguration.java which you'll see referenced in the class above that implements the Spring WebApplicationInitializer interface.
@ComponentScan(basePackages={"yhj"})
@org.springframework.context.annotation.Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/css/").addResourceLocations("/resources/css/**");
registry.addResourceHandler("/js/").addResourceLocations("/resources/js/**");
registry.addResourceHandler("/img/").addResourceLocations("/resources/img/**");
}
@Bean
public ViewResolver viewResolver(){
FreeMarkerViewResolver resolver =new FreeMarkerViewResolver();
resolver.setCache(true);
resolver.setSuffix(".ftl");
return resolver;
}
@Bean
public FreeMarkerConfigurer freeMarkerConfig(){
FreeMarkerConfigurer configurer =new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/views/");
return configurer;
}
// load the properties so we can use the @Value annotation
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[]{new ClassPathResource("myproject.properties")};
pspc.setLocations(resources);
pspc.setIgnoreUnresolvablePlaceholders(true);
return pspc;
}
}
So now I have a XML free Spring MVC webapp and I'm a happy bunny!
Additional notes
Something that caught me out was returning a FreeMarkerConfig rather than a FreeMarkerConfigurer object from the freeMarkerConfig() method originally.There was no compilation problem because FreemarkerConfigurer implements the FreemarkerConfig interface so it is a legitimate return type. However when the application was run up I was getting problems with Spring not being able to resolve the .ftl file from the view name returned by the Controller.