Stuts2 - вывод данных с помощью OGNL

Без понимания того, как данные хранятся внутри Struts2, невозможно построить качественное приложение, в котором необходимо передавать между действиями не только отдельные параметры, но и целые масивы. На этой странице рассмотрим использование OGNL для вывода данных и ValueStack для их хранения.

Так что же означает аббревиатура OGNL? OGNL - Object-Graph Navigation Language. По-русски означает "Язык навигации по объектам-графам". Проще говоря, OGNL - это язык выражений, который определяет, как выводить данные в Struts2.

При рассмотрении Действия был приведен пример приветствия пользователя, в котором необходимо ввести свое имя, чтобы попасть на страницу Wellcome.jsp. На странице приветствия в теге

<s:property value="name" />,

имя пользователя извлекается и отображается. Это и есть простейшее OGNL выражение. Struts2 позволяет строить намного более сложные OGNL выражения. Данный фреймворк прекрасно понимает, что Вы передаете на вход тегу - строку или OGNL выражение.

В случаях, когда строка более уместна, но Вам по каким-либо причинам надо передать выражение, то нет проблем. Используйте конструкции вида %{выражение}, и Struts2 будет их сначала вычислять, а уже потом передавать как строчку. На странице Интернационализации рассмотрен пример работы с выражениями при выборе языка локализации.

Но как Struts2 хранит и извлекает данные? Чтобы понять это, необходимо рассмотреть ValueStack. В Struts2 данные хранятся в объекте ValueStack, которое представляет собой хранилище. Т.е., если в Action-классе определено отдельное свойство, например "caption", и массив объектов, допустим "userList", то все эти данные будут сохранены в ValueStack, из которого мы, используя OGNL, можем их извлекать.

Представление данных

OGNL - это мощный язык выражений, который используется для обращения к ValueStack, извлечению и обработке данных. Рассмотрим несложный пример представления списка пользователей на странице. Создадим Action-класс UserShow.
Листинг Action-класса UserShow.java
package examples.ognl; public class UserShow extends ActionSupport { private String caption; private List userList; public String execute() throws Exception { caption = "Список пользователей"; return Action.SUCCESS; } // ... get/set методы }

В данном классе в качестве свойств определен строковой заголовок caption и список пользователей userList. Для упрощения методы get/set, а также импортируемые пакеты (import ...) в листинге не представлены. Если кто-то заинтересуется вопросом локализации заголовка caption, то на странице Интернационализации данный вопрос рассмотрен.

Допустим объект User включает свойства name, login, email. Структура User представлена на странице Использования сессии. Отобразим список пользователей на странице UserShow.jsp

Листинг шаблона UserShow.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Список пользователей</title> </head> <body> <h1><s:property value="caption"/></h1> <table border="1" width="100%"> <tr><tn>Имя пользователя/><tn>Login</tn><tn>Email</tn></tr> <s:iterator value="userList" status="stat"> <tr> <td><s:property value = "userList [ #stat.index ].name" /></td> <td><s:property value = "userList [ #stat.index ].login" /></td> <td><s:property value = "userList [ #stat.index ].email" /></td> </tr> </s:iterator> </body> </html>

Полагаю, смысл тегов <s:property/> и <s:iterator> достаточно очевиден - это вывод значения и итерация по массиву данных.

Для того, чтобы это все сработало, необходимо в файле конфигурации struts.xml описать действие :
Листинг файла конфигурации struts.xml
<package name="Default" namespace="/" extends="struts-default"> ... <action name="UserShow" class="examples.ognl.UserShow"> <result name="success">/UserShow.jsp</result> </action> ... </package>

Таким образом, при вызове действия UserShow фреймворк выполняет Action-класс с одноименным названием и открывает страницу UserShow.jsp, на которой отображает значение свойства caption и в табличном виде параметры пользователей.

Внутренние объекты

Для доступа к внутренним объектам в OGNL используется синтаксис идентичный JSP EL. Если, например у нас есть объект OrderItem со свойством product типа Product, у которого есть свойства name, manufacturer и т.д., то получить значения свойств объекта можно, используя выражения либо orderItem.product.name, либо orderItem.product.manufacturer.

Элементы массивов и списков

В Struts2 реализован механизм доступа к отдельным элементам списка, которые можно вывести последовательно, используя тег , либо вывести отдельный элемент из списка используя синтаксис object[index]. Например, если необходимо вывести только второй элемент заказа, то можно использовать следующие выражения :

  <h2>Второй элемент заказа:</h2>
  
     Производитель <s:property value="order.items[1].product.manufacturer"/>
     Товар               <s:property value="order.items[1].product.name"/> 
     Цена                <s:property value="order.items[1].price"/>
     Количество      <s:property value="order.items[1].amount"/> 
     Сумма             <s:property value="order.items[1].total"/>