Modèles JSP

Bien que les outils de développement Web progressent rapidement, ils sont toujours à la traîne par rapport à la plupart des boîtes à outils d'interface utilisateur graphique (GUI) telles que Swing ou VisualWorks Smalltalk. Par exemple, les boîtes à outils GUI traditionnelles fournissent des gestionnaires de mise en page, sous une forme ou une autre, qui permettent aux algorithmes de mise en page d'être encapsulés et réutilisés. Cet article explore un mécanisme de modèle pour JavaServer Pages (JSP) qui, comme les gestionnaires de disposition, encapsule la mise en page afin qu'elle puisse être réutilisée au lieu d'être répliquée.

Étant donné que la mise en page subit de nombreux changements au cours du développement, il est important d'encapsuler cette fonctionnalité afin qu'elle puisse être modifiée avec un impact minimal sur le reste de l'application. En fait, les gestionnaires de mise en page illustrent un exemple de l'un des principes de la conception orientée objet: encapsuler le concept qui varie, qui est également un thème fondamental pour de nombreux modèles de conception.

JSP ne fournit pas de support direct pour l'encapsulation de la mise en page, de sorte que les pages Web avec des formats identiques répliquent généralement le code de mise en page; par exemple, la figure 1 montre une page Web contenant des sections d'en-tête, de pied de page, de barre latérale et de contenu principal.

La mise en page de la page illustrée à la figure 1 est implémentée avec des balises de table HTML:

Exemple 1. Inclusion de contenu

Modèles JSP  
   
<% @ include file = "sidebar.html"%>
<% @ include file = "header.html"%>
<% @ include file = "introduction.html"%>
<% @ include file = "footer.html"%>

Dans l'exemple ci-dessus, le contenu est inclus avec la includedirective JSP , qui permet au contenu de la page de varier - en modifiant les fichiers inclus - sans modifier la page elle-même. Cependant, comme la mise en page est codée en dur, les changements de mise en page nécessitent des modifications de la page. Si un site Web comporte plusieurs pages avec des formats identiques, ce qui est courant, même de simples changements de mise en page nécessitent des modifications de toutes les pages.

Pour minimiser l'impact des modifications de mise en page, nous avons besoin d'un mécanisme pour inclure la mise en page en plus du contenu; de cette façon, la mise en page et le contenu peuvent varier sans modifier les fichiers qui les utilisent. Ce mécanisme est constitué de modèles JSP.

Utiliser des modèles

Les modèles sont des fichiers JSP qui incluent un contenu paramétré. Les modèles présentés dans cet article sont mis en œuvre avec un ensemble de balises personnalisées: template:get, template:putet template:insert. La template:getbalise accède au contenu paramétré, comme illustré dans l'exemple 2.a, qui produit des pages Web au format illustré à la figure 1.

Exemple 2.a. Un modèle

< template: get name = "title" />
   
< template: get name = "header" />

L'exemple 2.a est presque identique à l'exemple 1, sauf que nous utilisons à la template:getplace de la includedirective. Examinons comment template:getfonctionne.

template:getrécupère un bean Java avec le nom spécifié de la portée de la requête. Le bean contient l'URI (Uniform Resource Identifier) ​​d'un composant Web inclus par template:get. Par exemple, dans le modèle répertorié dans l'exemple 2.a, template:getobtient un URI - header.html- d'un bean nommé headerdans la portée de la requête. Par la suite, template:getcomprend header.html.

template:putplace les beans dans la portée de la requête qui sont ensuite récupérés par template:get. Le modèle est inclus avec template:insert. L'exemple 2.b illustre l'utilisation des balises putet insert:

Exemple 2.b. Utilisation du modèle de l'exemple 2.a

   
    insert template = "/ articleTemplate.jsp">
    
     put name = "title" content = "Templates" direct = "true" />
     
      put name = "header" content = "/ header.html" />
      
       put name = "sidebar" content = "/ sidebar.jsp" />
       
        put name = "content" content = "/ introduction.html" />
        
         put name = "footer" content = "/ footer.html" />
        
       
      
     
    
   

La insertbalise de début spécifie le modèle à inclure, dans ce cas le modèle répertorié dans l'exemple 2.a. Chaque putbalise stocke un bean dans la portée de la requête et la insertbalise de fin inclut le modèle. Le modèle accède ensuite aux beans comme décrit ci-dessus.

Un directattribut peut être spécifié pour template:put; si directest défini sur true, le contenu associé à la balise n'est pas inclus par template:get, mais est imprimé directement dans la outvariable implicite . Dans l'exemple 2.b, par exemple, le contenu du titre - Modèles JSP - est utilisé pour le titre de la fenêtre.

