404 error using Spring MVC Java Config on JBoss

2020-03-26 06:48发布

问题:

I wrote a small Spring MVC application with Java Config. It is working perfectly fine on Tomcat but not on JBoss EAP 6.2. It gets successfully deployed on JBoss but I get this warning when I request any page defined by Spring MVC and 404 error in browser.

WARN [org.springframework.web.servlet.PageNotFound] (http-/127.0.0.1:8080-1) No mapping found for HTTP request with URI [/example-web/pages/login.jsp] in DispatcherServlet with name 'dispatcher'

Here you can see my code:

public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class[] { RootConfiguration.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
    return new Class[] { WebMvcConfig.class };
}

@Override
protected String[] getServletMappings() {
    return new String[] { "/*" };
}

@Override
protected Filter[] getServletFilters() {
    return new Filter[] { new HiddenHttpMethodFilter() };
}
}

Here is my Spring MVC configuration:

@EnableWebMvc
@ComponentScan("com.spring.example.w.controller")
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("login").setViewName("login");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

And RootConfig:

@Configuration
@ComponentScan
public class RootConfiguration {
}

During deployment, I can see in the log that the requests do get mapped:

INFO  [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (ServerService Thread Pool -- 71) Mapped "{[/start],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView com.spring.example.w.controller.StartController.handleStart() throws javax.servlet.ServletException,java.io.IOException
INFO  [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping] (ServerService Thread Pool -- 71) Mapped URL path [/login] onto handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]
INFO  [org.springframework.web.context.ContextLoader] (ServerService Thread Pool -- 71) Root WebApplicationContext: initialization completed in 2530 ms
INFO  [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/example-web]] (ServerService Thread Pool -- 71) Initializing Spring FrameworkServlet 'dispatcher'
INFO  [org.springframework.web.servlet.DispatcherServlet] (ServerService Thread Pool -- 71) FrameworkServlet 'dispatcher': initialization started

Any help about why I get 404 error and this warning is highly appreciated. Once again I should emphasize that it is working on Tomcat. Thanks in advance.

回答1:

Was reading tutorial from SivaLabs, there was such a problem with running application on JBoss that work fine with tomcat. Problem was solving by changing DispatcherServlet mapping to "/app/*" . You can also try implementing WebApplicationInitializer instead of using abstract class. Here is example:

 @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        WebApplicationContext context = getContext();
        servletContext.addListener(new ContextLoaderListener(context));
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/"); // i have a more or less big website, and can't see advantages by using "/*" mapping, this can be also a problem. 
    }

    private AnnotationConfigWebApplicationContext getContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocations("ua.company.config.WebConfig", "ua.company.config.PersistenceConfig", "ua.company.config.SecurityConfig");
        return context;
    }


回答2:

It's possible that you were experiencing Red Hat bug 1094248, "Default servlet can't be overridden without web.xml". This issue apparently affects EAP 6.2, 6.3, and 6.4.0. From the bug report:

Mapping Spring dispatcher servlet to url pattern "/" does not work programmatically. In other words, overriding default servlet is not possible with Java code.

Consequence: Many users map Spring's DispatcherServlet to '/', and this works fine when done in web.xml. However when this configuration is done programmatically, default servlet is bind to "/" first. This prevents to bind DispatcherServlet later. Spring controllers are not mapped and 404 is retrieved.

Workaround (if any): Use web.xml configuration or map dispatcher servlet programmaticaly to some specific URL pattern. e.g. "/dispatcher/*"

For EAP 6.4, this was fixed in version 6.4.1. I don't know about earlier versions of EAP. The bug was fixed in January 2017, so you'd want to look for patches issued after then.

People with access to Red Hat's solutions knowledgebase may also want to look at solution 1211203.