Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Web MVC Java Configuration- Default Servlet Name

I wrote a small application to learn the java configuration in spring as I have been nagged by peers for a while now to upgrade our applications ;-), a simple todo list app, which has security and web mvc configuration, JPA for persistence, all through the java configuration. I am facing an issue when trying the run the application. The scurity config and JPA etc work fine but I get a null view after successful intercept of protected URLs

The main web app initializer class extends AbstractAnnotationConfigDispatcherServletInitializer

public class WiggleWebApplicationInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

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

    @Override
    protected Class<?>[] getServletConfigClasses() {

        return new Class<?>[] { WiggleWebAppConfig.class };
    }

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

    @Override
    protected void registerDispatcherServlet(ServletContext servletContext) {
        super.registerDispatcherServlet(servletContext);

        servletContext.addListener(new HttpSessionEventPublisher());

    }

    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);

        return new Filter[] { characterEncodingFilter };
    }
}

the WiggleApplicationConfig imports security, JPA and social

@Configuration
@ComponentScan(basePackages = { "wiggle.app.services.*" })
@Import({ WigglePersistenceConfig.class, WiggleSecurityConfig.class,
        WiggleSocialConfig.class })
public class WiggleApplicationConfig {

    @Bean
    public DateFormat dateFormat() {
        return new SimpleDateFormat("dd-MM-yyyy");
    }

}

The web config then adds default handler and the like

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "wiggle.app.controllers.*" })
public class WiggleWebAppConfig extends WebMvcConfigurerAdapter {

    private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/jsp/";
    private static final String VIEW_RESOLVER_SUFFIX = ".jsp";

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

    @Override
    public void configureDefaultServletHandling(
            DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public SimpleMappingExceptionResolver exceptionResolver() {
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();

        Properties exceptionMappings = new Properties();

        exceptionMappings.put("java.lang.Exception", "error/error");
        exceptionMappings.put("java.lang.RuntimeException", "error/error");

        exceptionResolver.setExceptionMappings(exceptionMappings);

        Properties statusCodes = new Properties();

        statusCodes.put("error/404", "404");
        statusCodes.put("error/error", "500");

        exceptionResolver.setStatusCodes(statusCodes);

        return exceptionResolver;
    }

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix(VIEW_RESOLVER_PREFIX);
        viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX);

        return viewResolver;
    }

}

All of this resides in package wiggle.app.config, going by my configuration /** is protected and should redirect to /login, which is open for all, the security filter chain does work all right, I see Access Denied after which there is redirection to /wiggle/login how ever I get a 404 after that with following log entries when I access the home page i.e. http://localhost:8080/wiggle/

Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faeba70: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffbcba8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 8A7C29831E56336A6FDF1A0E19200E70; Granted Authorities: ROLE_ANONYMOUS 
Voter: org.springframework.security.web.access.expression.WebExpressionVoter@c01ac1b, returned: 1 
Authorization successful 
RunAsManager did not change Authentication object 
/login reached end of additional filter chain; proceeding with original chain 
DispatcherServlet with name 'dispatcher' processing GET request for [/wiggle/login] 
Looking up handler method for path /login 
Did not find handler method for [/login] 
Matching patterns for request [/login] are [/**] 
URI Template variables for request [/login] are {} 
Mapping [/login] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler@688a42b5] and 1 interceptor 
Last-Modified value for [/wiggle/login] is: -1 
SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession. 
Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling 
Successfully completed request 
Chain processed normally 
SecurityContextHolder now cleared, as request processing completed 

I would usually put the following in an XML to take care of mappings

<beans:bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<!-- Enables annotated POJO @Controllers -->
<beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

and

 <!-- Scans within the base package of the application for @Components to configure as beans -->
 <context:component-scan base-package="com.code.controller" />

I am not able to find out what am I doing missing to enable similar behaviour with Java Configuration.

like image 767
Anadi Misra Avatar asked Aug 06 '14 15:08

Anadi Misra


People also ask

Which servlet is used in Spring MVC?

In Spring-MVC when you write annotation like @Controller, indirectly you are using a Servlet called Dispatcher Servlet. Dispatcher Servlet is defined in web. xml file with properties and class name which is mapped to . jsp pages and Controller part.

What is the default servlet container for Spring boot application?

The Spring Boot starters ( spring-boot-starter-web in particular) use Tomcat as an embedded container by default.

What is the Spring MVC front controller servlet name?

The DispatcherServlet is the front controller in Spring web applications. It's used to create web applications and REST services in Spring MVC. In a traditional Spring web application, this servlet is defined in the web. xml file.

What is default servlet in Tomcat?

The default servlet is the servlet which serves static resources as well as serves the directory listings (if directory listings are enabled). Where is it declared? It is declared globally in $CATALINA_BASE/conf/web.xml.


1 Answers

Turns out I missed an important piece of documentation w.r.t. this configuration, section 16.16.8 mvc:default-servlet-handler from the Spring Framework Docs

The caveat to overriding the "/" Servlet mapping is that the RequestDispatcher for the default Servlet must be retrieved by name rather than by path. The DefaultServletHttpRequestHandler will attempt to auto-detect the default Servlet for the container at startup time, using a list of known names for most of the major Servlet containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and WebSphere). If the default Servlet has been custom configured with a different name, or if a different Servlet container is being used where the default Servlet name is unknown, then the default Servlet’s name must be explicitly provided as in the following example:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable("myCustomDefaultServlet");
   }

}

hence I changed to this

@Override
public void configureDefaultServletHandling(
        DefaultServletHandlerConfigurer configurer) {
    configurer.enable("wiggleServlet");
}

There was another piece of misconfiguration

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "wiggle.app.controllers.*" })
public class WiggleWebAppConfig extends WebMvcConfigurerAdapter {

should be

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "wiggle.app.controllers" })
public class WiggleWebAppConfig extends WebMvcConfigurerAdapter {
like image 127
Anadi Misra Avatar answered Oct 14 '22 03:10

Anadi Misra