Изучение Grails: Oсвежите ваше приложение Grails

Придайте свежий вид своему приложению с помощью CSS, шаблонов, библиотек тегов и т. д.

В этой статье серии Изучение Grails Скотт Дэвис рассказывает о том, как можно радикально поменять внешний вид приложения Grails при помощи каскадных таблиц стилей (CSS), шаблонов, библиотек тегов и других технологий.

Скотт Дэвис, главный редактор, AboutGroovy.com

Скотт Дэвис (Scott Davis) является международно признанным автором, лектором и разработчиком программного обеспечения. Среди его книг: Groovy Recipes: Greasing the Wheels of Java, GIS for Web Developers: Adding Where to Your Application, The Google Maps API и JBoss At Work.



25.06.2010

Минул год с момента выхода первой статьи серии "Изучение Grails". Как и было обещано в последней статье 2008 г., в новом году будут продемонстрированы новые приложения. Итак, скажите "до свидания" программе планирования путешествий и встречайте систему для работы с блогами.

Мы будем называть это приложение Blogito. Можно считать, что это название произошло либо от испанского "маленький блог", либо от знаменитой цитаты Декарта: "Я мыслю – значит, я существую" (Cogito ergo sum). Полную версию исходного кода можно загрузить с сайта blogito.org. Эта и следующая статьи посвящены разработке функциональности данного приложения.

В настоящей статье основное внимание уделяется тому, как можно радикально изменить внешний вид приложения Grails. Наше прошлогоднее приложение для путешественников выглядело пугающе, вероятно, понравиться оно могло только программистам (правда, если быть честным, то на тот момент функциональность была важнее интерфейса). Теперь же, немного подправив страницы CSS и несколько шаблонов, мы создадим Web-приложение, которое будет разительно отличаться от стандартного интерфейса Grails. Читая статью, вы также освежите в памяти такие аспекты Grails, как генерация каркасов (scaffolding), автоматическое присвоение временных меток, редактирование шаблонов по умолчанию, создание собственных библиотек тегов, а также настройка ключевых конфигурационных файлов, например Bootstrap.groovy и URLMapper.groovy.

Об этой серии

Grails – это современная инфраструктура для разработки Web-приложений, сочетающая использование знакомых Java-технологий, например, Spring и Hibernate, с такими популярными в настоящее время принципами, как соглашения по конфигурированию (convention over configuration). Будучи написанной на языке Groovy, Grails позволяет легко интегрировать старый Java-код в новые приложения, предоставляя гибкие возможности динамического скриптового языка. Изучение Grails навсегда изменит ваш взгляд на Web-разработку.

Однако вначале вам необходимо установить Grails 1.1, которая на момент написания этой статьи еще была в статусе бета-версии.

Установка Grails 1.1

Grails работает быстрее, если у вас установлена Java 1.5 или 1.6. Чтобы проверить версию Java, выполните команду java -version.

Убедившись в наличии Java 1.5 или 1.6, для установки Grails достаточно просто выполнить следующее.

  1. Download файл grails.zip с сайта Grails.
  2. Распаковать grails.zip.
  3. Создать переменную окружения GRAILS_HOME.
  4. Добавить каталог GRAILS_HOME/bin в переменную PATH.

Если у вас есть приложение, созданное на основе предыдущей версии Grail, то вы можете перевести его на последнюю версию, выполнив команду grails upgrade. Однако что делать, если требуется работать одновременно с несколькими версиями Grails?

При работе с UNIX®-подобной операционной системой (т.е. ОС семейства UNIX, Linux® или OS X) можно легко переключаться между различными версиями, используя символическую ссылку в качестве значения переменной окружения $GRAILS_HOME. Например, на моем компьютере GRAILS_HOME указывает на каталог /opt/grails, и я могу легко менять версию Grails при помощи команды ln -s, как показано в листинге 1.

Листинг 1. Создание символической ссылки для переменной $GRAILS_HOME в UNIX, Linux и Mac OS X
$ ln -s /opt/grails-1.1-beta1 grails

