Работа с Grails: Cоздание первого Grails-приложения

Узнайте, как много возможностей заключено в этой маленькой инфраструктуре для разработки Web-приложений

Программистам на Java™ не нужно отказываться от своего любимого языка и существующей инфраструктуры для разработки, чтобы воспользоваться современной инфраструктурой для разработки Web-приложений. В первой части новой ежемесячной серии статей "Работа с Grails" эксперт по Java Скотт Дэвис знакомит с Grails и показывает, как построить первое Grails-приложение.

Скотт Дэвис, главный редактор, 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.



21.09.2009

Знакомство с Grails я начну с другой бесплатной инфраструктуры для разработки Web-приложений: Ruby on Rails. Когда Rails появился, он увлек множество разработчиков. Возможности скаффолдинга, заложенные в Rails, позволяли запустить новый проект за меньшее время, чем раньше. Идея "соглашений по конфигурации" (convention over configuration), лежащая в основе Rails, позволяет приложению "собирать" себя самому, основываясь на разумных схемах именования, а не на громоздких и подверженных ошибкам конфигурационных XML-файлах. Возможности метапрограммирования Ruby позволяют объектам "магически" наследовать методы и поля, которые им требуются во время работы, без загромождения исходного кода.

Инфраструктур Rails заслужил и по-прежнему заслуживает того одобрения, которое он получил, но он ставит Java-разработчиков перед трудными вопросами. Стоит ли отказываться от известной Java-платформы из-за обещаний новой платформы? И что делать с существующим кодом Java, существующими корпоративными серверами и штатом опытных Java-программистов?

Об этой серии статей

Grails - это современный инфраструктур для разработки Web-приложений, который сочетает известные Java-технологии, такие как Spring и Hibernate, с современными приемами, такими как "соглашение по конфигурации". Написанный на Groovy, Grails прозрачно интегрируется с существующим Java-кодом, добавляя гибкость и динамику языков сценариев. После изучения Grails ваши взгляды на разработку Web-приложений изменятся бесповоротно.

Здесь на сцену выходит Grails. Grails предоставляет те же возможности разработки, что и Rails, при этом сохраняя прочную связь с проверенными Java-технологиями. Но Grails - это не просто "еще один клон" Rails, перенесенный на платформу Java. Grails усвоил уроки, полученные в Rails, и соединил их с современными веяниями в Java-программировании. Это скорее развитие Rails, чем просто перенос на новую платформу.

Открывая цикл "Работа с Grails", эта статья знакомит с инфраструктурой Grails, показывает, как установить ее, и шаг за шагом показывает процесс создания первого Grails-приложения: планировщика поездок, который будет использоваться в последующих статьях этой серии.

Возможности Groovy

Так же как Rails глубоко привязан к языку программирования Ruby, Grails не смог бы существовать без возможностей Groovy (см. раздел Ресурсы). Groovy - это динамический язык, работающий в JVM и прозрачно интегрирующийся с языком Java. Если вы читали многолетний цикл статей Practically Groovy на Web-сайте developerWorks, то вы уже знакомы с возможностями этого языка. Если же нет, то ничего страшного, в процессе изучения Grails придется узнать очень много и о Groovy. Это не должно быть сложно, так как Groovy был специально спроектирован так, чтобы понравиться Java-разработчикам.

Например, Groovy позволяет существенно сократить количество Java-кода, который обычно приходится писать. Не требуется писать get и set-методы для доступа к полям, так как Groovy предоставляет их автоматически. Не нужно писать конструкции типа for Iterator i = list.iterator() для выполнения цикла по списку элементов; конструкция list.each делает то же самое более лаконично и наглядно. Проще говоря, Groovy - это то, как выглядел бы язык Java, если бы его написали в двадцать первом веке.

Groovy никогда бы не привлек Java-программистов, если бы для того, чтобы воспользоваться его преимуществами, приходилось полностью переписывать приложения. К счастью, Groovy прозрачно интегрируется с существующим кодом. Язык Groovy не заменяет язык Java, а усовершенствует его. Groovy можно быстро изучить за один день, так как Groovy-код - это Java-код. Эти два языка настолько совместимы, что можно переименовать работающий файл .java в файл .groovy (например, файл Person.java переименовать в Person.groovy), и получить абсолютно правильный (и исполняемый) файл Groovy, хотя он и не будет использовать никаких синтаксических преимуществ, предоставляемых Groovy.

