有这样的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 8 默认方法。它是必需的,因为 FreeMarker 基于
java.beans.Introspector
(官方 JavaBeans 内省器),而它忽略了它们。因此,正如 2.3.26 的版本历史记录所示(https://freemarker.apache.org/docs/versions_2_3_26.html):
添加了解决方法(默认情况下未启用)以将 Java 8 默认方法(以及它们定义的 bean 属性)公开给模板,尽管
(官方 JavaBeans 内省器)会忽略它们,至少从 JRE 1.8.0_66 开始是这样。要启用此解决方法,请将java.beans.Introspector
或incompatibleImprovements
的DefaultObjectWrapper
构造函数参数的值增加到 2.3.26,或者将其BeansWrapper
设置设置为 true。请注意,如果您将treatDefaultMethodsAsBeanMembers
的object_wrapper
设置保留为默认值,则将Configuration
的incompatibleImprovements
设置增加到 2.3.26 就足够了,因为它是由默认Configuration
继承的。object_wrapper
我的建议是增加
incompatibleImprovements
的 Configuration
设置。否则,会模拟一些令人惊讶的问题以实现 100% 向后兼容性。有一个关于如何设置它的页面:
https://freemarker.apache.org/docs/pgui_config_inknown_improvements.html#pgui_config_inknown_improvements_how_to_set