在Magnolia CMS中以编程方式渲染模板区域 [英] Programmatically render template area in Magnolia CMS

查看:88
本文介绍了在Magnolia CMS中以编程方式渲染模板区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Magnolia CMS 5.4,我想构建一个模块,该模块将呈现页面的某些内容并通过REST API公开它.该任务很简单,但不确定如何进行和/或从何处开始.

I am using Magnolia CMS 5.4 and I want to build a module that will render some content of a page and expose it over REST API. The task is simple but not sure how to approach it and/or where to start.

我希望我的模块为给定的引用生成部分模板或模板区域,假设这是页眉".我需要渲染标题模板/区域以获取HTML并将其返回作为对另一个系统的响应.

I want my module to generate partial template or an area of a template for a given reference, let's say that is "header". I need to render the header template/area get the HTML and return that as a response to another system.

所以问题是:这有可能吗?从哪里开始?

So questions are: is this possible at all and where to start?

推荐答案

在这里和在Magnolia论坛上提出问题后无法获得答案,我在源代码中进行了挖掘并找到了解决方法.

OK after asking here and on Magnolia forum couldn't get answer I dug in the source code and found a way to do it.

渲染的第一件事是基于不同的渲染器,这些渲染器可以是JCR,纯文本或Freemarker渲染器.在Magnolia中,这些决定并在RenderingEngine和实现中使用:DefaultRenderingEngine.渲染引擎将允许您渲染整个页面节点,这比我要实现的目标更近了一步.因此,让我们看看如何做到这一点:

First thing the rendering works based on different renderers and those could be JCR, plain text or Freemarker renderer. In Magnolia those are decided and used in RenderingEngine and the implementation: DefaultRenderingEngine. The rendering engine will allow you to render a whole page node which is one step closer to what I am trying to achieve. So let's see how could this be done:

我将跳过一些步骤,但是我添加了命令并使它可以在REST上运行,因此我可以看到将请求发送到端点时发生的情况.该命令扩展了BaseRepositoryCommand以允许访问JCR存储库.

I'll skip some steps but I've added command and made that work over REST so I could see what's happening when I send a request to the endpoint. The command extends BaseRepositoryCommand to allow access to the JCR repositories.

@Inject
public setDefaultRenderingEngine(
    final RendererRegistry rendererRegistry,
    final TemplateDefinitionAssignment templateDefinitionAssignment,
    final RenderableVariationResolver variationResolver,
    final Provider<RenderingContext> renderingContextProvider
) {
    renderingEngine = new DefaultRenderingEngine(rendererRegistry, templateDefinitionAssignment,
            variationResolver, renderingContextProvider);
}

这将创建您的渲染引擎,并且您可以从此处开始渲染具有少量小陷阱的节点.我曾尝试直接注入渲染引擎,但由于所有内部部件均为空/无效,因此无法正常工作,因此决定获取所有构造属性并初始化我自己的版本.

This creates your rendering engine and from here you can start rendering nodes with few small gotchas. I've tried injecting the rendering engine directly but that didn't work as all of the internals were empty/null so decided to grab all construct properties and initialise my own version.

下一步是我们要渲染页面节点.首先,渲染引擎基于为HttpServletResponse进行渲染并与请求/响应流紧密相关的想法而工作,尽管我们需要将生成的标记放入变量中,所以我添加了新的实现FilteringResponseOutputProvider:

Next step is we want to render a page node. First of all the rendering engine works based on the idea it's rendering for a HttpServletResponse and ties to the request/response flow really well, though we need to put the generated markup in a variable so I've added a new implementation of the FilteringResponseOutputProvider:

public class AppendableFilteringResponseOutputProvider extends FilteringResponseOutputProvider {

    private final FilteringAppendableWrapper appendable;

    private OutputStream outputStream = new ByteArrayOutputStream();

    public AppendableFilteringResponseOutputProvider(HttpServletResponse aResponse) {
        super(aResponse);

        OutputStreamWriter writer = new OutputStreamWriter(outputStream);
        appendable = Components.newInstance(FilteringAppendableWrapper.class);
        appendable.setWrappedAppendable(writer);
    }

    @Override
    public Appendable getAppendable() throws IOException {
        return appendable;
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        ((Writer) appendable.getWrappedAppendable()).flush();

        return outputStream;
    }

    @Override
    public void setWriteEnabled(boolean writeEnabled) {
        super.setWriteEnabled(writeEnabled);
        appendable.setWriteEnabled(writeEnabled);
    }
}