Такая глубокая совместимость между языками Groovy и Java означает, что Grails не нужно "изобретать колесо", когда речь идет о ключевых внутренних технологиях. Вместо этого он позволяет взглянуть на знакомые Java-библиотеки с точки зрения Groovy. Сценарии тестирования JUnit типа TestCase заключаются в Groovy-оболочку и представляются как объекты типа GroovyTestCase. Grails представляет новую точку зрения на сценарии сборки Ant посредством GANT - версии Ant, реализованной исключительно на Groovy. Grails помещает Hibernate за "тонкий" Groovy-фасад, называемый GORM (Grails Object Relational Mapping - расширение Grails для объектно-реляционного преобразования). Это только три примера того, как Grails позволяет использовать весь опыт, накопленный в Java, одновременно предоставляя преимущества современных приемов Web-разработки.

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


Установка Grails

Все, что требуется для запуска Grails-приложения, заключено в один ZIP-файл. Все зависимые библиотеки - Groovy, Spring и Hibernate и многие другие - уже установлены на место и готовы к использованию. Для установки Grails необходимо:

  1. Скачать и распаковать архив grails.zip с Web-сайта Grails (см. раздел Ресурсы).
  2. Установить переменную среды GRAILS_HOME.
  3. Добавить путь $GRAILS_HOME/bin в переменную среды PATH.

Конечно, необходимо иметь установленную версию JDK. (Grails хорош, но все-таки не настолько хорош). Grails 1.0 может запускаться на Java 1.4, 1.5 и 1.6. Если неизвестно, какая версия установлена, введите java -version в командной строке. Если необходимо, скачайте и установите версию JDK, совместимую с Grails (см. раздел Ресурсы).

После выполнения действий по установке необходимо ввести в командной строке grails -version для проверки правильности установки. Если выводится следующее приветственное сообщение, значит, все настроено правильно:

Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grails

Web-сервер и база данных в комплекте

Использование бесплатных продуктов

В приложении в этой статье будут использоваться Web-сервер и база данных, которые бесплатно поставляются с Grails. В следующей статье будут представлены пошаговые инструкции по запуску Grails на других серверах. Также можно посетить Web-сайт grails.org и ознакомиться с отличной онлайновой документацией (см. раздел Ресурсы).

Интересно, что для запуска Grails-приложений не требуется отдельно установленного Web-сервера. Grails поставляется со своим встроенным сервлет-контейнером - Jetty. Достаточно ввести grails run-app, и приложение будет запущено в контейнере Jetty (см. раздел Ресурсы) без необходимости проходить через обычные этапы установки. Запуск Grails-приложения на существующем корпоративном сервере приложений также не представляет проблем. Если ввести команду grails war, будет создан стандартный файл, который можно установить на Tomcat, JBoss, Geronimo, WebSphere® или любой другой сервлет-контейнер, совместимый с Java EE 2.4.

Также не требуется отдельно установленной базы данных. Grails поставляется с базой данных HSQLDB (см. раздел Ресурсы), написанной полностью на Java. Наличие базы данных, уже готовой к использованию, дает существенную прибавку к продуктивности. Использовать другую СУБД, например, MySQL, PostgreSQL, Oracle Database или DB2 также несложно благодаря Hibernate и GORM. Если имеется JAR-файл с JDBC-драйвером и настройки для стандартного подключения, то достаточно внести одно изменение в файл DataSource.groovy, чтобы переключить приложение на использование другой базы данных.


Создание первого Grails-приложения

Мне приходится много путешествовать - по меньшей мере 40 поездок в год. Я обнаружил, что календари оказывают мне огромную помощь, говоря мне, когда я должен быть где-то, но при этом не сообщают, где находится это место. У онлайновых карт противоположная проблема: они отлично справляются с вопросом "где", но не с вопросом "когда". Поэтому в этой и паре последующих статей этой серии будет подготовлено специальное Grails-приложение, которое поможет решать вопросы "где" и "когда" при планировании поездки.

