Search code examples
javaspringspring-bootthymeleafclassloader

Thymeleaf template is not able to find related JS, CSS and i18n files


I am working on spring boot 2 + thymeleaf web application. I want to render a template and it's static resources from a jar file. I am getting a 404 error for js, CSS, and message.properties file whereas template is rendering on the browser but related js, css not. To render a template from the jar file, I have configured ClassLoaderTemplateResolver as mentioned below :

  @Bean
public ClassLoaderTemplateResolver secondaryTemplateResolver() throws IOException {
    
    ClassLoaderTemplateResolver secondaryTemplateResolver = new 
     ClassLoaderTemplateResolver(getCustomeClassLoader());
    secondaryTemplateResolver.setPrefix("mytemplates/");
    secondaryTemplateResolver.setSuffix(".html");
    secondaryTemplateResolver.setTemplateMode(TemplateMode.HTML);
    secondaryTemplateResolver.setCharacterEncoding("UTF-8");
    secondaryTemplateResolver.setOrder(2);
    secondaryTemplateResolver.setCheckExistence(true);
    
    return secondaryTemplateResolver;
}

Where getCustomClassloader() will return the URLclassloader instance which loads my test.jar file (current class' classloader is passed as parent classloader). This jar file has all my templates (html file) + static files (JS,CSS,Properties). Below is the structure of jar file:

test.jar
 |
 |- mytemplates -> myhtml.html
 |- static
      |- js ->my.js
      |- css ->my.js
 |- i18N -> message.properties

It looks like spring boot or thymeleaf is not able to find resources from the Classloader/jar file where it can find the template. Could you please help me to fix this problem? How I can tell spring boot + thymeleaf to look into a specific classloader to find static resouces?

I have already tried setting up ClassLoaderTemplateResource but it invain.

@Bean
public ClassLoaderTemplateResource secondaryResouceResolver() throws IOException
{
    ClassLoaderTemplateResource secondaryResoucreResolver = new ClassLoaderTemplateResource(getCustomeClassLoader(),
        "static/", "UTF-8");

    return secondaryResoucreResolver;
}

Thanks in advance for your help!


Solution

  • I wasn't able to find any mechanism where I can use a jar file or classloader to point external static resources. Therefore, in order to point static resource (Js/css) and message files from jar files which are not in the classpath you need override some spring boot default configurations. First, you need to extract the jar file in some folder and then you need to override addResourceHandlers() method of WebMvcConfigurer interface like below :

     @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
        registry
          .addResourceHandler("js/**") /*This must be relative request url for js*/
          .addResourceLocations("file:/C:/MyStuff/jarfolder/js/")
          .setCachePeriod(3600)
          .resourceChain(true)
          .addResolver(new PathResourceResolver());
        
        registry
        .addResourceHandler("css/**")/*This must be relative request url for css*/
        .addResourceLocations("file:/C:/MyStuff/jarfolder/css/")
        .setCachePeriod(3600)
        .resourceChain(true)
        .addResolver(new PathResourceResolver());
    }
    

    In order to refer message source from jar file, not in the classpath. you need to extract it and then provide it's path as given below :

     @Bean
    public MessageSource messageSource() throws IOException
    {
        ReloadableResourceBundleMessageSource messageSource = 
            new ReloadableResourceBundleMessageSource();
       
        
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setUseCodeAsDefaultMessage(true);
        messageSource.addBasenames("classpath:i18n/messages");
      messageSource.addBasenames("file:/C:/MyStuff/jarfolder/messages");
        return messageSource;
    }
    

    This will serve the purpose to get static resources and message sources from external sources. If anyone knows a better solution so please leave your comment here.