I am working on a Java PDF Generation micro service using spring boot. The pdf generation is meant to be a 2 stage process.
Templating - html template with some sort of expression language, which reads a json structure directly
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.