Осторожно, спойлер!

Вам не кажется, что в следующих статьях этой серии будет рассматриваться совместное использование Grails вместе Google Calendar и Google Maps? Мне кажется....

Для начала необходимо войти в пустой каталог и ввести команду grails create-app trip-planner. После вспышки активности можно будет увидеть каталог trip-planner. Подобно Maven, Rails и AppFuse, Grails создает стандартную структуру каталогов для пользователя. Если вам кажется, что это безнадежно ограничивает вас, а с инфраструктурой невозможно работать, если вы не можете педантично создать собственное дерево каталогов, то, скорее всего, большого удовольствия от работы с Grails вы не получите. Соглашение, первая составляющая принципа "соглашение по конфигурации", позволяет взять любое Grails-приложение и немедленно понять, какие компоненты имеются и где они хранятся.

Далее необходимо перейти в каталог trip-planner и ввести команду grails create-domain-class Trip. Если все пройдет нормально, появятся два файла: grails-app/domain/Trip.groovy и grails-app/test/integration/TripTests.groovy. Тестирование будет рассматриваться в следующей статье. Пока же сфокусируемся на доменном классе, который начинается, как показано в листинге 1:

Листинг 1. Доменный класс, сгенерированный Grails
class Trip{

}

Пока смотреть не на что, но мы это исправим, добавив поля в класс Trip, как показано в листинге 2:

Листинг 2. Класс Trip с добавленными полями
class Trip { 
  String name
  String city
  Date startDate
  Date endDate
  String purpose
  String notes
}

Как уже говорилось, не нужно беспокоиться о создании get() и set()-методов, так как Groovy динамически сгенерирует их. Класс Trip также содержит много новых и полезных динамических методов, названия которых говорят сами за себя:

  • Trip.save()сохраняет данные в таблицу Trip в базе данных HSQLDB.
  • Trip.delete()удаляет данные из таблицы Trip.
  • Trip.list() возвращает список объектов Trip.
  • Trip.get() возвращает один экземпляр Trip.

Все эти и другие методы находятся в полном вашем распоряжении. Отметим, что класс Trip не расширяет родительский класс и не реализует "волшебный" интерфейс. Благодаря возможностям метапрограммирования Groovy эти методы просто появляются в соответствующем месте в соответствующих классах. (Эти методы, связанные с сохранением данных в базу данных, получают только классы в каталоге grails-app/domain).

Создание контроллера и видов

Создание класса для доменной области - это только первый шаг. Каждой модели для полноты картины требуется хороший контроллер и несколько видов. Предполагается, что читатель уже знаком с шаблоном MVC (Model-View-Controller - Модель-вид-контроллер) (см. раздел Ресурсы). Введите в командной строке: grails generate-all Trip, чтобы создать класс grails-app/controllers/TripController.groovy и соответствующий набор GSP-страниц (Groovy Server Pages - серверные страницы Groovy) в каталоге grails-app/views/Trip. Для каждого действия типа list в контроллере есть соответствующий файл list.gsp. Для действия create есть файл create.gsp. Здесь на практике становятся видны преимущества "соглашения по конфигурации": не требуется никаких XML-файлов для установления соответствия элементов. Каждый класс доменной области имеет пару в виде контроллера с соответствующим именем. При желании эту конфигурацию, основывающуюся на именах, можно обойти, но в большинстве ситуаций достаточно просто следовать соглашению, и приложение сразу заработает.

Рассмотрим файл grails-app/controller/TripController.groovy, показанный в листинге 3:

Листинг 3. Класс TripController
class TripController {
    ...
    def list = {
        if(!params.max) params.max = 10
        [ tripList: Trip.list( params ) ]
    }
    ...
}

