Thymeleaf + Spring: 去除默认元素 id
Thymeleaf + Spring: get rid of the default element id
在 Thymeleaf (2.1.4.RELEASE) 中使用 th:field
时,是否有任何方法可以抑制元素的自动生成 ID 属性?例如,给定代码:
<input type="text" th:field="*{year}" />
将产生以下 HTML:
<input type="text" id="year" name="year" value="" />
我要实现的是(没有id属性):
<input type="text" name="year" value="" />
在 JSP 中就像设置空 id 一样简单:
<form:input path="year" id="" />
但是 Thymeleaf 只是用默认生成的属性替换了这个空属性。
如果您不想在输入字段的 ID 中使用它,只需将值分配给 th:name 字段,
<input type="text" th:name="*{year}" />
会给你这样的输出,
<input type="text" name="2015" />
或者你可以在末尾使用一个字符串来让生成的id和name属性不同,像这样
<input type="text" th:name="*{year}" th:id="*{year} + '-year' " />
会给你输出,
<input type="text" name="2015" id="2015-year"/>
好的,我查看了 Thymeleaf 的源代码(2.1.4.RELEASE),在 Spring 方言中负责设置元素 id 的方法是 org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor.doProcess(...)
(source on Github) that calls org.thymeleaf.spring4.processor.attr.AbstractSpringFieldAttrProcessor.computeId(...)
(source on Github).如果你看computeId(...)
,你会发现没有简单的方法来设置空id。
所以我们需要用一种不简单的方式来做:) 这里是:
我创建了一个自定义方言并定义了一个自定义属性 noid
。标记如下所示:
<input type="text" th:field="*{year}" thex:noid="true" />
有一个很好的 tutorial 解释了如何在 Thymeleaf 中创建和使用自定义方言,下面是最重要的部分:属性处理器负责从给定元素中删除 id 属性。
重要注意事项:
- 高优先级值(9999)保证本处理器作为最后一个执行(所以本处理器执行后不会有其他处理器修改id)
- 修改类型设置为替换,因此我们将完全替换 id 元素的值
- removeAttributeIfEmpty(...) returns 是的,不言自明,如果为空则删除属性
- getModifiedAttributeValues(...) 将 id 设置为空值,因为上述方法 returns true,id 属性被删除
代码:
public class NoIdAttrProcessor extends AbstractAttributeModifierAttrProcessor {
public NoIdAttrProcessor() {
super("noid");
}
@Override
public int getPrecedence() {
return 9999;
}
@Override
protected ModificationType getModificationType(Arguments arguments, Element element, String attributeName, String newAttributeName) {
return ModificationType.SUBSTITUTION;
}
@Override
protected boolean removeAttributeIfEmpty(Arguments arguments, Element element, String attributeName, String newAttributeName) {
return true;
}
@Override
protected boolean recomputeProcessorsAfterExecution(Arguments arguments, Element element, String attributeName) {
return false;
}
@Override
protected Map<String, String> getModifiedAttributeValues(Arguments arguments, Element element, String attributeName) {
Map<String, String> values = new HashMap<>(1);
values.put("id", "");
return values;
}
}
在 Thymeleaf (2.1.4.RELEASE) 中使用 th:field
时,是否有任何方法可以抑制元素的自动生成 ID 属性?例如,给定代码:
<input type="text" th:field="*{year}" />
将产生以下 HTML:
<input type="text" id="year" name="year" value="" />
我要实现的是(没有id属性):
<input type="text" name="year" value="" />
在 JSP 中就像设置空 id 一样简单:
<form:input path="year" id="" />
但是 Thymeleaf 只是用默认生成的属性替换了这个空属性。
如果您不想在输入字段的 ID 中使用它,只需将值分配给 th:name 字段,
<input type="text" th:name="*{year}" />
会给你这样的输出,
<input type="text" name="2015" />
或者你可以在末尾使用一个字符串来让生成的id和name属性不同,像这样
<input type="text" th:name="*{year}" th:id="*{year} + '-year' " />
会给你输出,
<input type="text" name="2015" id="2015-year"/>
好的,我查看了 Thymeleaf 的源代码(2.1.4.RELEASE),在 Spring 方言中负责设置元素 id 的方法是 org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor.doProcess(...)
(source on Github) that calls org.thymeleaf.spring4.processor.attr.AbstractSpringFieldAttrProcessor.computeId(...)
(source on Github).如果你看computeId(...)
,你会发现没有简单的方法来设置空id。
所以我们需要用一种不简单的方式来做:) 这里是:
我创建了一个自定义方言并定义了一个自定义属性 noid
。标记如下所示:
<input type="text" th:field="*{year}" thex:noid="true" />
有一个很好的 tutorial 解释了如何在 Thymeleaf 中创建和使用自定义方言,下面是最重要的部分:属性处理器负责从给定元素中删除 id 属性。
重要注意事项:
- 高优先级值(9999)保证本处理器作为最后一个执行(所以本处理器执行后不会有其他处理器修改id)
- 修改类型设置为替换,因此我们将完全替换 id 元素的值
- removeAttributeIfEmpty(...) returns 是的,不言自明,如果为空则删除属性
- getModifiedAttributeValues(...) 将 id 设置为空值,因为上述方法 returns true,id 属性被删除
代码:
public class NoIdAttrProcessor extends AbstractAttributeModifierAttrProcessor {
public NoIdAttrProcessor() {
super("noid");
}
@Override
public int getPrecedence() {
return 9999;
}
@Override
protected ModificationType getModificationType(Arguments arguments, Element element, String attributeName, String newAttributeName) {
return ModificationType.SUBSTITUTION;
}
@Override
protected boolean removeAttributeIfEmpty(Arguments arguments, Element element, String attributeName, String newAttributeName) {
return true;
}
@Override
protected boolean recomputeProcessorsAfterExecution(Arguments arguments, Element element, String attributeName) {
return false;
}
@Override
protected Map<String, String> getModifiedAttributeValues(Arguments arguments, Element element, String attributeName) {
Map<String, String> values = new HashMap<>(1);
values.put("id", "");
return values;
}
}