You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Thymeleaf获取principal.username报错 jQuery拼接链接参数异常

问题描述

开发时尝试通过jQuery将用户名拼接至页面链接参数,遇到两个异常:

  • 配置了sec:authentication="principal.username"的span标签可以正常渲染用户名,但调用$("#emailTarget").attr("id")获取span内用户名时,返回undefined,不符合预期
  • 在配置了th:inline="javascript"的内联脚本中,通过[[${principal.username}]]直接取值触发Thymeleaf模板解析错误,核心报错为SpEL表达式解析异常:EL1007E: Property or field 'username' cannot be found on null,即取值时principal对象为null
错误堆栈
org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleText(InlinedOutputExpressionMarkupHandler.java:80)
    at org.attoparser.HtmlMarkupHandler.handleText(HtmlMarkupHandler.java:208)
    at org.attoparser.AbstractChainedMarkupHandler.handleText(AbstractChainedMarkupHandler.java:203)
    at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:557)
    at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301)
    ... 98 more
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "principal.username" (template: "index" - line 49, col 25)
    at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292)
    at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166)
    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.Expression.execute(Expression.java:138)
    at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144)
    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.TemplateModel.process(TemplateModel.java:136)
    at org.thymeleaf.engine.TemplateManager.process(TemplateManager.java:519)
    at org.thymeleaf.util.LazyProcessingCharSequence.writeUnresolved(LazyProcessingCharSequence.java:85)
    at org.thymeleaf.util.AbstractLazyCharSequence.write(AbstractLazyCharSequence.java:103)
    at org.thymeleaf.engine.AbstractTextualTemplateEvent.writeContent(AbstractTextualTemplateEvent.java:224)
    at org.thymeleaf.engine.Text.write(Text.java:78)
    at org.thymeleaf.engine.OutputTemplateHandler.handleText(OutputTemplateHandler.java:71)
    ... 107 more
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'username' cannot be found on null
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213)
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104)
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:51)
原始问题模板代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <meta charset="ISO-8859-1">
        <title>Registration and Login App</title>

        <link rel="stylesheet"
              href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
              integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
              crossorigin="anonymous">

    </head>
    <body>
        <!-- 导航栏 -->
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed"
                            data-toggle="collapse" data-target="#navbar" aria-expanded="false"
                            aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span> <span
                            class="icon-bar"></span> <span class="icon-bar"></span> <span
                            class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#" th:href="@{/}">Registration and
                        Login Module</a>
                </div>
                <div id="navbar" class="collapse navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li sec:authorize="isAuthenticated()"><a th:href="@{/logout}">Logout</a></li>
                    </ul>
                </div>
            </div>
        </nav>

        <br>
        <br>

        <div class="container">
            <h1>Registration and Login with Spring Boot, Spring Security,
                Thymeleaf, Hibernate and MySQL</h1>
            Welcome <span sec:authentication="principal.username"> User</span>
        </div>
        <a th:href="login" id="changeMe" class="btn btn-danger">Delete</a>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

        <script  type="text/javascript" th:inline="javascript">
            let email=[[${principal.username}]];
            $('#changeMe').prop("href", "/delete?email="+email)
        </script>
    </body>
</html>
问题根因
  • jQuery取值逻辑完全错误:attr("id")方法的作用是获取标签的id属性值,首先原代码里显示用户名的span根本没有设置id="emailTarget"属性,就算给span加上这个id,调用attr("id")拿到的也只是固定字符串emailTarget,不可能拿到标签内部渲染的文本内容。
  • Thymeleaf取值上下文错误:sec:authentication是thymeleaf-extras-springsecurity扩展提供的专属标签,它会单独从Security上下文获取认证信息,普通Thymeleaf模型变量里默认没有直接暴露principal对象,直接在th表达式里写${principal.username}自然会拿到null;如果用户处于未登录状态,认证对象本身就是null,也会触发空指针报错。
  • 缺少权限控制:删除操作属于登录后才可用的功能,原代码没有给删除按钮加登录态校验,未登录用户访问页面时也会执行用户名取值逻辑,进一步放大了空值问题。
修复方案
  1. 修正DOM取值逻辑
    如果要通过jQuery拿到span里渲染好的用户名,先给span加上对应id,再调用.text()方法获取标签内部文本:
<!-- 给用户名span添加id -->
<span id="emailTarget" sec:authentication="principal.username">User</span>
// 取span内渲染完成的用户名,去除首尾空格
let email = $("#emailTarget").text().trim();
$('#changeMe').prop("href", "/delete?email="+email)
  1. 修正Thymeleaf内联脚本取值语法
    如果要直接在脚本内通过Thymeleaf表达式拿认证信息,使用Spring Security扩展提供的内置对象#authentication取值,同时加默认值兜底,避免空指针:
<script type="text/javascript" th:inline="javascript">
// 未登录场景下自动使用空字符串作为兜底值,不会触发模板解析错误
let email = /*[[${#authentication.getPrincipal().getUsername()}]]*/ '';
$('#changeMe').prop("href", "/delete?email="+email)
</script>
  1. 加登录态权限控制
    给删除按钮添加sec:authorize="isAuthenticated()"属性,未登录用户访问页面时不会渲染这个按钮,从根源避免未登录场景下的空值问题。

内容的提问来源于stack exchange,提问作者metatrone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:21:28