Использование Struts Tiles + Spring Framework

Одной из фич Struts Framework, помимо MVC для веба, была библиотека тегов Tiles, идущая с ним. Тайлы много что могут, но главное что они помогают сделать наследования страниц. Да, так же как объекты, в корневом определяем базовые методы, а в предках что то переопределяем и добавляем новое.
При этом эта библиотека может использоваться и отдельно от Struts, она прекрасно интегрируется в Spring Framework.
Вот без тайлов как может выглядеть структура JSP страницы?

[инклюд хидера]
[тело страницы]
[инклюд футера]

Ну вроде так ничего сложного, типичный PHP стиль. А теперь допустим в хидере у нас что то меняется, например картинка раздела, подключается дополнительный css, JavaScript или еще что то. Вот тут все и начинается: в хидере пишется страшная логика охватывающая весь проект, которая, в зависимости от адреса, начинает что то включать/выключать, при инклюде передаются различные параметры, чтобы все это работало и т.д. Немного неудобно получается.

В Tiles это выглядело бы по другому, головной темплейт:

начало хидера
картинка с [адресом]
[вставить доп. код]
конец хидера
[вставить тело страницы]
футер

а далее, на прочих страницах мы пишем что наследуем головной хидер, и что у него заменяем адрес картинки, тело страницы и иногда доп. код. Значения по умолчанию этих полей настраиваются в конфигурационном файле тайлов, и могут быть пустыми.
Вот так все бы это выглядело в виде JSP кода:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/tags/struts-tiles" prefix="tiles" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
      <title><tiles:getAsString name="title"/></title>
      <tiles:getAsString name="head" />
  </head>
  <body onload="<tiles:getAsString name="onLoad"/>">
      <div id="header">
      МойСуперПуперСайт!
      <h1><tiles:getAsString name="title"/></h1>
      </div>
      <tiles:getAsString name="body" />
      <div id="footer">
      копирайты, об авторе или что там надо внизу страницы
      </div>
  </body>
</html>

Вот это вот <tiles:getAsString... и вставляет, определённые в наследнике, блоки данных.
далее страница которая хочет это наследовать выглядит так:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/tags/struts-tiles" prefix="tiles" %>
<tiles:insert definition="layout.root" flush="false">
  <tiles:put name="title">О сайте</tiles:put>
  <tiles:put name="body" direct="true">
     Всякий текст
  </tiles:put>
</tiles:insert>

Можно рассматривать это как наследование страниц, только в объекте мы переопределяем методы, а здесь куски html.

Настройка tiles в spring

<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles.TilesConfigurer"
          lazy-init="false">
   <property name="factoryClass">
       <value>org.apache.struts.tiles.xmlDefinition.I18nFactorySet</value>
   </property>
   <property name="definitions">
       <list>
           <value>/WEB-INF/tiles.xml</value>
       </list>
   </property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
    lazy-init="false">
    <property name="requestContextAttribute"><value>requestContext</value></property>
    <property name="viewClass">
        <value>org.springframework.web.servlet.view.tiles.TilesView</value>
    </property>
</bean>

В web.xml добавляем настройку кастомных jsp тегов:

<jsp-config>
    <taglib>
       <taglib-uri>/tags/struts-tiles</taglib-uri>
       <taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
    </taglib>
</jsp-config>

Настройка связей имен Tiles к файлам

Есть одна тонкость: полученные нами jsp напрямую не заработают если их указать в ModelAndView контроллера. Тут указывается лишь идентификатор тайла, а сами страницы настроены в WEB-INF/tiles.xml (это в нашем случае, а вообще в том файле который указан в значении definitions бина tilesConfigurer).
Это должен быть файлик примерно следующего вида:

<?xml version="1.0"?>
 <!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
       "http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">
<tiles-definitions>
    <definition name="layout.error" path="/tiles/common/errorLayout.jsp"/>
    <definition name="layout.simple" path="/tiles/common/simpleLayout.jsp">
         <put name="head" value=""/>
    </definition>
    <definition name="common.header" path="/tiles/common/header.jsp"/>
    <definition name="common.footer" path="/tiles/common/footer.jsp"/>
    <definition name="/index" path="/index.jsp"/>
    <definition name="user/login" path="/user/login.jsp"/>
    <definition name="404" path="/errors/404.jsp"/>
</tiles-definitions>

где name это имя тайла, а path это путь к существующей jsp. И приходится вот так прописывать все страницы, что нифига неудобно, особенно раздражает когда name и path на самом деле совпадают(как для index и user/login, отличается лишь тем что мне в name лень писать .jsp).

В общем как-то вот так.

  • http:// Six Apart

    >Вот это вот tiles:getAsString... и вставляет, определённые в наследнике, блоки данных.

    А что мешает вставить туда ПХП-переменные? Честно говоря, у меня складываеся впечателение, что ПХП-программеры изобретают велосипед и создают себе проблемы. Если в одном файле встречается больше одного тега

  • http:// igor

    Ничего не мешает. И этот элемент можно считать вставкой переменной.