$ ls -l | grep "grails"
lrwxr-xr-x   1 sdavis  admin        17 Dec  5 11:12 grails -> grails-1.1-beta1/
drwxr-xr-x  14 sdavis  admin       476 Nov 10  2006 grails-0.3.1
drwxr-xr-x  16 sdavis  admin       544 Feb  9  2007 grails-0.4.1
drwxr-xr-x  17 sdavis  admin       578 Apr  6  2007 grails-0.4.2
drwxr-xr-x  17 sdavis  admin       578 Jun 15  2007 grails-0.5
drwxr-xr-x  19 sdavis  admin       646 Jul 30  2007 grails-0.5.6
drwxr-xr-x  18 sdavis  admin       612 Sep 18  2007 grails-0.6
drwxr-xr-x  19 sdavis  admin       646 Feb 19  2008 grails-1.0
drwxr-xr-x  18 sdavis  admin       612 Apr  5  2008 grails-1.0.2
drwxr-xr-x  18 sdavis  admin       612 Oct  9 21:46 grails-1.0.3
drwxr-xr-x  18 sdavis  admin       612 Nov 24 20:43 grails-1.0.4
drwxr-xr-x  18 sdavis  admin       612 Dec  5 11:13 grails-1.1-beta1

Если вы работаете под Windows®, то проще всего непосредственно изменять значение переменной %GRAILS_HOME%. При этом не забывайте каждый раз перезапускать все выполняющиеся командные интерпретаторы.

Выполните команду grails -version, чтобы убедиться в корректности значения переменной GRAILS_HOME и в том, что вы используете последнюю версию Grails. Результат команды должен выглядеть как в листинге 2.

Листинг 2. Результат выполнения команды grails -version
$ grails -version
Welcome to Grails 1.1-beta2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grails

После того как установлен Grails 1.1, можно переходить непосредственно к разработке нового приложения.


Разработка приложения

Выполните команду grails create-app blogito для создания структуры каталогов будущего приложения. Затем перейдите в каталог blogito и запустите команду grails create-domain-class Entry, которая создаст класс для представления записей в блоге. Далее откройте файл Entry.groovy в каталоге grails-app/domain и добавьте в него строки из листинга 3.

Листинг 3. Создание класса Entry
class Entry {
  static constraints = {
    title()
    summary(maxSize:1000)
    dateCreated()
    lastUpdated()
  }
  
  String title
  String summary
  Date dateCreated
  Date lastUpdated
}

Каждый экземпляр класса Entry содержит поля title и summary. Если задать ограничение maxSize равным 1000 символам, то простое текстовое поле в автоматически генерируемых формах HTML будет заменено на текстовую область summary.

Вопрос добавления содержимого записей будет рассмотрен в следующий раз

В одной из следующих статей мы добавим поле body, в котором будет храниться содержимое записи. Пока мы пропустим этот вопрос, поскольку для реализации поля body необходимо иметь представление о том, как в Grails реализована аутентификация и загрузка файлов на сервер. Blogito предоставляет пользователям возможность загружать различные типы содержимого – HTML, изображения и даже MP3 для аудиотрансляций.

Не забывайте, что поля dateCreated и lastUpdated выполняют специальную функцию в Grails. Они хранят временные метки, которые отлично подходят для приложений, работающих с блогами. В частности, они позволяют отображать наиболее свежие записи в начале списка.

Создав класс для представления объектов из предметной области, можно переходить к контроллеру. Выполните команду grails create-controller Entry и добавьте содержимое листинга 4 в файл grails-app/controllers/EntryController.groovy.

Листинг 4. Создание класса EntryController
class EntryController {
    def scaffold = Entry
}

Строка def scaffold = Entryвыглядит, на первый взгляд, просто, однако на самом деле представляет собой инструкцию, получив которую Grails сгенерирует остальную часть каркаса для поддержки класса Entry. Как вы скоро увидите, будет создана таблица entry, содержащая колонки, соответствующие каждому полю класса Entry, а также специальные колонки ID (первичный ключ) и version (для наложения оптимистических блокировок). Кроме того, будет сгенерирован полный набор серверных страниц Groovy (GSP), реализующих рутинные, но необходимые функции CRUD (для добавления, выборки, обновления и удаления записей).

