SlingModels: Могу ли я добавить запрос SlingHttpServletRequest при адаптации из 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})

Который работает сейчас для reuqest а также resource

Код JSP:

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

Это правильный способ сделать это или есть способ адаптироваться от resource и еще сможет вводить request?

3 ответа

Решение

Вы не можете этого сделать, потому что ресурс не осведомлен о SlingHttpServletRequest. Если вам нужен запрос в вашей модели, сделайте его адаптируемым из запроса.

Была какая-то библиотека, которая позволяла это делать. Он использовал фильтр, чтобы сохранить текущий запрос в 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 не всегда возможно. И принимая во внимание тот факт, что вы всегда адаптируетесь из одного класса, даже если у вас есть более одного класса в поле адаптируемых (если вы адаптируетесь из запроса, у вас есть ресурс через getResource, а в случае, если вы принимаете из ресурса объект slingRequest поле будет пустым).

Это был мой случай, я должен был принять от Ресурса, и мне пришлось ввести некоторые вещи в мою модель слинга. Для этого я использовал 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

Я создал такой класс утилиты:

      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 после того, как вы закончите работу над ним. Если вы не сделаете это правильно, это может привести к утечке памяти.

Другие вопросы по тегам