[JAVA] Étendez Thymeleaf pour implémenter des balises uniques (partie 1)

Cette fois, je vais résumer comment créer un processeur et étendre Thymeleaf. Le processeur a différentes méthodes d'extension, donc cette fois je vais résumer comment créer vos propres balises. (C'est comme une balise \ <th: block >.)

Voir ci-dessous pour savoir comment créer et étendre un UtilityObject vous-même. Extension de Thymeleaf (UtilityObject)

environnement

Comportement des balises auto-fabriquées

Créons une version simplifiée de la balise T: messagesPanel du Framework TERASOLUNA. Le comportement détaillé est le suivant.

<ul>
  <li>Message 1</li>
  <li>Message 2</li>
</ul>

--Si vous spécifiez le nom de la balise dans les attributs externalElement et innerElement de la balise, il sera utilisé pour la sortie.

<sample:messagesPanel outerElement="div" innerElement="span" />
↓
<div>
  <span>Message 1</span>
  <span>Message 1</span>
</div>

Créer une classe de processeur

Commençons par créer la classe Core Processor. Puisque nous voulons créer une balise cette fois, nous allons créer une classe qui hérite de AbstractElementTagProcessor. (Créé en référence à StandardBlockTagProcessor.)

Tout d'abord, le constructeur

public class MessagesPanelTagProcessor extends AbstractElementTagProcessor {

  public MessagesPanelTagProcessor(String dialectPrefix){
    super(TemplateMode.HTML, dialectPrefix, "messagesPanel", dialectPrefix != null, null, false, 100000);
  }

  //~ Omis ~

}

Appelez le constructeur de la classe parent. La signification des arguments est la suivante.

Puis méthode doProcess

Utilisez cette méthode pour un traitement spécifique.

public class MessagesPanelTagProcessor extends AbstractElementTagProcessor {

  //~ Omis ~

  protected void doProcess(ITemplateContext context, IProcessableElementTag tag, IElementTagStructureHandler structureHandler) {

    // (1)
    RequestContext requestContext =
                (RequestContext) context
                        .getVariable(SpringContextVariableNames.SPRING_REQUEST_CONTEXT);

    Map<String, Object> model = requestContext.getModel();
    Object messages = model.get("messageList");
    
    if (messages == null) {
      // (2)
      structureHandler.removeElement();
      return;
    }

    // (3)
    List<String> messageList = (List<String>) model.get("messageList");
    String outerElement =
          tag.getAttributeValue("outerElement") == null ? "ul" : tag
                    .getAttributeValue("outerElement");
    String innerElement =
            tag.getAttributeValue("innerElement") == null ? "li" : tag
                    .getAttributeValue("innerElement");
    
    // (4)
    IModelFactory modelFactory = context.getModelFactory();
    IModel iModel = modelFactory.createModel();
    iModel.add(modelFactory.createOpenElementTag(outerElement));
    for (String message : messageList) {
        iModel.add(modelFactory.createOpenElementTag(innerElement));
        iModel.add(modelFactory.createText(HtmlEscape.escapeHtml4Xml(message)));
        iModel.add(modelFactory.createCloseElementTag(innerElement));
    }
    iModel.add(modelFactory.createCloseElementTag(outerElement));

    // (5)
    structureHandler.replaceWith(iModel, false);
  }
}
Numéro d'article La description
(1) En obtenant le RequestContext, vous pouvez en obtenir le modèle.
(2) Pour supprimer la balise, utilisez la méthode removeElement de l'argument IElementTagStructureHandler.
(3) Pour obtenir la valeur spécifiée pour l'attribut de la balise, utilisez la méthode getAttributeValue de l'argument IProcessableElementTag.
(4) Créez un élément à l'aide de IModelFactory et ajoutez-le à IModel. Il existe plusieurs types de méthodes createOpenElementTag et vous pouvez également créer des balises en spécifiant des attributs. Si vous souhaitez spécifier une classe arbitraire, etc., vous pouvez la créer en utilisant this.
(5) Initialement écrit à l'aide de la méthode replaceWith<sample:messagesPanel />Remplacez la balise par l'élément que vous avez créé jusqu'à présent.

