javaspringspring-bootspring-mvcspring5

Spring Boot application do not serve web content


I have Spring Boot Web application initially built for internal Tomcat server (works). Then I adopted that application to be run on Web Logic server. My application compile and deploys to the server without issues but when it is not serving MVC pages. Every call throws 404 error. From the error below it looks like spring dispatcher servlet is present but even locale is not set properly. I can't figure out what is wrong or missing here but when I create RestController instead of MVC it works and contents shows up. Application is based on Sprint Boot 2.3.2

<16 Aug 2020, 14:12:32,792 British Summer Time> <Notice> <Stdout> <BEA-000000> <14:12:32.792 [[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.springframework.web.servlet.PageNotFound - No mapping for GET /alf/home> <16 Aug 2020, 14:12:34,922 British Summer Time> <Notice> <Stdout> <BEA-000000> <14:12:34.922 [[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] DEBUG org.springframework.context.support.ReloadableResourceBundleMessageSource - No properties file found for [messages] - neither plain properties nor XML> <16 Aug 2020, 14:12:34,922 British Summer Time> <Notice> <Stdout> <BEA-000000> <14:12:34.922 [[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] DEBUG org.springframework.context.support.ReloadableResourceBundleMessageSource - No properties file found for [messages_en_IE] - neither plain properties nor XML> <16 Aug 2020, 14:12:34,922 British Summer Time> <Notice> <Stdout> <BEA-000000> <14:12:34.922 [[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] DEBUG org.springframework.context.support.ReloadableResourceBundleMessageSource - No properties file found for [messages_en] - neither plain properties nor XML> <16 Aug 2020, 14:12:34,923 British Summer Time> <Notice> <Stdout> <BEA-000000> <14:12:34.923 [[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] DEBUG org.springframework.context.support.ReloadableResourceBundleMessageSource - No properties file found for [messages_en_US] - neither plain properties nor XML> <16 Aug 2020, 14:12:34,969 British Summer Time> <Error> <HTTP> <BEA-101107> <[ServletContext@2002815395[app:alf_war_exploded module:alf-2.0.1 path:null spec-version:4.0]] Problem occurred while serving the error page. javax.servlet.jsp.JspTagException: No message found under code 'page.error.title.text' for locale 'en_US'. at org.springframework.web.servlet.tags.MessageTag.doEndTag(MessageTag.java:294) at jsp_servlet._web_45_inf._pages._error.__page_45_404._jsp__tag0(__page_45_404.java:199) at jsp_servlet._web_45_inf._pages._error.__page_45_404._jspService(page-404.jsp:9) at weblogic.servlet.jsp.JspBase.service(JspBase.java:35) at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:295) Truncated. see log file for complete stacktrace> <16 Aug 2020, 14:12:34,972 British Summer Time> <Notice> <Stdout> <BEA-000000> <14:12:34.972 [[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 404 NOT_FOUND> <16 Aug 2020, 14:12:34,974 British Summer Time> <Notice> <Stdout> <BEA-000000> <[[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'] [2020-08-16T14:12:34,973] [10.2.16.95-agr5311] INFO AutoLoginFilter::doFilter - END 2020-08-16 14:12:34:972,agr5311,10.2.16.95,2204,2193,11,/alf/home>

Application class:

@SpringBootApplication
@ComponentScan({"ie.gov.agriculture.alf", "ie.gov.agriculture.sso"})
public class AlfApplication extends SpringBootServletInitializer implements WebApplicationInitializer {

    public AlfApplication() {
        super();
        setRegisterErrorPageFilter(false); // disable ErrorPageFilter causing bullshit error messages
    }

    @Override
    public void onStartup(ServletContext servletContext) {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(AppConfig.class);
        appContext.register(WebMvcConfig.class);

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("SpringDispatcher", new DispatcherServlet(appContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");

        ContextLoaderListener contextLoaderListener = new ContextLoaderListener(appContext);
        servletContext.addListener(contextLoaderListener);

        // Filter.
        FilterRegistration.Dynamic filterReg = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
        filterReg.setInitParameter("encoding", "UTF-8");
        filterReg.setInitParameter("forceEncoding", "true");
        filterReg.addMappingForUrlPatterns(null, true, "/*");
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(AlfApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(AlfApplication.class, args);
    }
}

AppConfig class:

@Configuration
@EnableCaching
public class AppConfig {

    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("messages");
        return messageSource;
    }

    @Bean
    public LocalValidatorFactoryBean messageValidator() {
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        validator.setValidationMessageSource(this.messageSource());
        return validator;
    }

    @Bean
    public ConversionServiceFactoryBean convertionService() {
        return new ConversionServiceFactoryBean();
    }

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("alfCache");
    }
}

finally WebMvcConfig class:

@Configuration
@ServletComponentScan
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public ViewResolver getViewResolver() {
        UrlBasedViewResolver resolver = new UrlBasedViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        return resolver;
    }

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jsonConverter.setObjectMapper(objectMapper);
        return jsonConverter;
    }

    @Bean
    public CookieLocaleResolver cookieLocaleResolverExample() {
        CookieLocaleResolver localeResolver = new CookieLocaleResolver();
        localeResolver.setDefaultLocale(Locale.ENGLISH);
        localeResolver.setCookieName("alf-locale-cookie");
        localeResolver.setCookieMaxAge(3600);
        return localeResolver;
    }

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.UK);
        localeResolver.setDefaultTimeZone(TimeZone.getTimeZone("UTC"));
        return localeResolver;
    }

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

Solution

  • The answer to this problem is as always a simple trick, messages configuration bean should looks like this and everything work fine, the key is "classpath: " in setBasenema

    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages");
        return messageSource;
    }