Fermer

août 16, 2021

Chargement du contenu JSON dans AEM


Parlons de l'extraction, de la transformation et du chargement, également appelés ETL. Si vous êtes un professionnel AEM, c'est quelque chose que vous avez déjà traité. Il peut s'agir de produits, de biographies d'utilisateurs ou d'emplacements de magasins.

Les parties d'extraction et de transformation peuvent différer en fonction de votre source et de vos besoins. La partie chargement se fera presque toujours dans AEM. Bien qu'il puisse y avoir plusieurs façons de le faire, parlons de ce qui est prêt à l'emploi pour vous.

Sling Post Servlet

En tant que développeur AEM, le Sling Post Servlet est quelque chose que vous devriez connaître. En particulier, il existe une opération d'importation. Cela nous permet de faire ce qui suit :

curl -L https://www.boredapi.com/api/activity | 
curl -u admin:admin 
     -F":contentFile=@-" 
     -F":nameHint=activité" 
     -F":operation=import" 
     -F":contentType=json" 
     http://localhost:4502/content/mysite/us/en/jcr:content/root/container

Vous pouvez l'exécuter plusieurs fois. Vous obtiendrez des nœuds activity_* sous /content/mysite/us/en/jcr:content/root/container. Cela suppose que la source est déjà dans le format que vous désirez. Cela signifie que vous avez déjà effectué la partie transformation.

Et l'opération d'importation peut traiter des structures JSON plus complexes, même XML. Voici une sortie possible qui pourrait être fournie par une transformation :

{
    "jcr:primaryType": "cq:Page",
    "jcr:content": {
        "jcr:primaryType": "cq:PageContent",
        "jcr:title": "Ma page",
        "sling:resourceType": "monsite/composants/page",
        "cq:template": "/conf/mysite/settings/wcm/templates/page-content",
        "racine": {
            "jcr:primaryType": "nt:unstructured",
            "sling:resourceType": "monsite/composants/conteneur",
            "layout": "responsiveGrid",
            "récipient": {
                "jcr:primaryType": "nt:unstructured",
                "sling:resourceType": "monsite/composants/conteneur"
            }
        }
    }
}

Enregistrez-le dans un fichier nommé mypage.json et exécutez la commande curl suivante.

curl -u admin:admin 
     -F":nom=ma-page" 
     -F":contentFile=@mypage.json" 
     -F":operation=import" 
     -F":contentType=json" 
     -F":replace=true" 
     -F":replaceProperties=true" 
     http://localhost:4502/content/mysite/us/en

Et boum ! Vous avez une page instantanée. Cette fois, au lieu de :nameHintj'ai utilisé les propriétés :name et :replace. Exécuter à nouveau cette commande mettra à jour la page. La partie de chargement devient vraiment triviale et vous n'avez qu'à vous soucier de l'extraction et de la transformation. Heureusement, il est open source. Vous n'aurez pas à faire de décompilation aujourd'hui ! Lisons la fonction doPost de l'implémentation. Il y a trop de goodies dans lesquels nous pourrions plonger. Restons concentrés. Nous recherchons pour l'opération d'importation. L'avez-vous trouvé ?

Vous auriez dû vous retrouver avec la fonction doRun de ImportOperation.java. C'est là que tous ces paramètres de requête des commandes curl ci-dessus entrent en jeu. Descendez plus bas. Vous trouverez un appel à ContentImporter.importContent(Node, String, String, InputStream, ImportOptions, ContentImportListener). Pouvez-vous trouver son implémentation ?

Enfin, vous devriez vous retrouver avec l'implémentation DefaultContentImporter.java. Un composant OSGi qui implémente l'interface ContentImporter.

Utilisation par programme de l'importateur de contenu

Oui ! Faire des choses par programme . Maintenant que nous savons que le ContentImporter est disponible en tant que composant OSGi, tout ce dont nous avons besoin est :

@Reference
private ContentImporter contentImporter;