Les sites Web contenant plusieurs pages avec des formats identiques ont un modèle, tel que celui répertorié dans l'exemple 2.a, et de nombreuses pages JSP, telles que l'exemple 2.b, qui utilisent le modèle. Si le format est modifié, les modifications sont limitées au modèle.

Un autre avantage des modèles et de l'inclusion de contenu en général est la conception modulaire. Par exemple, le fichier JSP répertorié dans l'exemple 2.b inclut finalement header.html, répertorié dans l'exemple 2.c.

Exemple 2.c. header.html

   

Étant donné que le header.htmlcontenu est inclus, il n'a pas besoin d'être répliqué entre les pages qui affichent un en-tête. De plus, bien qu'il s'agisse d' header.htmlun fichier HTML, il ne contient pas le préambule habituel des balises HTML telles que ou parce que ces balises sont définies par le modèle. Autrement dit, comme le modèle inclut header.html, ces balises ne doivent pas être répétées dans header.html.

Remarque: JSP propose deux manières d'inclure du contenu: statiquement, avec la includedirective, et dynamiquement, avec l' includeaction. La includedirective inclut la source de la page cible au moment de la compilation et équivaut à C #includeou Java import. L' includeaction inclut la réponse de la cible générée lors de l'exécution.

Like the JSP include action, templates include content dynamically. So, although the JSP pages in Example 1 and Example 2.b are functionally identical, the former statically includes content, whereas the latter dynamically includes it.

Optional content

All template content is optional, which makes a single template useful to more Webpages. For example, Figure 2.a and Figure 2.b show two pages -- login and inventory -- that use the same template. Both pages have a header, footer, and main content. The inventory page has an edit panel (which the login page lacks) for making inventory changes.

Below, you'll find the template shared by the login and inventory pages:

 ... 
   
name='editPanel'/>
...

The inventory page uses the template listed above and specifies content for the edit panel:

   ... 
    ...  

In contrast, the login page does not specify content for the edit panel:


  

Because the login page does not specify content for the edit panel, it's not included.

Role-based content

Web applications often discriminate content based on a user's role. For example, the same JSP template, which includes the edit panel only when the user's role is curator, produces the two pages shown in Figures 3.a and 3.b.

The template used in Figures 3.a and 3.b uses template:get's role attribute:

 ... 
   
     ... 
     ... 
    
role='curator'/>
...

The get tag includes content only if the user's role matches the role attribute. Let's look at how the tag handler for template:get uses the role attribute:

public class GetTag extends TagSupport { private String name = null, role = null; ... public void setRole(String role) { this.role = role; } ... public int doStartTag() throws JspException { ... if(param != null) { if(roleIsValid()) { // include or print content ... } } ... } private boolean roleIsValid()  } 

Implementing templates

The templates discussed in this article are implemented with three custom tags:

  • template:insert
  • template:put
  • template:get

The insert tag includes a template, but before it does, put tags store information -- a name, URI, and Boolean value specifying whether content should be included or printed directly -- about the content the template includes. template:get, which includes (or prints) the specified content, subsequently accesses the information.

template:put stores beans in request scope but not directly because if two templates use the same content names, a nested template could overwrite the enclosing template's content.

To ensure that each template has access only to its own information, template:insert maintains a stack of hashtables. Each insert start tag creates a hashtable and pushes it on the stack. The enclosed put tags create beans and store them in the newly created hashtable. Subsequently, get tags in the included template access the beans in the hashtable. Figure 4 shows how the stack is maintained for nested templates.

Each template in Figure 4 accesses the correct footer; footer.html for template_1.jsp and footer_2.html for template_2.jsp. If the beans were stored directly in request scope, step 5 in Figure 4 would overwrite the footer bean specified in step 2.

Template tag implementations

The remainder of this article examines the implementation of the three template tags: insert, put, and get. We begin with sequence diagrams, starting with Figure 5. It illustrates the sequence of events for the insert and put tags when a template is used.

If a template stack does not already exist, the insert start tag creates one and places it in request scope. A hashtable is subsequently created and pushed on the stack.

Chaque putbalise de début crée un PageParameterbean, stocké dans la table de hachage créée par la insertbalise englobante .

La endbalise d' insertion comprend le modèle. Le modèle utilise des getbalises pour accéder aux beans créés par les putbalises. Une fois le modèle traité, la table de hachage créée par la insertbalise de début est retirée de la pile.

La figure 6 montre le diagramme de séquence pour template:get.

Modèles de listes de balises

Les implémentations de gestionnaire de balises pour les balises de modèle se révèlent simples. L'exemple 3.a répertorie la InsertTagclasse - le gestionnaire de balises pour template:insert.

Exemple 3.a. InsertTag.java