首页 > 解决方案 > Thymeleaf 元素模型处理

问题描述

如何在我自己的元素模型处理器中正确处理 HTML 标记及其正文?例如,我有以下 HTML 结构:

<my:form id="some_id">
    <my:input type="text" name="input-1"/>
    <my:input type="number" name="input-2"/>
</my:form>

我想my:form通过添加一些生成的属性来更改包装标签,以便输出看起来像这样<form id="some_id" other-attr="_generated_value_">...</form>,并通过向每个输入添加一个带有表单 id 的属性来处理每个内部my:input(并且通常处理这些标签应该是) ,例如<input type="text" name="input-1" id="generated_1" form-id="some_id">。通常my:input由我的AbstractAttributeTagProcessor分机处理。

到目前为止,我已经AbstractElementModelProcessor像这样扩展了创建处理器:

public class MyFormProcessor extends AbstractElementModelProcessor {

    private static final String ELEMENT_NAME = "form";
    private static final int PRECEDENCE = 1000;

    public MyFormProcessor( final String dialectPrefix ) {
        super(
                TemplateMode.HTML,
                dialectPrefix, // dialect prefix - 'my' in this case
                ELEMENT_NAME,
                true, // filter by element name prefix
                null,
                false,
                PRECEDENCE
        );
    }


    @Override
    protected void doProcess( ITemplateContext context,
                              IModel model,
                              IElementModelStructureHandler structureHandler ) {
        // what goes here?
    }
}

处理器已正确注册,并将表单及其主体转换为一系列事件,但我尚未弄清楚如何model正确修改,因为我在其元素上找不到任何修改方法。

提前感谢您的任何指导!

标签: javaspringmodelthymeleafextending

解决方案


为了使您的示例正常工作,我需要更改您的自定义 Thymeleaf 输入结构:

<my:form id="some_id">
    <my:input type="text" name="input-1">
    <my:input type="number" name="input-2">
</my:form>

不同之处在于我不会自动关闭<my:input>标签(它们以>not结尾/>。这是为了反映目标“独立”<input>元素的结构,这些元素也不是自动关闭的。

我的方法处理输入 HTML 的整个片段 - 因此,如果您也已经有一个单独的<my:input>标签处理器,那么我认为这需要比这更高的优先级。

这是doProcess()方法,代码中有注释:

@Override
protected void doProcess(ITemplateContext context,
        IModel model,
        IElementModelStructureHandler structureHandler) {
    final IModelFactory modelFactory = context.getModelFactory();

    // first handle the form element:
    String formID = null;
    final ITemplateEvent formEvent = model.get(0);
    if (formEvent instanceof IOpenElementTag) {
        // retrieve the form's ID value:
        IOpenElementTag ele = (IOpenElementTag) formEvent;
        IAttribute attr = ele.getAttribute("id");
        formID = attr.getValue();
    }

    // build the attributes we want the form element to use:
    Map<String, String> formAttrs = new HashMap<>();
    formAttrs.put("id", formID);
    formAttrs.put("other-attr", "_generated_value_");
    // create the form element: 
    IOpenElementTag formOpen = modelFactory
            .createOpenElementTag("form", formAttrs,
                    AttributeValueQuotes.DOUBLE,
                    false);

    model.replace(0, formOpen);

    int idInt = 1; // used to increment ID values
    // the loop processes all of the elements inside the form's opening
    // and closing tags:
    for (int i = 1; i < model.size() - 1; i++) {
        final ITemplateEvent inputEvent = model.get(i);

        if (inputEvent instanceof IOpenElementTag) {
            IOpenElementTag ele = (IOpenElementTag) inputEvent;
            // we will add some more attributes here:
            Map<String, String> attrs = ele.getAttributeMap();
            attrs.put("form-id", formID);
            attrs.put("id", "generated_" + idInt++); // the "idInt++" is just a demo - use whatever sequence you want here

            IOpenElementTag openEle = modelFactory
                    .createOpenElementTag("input", attrs,
                            AttributeValueQuotes.DOUBLE,
                            false);
            model.replace(i, openEle);
        }
    }

}

最终结果 HTML 如下:

<form other-attr="_generated_value_" id="some_id">
    <input type="text" name="input-1" form-id="some_id" id="generated_1">
    <input type="number" name="input-2" form-id="some_id" id="generated_2">
</form>

笔记

你可以做更多的事情来重构代码。

此处显示的方法可能有替代(也许更好)的方法。使用 Thymeleaf,通常有不止一种方法可以做某事。


推荐阅读