Et en supposant que vous ayez votre contenu via InputStreamnous pouvons importer le contenu sous n'importe quel nœud. À titre d'exemple, j'utilise le SimpleServlet généré dans le cadre de l'AEM Maven Archtype. J'utilise Lombok pour accélérer un peu les choses.

@Component(service = { Servlet.class })
@SlingServletResourceTypes(resourceTypes = "monsite/composants/page", méthodes = HttpConstants.METHOD_GET, extensions = "txt")
@ServiceDescription("Servlet de démonstration simple")
@Slf4j
la classe publique SimpleServlet étend SlingSafeMethodsServlet {

    privé statique final long serialVersionUID = 1L;

    @Référence
    privé ContentImporter contentImporter;

    @Passer outre
    DoGet void protégé (demande SlingHttpServletRequest finale, réponse finale SlingHttpServletResponse)
            jette
            IOException {

        final MyContentImportListener contentImportListener = new MyContentImportListener();
        nœud de nœud final = request.getResource().adaptTo(Node.class);

        if (nœud != null) {

            finale MyImportOptions importOptions = MyImportOptions.builder()
                                                                 .overwrite(true)
                                                                 .propertyOverwrite(true)
                                                                 .construire();
            essayez (InputStream inputStream = IOUtils.toInputStream("{"foo":"bar"}", StandardCharsets.UTF_8)) {
                this.contentImporter.importContent(node, "ma-structure-importée", "application/json", inputStream, importOptions, contentImportListener);
            } catch (final RepositoryException e) {
                log.error(e.getMessage(),e);
            }
        }

        response.setContentType("text/plain");
        response.getWriter().println(contentImportListener);

    }

    @Constructeur
    @Gettre
    classe finale statique privée MyImportOptions étend ImportOptions {

        enregistrement booléen final privé ;
        autoCheckout booléen final privé;
        écrasement booléen final privé ;
        private final boolean propertyOverwrite;

        @Passer outre
        public boolean isIgnoredImportProvider (extension de chaîne finale) { return false; }
    }

    @Gettre
    @ToString
    classe finale statique privée MyContentImportListener implémente ContentImportListener {

        modifications finales privées de com.google.common.collect.Multimap =
                com.google.common.collect.ArrayListMultimap.create();

        @Passer outre
        public void onReorder(final StringorderPath, final String beforeSibbling) {this.changes.put("onReorder", String.format("%s, %s",orderPath, beforeSibbling)); }

        @Passer outre
        public void onMove(final String srcPath, final String destPath) { this.changes.put("onMove", String.format("%s, %s", srcPath, destPath)); }

        @Passer outre
        public void onModify(final String srcPath) { this.changes.put("onModify", srcPath); }

        @Passer outre
        public void onDelete(final String srcPath) { this.changes.put("onDelete", srcPath); }

        @Passer outre
        public void onCreate(final String srcPath) { this.changes.put("onCreate", srcPath); }

        @Passer outre
        public void onCopy(final String srcPath, final String destPath) { this.changes.put("onCopy", String.format("%s, %s", srcPath, destPath)); }

        @Passer outre
        public void onCheckin(final String srcPath) { this.changes.put("onCheckin", srcPath); }

        @Passer outre
        public void onCheckout(final String srcPath) { this.changes.put("onCheckout", srcPath); }
    }
}

Conclusion

Tout d'abord, extrayez et transformez votre contenu dans la structure JSON souhaitée. Il doit représenter le contenu tel que vous le souhaitez. Ensuite, vous pouvez tirer parti de la fonction d'importation de Sling Post Servlet pour le rediriger vers AEM. Si vous devez être dans le contexte de l'instance AEM, vous pouvez utiliser le service Content Importer à la place.

En fin de compte, le chargement devient trivial, vous laissant vous concentrer sur l'exportation et la transformation les plus difficiles. Maintenant, consultez le blog de mon collègue qui décrit une façon de simplifier le processus de transformation.

À propos de l'auteur

Juan Ayala est un développeur principal dans la pratique Adobe chez Perficient, Inc. ., axé sur la plate-forme Adobe Experience et les éléments qui l'entourent.

En savoir plus sur cet auteur






Source link