Tiago Duque
Tiago Duque

Reputation: 2069

TemplateEngine not Finding file within templates folder

I'm building a SpringBoot app that loads internationalisation messages from Database. (Followed this tutorial)

From that, I had to create a ThymeleafConfiguration class and set a SpringTemplateEngine Bean. The tutorial gave only a rough idea about this configuration (only configured the message source, but not the other templateengine configurations), so it broke my controller page rendering (controller is now returning string instead of view).

I'm trying to configure the rest of my TemplateEngine (such as the TemplateResolver, which I think is the reason why the rendering is not correct), however, I can't figure out how to do it correctly [I keep getting "An error happened during template parsing (template: "ServletContext resource [/templates/login.html]")" messages].

How to configure SpringTemplateEngine correctly?

My configuration so far:

@Configuration
public class ThymeleafConfiguration implements WebMvcConfigurer, ApplicationContextAware{

    private ApplicationContext applicationContext;

    @Autowired
    private DatabaseMessageSource databaseMessageSource;

    @Bean
      public ViewResolver viewResolver() {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(thymeleafTemplateEngine());
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
      }

     private ITemplateResolver templateResolver() {
            SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
            resolver.setApplicationContext(applicationContext);
            resolver.setPrefix("/templates/");
            resolver.setSuffix(".html");
            resolver.setTemplateMode(TemplateMode.HTML);
            return resolver;
          }


    @Bean
    public SpringTemplateEngine thymeleafTemplateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());
        engine.setTemplateEngineMessageSource(databaseMessageSource);
        return engine;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;

    }

}

Controller class:

 @Controller
    public class ApplicationController {


    @RequestMapping("/home")
    public String home() {
        return "/home.html";
    }


    @RequestMapping("/core/index")
    public String index() {
        return "/core/index.html";
    }

    @RequestMapping("/login")
    public String login() {
        return "login";
    }

File structure

Upvotes: 1

Views: 2421

Answers (2)

splashout
splashout

Reputation: 544

Another example in case someone wants a working reference:

@Configuration
public class ThymeleafConfig implements InitializingBean {

public static final String TEMPLATE_LOCATION = "classpath:/thymeleaf/templates/email/";

protected static final Logger logger = CustomLoggerFactory.getLogger();

@Autowired
private ApplicationContext applicationContext;

@Bean
public SpringTemplateEngine emailTemplateEngine() {
    SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(htmlTemplateResolver());
    templateEngine.setTemplateResolver(textTemplateResolver());
    return templateEngine;
}

private SpringResourceTemplateResolver htmlTemplateResolver() {
    SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
    templateResolver.setApplicationContext(applicationContext);
    templateResolver.setOrder(Integer.valueOf(1));
    templateResolver.setPrefix(TEMPLATE_LOCATION);
    templateResolver.setSuffix(".html");
    templateResolver.setTemplateMode(TemplateMode.HTML);
    templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.toString());
    templateResolver.setCacheable(false);
    templateResolver.setCheckExistence(true);
    return templateResolver;
}

private SpringResourceTemplateResolver textTemplateResolver() {
    SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
    templateResolver.setApplicationContext(applicationContext);
    templateResolver.setOrder(Integer.valueOf(2));
    templateResolver.setPrefix(TEMPLATE_LOCATION);
    templateResolver.setSuffix(".txt");
    templateResolver.setTemplateMode(TemplateMode.TEXT);
    templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.toString());
    templateResolver.setCacheable(false);
    templateResolver.setCheckExistence(true);
    return templateResolver;
}

@Override
public void afterPropertiesSet() throws Exception {
    // this just prints the templates found
    String path = TEMPLATE_LOCATION;
    ClassPathResource resource = new ClassPathResource(path);
    try (InputStream inputStream = resource.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
        logger.info("Found the following templates in " + path);
        String line;
        while ((line = reader.readLine()) != null) {
            logger.info(line);
        }
    } catch (Exception e) {
        logger.error("Caught Exception listing email templates:" + e.toString());
    }
}
}

Upvotes: 0

Tiago Duque
Tiago Duque

Reputation: 2069

The problem is with

private ITemplateResolver templateResolver() {
    SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
    resolver.setApplicationContext(applicationContext);
    resolver.setPrefix("/templates/"); // Here!!!
    resolver.setSuffix(".html");
    return resolver;
}

Since the templates are within src/main/resources, it has to be pointed to classpath, as follows:

@Bean
public SpringResourceTemplateResolver templateResolver() {
    SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
    resolver.setApplicationContext(applicationContext);
    resolver.setPrefix("classpath:/templates/"); // It works after adding 'classpath:'
    resolver.setSuffix(".html");
    return resolver;
}

Also, there's a little change from the interface to a implementation class that should not interfere with the result.

Upvotes: 3

Related Questions