Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Process HTML file using Thymeleaf in Web based Scopes of Spring and store the processed template as String

I am trying to render an HTML file using thymeleaf and keep the resultant HTML content in a String variable in web-based scopes of Spring so that i can use it later for sending email or converting the content to pdf. I have gone through the implementation given in this website but its giving me error which i couldn't figure out. I am using spring boot 1.5.12.RELEASE with thymeleaf 3.0.9 n thymeleaf dialect 2.2.2. Below is my implementation. Please help.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

@Controller
public class jataController {

    @GetMapping(value = "/manual-thym")
    @ResponseBody
    public void justSample() {
        Context context = new Context();
        String filename = "templates/view/failure";
        String html = renderHtml(filename, context);
        System.out.println("template\n" + html);
    }

    private String renderHtml(String filename, Context context) {

        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();

        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCacheable(false);
        templateResolver.setOrder(1);
        templateResolver.setCharacterEncoding("UTF-8");

        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);

        String html = templateEngine.process(filename, context);

        return html;
    }
}

And the StackTrace:

2018-04-19 12:26:43.742 ERROR 6375 --- [nio-9000-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: ognl/PropertyAccessor] with root cause

java.lang.ClassNotFoundException: ognl.PropertyAccessor
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_162]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_162]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_162]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_162]
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_162]
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_162]
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_162]
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_162]
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_162]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_162]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_162]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_162]
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361) ~[na:1.8.0_162]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_162]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_162]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_162]
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.<init>(OGNLVariableExpressionEvaluator.java:83) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.standard.StandardDialect.getVariableExpressionEvaluator(StandardDialect.java:179) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.standard.StandardDialect.getExecutionAttributes(StandardDialect.java:393) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.DialectSetConfiguration.build(DialectSetConfiguration.java:263) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.EngineConfiguration.<init>(EngineConfiguration.java:123) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.TemplateEngine.initialize(TemplateEngine.java:336) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1079) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1059) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1048) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
    at com.siqes.flight.controller.jataController.renderHtml(jataController.java:37) ~[classes/:na]
    at com.siqes.flight.controller.jataController.justSample(jataController.java:19) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) ~[spring-boot-1.5.12.RELEASE.jar:1.5.12.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:111) ~[spring-boot-actuator-1.5.12.RELEASE.jar:1.5.12.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) ~[spring-boot-actuator-1.5.12.RELEASE.jar:1.5.12.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.16.RELEASE.jar:4.3.16.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:613) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.29.jar:8.5.29]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
like image 397
sam Avatar asked Apr 19 '18 07:04

sam


4 Answers

See update below

When you configure Thymeleaf you should define the template engine and the template resolver otherwise when you autowire defaults are used. If you create an instance every time it is not a good practice. Here a sample configuration:

@Configuration
@EnableWebMvc
public class ThymeleafConfiguration {

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
        return templateEngine;
    }

    @Bean
    public SpringResourceTemplateResolver thymeleafTemplateResolver() {
        SpringResourceTemplateResolver templateResolver 
          = new SpringResourceTemplateResolver();
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML5");
        return templateResolver;
    }
}

Then if you want to experiment programmatically you can autowire them but the usual flow for serving html pages with thymeleaf is to define the view resolver as well:

@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
    ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    viewResolver.setTemplateEngine(templateEngine());
    return viewResolver;
}

With all that in place you can write a controller as:

@Controller
public class MyController {

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test() {
        return "yourTemplateName";
    }
}

Parameters can be passed to the template by using model attributes.

UPDATE 31/07/2018

unfortunately I do not have the time to complete working proof of concept, however I think the below code is enough to show the flow. If you run it and call localhost:8080/test you should be able to see the output html in the console. The pdf generation can be added as a view resolver and/or invoked programmatically, in this example using xhtmlrenderer; I do not have the time to complete it so I commented it out but you can get the point: a service provide the html and pdf generation by autowiring the template engine.

enter image description here

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.github.paizo</groupId>
    <artifactId>html2pdf</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>html2pdf</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.14</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

ThymeleafConfiguration.java

@Configuration
public class ThymeleafConfiguration {

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
        return templateEngine;
    }

    @Bean
    public ClassLoaderTemplateResolver thymeleafTemplateResolver() {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setPrefix("templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML5");
        return templateResolver;
    }
}

HelloWorldController.java

@Controller
public class HelloWorldController {

    @Autowired
    private Html2PdfService pdfService;

