Plantillas JSP

Aunque las herramientas de desarrollo web están progresando rápidamente, todavía están por detrás de la mayoría de los kits de herramientas de interfaz gráfica de usuario (GUI), como Swing o VisualWorks Smalltalk. Por ejemplo, los kits de herramientas de GUI tradicionales proporcionan administradores de diseño, de una forma u otra, que permiten encapsular y reutilizar los algoritmos de diseño. Este artículo explora un mecanismo de plantilla para JavaServer Pages (JSP) que, al igual que los administradores de diseño, encapsula el diseño para que pueda reutilizarse en lugar de replicarse.

Debido a que el diseño sufre muchos cambios a lo largo del desarrollo, es importante encapsular esa funcionalidad para que pueda modificarse con un impacto mínimo en el resto de la aplicación. De hecho, los administradores de diseño demuestran un ejemplo de uno de los principios del diseño orientado a objetos: encapsular el concepto que varía, que también es un tema fundamental para muchos patrones de diseño.

JSP no proporciona soporte directo para encapsular el diseño, por lo que las páginas web con formatos idénticos suelen replicar el código de diseño; por ejemplo, la Figura 1 muestra una página web que contiene secciones de encabezado, pie de página, barra lateral y contenido principal.

El diseño de la página que se muestra en la Figura 1 se implementa con etiquetas de tabla HTML:

Ejemplo 1. Incluir contenido

Plantillas JSP  
   
<% @ include file = "sidebar.html"%>
<% @ include file = "header.html"%>
<% @ include file = "Introduction.html"%>
<% @ include file = "footer.html"%>

En el ejemplo mencionado anteriormente, el contenido se incluye con la includedirectiva JSP , lo que permite que el contenido de la página varíe, cambiando los archivos incluidos, sin modificar la página en sí. Sin embargo, debido a que el diseño está codificado de forma rígida, los cambios de diseño requieren modificaciones en la página. Si un sitio web tiene varias páginas con formatos idénticos, lo cual es común, incluso los cambios de diseño simples requieren modificaciones en todas las páginas.

Para minimizar el impacto de los cambios de diseño, necesitamos un mecanismo para incluir el diseño además del contenido; de esa manera, tanto el diseño como el contenido pueden variar sin modificar los archivos que los utilizan. Ese mecanismo son las plantillas JSP.

Usando plantillas

Las plantillas son archivos JSP que incluyen contenido parametrizado. Las plantillas descritas en este artículo se implementan con un conjunto de etiquetas personalizadas: template:get, template:put, y template:insert. La template:getetiqueta accede al contenido parametrizado, como se ilustra en el Ejemplo 2.a, que produce páginas web con el formato que se muestra en la Figura 1.

Ejemplo 2.a. Una plantilla

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

El ejemplo 2.a es casi idéntico al ejemplo 1, excepto que usamos en template:getlugar de la includedirectiva. Examinemos cómo template:getfunciona.

template:getrecupera un bean Java con el nombre especificado del alcance de la solicitud. El bean contiene el URI (Identificador uniforme de recursos) de un componente web incluido por template:get. Por ejemplo, en la plantilla listada en el Ejemplo 2.a, template:getobtiene un URI - header.html- de un bean nombrado headeren el alcance de la solicitud. Posteriormente, template:getincluye header.html.

template:putcoloca los beans en el ámbito de la solicitud que posteriormente recupera template:get. La plantilla se incluye con template:insert. El ejemplo 2.b ilustra el uso de las etiquetas puty insert:

Ejemplo 2.b. Usando la plantilla del Ejemplo 2.a

   
    insert template = "/ articleTemplate.jsp">
    
     poner nombre = "título" contenido = "Plantillas" directo = "verdadero" />
     
      poner nombre = "encabezado" contenido = "/ encabezado.html" />
      
       put name = "sidebar" content = "/ sidebar.jsp" />
       
        poner nombre = "contenido" contenido = "/ introducción.html" />
        
         put name = "footer" content = "/ footer.html" />
        
       
      
     
    
   

La insertetiqueta de inicio especifica la plantilla que se incluirá, en este caso la plantilla enumerada en el Ejemplo 2.a. Cada putetiqueta almacena un bean en el alcance de la solicitud y la insertetiqueta final incluye la plantilla. Posteriormente, la plantilla accede a los beans como se describe anteriormente.

Se directpuede especificar un atributo para template:put; si directse establece en true, el contenido asociado con la etiqueta no se incluye template:get, pero se imprime directamente en la outvariable implícita . En el Ejemplo 2.b, por ejemplo, el contenido del título (Plantillas JSP) se utiliza para el título de la ventana.

Los sitios web que contienen varias páginas con formatos idénticos tienen una plantilla, como la que se muestra en el Ejemplo 2.ay muchas páginas JSP, como el Ejemplo 2.b, que utilizan la plantilla. Si se modifica el formato, los cambios se limitan a la plantilla.

Otro beneficio de las plantillas y de la inclusión de contenido en general es el diseño modular. Por ejemplo, el archivo JSP que se enumera en el Ejemplo 2.b finalmente incluye header.html, que se enumera en el Ejemplo 2.c.

Ejemplo 2.c. header.html

   

Debido a que header.htmlse incluye contenido, no es necesario que se repita entre las páginas que muestran un encabezado. Además, aunque header.htmles un archivo HTML, no contiene el preámbulo habitual de las etiquetas HTML como o porque esas etiquetas están definidas por la plantilla. Es decir, debido a que la plantilla incluye header.html, esas etiquetas no deben repetirse en formato header.html.

Nota: JSP ofrece dos formas de incluir contenido: estáticamente, con la includedirectiva, y dinámicamente, con la includeacción. La includedirectiva incluye la fuente de la página de destino en el momento de la compilación y es equivalente a C #includeo Java import. La includeacción incluye la respuesta del objetivo generada en tiempo de ejecución.

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.

Cada putetiqueta de inicio crea un PageParameterbean, almacenado en la tabla hash creada por la insertetiqueta adjunta .

La endetiqueta de inserción incluye la plantilla. La plantilla utiliza getetiquetas para acceder a los beans creados por putetiquetas. Una vez que se procesa la plantilla, la tabla hash creada por la insertetiqueta de inicio se extrae de la pila.

La figura 6 muestra el diagrama de secuencia de template:get.

Listados de etiquetas de plantilla

Las implementaciones del controlador de etiquetas para las etiquetas de plantilla resultan sencillas. El ejemplo 3.a enumera la InsertTagclase: el controlador de etiquetas para template:insert.

Ejemplo 3.a. InsertTag.java