Saviez-vous que vous pouvez créer un flux RSS dans AEM (Adobe Experience Manager) pour des applications externes comme Eloqua ? Bien qu’AEM fournisse des fonctionnalités prêtes à l’emploi pour les flux RSS, leur personnalisation peut nécessiter des étapes supplémentaires. Vous trouverez ci-dessous plusieurs options pour créer des flux RSS dans AEM ainsi que les étapes pour en créer un à l’aide de HTL.
3 options pour créer un flux RSS dans AEM
- Remplacer la fonctionnalité JSP par défaut (approche JSP)
- Personnalisez le code JSP pour adapter le flux RSS en fonction de vos besoins
- Cette approche nécessite d’écrire une logique backend en Java et JSP
- Créer un servlet pour le flux RSS
- Implémentez la logique au sein du servlet pour récupérer et formater les données nécessaires dans le flux RSS XML
- Configurer le servlet pour répondre à des demandes spécifiques pour le point de terminaison du flux RSS
- Cette approche permet plus de contrôle et de flexibilité sur le processus de génération de flux RSS
- Utiliser HTL avec le modèle Sling (approche HTL)
- Écrire des modèles HTL combinés à un modèle Sling pour générer le flux RSS
- Tirez parti des modèles Sling pour récupérer des données d’AEM et les formater dans le modèle HTL
- Cette approche utilise le langage de création de modèles et les modèles de composants modernes d’AEM.
- HTL est préféré pour les tâches de création de modèles en raison de sa simplicité et de sa lisibilité
Flux RSS attendu
Vous trouverez ci-dessous la réponse du flux permettant à une source externe d’intégrer et d’envoyer des e-mails en conséquence. Ici, les résultats du flux peuvent être filtrés par noms de balises de catégorie (catégorie) à l’aide des paramètres de requête dans l’URL du flux.
- https://www.demoproject.com/products/aem.rss
- https://www.demoproject.com/products/aem.rss?category=web
<?xml version="1.0" encoding="UTF-8"?> <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> <channel> <atom:link rel="self" href="https://www.demoproject.com/products/aem" /> <link>https://www.demoproject.com/products/aem</link> <title>AEM</title> <description /> <pubDate>Fri, 29 Sep 2023 02:08:26 +0000</pubDate> <item> <guid>https://www.demoproject.com/products/aem/one.rss.xml</guid> <atom:link rel="self" href="https://www.demoproject.com/products/aem/sites" /> <link>https://www.demoproject.com/products/aem/sites</link> <title>Aem Sites</title> <description><![CDATA[AEM Sites is the content management system within Adobe Experience Manager that gives you one place to create, manage and deliver remarkable digital experiences across websites, mobile sites and on-site screens.]]></description> <pubDate>Tue, 31 Oct 2023 02:23:04 +0000</pubDate> </item> <item> <guid>https://www.demoproject.com/products/aem/two.rss.xml</guid> <atom:link rel="self" href="https://www.demoproject.com/products/aem/assets" /> <link>https://www.demoproject.com/products/aem/assets</link> <title>Aem Assets</title> <description><![CDATA[Adobe Experience Manager (AEM) Assets is a digital asset management system (DAM) that is built into AEM. It stores and delivers a variety of assets (including images, videos, and documents) with their connected metadata in one secure location.]]></description> <pubDate>Thu, 26 Oct 2023 02:21:19 +0000</pubDate> <category>pdf,doc,image,web</category> </item> </channel> </rss>
Étapes pour créer un flux RSS à l’aide de HTL
- Créez un fichier HTML sous le composant page
- Créez un modèle PageFeed Sling qui renvoie des données pour le flux RSS
- Ajouter une règle de réécriture dans le fichier de règles de réécriture du répartiteur
- Mettez à jour ignoreUrlParams pour les paramètres requis
Composant de page – RSS-html
Créez un fichier HTML avec le nom « rss.xml.html » sous page composant. « rss.html » ou « rss.xml.html » fonctionnent tous deux très bien pour cela. Ici, la convention de dénomination « rss.xml.html » indique qu’il génère des données XML. PageFeedModel fournit les données JSON de la page pour le flux attendu.
- La balise de catégorie est rendue uniquement lorsque les propriétés de la page sont créées avec des valeurs de balise
- CDATA (données de caractères) est une section du contenu de l’élément à restituer uniquement sous forme de données de caractères au lieu de balisage.
<?xml version="1.0" encoding="UTF-8"?>
<sly data-sly-use.model="com.demoproject.aem.core.models.PageFeedModel" />
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link rel="self" href="https://blogs.perficient.com/2024/05/03/create-an-rss-feed-using-htl/${model.link}"/>
${model.linkTag @ context="unsafe"}
<title>${model.title}</title>
<description>${model.subTitle}</description>
<pubDate>${model.publishedDate}</pubDate>
<sly data-sly-list.childPage="${model.entries}">
<item>
<guid>${childPage.feedUrl}</guid>
<atom:link rel="self" href="${childPage.link}"/>
${childPage.linkTag @ context="unsafe"}
<title>${childPage.title}</title>
<description><![CDATA[${childPage.description}]]></description>
<pubDate>${childPage.publishedDate}</pubDate>
<sly data-sly-test="${childPage.tags}">
<category>${childPage.tags}</category>
</sly>
</item>
</sly>
</channel>
</rss>
Modèle de flux de page
Il s’agit d’un modèle de composant qui prend currentPage comme racine et récupère une liste de ses pages enfants. Par la suite, il construit dynamiquement des propriétés telles que la date de publication et les catégories en fonction du champ de balise de la page. Ces propriétés permettent de filtrer les résultats en fonction des paramètres de requête. Une fois implémenté, vous pouvez intégrer de manière transparente ce modèle dans votre composant pour restituer le flux RSS.
- En utilisant currentPage, obtenez les propriétés de la page actuelle sous forme de carte de valeurs
- Récupérer le titre, la description, la date de publication, le lien vers la page actuelle
- Récupérer le titre, la description, la date de publication, le lien, les balises (catégories) pour les pages enfants
- Filtrer la liste des pages enfants en fonction de la valeur du paramètre de requête (catégorie)
//PageFeedModel sample code package com.demoproject.aem.core.models; import com.adobe.cq.export.json.ExporterConstants; import com.day.cq.commons.Externalizer; import com.day.cq.commons.jcr.JcrConstants; import com.day.cq.wcm.api.Page; import com.day.cq.wcm.api.PageFilter; import com.demoproject.aem.core.utility.RssFeedUtils; import lombok.Getter; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.SlingException; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.models.annotations.DefaultInjectionStrategy; import org.apache.sling.models.annotations.Exporter; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.SlingObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.inject.Inject; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; @Model(adaptables = { Resource.class, SlingHttpServletRequest.class }, resourceType = PageFeedModel.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) public class PageFeedModel { protected static final String RESOURCE_TYPE = "demoproject/components/page"; private static final Logger logger = LoggerFactory.getLogger(PageFeedModel.class); @SlingObject ResourceResolver resourceResolver; @SlingObject SlingHttpServletRequest request; @Inject private Page currentPage; @Getter private String title; @Getter private String link; @Getter private String linkTag; @Getter private String description; @Getter private List < ChildPageModel > entries; @Inject private Externalizer externalizer; @Getter private String feedUrl; @Getter private String publishedDate; @PostConstruct protected void init() { try { ValueMap properties = currentPage.getContentResource().adaptTo(ValueMap.class); title = StringEscapeUtils.escapeXml(null != currentPage.getTitle() ? currentPage.getTitle() : properties.get(JcrConstants.JCR_TITLE, String.class)); description = StringEscapeUtils.escapeXml(properties.get(JcrConstants.JCR_DESCRIPTION, String.class)); link = RssFeedUtils.getExternaliseUrl(currentPage.getPath(), externalizer, resourceResolver); feedUrl = link + ".rss.xml"; linkTag = RssFeedUtils.setLinkElements(link); String category = request.getParameter("category") != null ? request.getParameter("category").toLowerCase().replaceAll("\\s", "") : StringUtils.EMPTY; entries = new ArrayList < > (); Iterator < Page > childPages = currentPage.listChildren(new PageFilter(false, false)); while (childPages.hasNext()) { Page childPage = childPages.next(); ChildPageModel childPageModel = resourceResolver.getResource(childPage.getPath()).adaptTo(ChildPageModel.class); if (null != childPageModel) { if (StringUtils.isBlank(category)) entries.add(childPageModel); else { String tags = childPageModel.getTags(); if (StringUtils.isNotBlank(tags)) { tags = tags.toLowerCase().replaceAll("\\s", ""); List tagsList = Arrays.asList(tags.split(",")); String[] categoryList = category.split(","); boolean flag = true; for (String categoryStr: categoryList) { if (tagsList.contains(StringEscapeUtils.escapeXml(categoryStr)) && flag) { entries.add(childPageModel); flag = false; } } } } } } publishedDate = RssFeedUtils.getPublishedDate(properties); } catch (SlingException e) { logger.error("Repository Exception {}", e); } } }
//ChildPageModel package com.demoproject.aem.core.models; import com.adobe.cq.export.json.ExporterConstants; import com.day.cq.commons.Externalizer; import com.day.cq.commons.jcr.JcrConstants; import com.demoproject.aem.core.utility.RssFeedUtils; import lombok.Getter; import org.apache.commons.lang.StringEscapeUtils; import org.apache.sling.api.SlingException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.models.annotations.DefaultInjectionStrategy; import org.apache.sling.models.annotations.Exporter; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.SlingObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.inject.Inject; @Model(adaptables = { Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) public class ChildPageModel { private static final Logger logger = LoggerFactory.getLogger(ChildPageModel.class); @SlingObject Resource resource; @Getter private String title; @Getter private String link; @Getter private String linkTag; @Getter private String feedUrl; @Getter private String description; @Getter private String publishedDate; @Getter private String tags; @Inject private Externalizer externalizer; @PostConstruct protected void init() { try { if (null != resource) { String url = resource.getPath(); ResourceResolver resourceResolver = resource.getResourceResolver(); link = RssFeedUtils.getExternaliseUrl(url, externalizer, resourceResolver); feedUrl = link + ".rss.xml"; linkTag = RssFeedUtils.setLinkElements(link); ValueMap properties = resource.getChild(JcrConstants.JCR_CONTENT).adaptTo(ValueMap.class); title = StringEscapeUtils.escapeXml(properties.get(JcrConstants.JCR_TITLE, String.class)); description = StringEscapeUtils.escapeXml(properties.get(JcrConstants.JCR_DESCRIPTION, String.class)); publishedDate = RssFeedUtils.getPublishedDate(properties); tags = StringEscapeUtils.escapeXml(RssFeedUtils.getPageTags(properties, resourceResolver)); } } catch (SlingException e) { logger.error("Error: " + e.getMessage()); } } }
//RSS Feed Utils package com.demoproject.aem.core.utility; import com.day.cq.commons.Externalizer; import com.day.cq.commons.jcr.JcrConstants; import com.day.cq.tagging.Tag; import com.day.cq.tagging.TagManager; import com.day.cq.wcm.api.NameConstants; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ValueMap; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @desc RSS Feed Utils */ @Slf4j public class RssFeedUtils { public static final String FORMAT_DATE = "E, dd MMM yyyy hh:mm:ss Z"; public static final String CONTENT_PATH = "/content/demoproject/us/en"; public static String getPublishedDate(ValueMap pageProperties) { String publishedDate = StringUtils.EMPTY; SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT_DATE); Date updatedDateVal = pageProperties.get(JcrConstants.JCR_LASTMODIFIED, pageProperties.get(JcrConstants.JCR_CREATED, Date.class)); if (null != updatedDateVal) { Date replicatedDate = pageProperties.get(NameConstants.PN_PAGE_LAST_REPLICATED, updatedDateVal); publishedDate = dateFormat.format(replicatedDate); } return publishedDate; } public static String getExternaliseUrl(String pagePath, Externalizer externalizer, ResourceResolver resourceResolver) { String url = StringUtils.EMPTY; if (StringUtils.isNotBlank(pagePath) && null != externalizer && null != resourceResolver) url = externalizer.publishLink(resourceResolver, resourceResolver.map(pagePath)).replace(CONTENT_PATH, ""); return url; } public static String setLinkElements(String link) { String url = StringUtils.EMPTY; if (StringUtils.isNotBlank(link)) { url = "<link>" + link + "</link>"; } return url; } public static String getPageTags(ValueMap properties, ResourceResolver resourceResolver) { String tags = StringUtils.EMPTY; String[] pageTags = properties.get(NameConstants.PN_TAGS, String[].class); if (pageTags != null) { List < String > tagList = new ArrayList < > (); TagManager tagManager = resourceResolver.adaptTo(TagManager.class); for (String tagStr: pageTags) { Tag tag = tagManager.resolve(tagStr); if (tag != null) { tagList.add(tag.getName()); } } if (!tagList.isEmpty()) tags = String.join(",", tagList); } return tags; } }
Modifications du répartiteur
demoproject_rewrites.rules
Dans le projet client réécrit.rules (/src/conf.d/rewrites) fichier ajoutez une règle de réécriture pour l’extension .rss. Cette règle de réécriture prend une URL se terminant par .rss et la réécrit pour pointer vers un fichier rss.xml correspondant dans le composant de page, modifiant ainsi l’extension de fichier de .rss à .rss.xml.
#feed rewrite rule RewriteRule ^/(.*).rss$ /content/demoproject/us/en/$1.rss.xml [PT,L]
100_demoproject_dispatcher_farm.any
Définissez les paramètres d’URL qui ne doivent pas être mis en cache pour le flux RSS. Il est recommandé de configurer le paramètre ignoreUrlParams sous forme de liste verte. En tant que tel, tous les paramètres de requête sont ignorés et seuls les paramètres de requête connus ou attendus sont exemptés (refusés) d’être ignorés.
Lorsqu’un paramètre est ignoré pour une page, la page est mise en cache lors de sa demande initiale. Par conséquent, le système répond ensuite aux requêtes pour la page en utilisant la version mise en cache, quelle que soit la valeur du paramètre dans la requête. Ici, nous ajoutons des paramètres d’URL ci-dessous pour diffuser le contenu en direct comme requis par une application externe.
/ignoreUrlParams { /0001 { /glob "*" /type "allow" } /0002 { /glob "category" /type "deny" } /0003 { /glob "pubdate_gt" /type "deny" } /0004 { /glob "pubdate_lt" /type "deny" } }
Pourquoi HTL est-il meilleur ?
Nous pouvons utiliser cette approche pour produire n’importe quel flux XML, allant au-delà des flux RSS. Nous avons la possibilité d’ajouter des propriétés personnalisées pour adapter le flux à nos besoins spécifiques. De plus, nous pouvons facilement appliquer des filtres à l’aide de paramètres de requête.
Un grand merci à mon directeur, Grace Siwickipour son aide précieuse dans la réflexion sur la mise en œuvre et la réalisation de ce travail de blog.
Source link