When trying to setup multiple servlets and switching from XML based configuration to Java annotation, the @EnableWebMvc
annotation seems to be doing something different compared to <mvc:annotation-driven/>
I've gone ahead and converted the xml configurations to Java annotated classes. However, when registering the java classes in my WebApplicationInitializer, the XML configurations load my controllers fine for each servlet, but when using the Java annotation, I get 404's on my controllers. If I register just one servlet with the annotation configuration, it works fine, but two or more result in 404's.
web-servlet.xml
<beans...>
<context:component-scan base-package="com.foo.bar" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<context:exclude-filter type="aspectj" expression="com.foo.bar.server.external.*"/>
</context:component-scan>
<security:global-method-security proxy-target-class="true" secured-annotations="enabled" pre-post-annotations="enabled"/>
<mvc:annotation-driven/>
<mvc:resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/>
<mvc:default-servlet-handler/>
<mvc:interceptors>
...
</mvc:interceptors>
<!-- selects a static view for rendering without the need for an explicit controller -->
<mvc:view-controller path="/login"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="ignoreAcceptHeader" value="true"/>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
</map>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</list>
</property>
<property name="order" value="1" />
</bean>
</beans>
web-servlet.java
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.foo.bar",
useDefaultFilters = false,
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.foo.bar.server.external.*"),
@ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.foo.bar.web..*")
}
)
@EnableGlobalMethodSecurity(proxyTargetClass = true, securedEnabled = true, prePostEnabled = true)
public class WebServlet extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/, classpath:/META-INF/web-resources/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true);
configurer.mediaType("json", MediaType.APPLICATION_JSON);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
...
}
@Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
// Define all possible view resolvers
List<View> defaultViews = new ArrayList<>();
defaultViews.add(mappingJackson2JsonView());
resolver.setDefaultViews(defaultViews);
return resolver;
}
@Bean
public MappingJackson2JsonView mappingJackson2JsonView() {
MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
mappingJackson2JsonView.setPrettyPrint(true);
return mappingJackson2JsonView;
}
}
external-servlet
<beans...>
<context:component-scan base-package="com.foo.bar.server.external" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<mvc:annotation-driven/>
<mvc:interceptors>
<bean class="com.foo.bar.server.external.CheckExtInterceptor"/>
</mvc:interceptors>
</beans>
external-servlet.java
@Configuration
@ComponentScan(basePackages = "com.foo.bar.server.external",
useDefaultFilters = false,
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class))
@EnableWebMvc
public class ExtServlet extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkExtInterceptor());
}
@Bean
public checkExtInterceptor checkExtInterceptor() {
return new CheckExtInterceptor();
}
}
webAppInitializer.java
public class FooWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("defaultHtmlEscape", "true");
servletContext.setInitParameter("spring.profiles.default", "dev");
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.setDisplayName("Foo Bar");
rootContext.register(FooApplication.class);
rootContext.setServletContext(servletContext);
createFilters(servletContext);
servletContext.addListener(new Log4jConfigListener());
servletContext.addListener(new ContextLoaderListener(rootContext));
// THIS WORKS
// XmlWebApplicationContext webContext = new XmlWebApplicationContext();
// webContext.setConfigLocation("/WEB-INF/spring/web-servlet.xml");
// THIS DOESN'T WHEN 2 SERVLETS ARE REGISTERED
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(WebServlet.class);
ServletRegistration.Dynamic webServlet = servletContext.addServlet("web", new DispatcherServlet(webContext));
webServlet.setLoadOnStartup(1);
webServlet.addMapping( "/*");
// THIS WORKS
// XmlWebApplicationContext extContext = new XmlWebApplicationContext();
// extContext.setConfigLocation("/WEB-INF/spring/ext-servlet.xml");
// THIS DOESN'T WHEN 2 SERVLETS ARE REGISTERED
AnnotationConfigWebApplicationContext extContext = new AnnotationConfigWebApplicationContext();
extContext.register(ExtServlet.class);
ServletRegistration.Dynamic extServlet = servletContext.addServlet("ext",
new DispatcherServlet(extContext));
extServlet.setLoadOnStartup(2);
extServlet.addMapping("/ext/*");
}
}
I'm expecting the annotation configuration to act the same but not sure what would be the underlying difference. Not much information out there for having 2 servlets with @EnableWebMvc
on both servlets, and the controllers shouldn't be returning 404's when not using XML configurations.