    @GetMapping(path = "/test")
    public String hello() {
        Map parameters = new HashMap();
        parameters.put("name", "Borat");
        System.out.println(pdfService.template2Html("test", parameters));
        return "test";
    }

//    @ResponseBody
//    @GetMapping
//    public ResponseEntity helloPdf() {
//        Map parameters = new HashMap();
//        parameters.put("name", "Borat");
//        pdfService.template2Pdf("test", parameters);
//        String filePath = "PATH_HERE";
//        InputStream inputStream = new FileInputStream(new File(filePath));
//        InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
//        HttpHeaders headers = new HttpHeaders();
//        headers.setContentLength();
//        return new ResponseEntity(inputStreamResource, headers, HttpStatus.OK);
//    }
}

Html2PdfService.java

@Service
public class Html2PdfService {

    @Autowired
    private TemplateEngine templateEngine;

    public OutputStream template2Pdf(String templateName, Map parameters) {
//        OutputStream outputStream = new BufferedOutputStream();
//        IOUtils.copy()
//
//        Context ctx = new Context();
//        String processedHtml = templateEngine.process(templateName, ctx);
//        ITextRenderer renderer = new ITextRenderer();
//        renderer.setDocumentFromString(processedHtml);
//        renderer.layout();
//        renderer.createPDF(os, false);
//        renderer.finishPDF();
        return null;
    }

    public String template2Html(String templateName, Map parameters) {
        Context ctx = new Context();
        ctx.setVariable("name", "pippo");
        String processedHtml = templateEngine.process(templateName, ctx);
        return processedHtml;
    }
}

Html2pdfApplication.java

@SpringBootApplication
public class Html2pdfApplication {

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

as a side note if you plan to generate the pdf on the fly and serve it as response in the controller I suggest to use streams and not byte arrays or temp files.

like image 129
Paizo Avatar answered Sep 28 '22 06:09

Paizo


If TemplateEngine is autowired inside a singleton bean, then the below mentioned code works perfect.

@Controller
public class jataController {

    @Autowired
    private TemplateEngine templateEngine;

    @GetMapping(value = "/manual-thym")
    @ResponseBody
    public void justSample() {
        Context context = new Context();
        String filename = "templates/view/generated-ticket.html";
        String html = renderHtml(filename, context);
        System.out.println("template\n" + html);
    }

    private String renderHtml(String filename, Context context) {

        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCacheable(false);
        templateResolver.setOrder(1);
        templateResolver.setCharacterEncoding("UTF-8");

        templateEngine.setTemplateResolver(templateResolver);

        String html = templateEngine.process(filename, context);

        return html;
    }
}

but if TemplateEngine is autowired on a request scope bean type, it gives exception and thymeleaf will create a memory leak. So finally with lots of hit and tries, i got a working solution and thanks to @Paizo. It might contain some bad practice but this is how it worked:

@Controller
@Configuration
@EnableWebMvc
@ApplicationScope
public class MyThymeleafConfig {

    @GetMapping("/view-template")
    @ResponseBody
    public void viewTemplates() {

        Context context = new Context();
        context.setVariable("mydata", "this is it");

        String html = templateEngine().process("templates/view-to-process.html", context);
        System.out.println(html);
    }


    /*

    configuration for thymeleaf and template processing

    */

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
        return templateEngine;
    }

    @Bean
    public SpringResourceTemplateResolver thymeleafTemplateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setPrefix("classpath:");
        templateResolver.setSuffix(".html");
        templateResolver.setCacheable(false);
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        return viewResolver;
    }
}

and to serve the static resources we need to define another bean, which is as follows:

@Configuration
@EnableWebMvc
public class StaticResourceConfig implements WebMvcConfigurer {

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

This solution cannot be found on any forum. However i would ask as well as request any Spring developer to provide a better implementation for the above code.

like image 45
sam Avatar answered Sep 28 '22 04:09

sam


Using Maven, add ognl dependency to your pom.xml file, e.g. (find the latest dependency/version in MVNRepository):

<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>3.1.12</version>
</dependency>
like image 31
Sabina Orazem Avatar answered Sep 28 '22 04:09

Sabina Orazem


I'm using similar Springboot and Thymeleaf versions and something like this worked for me on a few projects :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

@Component
public class EmailProcessor {

    private TemplateEngine htmlTemplateEngine;

    @Autowired
    public EmailProcessor(TemplateEngine templateEngine) {
        this.htmlTemplateEngine = templateEngine;
    }


    public String process(User user) {

        final Context ctx = new Context();

        if (user != null) {
            ctx.setVariable("user", user);
        }

        return htmlTemplateEngine.process("emails/template", ctx);
    }
}

Email template is just a regular Thymeleaf template which is located in:

resouces/templates/emails/template.html

like image 32
Leto Avatar answered Sep 28 '22 05:09

Leto