Freemarker.core.InvalidReferenceException 尝试验证用户输入时出现错误 Apache FreeMarker出租物业

问题描述 投票:0回答:1

有这样的ftlh文件和注册表:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Rental Property</title>
</head>
<body>
<h2>User Registration</h2>
<form action="/registration" method="POST">

    <label for="name">Name:</label>
    <input type="text" id="name" name="name" value="${userForm.name!}" required>
    <#if errors?? && errors?has_content && errors.hasFieldErrors("name")>
        <div style="color:red;">${errors.getFieldError('name').defaultMessage}</div>
    </#if>

    <label for="lastName">Last Name:</label>
    <input type="text" id="lastName" name="lastName" value="${userForm.lastName!}" required>
    <#if errors?? && errors?has_content && errors.hasFieldErrors("lastName")>
        <div style="color:red;">${errors.getFieldError("lastName").defaultMessage}</div>
    </#if>

    <label for="email">Email Address:</label>
    <input type="email" id="email" name="email" value="${userForm.email!}" required>
    <#if errors?? && errors?has_content && errors.hasFieldErrors("email")>
        <div style="color:red;">${errors.getFieldError("email").defaultMessage}</div>
    </#if>

    <label for="phone">Phone:</label>
    <input type="tel" id="phone" name="phone" value="${userForm.phone!}">
    <#if errors?? && errors?has_content && errors.hasFieldErrors("phone")>
        <div style="color:red;">${errors.getFieldError("phone").defaultMessage}</div>
    </#if>

    <label for="password">Password:</label>
    <input type="password" id="password" name="password" required>
    <#if errors?? && errors?has_content && errors.hasFieldErrors("password")>
        <div style="color:red;">${errors.getFieldError("password").defaultMessage}</div>
    </#if>

    <label for="replayPassword">Repeat Password:</label>
    <input type="password" id="replayPassword" name="replayPassword" required>
    <#if errors?? && errors?has_content && errors.hasFieldErrors("replayPassword")>
        <div style="color:red;">${errors.getFieldError("replayPassword").defaultMessage}</div>
    </#if>

    <label for="birthday">Date of Birth:</label>
    <input type="date" id="birthday" name="birthday">
    <#--    <#if errors?has_content && errors.hasFieldErrors("birthday")>-->
    <#--        <div style="color:red;">${errors.getFieldError("birthday").defaultMessage}</div>-->
    <#--    </#if>-->

    <button type="submit">Register</button>
</form>
</body>
</html>

有这样一种post请求处理方法:

@PostMapping("/registration")
    public String registration(@ModelAttribute @Valid UserForm userForm,
                               BindingResult result, Model model)
    {
        userValidator.validate(userForm, result);
        model.addAttribute("errors", result);
        if (result.hasErrors())
            return "registration";
        return "redirect:/";
    }

UserForm.java 类的每个字段上方是来自 jakarta.validation.constraints 的验证注释以及自定义验证器类。 当尝试在此控制器方法内发送有错误的数据时,验证将按其应有的方式工作,查找所有错误,并在尝试向用户显示不正确的数据时发生错误:

freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> errors.getFieldError('name')  [in template "registration.ftlh" at line 14, column 35]

----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
    - Failed at: ${errors.getFieldError("name").defaul...  [in template "registration.ftlh" at line 14, column 33]
----
    at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) ~[freemarker-2.3.33.jar:2.3.33]
    at freemarker.core.UnexpectedTypeException.newDescriptionBuilder(UnexpectedTypeException.java:85) ~[freemarker-2.3.33.jar:2.3.33]...

我尝试将 ftlh 文件中的错误键更改为单引号,更改验证,发送整个组装的 UserForm 对象。

java spring validation model-view-controller freemarker
1个回答
0
投票

我怀疑问题是您没有启用公开 Java 8 默认方法。它是必需的,因为 FreeMarker 基于

java.beans.Introspector
(官方 JavaBeans 内省器),而它忽略了它们。因此,正如 2.3.26 的版本历史记录所示(https://freemarker.apache.org/docs/versions_2_3_26.html):

添加了解决方法(默认情况下未启用)以将 Java 8 默认方法(以及它们定义的 bean 属性)公开给模板,尽管

java.beans.Introspector
(官方 JavaBeans 内省器)会忽略它们,至少从 JRE 1.8.0_66 开始是这样。要启用此解决方法,请将
incompatibleImprovements
DefaultObjectWrapper
BeansWrapper
构造函数参数的值增加到 2.3.26,或者将其
treatDefaultMethodsAsBeanMembers
设置设置为 true。请注意,如果您将
object_wrapper
Configuration
设置保留为默认值,则将
incompatibleImprovements
Configuration
设置增加到 2.3.26 就足够了,因为它是由默认
object_wrapper
继承的。

我的建议是增加

incompatibleImprovements
Configuration
设置。否则,会模拟一些令人惊讶的问题以实现 100% 向后兼容性。有一个关于如何设置它的页面: https://freemarker.apache.org/docs/pgui_config_inknown_improvements.html#pgui_config_inknown_improvements_how_to_set

© www.soinside.com 2019 - 2024. All rights reserved.