从自定义标记中注入spring标记中的动态属性

时间:2014-05-22 11:27:55

标签: spring java-ee spring-mvc tags dynamic-attributes

我有一个自定义的jsp标签,用于输出弹簧形式输入字段(以及其他布局元素)。我需要做的是能够接受动态属性并按原样在输入字段中使用它们。

例如使用:

<mytag:myinputtag arbitraryAttribute="value"/>

应输出

<input:form arbitraryAttribute="value" />

不幸的是,它没有按预期工作,因为它会抛出一个未终止的形式:输入标记异常。 以下是我使用的代码:

<%@ tag dynamic-attributes="attributes" %>
<c:set var="expandedAttributes">
  <c:forEach var="a" items="${ attributes }">
    ${a.key}="${a.value}"<%= " " %>
  </c:forEach> 
</c:set>

<form:input (...) ${expandedAttributes} />

我可以理解为什么由于EL expr和标签的分辨率顺序,它没有按预期工作。因此我还测试了使用scriptlet直接注入

<form:input (...) <%= (String)jspContext.getAttribute("expandedAttributes")%>  --%>

所以我需要一个解决这个问题的方法,因为我无法预览可以添加到输入的所有属性。因此我想到了以下几种可能性:

  • 使用<input代替<form:input,这意味着我必须完全复制&#34;路径&#34;的弹簧代码。属性(不是好主意)
  • 扩展表单:输入标记,将动态属性复制到默认属性中并执行标准标记呈现(不知道是否是一个可行的解决方案,如果spring更改其输入标记实现,那么它将无法正常工作)
  • 枚举我需要的所有属性,这会使标记代码变得庞大且难以维护

我想知道是否有一个更好的解决方案我还没有,或者第二种可能性是否可行。

由于

1 个答案:

答案 0 :(得分:1)

在这个问题上工作了一个月之后我已经考虑过删除和删除标记文件alltogheter

没有任何实现允许我按照我的意愿注入属性,所以我改变了方法并尝试生成一个标记,生成一个主体,然后对其进行评估。此方法也不起作用,因为jsp和标记在执行之前编译,因此无法在标记体中注入JSP代码。

所以我找到了一个目前有效的解决方案,它是这样的:

我创建了自己的输入标记,该标记从spring InputTag.java扩展而来。 此标记接受名为dynAttrs的特殊属性java.util.Map;这些是从我的父标记传递的动态属性。其余的有效/接受标记属性与spring输入标记相同。

然后在writeTagContent方法中,我检查dynAttrs是否可用,以及我所做的每个属性:

  • 如果属性是类字段,请使用PropertyAccessor设置值(例如onClick
  • 如果属性不是类字段(或字段不可写),那么它将被注入动态属性(例如data-customData

从这里开始,我只需要调用super.writeTagContent()和voilà,spring对我来说真的很神奇!

使用示例:

<my:customTextField path="model.path" attr1="val1" attr2="val2" disabled="true"/>

它将在

中转换
<div class="bla bla bla">
  <my:input path="model.path" disabled="true" dynAttrs="[{attr1,val1},{attr2,val2}]"/>
</div>

并在

中转换为流
<div class="bla bla bla">
  <form:input path="model.path" disabled="disabled" attr1="val1" attr2="val2"/>
</div>

然后将呈现为

<div class="bla bla bla">
  <input id="model.path" name="model.path" disabled="disabled" attr1="val1" attr2="val2"/>
</div>

所以我可以在运行时动态地在spring的输入标签中注入任意数量的动态属性!


注意:由于我不喜欢这种方法,但我已经为此解决方案准备了两个其他实现:

  • 使用apache common的 BeanUtils.populate 直接用dynAttrs填充标记,但在这种情况下错误管理可能很关键。

  • hashmap 中缓存此标记中的所有可访问字段,并使用field.setValue(this,dynAttrs.get(attrName))手动更新它们(应该更快,因为它不需要每个都检索字段打电话,但也许PropertyAccessor做同样的事情?)。