java - In Thymeleaf how can you use separate resolvers for HTML and JavaScript to copy JavaScript from a file into the generated HTML -
i creating proof of concept program later brought larger project. thymeleaf seemed template engine try (natural templates active development) , seems fit have been having following issue.
goal: take json , generate html file work offline report viewing. trying convert premade html template single html page no external references other files or internet.
problem: can't javascript resolve correctly inside template resolver.
detailed description: have attempted keep javascript , html in separate directories. way javascript can use '.js' suffix , html can use '.html' suffix.
in order created 2 resolvers, 1 html , 1 js. have seen similar things done html fragments , seemed work other people.
the problem js resolver never seems used when hits <script th:include="jquery.min></script"
part of demo.tpl.html file. figured because .setorder(1)
on html resolver , .setorder(2)
on js resolver when can't find 'jquery.min' template first resolver query second resolver such template.
i attempted resolution js resolver set first resolver , attempted resolve 'demo.js' (which doesn't exist) instead of failing , checking second resolver in list have 'demo.tpl.html' available resolve.
it seems if ever uses first resolver , second resolver ignored.
relevant environment details:
... <properties> <jdk.version>1.8</jdk.version> </properties> ... <dependency> <groupid>org.thymeleaf</groupid> <artifactid>thymeleaf</artifactid> <version>3.0.0.release</version> </dependency>
also, not using spring, command line tool , wanted keep light possible , didn't see need spring.
the type of resolver using filetemplateresolver since not using servlet resolve html directly browser.
file structure:
github link: https://github.com/njfife/jsontohtmlreportgenerator
the commit @ time of question: 619fb96
applicationstart.java (main):
public class applicationstart { public static void main(string ... args) { ... stuff ... jsonconverter jsonconverter = new jsonconverter(); string html = jsonconverter.render(); // fails system.out.println(html); ... stuff .. } }
jsonconverter.java:
public class jsonconverter { private templateengine templateengine; private standardmessageresolver messageresolver; private properties properties; private context context; private classloader classloader = this.getclass().getclassloader(); // of top of not related issue // skip template resolvers built public jsonconverter() { // set template location file templates = new file(classloader.getresource("templates").getfile()); // translation data this.properties = new properties(); this.context = new context(); // hardcoded spanish testing this.context.setlocale(new locale("es")); // translation , message stuff, not // issue in case. try { stringbuilder defaultfilename = new stringbuilder(); defaultfilename.append("messages"); if(!context.getlocale().equals(locale.english)) { defaultfilename.append("_"); defaultfilename.append(context.getlocale().tostring()); } defaultfilename.append(".properties"); inputstream propertiesstream = classloader .getresourceasstream(defaultfilename.tostring()); this.properties.load(propertiesstream); } catch (exception e) { system.out.println("error!"); } // here down probally issue this.templateengine = new templateengine(); // build html resolver filetemplateresolver htmlfiletemplateresolver = new filetemplateresolver(); htmlfiletemplateresolver .setprefix(templates.getabsolutepath() + "/html/"); htmlfiletemplateresolver.setsuffix(".tpl.html"); htmlfiletemplateresolver.settemplatemode(templatemode.html); htmlfiletemplateresolver.setcacheable(false); htmlfiletemplateresolver.setcharacterencoding("utf-8"); htmlfiletemplateresolver.setorder(1); // set primary messageresolver = new standardmessageresolver(); messageresolver.setdefaultmessages(this.properties); templateengine.setmessageresolver(messageresolver); filetemplateresolver javascriptfiletemplateresolver = new filetemplateresolver(); javascriptfiletemplateresolver .setprefix(templates.getabsolutepath() + "/includes/"); javascriptfiletemplateresolver.setsuffix(".js"); javascriptfiletemplateresolver .settemplatemode(templatemode.javascript); javascriptfiletemplateresolver.setcacheable(false); javascriptfiletemplateresolver.setcharacterencoding("utf-8"); javascriptfiletemplateresolver.setorder(2); // resolve resource location templateengine.addtemplateresolver(htmlfiletemplateresolver); templateengine .addtemplateresolver(javascriptfiletemplateresolver); } public string render() { // testing programatic alteration of context context.setvariable("name", "nathan"); // fails render html when when including jquery return templateengine.process("demo", context); } }
relevant html template:
... stuff .. <head> <meta charset="utf-8"> <title>title</title> </head> <body> <th:block> <script th:include="jquery.min"></script> <script th:include="highcharts.min"></script> </th:block> <h1>chart demo</h1> <div id="container"></div> <p th:text="#{hello}"></p> <p th:text="${name}"></p> <p th:text="#{message}"></p> <p th:text="#{message.with.var(${name})}"></p> </body> ... stuff ...
tl;dl - if want templateengine switch resolvers when source template file isn't in current resolver's path have set checkexistence
flag true
calling yourtemplateresolver.setcheckexistence(true);
. if don't attempt resolve template first resolver in list if there no template file name in path.
also, th:include
deprecated don't use it, use th:insert
or 1 of other options instead.
so, decided walk through source code , find deciding templateresolver use template , came across block of code:
for (final itemplateresolver templateresolver : configuration.gettemplateresolvers()) { final templateresolution templateresolution = templateresolver.resolvetemplate(configuration, ownertemplate, template, templateresolutionattributes); if (templateresolution != null) { if (logger.istraceenabled()) { logger.trace( "[thymeleaf][{}] template resolver match! resolver \"{}\" resolve template \"{}\"", new object[] {templateengine.threadindex(), templateresolver.getname(), loggingutils.loggifytemplatename(template)}); } return templateresolution; } if (logger.istraceenabled()) { logger.trace( "[thymeleaf][{}] skipping template resolver \"{}\" template \"{}\"", new object[] {templateengine.threadindex(), templateresolver.getname(), loggingutils.loggifytemplatename(template)}); } }
for reason template resolution comming 'not null' though there no file present.
digging resolvetemplate
function found conditional:
if (this.checkexistence && !templateresource.exists()) { // check if flag set true return null; }
adding htmlfiletemplateresolver.setcheckexistence(true);
and changing "demo.tpl.html" file use th:insert
instead of th:include
fixed everything.
<th:block> <script th:insert="jquery.min"></script> <script th:insert="highcharts.min"></script> </th:block>
not sure why need tell templateresolver existence of template requirement resolver being valid resolver template. @ least think default should true don't think mine standard use case it's possible outlier here.
Comments
Post a Comment