Далее выполните команду grails run-app и откройте страницу с адресом http://localhost:8080/blogito в браузере. Кликните на ссылке EntryController, а затем на New Entry. Как видите, в форме ввода новой записи содержатся все поля класса Entry (рисунок 1). К сожалению, поля, соответствующие временным меткам, не должны быть доступны пользователям, поэтому придется подкорректировать шаблоны по умолчанию, чтобы устранить эту проблему.

Рисунок 1. Редактируемые временные метки в форме для создания экземпляров Entry
Редактируемые временные метки в форме для создания экземпляров Entry

Редактирование шаблонов по умолчанию

После выполнения команды grails generate-views Entry поля dateCreated и lastUpdated можно вручную удалить из файлов GSP, однако это скорее лечение симптомов, чем болезни. Скорее всего, данные поля никогда не должны фигурировать в формах для создания и редактирования записей, поэтому лучше изменить шаблон, применяющийся при выполнении def scaffold.

Для этого сначала выполните команду grails install-templates, а затем загляните в каталог src/templates/scaffolding, в котором находятся файлы create.gsp и edit.gsp. Добавьте dateCreated и lastUpdated в список excludedProps в каждом из файлов (листинг 5).

Листинг 5. Исключение полей с временными метками из шаблонов страниц list.gsp и show.gsp
excludedProps = ['version',
                 'id',
                 'dateCreated',
                 'lastUpdated',
                 Events.ONLOAD_EVENT,
                 Events.BEFORE_DELETE_EVENT,
                 Events.BEFORE_INSERT_EVENT,
                 Events.BEFORE_UPDATE_EVENT]

Перезапустите Grails и убедитесь, что эти поля больше не представлены в формах HTML (рисунок 2).

Рисунок 2. Форма без временных меток
Форма без временных меток

Изменение принципа сортировки записей

Начав добавлять новые записи, вы обнаружите, что по умолчанию они сортируются в порядке убывания ID. При этом сообщения в блогах, как правило, отображаются в обратном хронологическом порядке, т.е. наиболее свежие показываются вверху списка. В предыдущих версиях Grails для изменения порядка следования записей приходилось вручную редактировать код замыкания list в файле EntryController.groovy, добавляя две строки, показанные в конце листинга 6. С одной стороны, это несложно, но с другой – этот код уже не будет частью автоматически генерируемого каркаса приложения. (Если вас интересует реализация контроллера по умолчанию, то вы можете заглянуть в файл src/templates/scaffolding/Controller.groovy или выполнить команду grails generate-controller Entry.)

Листинг 6. Сортировка в Grails 1.0.x
def list = {
    if(!params.max) params.max = 10
    if(!params.sort) params.sort = "lastUpdated"
    if(!params.order) params.order = "desc"
    [ entryList: Entry.list( params ) ]
}

В Grails 1.1 появилась простая, но исключительно полезная конструкция в статическом блоке mapping – sort. Добавьте блок mapping, приведенный в листинге 7, в файл Entry.groovy. Теперь сортировка задается в классе модели, а следовательно можно по-прежнему использовать стандартный def scaffold в контроллере.

Листинг 7. Добавление конструкции sort в статический блок mapping
class Entry {
  static constraints = {
    title()
    summary(maxSize:1000)
    dateCreated()
    lastUpdated()
  }
  
  static mapping = {
    sort "lastUpdated":"desc"
  }  
    
  String title
  String summary
  Date dateCreated
  Date lastUpdated
}

Перезапустите Grails и проверьте, что вновь добавляемые записи действительно отображаются вверху, как показано на рисунке 3.

Рисунок 3. Новый порядок сортировки записей
Новый порядок сортировки записей

Создание тестовых записей в процессе разработки

Вы заметили, что созданные вами записи исчезают при каждом новом запуске Grails. Это не ошибка, так и было задумано. Таблица entry уничтожается и создается заново при каждом запуске Grails. В этом можно убедиться, заглянув в файл grails-app/conf/DataSource.groovy. Как видите, в режиме разработки значением db-create является create-drop.

Это значение можно заменить на update, но это также не лучший вариант. На начальных этапах разработки схема базы данных, как правило, нестабильна, поскольку постоянно добавляются и удаляются новые поля, модифицируются ограничения и т.д. Поэтому имеет смысл сохранить режим create-drop, пока все не стабилизируется.

