3

I am working on a Java PDF Generation micro service using spring boot. The pdf generation is meant to be a 2 stage process.

  1. Templating - html template with some sort of expression language, which reads a json structure directly

  2. HTML to PDF - this generates a pdf from the html produced in step 1

Note: I have some java and JavaScript (nunjucks/nodejs) solution for steps 1 and 2, but I really need a more maintainable approach as follows.

  • My restful endpoint will take 2 parameters an html template and a json
  • The json structure maps to the html template one to one and both files have been predefined to strict contract.
  • The service endpoint should not do any object mapping of json data to html Dom elements e.g. table, rows, etc
  • The endpoint only embeds the json data to the html using logic in java code
  • The html gets executed/rendered and reads the json directly using some sort of expression language, since it contains the json structure
  • The endpoint then response with an html with the dynamic data, which can be sent to the pdf generator web service endpoint

Below is a sample code:

@POST
 @Path("createPdf")   
 public Response createPdf(String htmlTemplateParam, String json) {

 //Read template from endpoint param or start off with reading local html template from resource folder
String templateHtml = IOUtils.toString(getClass().getResourceAsStream(HTMLTemplateFiles.INCOMING_TEMPLATE));

RequestJson requestJson = [Prepare json before passing to HTML Template]];

if(requestJson.isContentValid()) {

    LOG.info("incoming data successfully validated");

    // TODO     
    // Pass the requestJson (Endpoint Param JSON ) to templateHtml
    // Trigger the reading of the Json data and populating different HTML DOM elements using some sort of expression predefined in HTML

    // Get hold of the rendered HTML         
    String resolvedHtml = [HTML with data from json param into endpoint];

    // The next bit is done
    String pdf = htmlToPdfaHandler.generatePdfFromHtml(resolvedHtml);

    javax.ws.rs.core.Response response = Response.ok().entity(Base64.decodeBase64(pdf)).build();
            }
}

The templating stage one is where I need help.

Please, what is the best technical solution for this?

I am comfortable with Java and JavaScript framework and happy to learn any framework you suggest.

But, my main design goal is to ensure that as we have new templates and a template and data changes, a non-techie can change html/json and generate pdf.

Also, no java code changes should be required for template and data changes.

There are a few things in my head like jsonpath, thyme leaf, JavaScript, etc But, I love best practice and like to learn from someone with the real-life experience of similar use case.

After further research and first answer I am also thinking of the freemarker solution below.

But, how would I create a free marker template-data auto-magically from reading input json.i.e. without creating POJO/DTO?

Based on first answer :

     Configuration cfg = new Configuration(new Version("2.3.23"));
            cfg.setDefaultEncoding("UTF-8");

            // Loading you HTML template (via file or input stream):
            Template template = cfg.getTemplate("template.html");

  // Will this suffice for all JSON Structure, including nested deep ones

           Type mapType = new TypeToken<Map<String, Object>>(){}.getType(); 

    Map<String, String[]> templateData = new Gson().fromJson(json, mapType);

            try (StringWriter out = new StringWriter()) {
         // In output stream the result will be template with values from map:
                template.process(templateData, out);
                System.out.println(out.getBuffer().toString());

                out.flush();
            }

Thanks in advance.

NOTE: Code snippets, pseudo code, references are welcomed.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Mega
  • 1,304
  • 5
  • 22
  • 37
  • Are you free to choose format of html? If so you can use one of template engines, like Thymeleaf or FreeMarker. – alexey28 May 29 '19 at 08:08
  • Hi, yes. But, how do i pass JSON to HTML in java code and trigger data binding and rendering of HTML in java code? – Mega May 29 '19 at 09:02

1 Answers1

1

One of the options might be FreeMarker usage:

    Configuration cfg = new Configuration(new Version("2.3.23"));
    cfg.setDefaultEncoding("UTF-8");

    // Loading you HTML template (via file or input stream):
    Template template = cfg.getTemplate("template.html");

    // You need convert json to map of parameters (key-value):
    Map<String, Object> templateData = new HashMap<>();
    templateData.put("msg", "Today is a beautiful day");

    try (StringWriter out = new StringWriter()) {
        // In output stream the result will be template with values from map:
        template.process(templateData, out);
        System.out.println(out.getBuffer().toString());

        out.flush();
    }
alexey28
  • 5,170
  • 1
  • 20
  • 25
  • Hello Alexey28, Thanks for your input. Some changes will be required to use ur code. I will like to pass/embed the JSON directly into the HTML and any binding of json to html elements or iteration of json list should be done in HTML. So, no json parsing in my webservice endpoint. But, I will need a kind of process method, which injects the json into the html and triggers the reading and parsing of the json in the html. Then spit out html as string for pdf generator. Any more help will be appreciated. – Mega May 29 '19 at 10:50
  • Using the GSON library and reviewing the following https://stackoverflow.com/questions/443499/convert-json-to-map I am thinking of creating the template data as follows, so that there is no DTO or POJO Creation required in the Java web service code. Type mapType = new TypeToken>(){}.getType(); Map templateData = new Gson().fromJson(easyString, mapType); – Mega May 29 '19 at 17:04