Первое, что скорее всего заметят Java-программисты, это то, как много действий выполняет такой компактный код. Например, рассмотрим действие list. Самое важное происходит на последней строке этого метода. Grails возвращает коллекцию типа HashMap, содержащую единственный элемент с именем tripList. (Последняя строка в методе Groovy - это неявное выражение return. При желании можно напечатать слово return явно). Элемент tripList - это объект типа ArrayList, содержащий объекты типа Trip, извлеченные из базы данных методом Trip.list(). Обычно этот метод возвращает все записи из таблицы. Строка, расположенная над этой строкой, говорит: "если кто-нибудь передаст в URL параметр с именем max, необходимо на основании его значения ограничить количество возвращенных объектов Trip. Если такого параметра нет, то ограничить количество объектов Trip десятью". URL-адрес http://localhost:8080/trip-planner/trip/list вызывает эту функциональность. Например, URL-адрес http://localhost:8080/trip-planner/trip/list?max=3 покажет только три поездки вместо обычных десяти. Если еще имеются поездки, которые можно показать, то Grails автоматически создаст ссылки для перехода на страницы со следующими и предыдущими наборами элементов.

Так где же используется эта коллекция типа HashMap? Рассмотрим файл grails-app/views/list.gsp, показанный в листинге 4:

Листинг 4. Файл list.gsp
<g:each in="${tripList}" status="i" var="trip">
  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    <td>
      <g:link action="show" id="${trip.id}">${trip.id?.encodeAsHTML()}</g:link>
    </td>
  </tr>
</g:each>

Файл list.gsp - это по сути простой HTML документ с небольшим количеством GroovyTagLibs (библиотек Groovy-тегов). Все, перед чем стоит префикс g:, является Groovy-тегом. В листинге 4 тег <g:each> проходит по всем объектам Trip в коллекции tripList типа ArrayList и строит таблицу, соответствующую синтаксису HTML.

Чтобы понять, как работают контроллеры, необходимо разобраться с "тремя R": return (вернуть), redirect (перенаправить) и render (сформировать графическое отображение). Некоторые типы действий используют преимущества неявного выражения return, чтобы возвращать данные на GSP-страницу с таким же именем. Другие действия выполняют перенаправление. Например, действие типа index вызывается, если пользователь не указал тип действия в URL:

def index = { redirect(action:list,params:params) }

В этом случае класс TripController выполняет перенаправление к действию list, передавая при этом все параметры (или объект типа QueryString (строка запроса)) в коллекции params типа HashMap.

Наконец, действие типа save (см. листинг 5) не имеет соответствующей страницы save.gsp. Оно перенаправляет пользователя на страницу действия show, если запись была сохранена в базу данных без ошибок. В противном случае оно отображает страницу create.gsp, где можно увидеть возникшие ошибки и попробовать выполнить действие снова.

Листинг 5. Действие типа save
def save = {
  def trip = new Trip(params)
  if(!trip.hasErrors() && trip.save()) {
    flash.message = "Trip ${trip.id} created"
    redirect(action:show,id:trip.id)
  }
  else {
    render(view:'create',model:[trip:trip])
  }
}

Однако вместо того чтобы просто обсуждать, как работает Grails, стоит увидеть его в действии.


Работающее приложение

Введите grails run-app в командной строке. После набора сообщений Log4J, выведенных в консоль, должно быть показано сообщение с таким текстом:

Server running. Browse to http://localhost:8080/trip-planner

Если на порту 8080 уже находится запущенный сервер, в результате сбоя будет выведен дамп ядра с сообщением:

Server failed to start: java.net.BindException: Address already in use

Есть два способа легко изменить порт, на котором работает Jetty. Можно выполнить это изменение буквально на лету, введя команду grails -Dserver.port=9090 run-app. Чтобы сделать это изменение постоянным, необходимо в файле $GRAILS_HOME/scripts/Init.groovy найти строку, которая начинается с serverPort, и изменить ее значение:

serverPort = System.getProperty('server.port') ? 
             System.getProperty('server.port').toInteger() : 9090

После того как Grails был запущен на выбранном порту, можно ввести URL в Web-браузер. При этом должна появиться страница приветствия со списком всех контроллеров, как показано на рисунке 1:

Рисунок 1. Экран приветствия Grails-приложения
Рисунок 1. Экран приветствия Grails-приложения

