17

I want to create pdf report in a spring mvc application. I want to use themeleaf for designing the html report page and then convert into pdf file. I don't want to use xlst for styling the pdf. Is it possible to do that way?

Note: It is a client requirement.

Anindya Chatterjee
  • 5,824
  • 13
  • 58
  • 82

2 Answers2

9

You can use SpringTemplateEngine provided by thymeleaf. Below is the dependency for it:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring4</artifactId>
</dependency>

Below is the implementation I have done to generate the PDF:

@Autowired
SpringTemplateEngine templateEngine;

public File exportToPdfBox(Map<String, Object> variables, String templatePath, String out) {
    try (OutputStream os = new FileOutputStream(out);) {
        // There are more options on the builder than shown below.
        PdfRendererBuilder builder = new PdfRendererBuilder();
        builder.withHtmlContent(getHtmlString(variables, templatePath), "file:");
        builder.toStream(os);
        builder.run();
    } catch (Exception e) {
        logger.error("Exception while generating pdf : {}", e);
    }
    return new File(out);
}

private String getHtmlString(Map<String, Object> variables, String templatePath) {
    try {
        final Context ctx = new Context();
        ctx.setVariables(variables);
        return templateEngine.process(templatePath, ctx);
    } catch (Exception e) {
        logger.error("Exception while getting html string from template engine : {}", e);
        return null;
    }
}

You can store the file in Java temp directory shown below and send the file wherever you want:

System.getProperty("java.io.tmpdir");

Note: Just make sure you delete the file once used from the temp directory if your frequency of generating the pdf is high.

Grimthorr
  • 6,856
  • 5
  • 41
  • 53
Vijay
  • 558
  • 6
  • 22
  • can't get variables in template – zhuochen shen May 08 '19 at 06:01
  • 3
    What is the `PdfRendererBuilder` you used in the example? The provided library doesn't include it. – vkirilichev Dec 02 '19 at 08:52
  • @zhuochenshen the variable includes your Html body. Start and end strings ... , header, body and footer message. You can also set variables with the models final Context ctx = new Context(); ctx.setVariable("model", pdfModel); – Vijay Jan 02 '20 at 13:25
  • 5
    @vkirilichev - PdfRendererBuilder is used to run the XHTML/XML to PDF conversion and output to an output stream set by toStream. You need to add the following dependency for it: com.openhtmltopdf openhtmltopdf-pdfbox 0.0.1-RC7 – Vijay Jan 02 '20 at 13:33
5

You'll need to use something like flying-saucer-pdf, create a component a bit like:

@Component
public class PdfGenaratorUtil {
    @Autowired
    private TemplateEngine templateEngine;
    public void createPdf(String templateName, Map<String, Object> map) throws Exception {
        Context ctx = new Context();
        Iterator itMap = map.entrySet().iterator();
        while (itMap.hasNext()) {
            Map.Entry pair = (Map.Entry) itMap.next();
            ctx.setVariable(pair.getKey().toString(), pair.getValue());
        }

        String processedHtml = templateEngine.process(templateName, ctx);
        FileOutputStream os = null;
        String fileName = UUID.randomUUID().toString();
        try {
            final File outputFile = File.createTempFile(fileName, ".pdf");
            os = new FileOutputStream(outputFile);

            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(processedHtml);
            renderer.layout();
            renderer.createPDF(os, false);
            renderer.finishPDF();

        }
        finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) { /*ignore*/ }
            }
        }
    }
}

Then simply @Autowire this component in to your controller/service component and do something like:

Map<String,String> data = new HashMap<String,String>();
    data.put("name","James");
    pdfGenaratorUtil.createPdf("greeting",data); 

where "greeting" is the name of your template

See http://www.oodlestechnologies.com/blogs/How-To-Create-PDF-through-HTML-Template-In-Spring-Boot for details

SilentICE
  • 700
  • 8
  • 25