本文介绍了传递给 Thymeleaf 片段的参考对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有一个 Parent 类,它在 ParentForm 支持类中作为母亲和父亲实例化了两次.Web 表单要求将每个父级的名字和姓氏验证为 NotNull.我专门为母亲"实例创建了一个 Thymeleaf 片段,但我想让该片段对两个 Parent 实例都通用:
<div class="form-row clearfix"><div th:classappend="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')} ? has-error : ''"><label class="control-label col-xs-12" th:classappend="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')} ? has-error: ''">妈妈的名字是什么?</label>
<div class="col-sm-11 col-sm-offset-1 col-xs-12"><div class="form-row form-group"><div th:classappend="${#fields.hasErrors('mother.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6"><div class="input-group"><label th:for="mother.firstName" class="control-label">First </label><input type="text" th:field="*{mother.firstName}" th:value="*{mother.firstName}" class="form-control"/>
<div th:classappend="${#fields.hasErrors('mother.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6"><div class="input-group"><label th:for="mother.lastName" class="control-label">Last </label><input type="text" th:field="*{mother.lastName}" th:value="*{mother.lastName}" class="form-control"/>
<div th:if="${#fields.hasErrors('mother.firstName') 或 #fields.hasErrors('mother.lastName')}" class="form-row clearfix has-error"><div class="help-block small"><ul><li th:each="err : ${#fields.errors('mother.firstName')}" th:text="${err}"></li><li th:each="err : ${#fields.errors('mother.lastName')}" th:text="${err}"></li>
Parent 类具有 firstName 和 lastName 以及使用标准命名约定的 getter/setter.这一切都按预期工作 - 验证、显示、绑定.
所以我试图通过将签名更改为类似 th:fragment="name(parent, parentType)" 并将mother"实例替换为parent"来使片段通用像这样的例子:
<div class="form-row clearfix"><div th:classappend="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')} ? has-error : ''"><label class="control-label col-xs-12" th:classappend="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')} ? has-error: ''" th:text="|${parentType} 的名字是什么?|"></label>
<div class="col-sm-11 col-sm-offset-1 col-xs-12"><div class="form-row form-group"><div th:classappend="${#fields.hasErrors('parent.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6"><div class="input-group"><label th:for="parent.firstName" class="control-label">First </label><input type="text" th:field="*{parent.firstName}" th:value="*{parent.firstName}" class="form-control"/>
<div th:classappend="${#fields.hasErrors('parent.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6"><div class="input-group"><label th:for="parent.lastName" class="control-label">Last </label><input type="text" th:field="*{parent.lastName}" th:value="*{parent.lastName}" class="form-control"/>
<div th:if="${#fields.hasErrors('parent.firstName') 或 #fields.hasErrors('parent.lastName')}" class="form-row clearfix has-error"><div class="help-block small"><ul><li th:each="err : ${#fields.errors('parent.firstName')}" th:text="${err}"></li><li th:each="err : ${#fields.errors('parent.lastName')}" th:text="${err}"></li>
其中parent"是对象的实例,而parentType"只是用于显示目的的父类型(例如mother"或father")的字符串值.
<div th:replace="fragments/survey/mother::name(*{mother}, 'mother')"></div>
我以这种方式尝试时遇到的错误:
Caused by: org.attoparser.ParseException:评估 SpringEL 表达式的异常:#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')"(模板:fragments/survey/mother" - 第 7 行,第 18 栏)引起:org.thymeleaf.exceptions.TemplateProcessingException:评估 SpringEL 表达式的异常:#fields.hasErrors('parent.firstName') 或 #fields.hasErrors('parent.lastName')"(模板:fragments/survey/mother"- 第 7 行,第 18 栏)
如何以通用方式引用#fields.hasErrors() 方法中的字段?
Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'parent' of bean class [gsmParentForm]: Bean property 'parent' 不可读或具有无效的 getter 方法:返回类型是否为getter 匹配 setter 的参数类型?
显然,bean 属性被命名为mother"和father",那么如何让这个通用片段绑定到mother"和father"而不是parent"?
解决方案
所以,首先你必须意识到对于诸如 th:field
和 #fields.hasErrors()
之类的东西code>,字符串结果必须匹配到支持对象的完整路径(而不是像 parent
这样的局部变量).你不能使用 *{parent.firstName}
因为 ParentForm 没有 getParent().getFirstName().为此,您必须使用预处理
不需要将对象传递给片段,您只需要对象名称即可.(就您而言,由于 parentType 已经有母亲或父亲,我将在示例中使用它们.)进行这些更改后,您的字段应如下所示:
<div th:classappend="${#fields.hasErrors(parentType + '.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6><div class="input-group"><label th:for="${parentType + '.firstName'}" class="control-label">First </label><input type="text" th:field="*{__${parentType}__.firstName}" class="form-control"/><div th:classappend="${#fields.hasErrors(parentType + '.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6"><div class="input-group"><label th:for="${parentType + '.lastName'}" class="control-label">Last</label><input type="text" th:field="*{__${parentType}__.firstName}" class="form-control"/>
另外,旁注...如果您使用 th:field
,则不必使用 th:value
.th:field
为您做到这一点.
I have a Parent class that is instantiated twice in ParentForm backing class as mother and father. The web form expects a first and last name to be validated for each Parent as NotNull. I created a Thymeleaf fragment specifically for the "mother" instance, but I want to make the fragment generic for both Parent instances:
<div class="form-group" th:fragment="name">
<div class="form-row clearfix">
<div th:classappend="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')} ? has-error : ''">
<label class="control-label col-xs-12" th:classappend="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')} ? has-error : ''">What is the mother's name?</label>
</div>
<div class="col-sm-11 col-sm-offset-1 col-xs-12">
<div class="form-row form-group">
<div th:classappend="${#fields.hasErrors('mother.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6">
<div class="input-group">
<label th:for="mother.firstName" class="control-label">First </label>
<input type="text" th:field="*{mother.firstName}" th:value="*{mother.firstName}" class="form-control"/>
</div>
</div>
<div th:classappend="${#fields.hasErrors('mother.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6">
<div class="input-group">
<label th:for="mother.lastName" class="control-label">Last </label>
<input type="text" th:field="*{mother.lastName}" th:value="*{mother.lastName}" class="form-control"/>
</div>
</div>
</div>
</div>
</div>
<div th:if="${#fields.hasErrors('mother.firstName') or #fields.hasErrors('mother.lastName')}" class="form-row clearfix has-error">
<div class="help-block small">
<ul>
<li th:each="err : ${#fields.errors('mother.firstName')}" th:text="${err}"></li>
<li th:each="err : ${#fields.errors('mother.lastName')}" th:text="${err}"></li>
</ul>
</div>
</div>
</div>
The Parent class has firstName and lastName along with the getters/setters using standard naming convention. This all works as expected - validation, display, binding.
So I'm trying to make the fragment generic by changing the signature to something like th:fragment="name(parent, parentType)" and replacing the "mother" instances to "parent" instances like so:
<div class="form-group" th:fragment="name(parent, parentType)">
<div class="form-row clearfix">
<div th:classappend="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')} ? has-error : ''">
<label class="control-label col-xs-12" th:classappend="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')} ? has-error : ''" th:text="|What is the ${parentType}'s name?|"></label>
</div>
<div class="col-sm-11 col-sm-offset-1 col-xs-12">
<div class="form-row form-group">
<div th:classappend="${#fields.hasErrors('parent.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6">
<div class="input-group">
<label th:for="parent.firstName" class="control-label">First </label>
<input type="text" th:field="*{parent.firstName}" th:value="*{parent.firstName}" class="form-control"/>
</div>
</div>
<div th:classappend="${#fields.hasErrors('parent.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6">
<div class="input-group">
<label th:for="parent.lastName" class="control-label">Last </label>
<input type="text" th:field="*{parent.lastName}" th:value="*{parent.lastName}" class="form-control"/>
</div>
</div>
</div>
</div>
</div>
<div th:if="${#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')}" class="form-row clearfix has-error">
<div class="help-block small">
<ul>
<li th:each="err : ${#fields.errors('parent.firstName')}" th:text="${err}"></li>
<li th:each="err : ${#fields.errors('parent.lastName')}" th:text="${err}"></li>
</ul>
</div>
</div>
</div>
Where "parent" is the instance of the object and "parentType" is simply the string value for the parent type (e.g. "mother" or "father") for display purposes.
<div th:replace="fragments/survey/mother::name(*{mother}, 'mother')"></div>
The errors that I get when I try it this way:
Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')" (template: "fragments/survey/mother" - line 7, col 18)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#fields.hasErrors('parent.firstName') or #fields.hasErrors('parent.lastName')" (template: "fragments/survey/mother" - line 7, col 18)
How can I reference the field in the #fields.hasErrors() method in a generic way?
Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'parent' of bean class [g.s.m.ParentForm]: Bean property 'parent' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
Obviously, the bean properties are named "mother" and "father," so how do I get this generic fragment to bind to "mother" and "father" rather than "parent?"
解决方案
So, first you have to realize that for stuff like th:field
and #fields.hasErrors()
, the string result has to match the complete path to the backing object (and not to a local variable like parent
). You cannot use *{parent.firstName}
because ParentForm has no getParent().getFirstName(). In order to do this, you have to use preprocessing
Instead of passing the object to the fragment, all you need is the object name. (In your case, since parentType already has mother or father, I'm going to use them in the examples.) After making these changes, your fields should look something like this:
<div th:classappend="${#fields.hasErrors(parentType + '.firstName')} ? has-error : ''" class="col-xs-12 col-sm-6">
<div class="input-group">
<label th:for="${parentType + '.firstName'}" class="control-label">First </label>
<input type="text" th:field="*{__${parentType}__.firstName}" class="form-control"/>
</div>
</div>
<div th:classappend="${#fields.hasErrors(parentType + '.lastName')} ? has-error : ''" class="col-xs-12 col-sm-6">
<div class="input-group">
<label th:for="${parentType + '.lastName'}" class="control-label">Last </label>
<input type="text" th:field="*{__${parentType}__.firstName}" class="form-control"/>
</div>
</div>
Also, a sidenote... if you are using th:field
, you do not have to use th:value
. th:field
does that for you.
这篇关于传递给 Thymeleaf 片段的参考对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
08-21 00:16