Можно изменить файл grails-app/conf/BootStrap.groovy таким образом, чтобы избавиться от необходимости каждый раз вводить тестовые данные в процессе разработки. В листинге 8 приведен пример кода, который добавляет новые записи при каждом запуске Grails.

Листинг 8. Добавление тестовых записей в процессе разработки
import grails.util.GrailsUtil

class BootStrap {

  def init = { servletContext ->
    switch(GrailsUtil.environment){
      case "development":
        new Entry(
          title:"Grails 1.1 beta is out", summary:"Check out the new features").save()
        new Entry(
          title:"Just Released - Groovy 1.6 beta 2", summary:"It is looking good.").save()
      break

      case "production":
      break
    }

  }
  def destroy = {
  }
}

Перезапустив Grails, вы должны увидеть в таблице entry записи, показанные на рисунке 4.

Рисунок 4. Тестовые записи, добавляемые при старте приложения
Тестовые записи, добавляемые при старте приложения

Оформление списка

Автоматически сгенерированная HTML-таблица выглядит неплохо для начала, однако очевидно, что она не может претендовать на роль постоянного решения для Blogito. Как правило, страницы блогов показывают дату, заголовок и краткое содержание записей в вертикальном, а не горизонтальном порядке, причем записи расположены одна под другой.

Чтобы сделать соответствующие изменения, сначала выполните команду grails generate-views Entry. Страницы GSP, которые ранее являлись частью динамического каркаса, теперь должны появиться в каталоге grails-app/views/entry. Откройте файл list.gsp и измените заголовок с Entry List на Blogito. Далее удалите блоки <h1> и <g:if> и замените элемент <div class="list"> на фрагмент, показанный в листинге 9.

Листинг 9. Изменение внешнего вида страницы list.gsp
<div class="list">
 <g:each in="${entryInstanceList}" status="i" var="entryInstance">
  <div class="entry">
   <span class="entry-date">${entryInstance.lastUpdated}</span>
   <h2><g:link action="show" id="${entryInstance.id}"
   >${entryInstance.title}</g:link></h2>
   <p>${entryInstance.summary}</p>                
  </div>  
 </g:each>
</div>

Обратите внимание, насколько упростился код страницы. Теги <fieldValue> можно удалить, поскольку они привязывают поля классов модели к полям формы HTML, а на данной странице этого не требуется. Каждый экземпляр Entry помещается в именованный элемент <div>, а поле lastUpdated – в именованный элемент <span>. При помощи атрибутов class можно использовать стили CSS, о которых будет рассказано чуть ниже. Поля title и summary находятся внутри стандартных HTML-тегов для разметки заголовков и абзацев.

CSS 101: <div> или <span>

Некоторых разработчиков шокирует, когда вы начинаете рассуждать о CSS и других технологиях, которые чаще ассоциируются с работой дизайнера, чем программиста. Я совершенно согласен с мнением, что страницы CSS можно проектировать так, что они в итоге окажутся невероятно сложными. Однако, справедливо и обратное: простые CSS-страницы действительно очень просты.

Все элементы HTML можно разделить на две большие категории: теги уровня блока и последовательные (inline) теги. Теги первого типа, к которым относятся <h1>, <p> и <div>, используются для выделения крупного фрагмента содержимого страницы. Как правило, бразуер неявно добавляет символ перевода строки в конец каждого блочного элемента. Внешний вид тегов <h1> и <p> заранее определен. Тег <div> чаще всего используется для помещения в него фрагмента содержимого, т.к. далее ему можно будет присвоить имя и применить нужный стиль для оформления.

Последовательные элементы, например <a>, <strong> и <span>, как правило, используются для помещения в них одного или нескольких слов, а не целого абзаца. В конец этих тегов не добавляется перевод строки. Формат некоторых из них, например <strong> и <em>, задан жестко, подобно блочным элементам, в то время как к другим, например <span>, можно применить нужный стиль CSS.

Принцип именования элементов <span> и <div> может сбивать с толку начинающих. Все дело в том, что атрибуты classсодержатся во многих элементах на одной странице, поэтому имеет смысл создавать такие классы CSS, как, например, entry или entry-date, благодаря чему все одноименные элементы будут выглядеть одинаково. Имена этих классов на странице CSS должны начинаться с точки, например .entry или .entry-date.