因此,该类的想法是公开输出流,并仍然保留FilteringAppendableWrapper,这将使我们可以过滤要编写的内容.通常情况下不需要这样做,您可以坚持使用AppendableOnlyOutputProviderStringBuilder可附加的内容,并轻松地检索整个页面标记.

So idea of the class is to expose the output stream and still preserve the FilteringAppendableWrapper that will allow us the filter the content we want to write. This is not needed in the general case, you can stick to using AppendableOnlyOutputProvider with StringBuilder appendable and easily retrieve the entire page markup.

// here I needed to create a fake HttpServletResponse
OutputProvider outputProvider = new AppendableFilteringResponseOutputProvider(new FakeResponse());

一旦有了输出提供程序,就需要一个页面节点,并且由于要伪造它,因此需要将Magnolia全局环境设置为能够检索JCR节点:

Once you have the output provider you need a page node and since you are faking it you need to set the Magnolia global env to be able to retrieve the JCR node:

// populate repository and root node as those are not set for commands
super.setRepository(RepositoryConstants.WEBSITE);
super.setPath(nodePath); // this can be any existing path like: "/home/page"
Node pageNode = getJCRNode(context);

现在我们有了内容提供者,并且要渲染的下一节点实际上正在运行渲染引擎:

Now we have the content provider and the node we want to render next thing is actually running the rendering engine:

renderingEngine.render(pageNode, outputProvider);
outputProvider.getOutputStream().toString();

就是这样,您应该呈现您的内容,并且可以随意使用它.

And that's it, you should have your content rendered and you can use it as you wish.

现在我们进入我的特殊情况,在这里我只想呈现整个页面的一个区域,在这种情况下,这就是页面的页眉.尽管您需要添加一个覆盖编写过程的渲染侦听器,但这全部由相同的renderingEngine处理.首先将其注入命令中:

Now we come to my special case where I want to render just an area of the whole page in this case this is the Header of the page. This is all handled by same renderingEngine though you need to add a rendering listener that overrides the writing process. First inject it in the command:

@Inject
public void setAreaFilteringListener(final AreaFilteringListener aAreaFilteringListener) {
    areaFilteringListener = aAreaFilteringListener;
}

这是发生魔术的地方,AreaFilteringListener将检查您当前是否正在渲染请求的区域,如果执行了此操作,则将启用输出提供程序进行写入,否则将其锁定并跳过所有不相关的区域.您需要像这样将侦听器添加到渲染引擎:

This is where the magic happens, the AreaFilteringListener will check if you are currently rendering the requested area and if you do it enables the output provider for writing otherwise keeps it locked and skips all unrelated areas. You need to add the listener to the rendering engine like so:

// add the area filtering listener that generates specific area HTML only
LinkedList<AbstractRenderingListener> listeners = new LinkedList<>();
listeners.add(areaFilteringListener);
renderingEngine.setListeners(listeners);

// we need to provide the exact same Response instance that the WebContext is using
// otherwise the voters against the AreaFilteringListener will skip the execution
renderingEngine.initListeners(outputProvider, MgnlContext.getWebContext().getResponse());

我听到你问:但是我们在哪里指定要渲染的区域?",啊哈来了:

I hear you ask: "But where do we specify the area to be rendered?", aha here is comes:

// enable the area filtering listener through a global flag
MgnlContext.setAttribute(AreaFilteringListener.MGNL_AREA_PARAMETER, areaName);
MgnlContext.getAggregationState().setMainContentNode(pageNode);

区域过滤侦听器正在检查要设置的特定木兰上下文属性:"mgnlArea",如果发现它将读取其值并将其用作区域名称,请检查该区域是否存在于节点中,然后启用写入操作一旦我们到达该地区.也可以通过以下网址使用此网址: https://demopublic.magnolia-cms. com/〜mgnlArea = footer〜.html ,这将为您提供作为HTML页面生成的页脚区域.

The area filtering listener is checking for a specific Magnolia context property to be set: "mgnlArea" if that's found it will read its value and use it as an area name, check if that area exists in the node and then enable writing once we hit the area. This could be also used through URLs like: https://demopublic.magnolia-cms.com/~mgnlArea=footer~.html and this will give you just the footer area generated as an HTML page.

这是完整的解决方案: http://yysource.com/2016/03/programatically-render-template-area-in-magnolia-cms/

here is the full solution: http://yysource.com/2016/03/programatically-render-template-area-in-magnolia-cms/

这篇关于在Magnolia CMS中以编程方式渲染模板区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