Dominando OGNL en Struts2: Expresiones y Símbolos Clave

OGNL (Object-Graph Navigation Language) es el motor de expresiones que Struts2 utiliza para enlazar datos entre la vista y los componentes del controlador. Permite navegar por el grafo de objetos, acceder a propiedades, invocar métodos y manipular colecciones mediante una sintaxis sencilla y uniforme. Por ejemplo, en un formulario de inicio de sesión, el atributo name de un campo aplica OGNL para asignar el valor a una propiedad del Action:

<input type="text" name="usuario"/>

En la página de bienvenida, la etiqueta <s:property value="usuario"/> recupera ese mismo valor directamente desde el ValueStack.

Uso básico de OGNL

Constantes y operadores

Se admiten las operaciones aritméticas y lógicas de Java. Las cadenas se delimitan con comillas simples o dobles, con una particularidad: un único carácter entre comillas simples se interpreta como char, por lo que para representar un String de un solo carácter es necesario escapar o emplear comillas dobles.

<s:property value=" 'hola' "/>   <%-- String 'hola' --%>
<s:property value="8 + 3 * 2"/> <%-- evalúa a 14 --%>

Invocación de métodos

Es posible llamar métodos de objetos presentes en el contexto. Más adelante se mostrarán ejemplos con métodos estáticos y con colecciones.

Acceso al ValueStack

Cuando una expresión OGNL no lleva prefijo, la búsqueda se realiza contra el ValueStack. Struts2 sitúa la instancia del Action en la cima de esta pila; por tanto, <s:property value="usuario"/> equivale a recorrer la pila desde la cima hasta encontrar la propiedad usuario del Action.

Acceso al ActionContext con

El símbolo # permite acceder a los objetos del ActionContext que no residen en el ValueStack:

  • #parameters : parámetros de la petición (request.getParameter())
  • #request : atributos del ámbito request
  • #session : atributos de sesión
  • #application : atributos del contexto de aplicación
  • #attr : busca en el orden request → session → application

Ejemplo integrado con sesión y aplicación

Se define un Action LoginAction que almacena datos en distintos ámbitos:

public class LoginAction extends ActionSupport {
    private String usuario;
    private String clave;

    public String execute() throws Exception {
        ActionContext ctx = ActionContext.getContext();
        ctx.getSession().put("usuario", "dato desde sesión");
        ctx.getApplication().put("mensajeApp", "Mensaje global");
        return SUCCESS;
    }
    // getters y setters omitidos
}

En la vista JSP se recuperan los valores con diversas variantes de OGNL:

<%@ taglib prefix="s" uri="/struts-tags" %>
<p>Usuario (ValueStack): <s:property value="usuario"/></p>
<p>Parámetro URL: <s:property value="#parameters.usuario"/></p>
<% request.setAttribute("datoRequest","valor en request"); %>
<p>Request: <s:property value="#request.datoRequest"/></p>
<p>Sesión: <s:property value="#session.usuario"/></p>
<p>Aplicación: <s:property value="#application.mensajeApp"/></p>
<p>Attr: <s:property value="#attr.usuario"/></p>

Métodos y propiedades estáticas con @

Para habilitar el acceso a métodos estáticos en versiones recientes de Struts2 es necesario añadir la siguiente constante en struts.xml:

<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>

Se crea una clase de utilidad con un campo y un método estático:

package com.ejemplo.util;
public class RecursosEstaticos {
    public static String VERSION = "2.5";
    public static void mostrarVersion() {
        System.out.println("Versión: " + VERSION);
    }
}

En el JSP se referencian mediante @ruta.completa@:

<s:property value="@com.ejemplo.util.RecursosEstaticos@VERSION"/>
<s:property value="@com.ejemplo.util.RecursosEstaticos@mostrarVersion()"/>

El símbolo # en profundidad

Acceso al contexto

Además de los mapas de ámbito (#request, #session, etc.), se puede usar la notación de corchetes: #session['usuario'] es equivalente a #session.usuario.

Filtrado y proyección sobre colecciones

Con {? condición} y la varible #this se filtran elementos de una lista:

<s:property value="usuarios.{? #this.edad > 18}"/>

Construcción de mapas

Se pueden definir mapas literales con #{clave:valor, ...}:

<s:set var="mapa" value="#{'idioma':'es','pais':'AR'}"/>
<s:property value="#mapa['idioma']"/>
<s:property value="#mapa.pais"/>

Símbolo % (forzar evaluación OGNL)

Cuando un atributo de etiqueta se trata como texto literal, %{expresión} obliga a interpretarlo como OGNL:

<s:url value="%{#mapa['idioma']}"/>

Símbolo $ (configuración e internacionalización)

En archivos de recursos i18n

Se puede acceder a valores del ValueStack dentro de los mensajes:

validacion.edad=La edad debe estar entre ${min} y ${max}

En validadores XML

<field-validator type="int">
  <param name="min">18</param>
  <param name="max">65</param>
  <message key="validacion.edad"/>
</field-validator>

Resultados dinámicos

En struts.xml se puede definir una vista que depende de una propiedad del Action:

<action name="iniciar" class="com.ejemplo.LoginAction">
  <result>${vistaDestino}</result>
</action>

El Action debe exponer el método getVistaDestino() y asignarle un valor como /bienvenido.jsp o /error.jsp según la lógica.

El símbolo @ para estándares del JDK

Además de las clases propias, se pueden envocar métodos estáticos de clases del JDK usando doble arroba @@. Esto evita escribir el nombre completo de la clase:

<s:property value="@@max(34, 78)"/>   <%-- Math.max --%>
<s:property value="@@min(10, 5)"/>    <%-- Math.min --%>

Etiquetas: OGNL struts2 ValueStack ActionContext EL

Publicado el 10-18 03:35