Вам также могут встретиться элементы с атрибутом id. Значения этого атрибута должны быть уникальными в рамках одного документа HTML. Например, ниже мы создадим элемент <div id="header">. Это означает, что на этой странице может быть всего один заголовочный элемент. При описании стилей значения id должны начинаться с символа решетки, например #header.

Чтобы освежить свои знания CSS, обратитесь к разделу Ресурсы.

Обновите страницу со списком в браузере (см. рисунок 5). Пока сложно утверждать, что страница сильно улучшилась, однако для соответствующего оформления достаточно добавить лишь несколько простых инструкций CSS.

Рисунок 5. Новый список записей без CSS
Новый список записей без CSS

Добавьте CSS из листинга 10 в конец файла web-app/css/main.css.

Листинг 10. Изменение внешнего вида list.gsp при помощи CSS
/* Изменение внешнего вида Blogito */
.entry {
  padding-bottom: 2em;
}

.entry-date {
  color: #999;
}

Теперь снова обновите страницу в браузере. Как видите, страница стала выглядеть несколько более стильно (рисунок 6). Мы еще не закончили, но для начала она смотрится неплохо.

Рисунок 6. Новый список записей с применением CSS
Новый список записей с применением CSS

Создание библиотеки тегов Date

CSS 102: em или px

Просматривая стили в файле main.css, вы, наверное, заметили, что во многих случаях размер шрифта выражается в пикселах. Использование шрифтов фиксированного размера технически допустимо (и весьма распространено), однако может негативно влиять на удобство и простоту использования. В частности, такие шрифты будут проклинать пользователи с нарушениями зрения, а также те, кто предпочитают использовать огромные мониторы или микроскопические разрешения. Страницы, которые смотрятся хорошо на экране Web-разработчика, далеко не всегда выглядят привлекательно на огромном разнообразии других мониторов, начиная от дисплеев с диагональю как в кинотеатре, и заканчивая устройствами наподобие iPhone.

Использование пикселов в качестве единицы измерения в CSS вполне подходит для элементов фиксированного размера, например изображений. Однако, как правило, для указания размера шрифта лучше использовать относительные единицы, такие как em. 1em равен 100% размера шрифта по умолчанию в данном браузере, либо размеру родительского элемента. 2em в 2 раза больше размера по умолчанию и т.д.

За более подробной информацией обратитесь к разделу Ресурсы.

Теперь пришло время попробовать улучшить визуальное представление даты последнего редактирования (lastUpdated). Если вы планируете повторно использовать этот элемент, то лучше всего его поместить в библиотеку тегов (TagLib). Выполните команду grails create-tag-lib Date и добавьте код, показанный в листинге 11, в файл grails-app/taglib/DateTagLib.groovy.

Листинг 11. Класс DateTagLib
import java.text.SimpleDateFormat

class DateTagLib {
  def longDate = {attrs, body ->
    //разбор полученной даты
    def b = attrs.body ?: body()
    def d = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(b)
        
    //если атрибут format не задан, то использовать следующий
    def pattern = attrs["format"] ?: "EEEE, MMM d, yyyy"
    out << new SimpleDateFormat(pattern).format(d)
  }
}

Далее поместите поле lastUpdated в файле grails-app/views/entry/list.gsp в новый тег <g:longDate>, как показано в листинге 12.

Листинг 12. Использование тега <g:longDate> на странице list.gsp
<div class="entry">
  <span class="entry-date"><g:longDate>$
  {entryInstance.lastUpdated}</g:longDate></span>
  <h2>${entryInstance.title}</h2>                  
  <p>${entryInstance.summary}</p>                
</div>

Перезапустите Grails и обновите страницу в браузере. Вы должны увидеть даты в новом формате (рисунок 7).

Рисунок 7. Отображение дат в новом формате при помощи тега <g:longDate>
Отображение дат в новом формате при помощи тега <g:longDate>

Создание частичного шаблона

Размещение элементов на странице выглядит неплохо, и было бы целесообразно использовать такую же схему для show.gsp. Для этого создайте страницу _entry.gsp в каталоге grails-app/views/entry и добавьте в нее код из листинга 13 (разумеется, вы с тем же успехом можете скопировать его из list.gsp).

