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 , похоже, другого способа сделать это нет.
Вот несколько статей о том, как это сделать:
- https://github.com/Adobe-Consulting-Services/acs-aem-samples/blob/master/core/src/main/java/com/adobe/acs/samples/filters/impl/SampleThreadLocalFilter.java
- https://www.javacodegeeks.com/2012/05/threading-stories-threadlocal-in-web.html
- 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 после того, как вы закончите работу над ним. Если вы не сделаете это правильно, это может привести к утечке памяти.