SlingModels:从 Resource 适配时可以注入 SlingHttpServletRequest 吗?

SlingModels: Can I inject the SlingHttpServletRequest when adapting from Resource?

我是 SlingModels 的新手,注释还不是很清楚。我目前正在尝试将一些基本基础组件从 AEM 6.2 转换为使用 SlingModels。

对于图像组件,基金会JSP使用SlingHttpServletRequest 来设置ImageDoctype。所以我尝试了以下方法:

@Model(adaptables = {Resource.class})
public class ImageModel {
    @SlingObject
    private SlingHttpServletRequest request;

    @SlingObject
    private Resource resource;
}

但是有了这个 request 是空的。所以我改用:

@Model(adaptables = {SlingHttpServletRequest.class})

现在适用于 reuqestresource

JSP代码:

<sling:adaptTo adaptable="${slingRequest}" adaptTo="models.ImageModel" var="m"/>

这是正确的方法吗?还是有办法适应 resource 并且仍然能够注入 request

您不能那样做,因为 SlingHttpServletRequest 无法识别资源。如果您的模型中需要 Request,请使其适应 Request。

有一些图书馆允许这样做。它使用 Filter 将当前 Request 存储在 ThreadLocal 中,然后从中读取它,但我不推荐这种方法。 ThreadLocal 只是另一个全局的。

@Model(adaptables =  { SlingHttpServletRequest.class, Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class ImageModel {
    @Self 
    private Resource resource;

    @SlingObject
    private ResourceResolver resourceResolver;

    @SlingObject
    SlingHttpServletRequest slingRequest;
}

采用 SlingHttpServletRequest 并不总是可行的。并考虑到您总是从一个 class 适应这一事实,即使您在适应字段中有多个 class (如果您根据请求进行适应,您可以通过 getResource 获得资源并在如果您从资源中采用 slingRequest 对象字段将为空)。

那是我的情况,我不得不从 Resource 中采用,并且我不得不向我的 Sling 模型中注入一些东西。为此,我使用了 ThreadLocal,看起来没有其他方法可以做到这一点。

以下是有关如何执行此操作的一些文章:

  1. https://github.com/Adobe-Consulting-Services/acs-aem-samples/blob/master/core/src/main/java/com/adobe/acs/samples/filters/impl/SampleThreadLocalFilter.java
  2. https://www.javacodegeeks.com/2012/05/threading-stories-threadlocal-in-web.html
  3. https://github.com/luontola/dimdwarf/blob/453f7aee9efc364ebad80531c05081e255323c07/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/context/ThreadContext.java

我创建了一个 util class 这样的:

public final class SomeThreadContext {

    private static final ThreadLocal<Boolean> SOME_BOOLEAN_PROPERTY = new ThreadLocal<>();

    private SomeThreadContext() {
    }

    public static void setSomeFlag(boolean someFlag) {
        if (SOME_BOOLEAN_PROPERTY.get() != null) {
            throw new IllegalStateException("Flag already set up.");
        }
        SOME_BOOLEAN_PROPERTY.set(someFlag);
    }

    public static boolean isSomeFlagEnabled() {
        return SOME_BOOLEAN_PROPERTY.get() != null && SOME_BOOLEAN_PROPERTY.get();
    }

    public static void tearDown() {
        if (SOME_BOOLEAN_PROPERTY.get() == null) {
            throw new IllegalStateException("Flag already torn down.");
        }
        SOME_BOOLEAN_PROPERTY.remove();
    }
}

你应该在创建模型之前使用setSomeFlag(它可以是过滤器或其他地方),isSomeFlagEnabled应该在模型内部使用并且在结束使用模型后,您总是必须使用 tearDown(您可以在最后一个块中执行此操作)。

您可以根据需要拥有任意数量的参数,最重要的是在完成工作后始终清理您的 ThreadLocal。如果您没有正确执行此操作,可能会导致内存泄漏。