Листинг 13. Код _entry.gsp
<div class="entry">
 <span class="entry-date"><g:longDate>
 ${entryInstance.lastUpdated}</g:longDate></span>
 <h2><g:link action="show" id="${
 entryInstance.id}">${entryInstance.title}</g:link></h2>
 <p>${entryInstance.summary}</p>
</div>

Подредактируйте страницу list.gsp как показано в листинге 14, чтобы начать использовать новый частичный шаблон.

Листинг 14. Использование частичного шаблона _entry.gsp в list.gsp
<div class="list">
  <g:each in="${entryInstanceList}" status="i" var="entryInstance">
    <g:render template="entry" bean="${entryInstance}" var="entryInstance" />
  </g:each>
</div>

Теперь этот частичный шаблон можно также применить на странице show.gsp (листинг 15).

Листинг 15. Использование частичного шаблона _entry.gsp в show.gsp
<div class="body">
  <g:render template="entry" bean="${entryInstance}" var="entryInstance" />
  <div class="buttons">
    <!-- и так далее -->
  </div>
</div>

Обновите список в браузере. Он должен выглядеть в точности так же, как и ранее. Теперь нажмите на заголовок записи и убедитесь, что для ее показа применяется тот же шаблон.


Оформление заголовка

Как видите, приложение начинает принимать очертания, и пришло время заменить стандартный заголовок Grails на ваш собственный.

Вы не увидите ссылки на логотип Grails ни в list.gsp, ни в show.gsp. Как вы помните, Grails использует SiteMesh для компоновки страниц из различных частей. Если вы посмотрите в код страницы grails-app/views/layouts/main.gsp, то увидите, в каком месте включается файл grails_logo.jpg.

Создайте еще одни частичный шаблон под именем named _header.gsp в каталоге grails-app/views/layouts и добавьте в него фрагмент кода из листинга 16. Обратите внимание на то, что Blogito – это обратная ссылка на главную страницу.

Листинг 16. Код частичного шаблона _header.gsp
<div id="header">
  <p><g:link class="header-main" controller="entry">
  Blogito</g:link></p>
  <p class="header-sub">A tiny little blog</p>
</div>

Теперь измените main.gsp, включив в него файл _header.gsp, как показано в листинге 17.

Листинг 17. Использование нового шаблона _header.gsp на страницу main.gsp
<body>
  <div id="spinner" class="spinner" style="display:none;">
    <img src="${createLinkTo(dir:'images',file:'spinner.gif')}" 
    alt="Spinner" />
  </div> 
  <g:render template="/layouts/header"/>        
  <g:layoutBody />  
</body>

CSS 103: padding или margin

Модель, использующаяся в CSS для управления отступами внутри и снаружи блочных элементов, может на первый взгляд показаться несколько запутанной. В двух словах: атрибут padding увеличивает пространство внутри блока, а margin – пространство между блоком и внешними элементами.

padding используется в заголовке в листинге 18, чтобы увеличить промежуток между текстом и границей голубого прямоугольника. margin применяется, чтобы увеличить пространство вокруг голубого прямоугольника, т.е. между элементами header <div> и nav <div>.

Вы можете задать отступы для всех четырех сторон блока одновременно при помощи padding: 2em; или margin: 2em;. Для задания отступа с конкретной стороны используются атрибуты margin-top, margin-right, margin-bottom или margin-left. Можно даже указать разные отступы для каждой стороны в одной строке (см. листинг 18). Для этого необходимо запомнить порядок следования сторон: TRBL (верхняя, правая, нижняя, левая).

Более подробно модель оформления блоков в CSS описана по ссылкам в разделе Ресурсы.

Наконец, добавьте в to web-app/css/main.css стили, показанные в листинге 18.

Листинг 18. Стили CSS для частичного шаблона _header.gsp
#header {
  background: #67c;
  padding: 2em 1em 2em 1em;
  margin-bottom: 1em;
}

a.header-main:link, a.header-main:visited {
  color: #fff;
  font-size: 3em;
  font-weight: bold;
}

.header-sub {
  color: #fff;
  font-size: 1.25em;
  font-style: italic;
}