Затем необходимо нажать на ссылку TripController, и вам будет представлено полноценное CRUD-приложение (Create, Read, Update, Delete - создать, считать, обновить, удалить), с которым уже можно работать.

Новые поездки создаются с помощью страницы, изображенной на рисунке 2:

Рисунок 2. Страница Create Trip (создать поездку)
Рисунок 2. Страница Create Trip (создать поездку)

Редактирование поездок производится с помощью страницы, изображенной на рисунке 3:

Рисунок 3. Страница Trip List (список поездок)
Рисунок 3. Страница Trip List (список поездок)

Так сколько же времени потребовалось на создание и запуск приложения? И сколько для этого потребовалось строк кода? Узнать об этом можно следующим способом:

  1. Нажать Ctrl-C для выключения Grails.
  2. Ввести grails stats.

На экране будут напечатаны следующие данные:

  +----------------------+-------+-------+
  | Name                 | Files |  LOC  |
  +----------------------+-------+-------+
  | Controllers          |     1 |    66 | 
  | Domain Classes       |     1 |     8 | 
  | Integration Tests    |     1 |     4 | 
  +----------------------+-------+-------+
  | Totals               |     3 |    78 | 
  +----------------------+-------+-------+

Для реализации всей функциональности приложения потребовалось менее 100 строк кода. Неплохо, но перед завершением статьи хотелось бы продемонстрировать еще одну возможность Grails.

Генерация контроллера и видов - это отличное упражнение, а наличие физических файлов на диске иллюстрирует, как все детали связаны между собой. Однако давайте удалим содержимое класса TripController и заменим его следующим содержимым:

  class TripController{
    def scaffold = Trip
  }

Эта единственная строка кода указывает Grails сделать то же самое, что было сделано с предыдущим контроллером, с одним исключением: сгенерировать все действия list, save и edit динамически - прямо в памяти во время выполнения. Три строки кода вместо 66 приводят к абсолютно такому же поведению приложения.

Снова введите grails run-app. Да, все введенные данные пропали, но это не страшно. Выключите Grails комбинацией клавиш Ctrl-C и напечатайте в командной строке grails prod run-app. Приложение будет запущено в рабочем режиме, что означает, что данные будут сохраняться между перезапусками сервера. Снова пройдем через TripController и сохраним несколько записей. В поведении приложения не заметно никакой разницы. Понимание того, что все, что показывается в Web-браузере, обеспечивается 15 строчками кода, дает представление о силе и возможностях Grails.


Заключение

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

Статья, которая выйдет в следующем месяце, будет посвящена инфраструктуре GORM. Мы будем сохранять данные в базу данных MySQL, добавим валидацию данных и установим связь "один-ко-многим". Мы значительно увеличим возможности приложения для планирования поездок без добавления большого количества кода.

Пока же рекомендую поупражняться с Groovy и Grails и уверяю, что ваши взгляды на Web-разработку радикально изменятся.

Ресурсы

Научиться

  • Mastering Grails: Build your first Grails application: оригинал статьи (EN).
  • Grails: Web-сайт, посвященный Grails.
  • Practically Groovy: : серия статей на страницах developerWorks, в которой исследуется практическое использование Groovy и рассматривается, когда и как его следует применять.
  • Groovy: Web-сайт проекта Groovy с дополнительной информацией.
  • AboutGroovy.com (EN): Web-сайт с последними новостями и ссылками на статьи о Groovy.
  • What's the secret sauce in Ruby on Rails? (Bruce Tate, developerWorks, май 2006 г.): в этой статье Брюса Тейта (Bruce Tate) из серии Crossing borders на страницах developerWorks рассказывается, почему Rails произвел такое впечатление.
  • HSQLDB и Jetty: База данных, написанная исключительно на Java, и сервлет-контейнер, поставляемые с Grails.
  • Model-View-Controller (EN): популярный шаблон проектирования, используемый в Grails.
  • Safari bookstore: сайт магазина книг по ИТ.(EN)
  • Раздел Технология Java сайта developerWorks: сотни статей обо всех аспектах Java-программирования.

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

Обсудить

Комментарии

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=429908
ArticleTitle=Работа с Grails: Cоздание первого Grails-приложения
publish-date=09212009