thymeleaf 模板解析 th:onclick 事件异常 & 常见的 thymeleaf 往 js 参数传值解决方法

问题描述

thymeleaf 模板解析异常,异常点:th:onclick 事件解析问题。

问题日志

2019-10-08 16:50:25 [http-nio-8080-exec-5] ERROR org.thymeleaf.TemplateEngine - [THYMELEAF][http-nio-8080-exec-5] Exception processing template "images.html": An error happened during template parsing (template: "class path resource [templates/images.html]")
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/images.html]")
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241)
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100)
	at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
	at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362)
	at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1371)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1117)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1056)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.filters.RemoteIpFilter.doFilter(RemoteIpFilter.java:904)
	at org.apache.catalina.filters.RemoteIpFilter.doFilter(RemoteIpFilter.java:961)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.demo.zhulong.filter.XSSFilter.doFilter(XSSFilter.java:94)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:96)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:41002)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.attoparser.ParseException: Only variable expressions returning numbers or booleans are allowed in this context, any other datatypes are not trusted in the context of this expression, including Strings or any other object that could be rendered as a text literal. A typical case is HTML attributes for event handlers (e.g. "onload"), in which textual data from variables should better be output to "data-*" attributes and then read from the event handler. (template: "images.html" - line 68, col 52)
	at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
	at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
	... 60 common frames omitted
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Only variable expressions returning numbers or booleans are allowed in this context, any other datatypes are not trusted in the context of this expression, including Strings or any other object that could be rendered as a text literal. A typical case is HTML attributes for event handlers (e.g. "onload"), in which textual data from variables should better be output to "data-*" attributes and then read from the event handler. (template: "images.html" - line 68, col 52)
	at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:181)
	at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66)
	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109)
	at org.thymeleaf.standard.expression.AdditionExpression.executeAddition(AdditionExpression.java:96)
	at org.thymeleaf.standard.expression.ComplexExpression.executeComplex(ComplexExpression.java:62)
	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:112)
	at org.thymeleaf.standard.expression.AdditionExpression.executeAddition(AdditionExpression.java:89)
	at org.thymeleaf.standard.expression.ComplexExpression.executeComplex(ComplexExpression.java:62)
	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:112)
	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138)
	at org.thymeleaf.standard.processor.StandardDOMEventAttributeTagProcessor.doProcess(StandardDOMEventAttributeTagProcessor.java:214)
	at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74)
	at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95)
	at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633)
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314)
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205)
	at org.thymeleaf.engine.Model.process(Model.java:282)
	at org.thymeleaf.engine.Model.process(Model.java:290)
	at org.thymeleaf.engine.IteratedGatheringModelProcessable.processIterationModel(IteratedGatheringModelProcessable.java:367)
	at org.thymeleaf.engine.IteratedGatheringModelProcessable.process(IteratedGatheringModelProcessable.java:221)
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleCloseElement(ProcessorTemplateHandler.java:1640)
	at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleCloseElementEnd(TemplateHandlerAdapterMarkupHandler.java:388)
	at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleCloseElementEnd(InlinedOutputExpressionMarkupHandler.java:322)
	at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleCloseElementEnd(OutputExpressionInlinePreProcessorHandler.java:220)
	at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleCloseElementEnd(InlinedOutputExpressionMarkupHandler.java:164)
	at org.attoparser.HtmlElement.handleCloseElementEnd(HtmlElement.java:169)
	at org.attoparser.HtmlMarkupHandler.handleCloseElementEnd(HtmlMarkupHandler.java:412)
	at org.attoparser.MarkupEventProcessorHandler.handleCloseElementEnd(MarkupEventProcessorHandler.java:473)
	at org.attoparser.ParsingElementMarkupUtil.parseCloseElement(ParsingElementMarkupUtil.java:201)
	at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:725)
	at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301)
	... 62 common frames omitted

错误原因

网传几乎所有的解决方法都是以下几种:
1. 嵌套[[]]两层中括号包裹的方式往 js 中传值:

<a class="btn" th:onclick="getName([[${person.name}]]);">test</a>

2. 采用转义拼接字符串方式往 js 中传值:

<a th:onclick="'javascript:del(\''+${data}+'\')'">test</a>

若项目采用的 thymeleaf 版本基于 2.x,如果传输数字或布尔值,以上方式或许有用。

但是对于 3.x 版本的 thymeleaf 完全行不通!!3.x版本的thymeleaf为了防止注入攻击,已经升级了安全机制,不能考虑采用以上方式解决。
(查看 pom 文件中的此项配置:

        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

此项若无特殊设置,默认为最新版本。)

根据错误提示,在此上下文中仅允许返回数字或布尔值的变量表达式,在此表达式的上下文中不信任任何其他数据类型,(所以如果传输数字或布尔值,常见的解决方式或许有用),包括字符串或可以呈现为文本文字的任何其他对象。

典型的情况是事件处理程序的HTML属性(例如“ onload”),其中变量中的文本数据最好输出到“ data- *”属性,然后再从事件处理程序中读取。

解决方式

修改前:

<a th:onclick="'javascript:modInfo(\''+${image.uuid}+'\');'"></a>

修改后:

<a th:data-id="${image.uuid}" th:onclick="javascript:modInfo(this.getAttribute('data-id'))">test</a>

即将需要传递的字符串 ${image.uuid} 先以 th:data- * 属性定义,然后在 th:onclick 点击事件中,以 this.getAttribute() 方式获取定义的 data-* 属性传值。

js 代码写在 body 之后:

    <script type="text/javascript" th:inline="javascript">
        function modInfo(obj) {
            alert(obj);
            // ....
        }
    </script>

参考链接

https://my.oschina.net/u/2312080/blog/2878183
https://blog.csdn.net/Lactually/article/details/84306960

心得

根据自己具体的错误问题寻找解决方案,直接搜索知识点获得的结果可能并不适合自己的问题(如版本迭代、API 更新等,此类问题往往容易忽视),反而更加误入歧途浪费时间。

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值