使用thymeleaf + spring创建自定义标签(就像JSP一样)

xeo*_*eon 2 spring-mvc thymeleaf

我正在尝试使用Thymeleaf创建自定义标记,就像在JSP中一样.我现在的标签是:

<select th:include="fragments/combobox :: combobox_beans (beans=${@accountService.getAccounts()}, innerHTML='id,description,currency', separator=' - ', dumbHtmlName='List of accounts', name='sender' )" th:remove="tag"></select>
Run Code Online (Sandbox Code Playgroud)

目的只是定义bean列表,要在屏幕上显示的bean的属性,它们之间的分隔符,显示为本机模板时的默认值,以及我们在此处理的原始bean的属性名称.

combobox.html:

<div th:fragment="combobox_beans (beans, innerHTML, separator, dumbHtmlName, name)">
<select th:field="*{__${name}__}" class="combobox form-control" required="required">
    <option th:each="obj : ${beans}" th:with="valueAsString=${#strings.replace( 'obj.' + innerHTML, ',', '+''  __${separator}__ ''+ obj.')}"
        th:value="${obj}" th:text="${valueAsString}" >            
        <p th:text="${dumbHtmlName}" th:remove="tag"></p>
    </option>
</select>
Run Code Online (Sandbox Code Playgroud)

我需要选项标签的文本基于片段的innerHTML属性(innerHTML ='id,description,devise')中设置的属性.我最终选择了这个文字:

<option value="...">obj.id+' - '+ obj.description+' - '+ obj.currency</option>
Run Code Online (Sandbox Code Playgroud)

而不是期望的结果

<option value="...">2 - primary - USD</option>
Run Code Online (Sandbox Code Playgroud)

我知道这是由于使用了Strings库导致字符串.有没有办法让Thymeleaf重新评估这个字符串再被理解为一个对象?

也许在这种情况下使用字符串库是错误的...也许我需要使用th:each将每个bean作为一个对象进行处理并读取它的属性,但是又如何只获取innerHtml中指定的属性?

任何人都有解决方案或解决方案吗?
谢谢.

irp*_*pbc 6

如果有办法在Thymeleaf/Spring表达单独做你想做的事情,那肯定是非常复杂和冗长的啰嗦,加上它可能是一个痛苦的阅读.

更简单的方法是将自定义实用程序对象添加到表达式上下文中.只需很少的代码.这个答案显示了它.

然后,您需要在Spring xml配置中将新方言添加为模板引擎的附加方言.假设你有一个相当标准的Spring配置,它应该与此类似.

<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
  <property name="templateResolver" ref="templateResolver" />
  <property name="additionalDialects">
    <set>
      <bean class="mypackage.MyUtilityDialect" />
    </set>
  </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

现在为实用程序对象

您想要的是按名称从对象获取属性,并将它们的值与分隔符组合.似乎属性名称列表可以是任何大小.要按名称访问属性,最方便的是使用像Apache beanutils这样的库.

使用Java 8流库,lambdas和Beanutils,您的自定义实用程序对象可能看起来像这样:

public class MyUtil {

  public String joinProperties(Object obj, List<String> props, String separator){
    return props.stream()
          .map(p -> PropertyUtils.getProperty(obj,p).toString())
          .collect(Collectors.joining(separator))
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,当您将方言添加到SpringTemplateEngine时,您可以调用您的实用程序:

th:with="valueAsString=${#myutils.joinProperties(obj,properties,separator)}"
Run Code Online (Sandbox Code Playgroud)

我已经用a 替换了你的innerHTML参数,因为它更有意义.它本质上是一个属性名称列表,Spring EL支持内联列表.propertiesList<String>

你的主叫标签应该是这样的.

<select th:include="fragments/combobox :: combobox_beans (beans=${@accountService.getAccounts()}, properties=${ {'id','description','currency'} }, separator=' - ', dumbHtmlName='List of accounts', name='sender' )" th:remove="tag"></select>
Run Code Online (Sandbox Code Playgroud)