【问题标题】:Thymeleaf: replace newline characters with <br>Thymeleaf:用 <br> 替换换行符
【发布时间】:2015-06-04 22:06:01
【问题描述】:

我有一个可能包含换行符的字段 (&lt;textarea name="desc" /&gt;),我想用对应的 HTML 替换它们:&lt;br /&gt;。我怎样才能做到这一点?我正在使用 Thymeleaf 2.1.4.RELEASE。

【问题讨论】:

  • 如果我将其理解为替换某些模型属性(未呈现的 HTML)中的文本字符,我是否遗漏了什么?如果是这样,那你为什么不在控制器中使用纯 Java 来做呢?
  • @HalleKnast:这种工作是特定于视图的。如果您添加另一个呈现 *.doc 文件的视图实现会发生什么?您最终会得到带有“
    ”的模型属性公开字符串,这些字符串在 .doc 格式中是无效的 - 这就是为什么它不是控制器的工作。

标签: java spring spring-mvc thymeleaf


【解决方案1】:

正如 dominik 所述,\n 换行不起作用。但是,您可以使用&amp;#10;

${#strings.replace(desc,'&#10;','&lt;br&gt;')}

或者通过转义来防止代码注入:

${#strings.replace(#strings.escapeXml(desc),'&#10;','&lt;br&gt;')}

【讨论】:

  • 只是为了帮助人们。 是换行符的 ASCII。它就像一个魅力:)
  • IntelliJ 在正确解析它时存在一些问题,但它在运行时确实有效。
【解决方案2】:

As in JSP,用简单明了是不行的

${#strings.replace(desc, '\n', '<br />')}

至少有两个问题:

  • '\n' 被底层表达式语言(在我的情况下为 SpEL,因为我使用 Spring MVC)视为由两个单独的字符组成的字符串文字:'\' 和 'n' 而不是单个换行符李>
  • 抛出异常,因为 Thymeleaf 底层 XML 解析器不允许将 &amp;lt;&amp;gt; 放入表达式中

我为第一个问题找到的解决方案是在控制器中设置换行符并将其传递给视图。

要解决第二个问题,您需要使用&amp;lt; 而不是&amp;lt;&amp;gt; 而不是&amp;gt;。还要记住,这意味着使用th:utext 而不是th:text

// in controller:
model.addAttribute("newLineChar", '\n');

// in view
${#strings.replace(desc, newLineChar, '&lt;br /&gt;')}

如果您使用的是 Thymeleaf + Spring(这意味着 Thymeleaf 将使用 SpEL 而不是 OGNL),您也可以使用 SpEL T operator。这样您就不必在控制器中声明换行变量,但请注意在这种情况下,换行符会因您的应用运行的操作系统而异:

${#strings.replace(desc, T(System).getProperty('line.separator'), '&lt;br /&gt;')}

我最终要使用的是上面的组合+定义public static final String LF = "\n";的Apache StringUtils:

${#strings.replace(desc, T(org.apache.commons.lang3.StringUtils).LF, '&lt;br /&gt;')}

【讨论】:

  • 真的吗?这对我不起作用,做一些微不足道的事情看起来很复杂
【解决方案3】:

可以使用自定义方言和属性处理器来处理此操作,而无需大量内联 SpEl 或 hack。

创建自定义属性处理器

public class NewlineAttrProcessor extends AbstractUnescapedTextChildModifierAttrProcessor
{
    public NewlineAttrProcessor()
    {
        super("nl2br");
    }

    @Override
    protected String getText(Arguments arguments, Element element, String attributeName)
    {
        final Configuration configuration = arguments.getConfiguration();

        final IStandardExpressionParser parser =
            StandardExpressions.getExpressionParser(configuration);

        final String attributeValue = element.getAttributeValue(attributeName);

        final IStandardExpression expression =
            parser.parseExpression(configuration, arguments, attributeValue);

        final String value = (String)expression.execute(configuration, arguments);
        return StringUtils.replace(value, "\n", "<br />");
    }

    @Override
    public int getPrecedence()
    {
        return 10000;
    }
}

您必须扩展AbstractUnescapedTextChildModifierAttrProcessor 处理器,否则您将获得&lt;br /&gt; 的html 实体标签,并且您实际上不会获得换行符。

创建自定义方言

要实现自定义方言,您需要这样的方言类:

public class MyCustomDialect extends AbstractDialect
{
    @Override
    public String getPrefix()
    {
        return "cd";
    }

    @Override
    public Set<IProcessor> getProcessors()
    {
        final Set<IProcessor> processors = new HashSet<>();
        processors.add(new NewlineAttrProcessor());
        return processors;
    }
}

getPrefix 方法的返回值用于调用您制作的任何自定义处理器。例如,Thymeleaf 使用th。我们在上面实现的自定义处理器正在寻找nl2br,所以要调用它,您可以使用cd:nl2br 属性而不是th:text

注册您的新方言

在您的主类中,您只需要创建一个@Bean,它将返回您方言类的一个新实例。

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public MyCustomDialect myCustomDialect()
    {
        return new MyCustomDialect();
    }
}

使用您的自定义处理器

最后,在您的模板文件中,您将有一个这样的 HTML 标记:

&lt;div cd:nl2br="${myObject.myField}"&gt;MY MULTILINE FIELD&lt;/div&gt;

有关实现自定义方言的更详尽指南,我推荐 Thymeleaf 文档:

【讨论】:

    最近更新 更多