После обновления страница должна выглядеть как на рисунке 8. Нажмите на заголовке какой-либо записи, а затем вновь на ссылку Blogito вверху экрана, чтобы вернуться на главную страницу.

Рисунок 8. Новое оформление верхней части страницы
Новое оформление верхней части страницы

Скрытие панели навигации до момента аутентификации

Еще одним характерным признаком приложения Grails является навигационная панель. Несмотря на то что аутентификация пользователя будет реализована только в следующей статье, уже сейчас можно не показывать панель навигации пользователям, не выполнившим вход в систему. Для этого достаточно заключить элемент <div> панели в простую проверку <g:if>. Этот элемент проверяет наличие переменной user в области видимости сессии.

Измените страницы list.gsp и show.gsp как показано в листинге 19.

Листинг 19. Скрытие навигационной панели, если пользователь не аутентифицирован
<g:if test="${session.user}">
  <div class="nav">
      <span class="menuButton">
         <a class="home" href="${createLinkTo(dir:'')}">Home</a>
      </span>
      <span class="menuButton">
         <g:link class="create" action="create">New Entry</g:link>
      </span>
  </div>
</g:if>

Добавьте такую же проверку для кнопок на странице show.gsp (вы же не хотите, чтобы неаутентифицированные пользователи могли редактировать и удалять записи, правда?).

Наконец, добавьте еще один маленький штрих к странице list.gsp из эстетических соображений. Вынесите блок paginateButtons <div> из body <div> как показано в листинге 20. Таким образом, панель растянется на всю ширину экрана, улучшив восприятие нижней части страницы.

Листинг 20. Вынос блока paginateButtons <div> за пределы body <div> по эстетическим соображениям
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  <meta name="layout" content="main" />
  <title>Blogito</title>
 </head>
 <body>
  <g:if test="${session.user}">
   <div class="nav">
    <span class="menuButton">
      <a class="home" href="${createLinkTo(dir:'')}">Home</a>
    </span>
    <span class="menuButton">
      <g:link class="create" action="create">New Entry</g:link>
    </span>
   </div>
  </g:if>
   <div class="body">
    <div class="list">
     <g:each in="${entryInstanceList}" status="i" var="entryInstance">
      <g:render template="entry" bean="${entryInstance}" var="entryInstance" />
     </g:each>
    </div>
   </div>    
   <div class="paginateButtons">
    <g:paginate total="${Entry.count()}" />
   </div>
 </body>
</html>

Также добавьте фрагмент CSS, показанный в листинге 21, чтобы блок paginateButtons <div> отображался под body <div>, а не рядом с ним.

Листинг 21. CSS, гарантирующая, что блок paginateButtons <div> будет отображаться внизу экрана
.paginateButtons{
  clear: left;
}

Последний раз обновите страницу в браузере. Она должна выглядеть как на рисунке 9.

Рисунок 9. Скрытие навигационной панели
Скрытие навигационной панели

Задание домашней страницы

Теперь, когда все готово, осталось сделать EntryController домашней страницей по умолчанию. Для этого необходимо добавить связывание относительного пути / (последнего символа в URL http://localhost:9090/blogito/) с EntryController. Измените файл grails-app/conf/UrlMappings.groovy в соответствии с листингом 22.

Листинг 22. Задание EntryController в качестве домашней страницы по умолчанию
class UrlMappings {
    static mappings = {
      "/$controller/$action?/$id?"{
            constraints {
                   // добавьте ограничения здесь
              }
        }
        "/"(controller:"entry")
        "500"(view:'/error')
   }
}

Заключение

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

В следующей статье мы продолжим работу над приложением Blogito. Будет добавлен класс User, с помощью которого разные пользователи смогут добавлять записи. Вы также познакомитесь с кодеками Grails и поэкспериментируете с отображениями URL. Не забывайте, что полную версию приложения можно загрузить с сайта http://blogito.org. Пока же – получайте удовольствие от изучения Grails.

Ресурсы

Научиться

Получить продукты и технологии

  • Grails: загрузите последнюю версию Grails. (EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=498125
ArticleTitle=Изучение Grails: Oсвежите ваше приложение Grails
publish-date=06252010