** * Une addition *** Apparemment, la méthode IModelFactory.createText affiche la balise HTML telle quelle lorsque la chaîne de caractères donnée en argument contient une balise HTML. Le StandardTextTagProcessor qui correspond au th: text de Thymeleaf utilise une bibliothèque appelée unbescape pour le traitement d'échappement, donc le traitement d'échappement doit être effectué en utilisant une bibliothèque similaire. L'échantillon ci-dessus a été modifié.

Créer une classe de dialecte

Vous devez créer la classe Dialog comme vous l'avez fait lorsque vous avez créé vous-même l'objet UtilityObject. Si vous avez déjà créé la classe Dialog, vous pouvez y ajouter.

Si vous ajoutez un processeur, vous devez implémenter l'interface IProcessorDialect, mais comme il existe une classe abstraite appelée AbstractProcessorDialect qui l'implémente, cette fois nous en hériterons.

public class SampleDialect extends AbstractProcessorDialect {

    public SampleDialect() {
        super("sample", "sample", 1000);
    }

    @Override
    public Set<IProcessor> getProcessors(String dialectPrefix) {
        Set<IProcessor> processors = new HashSet<>();
        processors.add(new MessagesPanelTagProcessor(dialectPrefix));
        return processors;
    }
}

Enregistrer le dialecte

Cela fait également la même chose que nous avons fait avec l'objet utilitaire. Veuillez vous référer à ce qui suit. https://qiita.com/d-yosh/items/edf6ac4e19a7f967a058#dialect%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B

Essayez de bouger

J'ai créé le contrôleur et le code HTML suivants et confirmé l'opération.

@Controller
public class HelloController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {

        model.addAttribute("messageList", Arrays.asList("Message 1","Message 2"));
        return "home";
    }
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
  <h1>Hello world!</h1>
  <hoge:messagesPanel />
  <hoge:messagesPanel outerElement="div" innerElement="span"/>
</body>
</html>

La sortie devrait ressembler à ceci:

<html><head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
  <h1>Hello world!</h1>
  <ul>
    <li>Message 1</li>
    <li>Message 2</li>
  </ul>
  <div>
    <span>Message 1</span>
    <span>Message 2</span>
  </div>
</body>
</html>

Où j'étais accro

Je ne savais pas comment obtenir le modèle.

Pour le moment, si je déboguais et vérifiais le contenu de l'argument, il semblait que je pouvais obtenir le RequestContext, alors j'ai essayé de l'obtenir à partir de là. Il y a peut-être un autre bon moyen ...

Après setBody, le premier tag est resté

IElementTagStructureHandler a une méthode appelée setBody, donc je me demandais si je devais l'utiliser. Ensuite, la balise \ <sample: messagesPanel / > a également été affichée. Lorsque j'ai vérifié, il y avait une méthode appelée removeTags, donc j'ai pensé que \ <sample: messagesPanel / > devrait disparaître si j'utilisais cela, mais cette fois, le contenu défini dans Body n'était pas affiché. Lorsque j'ai vérifié leurs classes d'implémentation, presque chaque méthode a appelé une méthode appelée resetAllButVariablesOrAttributes, et celle-ci a renvoyé les informations de configuration à l'état initial. Si vous souhaitez conserver la première balise active, utilisez setBody, et si vous souhaitez supprimer la première balise, utilisez replaceWith.

Recommended Posts

Étendez Thymeleaf pour implémenter des balises uniques (partie 1)
Étendre Thymeleaf (UtilityObject)
Introduction à Ratpack (9) --Thymeleaf
Je souhaite implémenter une fonction d'édition des informations produit ~ part1 ~