Перейти к тексту

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

При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

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

  • Закрыть [x]

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

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

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

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

  • Закрыть [x]

Создание простого Wiki-приложения при помощи Project Zero и API для доступа к данным среды WebSphere sMash

Разработка простого приложения Wiki в соответствии с классической архитектурой "модель-представление-контроллер"

Брэндон Дж. У Смит, инженер по программному обеспечению, IBM
Brandon Smith
Брэндон Смит (Brandon Smith) работает над проектом Project Zero в IBM, курируя широкий круг вопросов. Он имеет степень магистра из университета Карнеги-Меллон. С ним можно связаться на сайте 16cards.com, а также по адресу brandon+dW@16cards.com.
Ханумант Р. Канти, архитектор программного обеспечения, IBM
Hanumanth Kanthi photo
Ханумант Канти (Hanumanth Kanthi) занимает должность IT-архитектора в группе «IBM Software Services for WebSphere». Он имеет степень магистра компьютерных наук Технологического университета Виктории, Австралия. С ним можно связаться по адресу kanthi@us.ibm.com.

Описание:  Project Zero – это платформа упрощенной разработки, предназначенная для быстрого создания приложений Web 2.0, обладающих сервис-ориентированной архитектурой (Service-Oriented Architecture - SOA). В набор библиотек, составляющих арсенал Project Zero, входит реализация упрощенного API для выполнения запросов SQL. В данной статье вы узнаете, как использовать данный API при создании простого Wiki-приложения.

Дата:  05.03.2010
Уровень сложности:  средний
Активность:  2566 просмотров
Комментарии:  


Примечание редактора: IBM® WebSphere® sMash и IBM WebSphere sMash Developer Edition основаны на проекте-инкубаторе Project Zero, получившем широкое признание. Project Zero - это сообщество разработчиков WebSphere sMash, которое по-прежнему будет предлагать бесплатную платформу разработки приложений с новейшими сборками, функциональными возможностями и поддержкой.

Перед началом работы

Данная статья ориентирована на читателей, имеющих базовое представление о Project Zero. Если вы только начинаете знакомиться с этой средой, то обратитесь к вводной статье под заголовком “Создание REST-сервисов для вашего Web-приложения”, а также руководству, озаглавленному “Приступаем к работе с Project Zero и PHP”. Ознакомившись с Project Zero, вы можете скачать саму платформу (см. Ресурсы) и самостоятельно создать простое приложение.

Введение

Как замечательно выразился Ларри Уолл: оставляйте простые вещи простыми, а сложные делайте осуществимыми.

Сценарии использования средств доступа к данным могут быть как простыми, так и очень сложными. Поэтому многие разработчики жалуются на отсутствие API для доступа к данным, который был бы достаточно гибок для решения сложных задач, но при этом бы не был громоздким в простых ситуациях. Программный интерфейс для доступа к данным, предоставляемый Project Zero под названием zero.data, является именно таким средством. Он не задумывался для использования в качестве уровня абстракции, подобно Hibernate или архитектуре сохранения объектов Java™ (Java Persistence Architecture). Вместо этого данный API представляет собой библиотеку, целью которой является именно простота использования в несложных ситуациях и возможность применения в сложных случаях. Как вы увидите ниже, сама библиотека является тонкой оболочкой поверх SQL. В листинге 1 показан пример выполнения простого запроса и обработки результатов в виде списка объектов JavaBean.


Листинг 1. Использование zero.data для выборки объектов из базы данных в виде списка и ассоциативного массива значений
        
Manager data = Manager.create("myDb");
List<Person> results = data.queryList("SELECT * FROM person", Person.class);
List<Map<String,Object>> resultsMap = data.queryList("SELECT * FROM person");

В течение последнего года команда Project Zero тесно сотрудничала с группой разработчиков IBM® Information Management в процессе работы над pureQuery – высокопроизводительной платформы доступа к данным, включающей в себя средства разработки, программные интерфейсы и усовершенствованную среду выполнения Java-приложений. В zero.data используются интерфейсы и среда выполнения pureQuery. При этом использование zero.data не исключает использования средств pureQuery, так как последние генерируют Java-артефакты. Однако на момент написания этой статьи средства pureQuery не были интегрированы с Project Zero (более подробную информацию о pureQuery можно найти в разделе Ресурсы). Взаимодействие между интерфейсами Projext Zero и pureQuery показано на рисунке 1.


Рисунок 1. Связь между zero.data в Project Zero и API для доступа к реляционным данным
Relationship between Project Zero's zero.data relational data access APIs
Сообщество Project Zero
Зайдите на страницу Project Zero и прочитайте о мощной, но в то же время простой в использовании, платформе для разработки и выполнения современных Web-приложений. В активном сообществе разработчиков обсуждается развитие проекта, предлагается помощь коллегам, а также приветствуются новые идеи!

zero.data предоставляет тонкую оболочку вокруг функциональности, предлагаемой средой выполнения и программными интерфейсами pureQuery. Использование zero.data имеет преимущества по сравнению с работой непосредственно через API pureQuery, так как это упрощает приложение, созданное при помощи Project Zero (например, в части конфигурирования и работы с пулами соединений). Кроме того, это позволяет скриптам Groovy и PHP работать с pureXML через общий API, причем используя интерфейсы pureXML с учетом особенностей языка. Например, методы Groovy-версии интерфейса используют замыкания, в то время как в PHP-версии их заменяют идентификаторы ресурсов.

В данной статье будут рассматриваться интерфейсы для Groovy. Если вас интересуют версии интерфейсов для Java или PHP, то обратитесь к документации Project Zero. Далее мы расскажем об основах использования zero.data в приложениях Zero. Мы начнем с вопросов работы с данными через интерфейс zero.data.groovy.Manager, включая цели, которые преследовались при его проектировании. При этом мы будем рассматривать API с позиций как Java-, так и Groovy-программистов. Далее, быстро перейдя к практике, мы спроектируем простое приложение, использующее zero.data API. После этого останется добавить простые страницы Wiki, инициализировать таблицы и закончить реализацию приложения. Весь процесс в целом будет состоять из следующих основных шагов:

Работа с данными

zero.data.groovy.Manager (далее просто Manager) предлагает удобный интерфейс для работы с реляционными базами данных, в частности, выполнения запросов. В наиболее простом случае данному классу передается текст SQL-запроса в виде строки. В Groovy параметры передаются в составе той же строки, например: data.queryFirst("SELECT * FROM t WHERE id=$id")). Далее Manager готовит строку к выполнению при помощи класса PreparedStatement, выполняет запрос и возвращает результаты. При этом он самостоятельно закрывает созданные ресурсы, такие как набор выбранных записей (result set), подготовленный к выполнению запрос и соединение с базой данных.

Manager предлагает набор методов для выполнения следующих операций:

  • Выполнение запроса и итерирование по списку результатов при помощи замыкания.
  • Выполнение запроса и возвращение первой записи в ResultSet, преобразуя ее к одному и следующих представлений:
    • экземпляру класса Java Bean
    • экземпляру java.util.Map
  • Выполнение запроса и возвращение полного набора записей, преобразованного к одному из следующих представлений:
    • java.util.Iterator
    • java.util.List
    • массив Java
  • Выполнение запроса и возвращение экземпляра ResultSet
  • Выполнение операторов языка управления данными, таких как INSERT, UPDATE и DELETE, в том числе специализированного метода для генерации ключей.

Простой программный интерфейс

Имеет смысл оценить, насколько использование Manager позволяет снизить объем механической работы, и сконцентрироваться на функциональности приложения, а не на написании кода для работы с базой данных, чреватого ошибками. Для сравнения в листинге 2 показан JDBC-вариант кода, ранее приведенного в листинге 1. На этом примере видно, насколько легко Manager позволяет решать простые задачи.


Листинг 2. Выбора данных в виде Map требует гораздо больше кода при использовании JDBC
        
// Считается, что соединение было установлено ранее
// Обратитесь к документации по JDBC за подробностями

List<Map<String,Object>> results = new ArrayList<Map<String,Object>>();
try {
  PreparedStatement stmt =
    connection.prepareStatement("SELECT * FROM person");
  ResultSet rs = stmt.executeQuery();
  try {
    while(rs.next()) {
      ResultSetMetaData meta = rs.getMetaData();
      int numColumns = meta.getColumnCount();
      Map<String,Object> row = new HashMap<String,Object>(numColumns);
      for (int i = 1; i <= numColumns; i++) {
        row.put(meta.getColumnName(i).toLowerCase(), rs.getObject(i));
      }
      results.add(row);
    }
  } finally {
    rs.close();
  }
} finally {
  stmt.close();
}

Приложения редко работают с JDBC напрямую подобно тому, как показано в листинге 2. Большинство инфраструктур предоставляют промежуточные слои и в некоторой степени упрощают работу с базой данных. Мы убеждены, что Manager – это очень мощный механизм, позволяющий элегантно решать простые задачи и находить подходы к сложным. Например, вдобавок к возвращению единичных объектов или коллекций List, Iterator, Array и Map объектов Java Bean, как показано в листинге 1, zero.data предоставляет возможность, основанную на использовании шаблонного метода, который позволяет вам, а также сторонним разработчикам, реализовывать сложные сценарии обработки ResultSet.

Подобные сложные вопросы использования шаблонного метода будут обсуждаться в более поздней статье на сайте developerWorks. Как упоминалось ранее, zero.data реализована поверх среды выполнения pureQuery. Данная среда не только предоставляет инфраструктуру для гибкой, но предсказуемой работы с данными через открытые интерфейсы, но также способствует написанию кода, пригодного для повторного использования. Например, сама среда выполнения pureQuery в немалой степени состоит из интерфейсов, которые вы, как разработчик, можете реализовать, расширяя тем самым инфраструктуру. Таким образом, среда является настолько гибкой, что позволяет реализовывать как единичные расширения для конкретного приложения, так и создавать библиотеки для многократного использования, состоящие из компонентов для обработки результатов запросов (ResultSet).

Как видно из рисунка 1, класс Manager является оболочкой вокруг zero.data.Manager, предоставляя методы, удобные для вызова из Groovy. Ниже приведено сравнение API, реализуемых классами Manager и zero.data.Manager. Как видите, эти классы обладают схожей функциональностью. Оба класса содержат группы методов, которые решают одну и ту же задачу, но в разных частных случаях. Например, метод queryList возвращает java.util.List, в то время как queryIterator возвращает java.util.Iterator. Это говорит само за себя. Каждая из таких групп состоит из трех перегруженных методов, причем сигнатуры и назначения методов аналогичны для всех групп. Полностью группы, перегруженные методы, а также их описания представлены в таблице 1. Более подробную информацию можно найти в документации Javadoc для проекта Project Zero


Таблица 1. Краткий обзор методов Manager
МетодОписаниеВариацииСигнатура в Groovy
queryFirstВозвращает первую строку в ResultSet.Map<String,Object> queryFirst(String, Object...)Map<String,Object> queryFirst(GString)
T queryFirst(String, Class<T>, Object...)T queryFirst(GString, Class<T>)
T queryFirst(String, RowHandler<T>, Object...)T queryFirst(GString, RowHandler<T>)
queryListВозвращает ResultSet в виде экземпляра java.util.List.List<Map<String,Object>> queryList(String, Object...)List<Map<String,Object>> queryList(GString)
List<T> queryList(String, Class<T>, Object...)List<T> queryList(GString, Class<T>)
List<T> queryList(String, RowHandler<T>, Object...)List<T> queryList(GString, RowHandler<T>)
queryIteratorВозвращает ResultSet в виде экземпляра java.util.Iterator.Iterator<Map<String,Object>> queryIterator(String, Object...)Iterator<Map<String,Object>> queryIterator(GString)
Iterator<T> queryIterator(String, Class<T>, Object...)Iterator<T> queryIterator(GString, Class<T>)
Iterator<T> queryIterator(String, RowHandler<T>, Object...)Iterator<T> queryIterator(GString, RowHandler<T>)
queryArrayВозвращает ResultSet в виде массиваMap<String,Object>[] queryArray(String, Object...)Map<String,Object>[] queryArray(GString)
T[] queryArray(String, Class<T>, Object...)T[] queryArray(GString, Class<T>)
T[] queryArray(String, RowHandler<T>, Object...)T[] queryArray(GString, RowHandler<T>)
updateИзменяет данные и возвращает количество обновленных строкint update(String, Object...)int update(GString)
insertВыполняет вставку и возвращает сгенерированный ключ, преобразованный к экземпляру класса, переданного в качестве второго параметра. В Groovy-версии ключ всегда преобразуется к типу int. T insert(String, Class<T>, String[], Object...)int insert(GString, List<String>)

Программирование на Java и Groovy

Как видно из таблицы 1, zero.data применима в разнообразных ситуациях, предлагая обширный набор методов для доступа к данным. Из них ниже будут использоваться только queryFirst(GString), queryList(GString), update(GString) и insert(GString, List), относящиеся к API для Groovy (класс zero.data.groovy.Manager).

Groovy – это динамически-типизируемый, объектно-ориентированный язык для платформы Java. Существует распространенное заблуждение, заключающееся в том, что Groovy призван заменить Java. Благодаря тому, что код на Groovy компилируется в байт-код Java, приложения Groovy могут использовать стандартные программные интерфейсы Java, а также написанные на нем библиотеки. Таким образом, Groovy не является заменой Java, а просто предлагает альтернативный синтаксис, который изобилует конструкциями, позволяющими писать более краткий код.

Например, как вы помните, используя Java-версию API zero.data среды Project Zero, нам удалось сократить объем кода по сравнению с работой непосредственно через JDBC. А теперь взгляните в листинг 3, в котором сравниваются реализации одной и той же функциональности на Java и Groovy.


Листинг 3. Сравнение функционально эквивалентных фрагментов кода на Java и Groovy
        
// Java
Manager data = zero.data.Manager.create("wiki");
data.inTransaction(new LocalTransaction() {
  public void execute() {
    data.update("UPDATE mytable SET name=? WHERE id=?", 1, "new name");
    data.insert("INSERT INTO anothertable (name) VALUES (?)", "another name");
    List<Map<String,Object>> results = data.queryList("SELECT * FROM sometable");
    for (Map<String,Object> row : results) {
      for (String key : row.keySet()) {
        System.out.println("key: " + key + ", value: " + row.get(key));
      }
    }
  }
});

// Groovy
def data = zero.data.groovy.Manager.create("wiki")
data.inTransaction {
  data.update("UPDATE mytable SET name=$name WHERE id=$id")
  data.insert("INSERT INTO anothertable (name) VALUES ($name)")
  data.eachRow("SELECT * FROM sometable") { row ->
    row.each { key, value -> 
      println("key: $key, value: $value")
    }
  }
}

Как видно из листинга 3, отличительные особенности Groovy не ограничиваются тем, что он позволяет сократить число строк кода. Например, в Java-версии метода inTransaction приходится явно создавать анонимный экземпляр класса LocalTransaction, в то время как в Groovy это делается неявно при помощи замыкания. Замыкания в Groovy представляют собой возможность создавать “мобильные” участки кода. Вместо создания в Java анонимного экземпляра абстрактного класса LocalTransaction и передачи его в метод inTransaction в Groovy можно заключить участок кода внутри замыкания (между фигурными скобками), что позволит передать его в метод inTransaction значительно более лаконичным образом. Более полное описание возможностей замыканий можно найти в документации Groovy (см. Ресурсы), которая также содержит примеры создания API, принимающих замыкания в качестве аргументов.

Во фрагменте кода на Groovy в листинге 3 замыкания используются еще в двух местах. Метод eachRow принимает замыкание в качестве параметра и выполняет его для каждого из результатов запроса. Внутри него, как видите, вызывается другое замыкание, которое просто перебирает записи ассоциативного массива, печатая ключи и значения.

Проектирование приложения

Использование API zero.data в этой статье

В Project Zero используется Groovy в качестве динамически типизируемого языка, который поддерживает, но не навязывает статическую проверку типов на этапе компиляции. Поэтому в данной статье используется версия API, в которой применяется Map – ассоциативный массив, связывающий строки в ResultSet с экземплярами java.util.Map, в которой, в свою очередь, ключами являются названия колонок, а значениями – данные этих колонок.

В оставшейся части статьи мы продемонстрируем мощь zero.data на примере создания простого wiki-приложения в соответствии с принципами архитектуры «модель-представление-контроллер». На рисунке 2 показана общая схема реализации данной архитектуры в приложениях Zero; технические особенности написания кода, диктуемые инфраструктурой Zero, будут приведены ниже.

Архитектура «модель-представление-контроллер»

Взгляните на рисунок 2, на котором показано, как архитектура «модель-представление-контроллер» реализуется в приложениях Project Zero.


Рисунок 2. Реализация архитектуры "модель-представление-контроллера" в приложениях Project Zero
Model-View-Controller implementation in a Project Zero application

Первым делом создадим проект для будущего приложения Project Zero. На рисунках ниже показана работа с подключаемым модулем Project Zero для Eclipse. Данный модуль предоставляет удобный интерфейс, облегчая тем самым создание приложений (при этом тех же результатов можно добиться и при использовании утилит командной строки).

Сначала надо создать приложение Zero. Подробно процесс создания приложения при помощи модуль Project Zero для Eclipse был описан в статье "Введение в Project Zero, часть 1". Кроме того, в ней рассказывалось о различных компонентах, составляющих приложения Project Zero, в частности, каталогах. Тем не менее, мы повторим базовые шаги ниже.

Создайте приложение, выбрав пункт меню File > Project.. Далее в появившемся диалоговом окне вам будет предложено выбрать тип мастера для создания проекта. Выберите пункт Project Zero > Project Zero Application. Внешний вид мастера показан на рисунке 3.


Рисунок 3. Выбор мастера создания приложения Project Zero
Select the Project Zero Application wizard

На первой странице мастера надо ввести название приложение. В качестве названия может выступать любая строка, но стоит выбрать говорящее само за себя имя, например, mywiki (рисунок 4).


Рисунок 4. Указание имени нового приложения Project Zero
New Project Zero Application name prompt

В результате в вашем рабочем пространстве Eclipse будет создан проект, включающий в себя стандартную структуру каталогов приложения Project Zero, а также некоторых автоматически генерируемых артефактов. Проект mywiki должен выглядеть как на рисунке 5.


Рисунок 5. Структура каталогов приложения Project Zero
Project Zero application folder structure

Добавление в проект zero.data делается очень просто, благодаря тому, что в Project Zero используется инфраструктура Ivy для управления зависимостями. Требуемые библиотеки описываются в XML-файле ${app_home}/config/ivy.xml. В целях простоты и удобства при демонстрации примеров мы будем использовать сервер Apache Derby во встроенном режиме работы. Для этого надо добавить следующие две строки в файл зависимостей:


Листинг 4. Редактирование файла ivy.xml, описывающего зависимости приложения
        
<dependency org="zero" name="zero.data" rev="1.0+"/>
<dependency org="org.apache.derby" name="derby" rev="10.3.1.4"/>

Обфускация паролей

При использовании Derby во встроенном режиме не требуется задавать параметра соединения, которые обычно необходимые при работе с внешними базами данных. В частности, бросается в глаза отсутствие свойства password для хранения пароля. В Project Zero есть специальный механизм для обфускации паролей, чтобы они не хранились в текстовых файлах. Более подробную информацию об использовании данной возможности можно найти в Project Zero documentation.

Добавьте в проект необходимые библиотеки в соответствие с инструкциями, приведенными в статье "Введение в Project Zero, часть 1", а затем продолжим.

Конфигурирование zero.data

zero.data использует javax.sql.DataSource для соединения с базами данных. Параметры соединения с одной или несколькими базами данных задаются в конфигурационном файле zero.config, который является частью приложений Project Zero. В листинге 5 показано описание параметров соединения с базой данных, которой присваивается ключевое значение 'wiki'.


Листинг 5. Конфигурирование zero.data в файле zero.config
        
/config/db/wiki = {
  "class" : "org.apache.derby.jdbc.EmbeddedDataSource",
  "databaseName" : "db/wiki",
  "connectionAttributes" : "create=true"
}

Получение ссылки на экземпляр Manager

После установки нужных параметров соединения с базой данных необходимо получить ссылку на экземпляр класса Manager. С его помощью можно выполнять запросы и манипулировать данными, используя описанные выше методы. Готовый к работе объект Manager можно получить, вызвав метод create и передав в него ключевое значение, присвоенное базе данных в файле zero.config. В нашем случае это 'wiki'. Пример показан в листинге 6.


Листинг 6. Получение ссылки на сконфигурированный экземпляр Manager
        
def data = zero.data.groovy.Manager.create('wiki')

Как видно из листингов 4, 5 и 6, для создания прототипа приложения Zero требуется совсем немного усилий. Далее мы начнем создавать приложение wiki, формулируя базовые требования и постепенно преобразуя их в код.

Создание простого приложения wiki

Мы продемонстрируем использование zero.data на примере создания простого wiki-приложения. В простейшем случае wiki служит для создания, редактирования, связывания и отображения wiki-страниц. Таким образом, данный пример позволит проиллюстрировать операции создания, выборки и модификации из стандартного набора CRUD (create, retrieve, update, delete). Мы обойдем вниманием только операцию удаления.

Почему wiki?

Чем обоснован выбор wiki для демонстрации работы с API zero.data? Во-первых, это достаточно простое приложение, поэтому можно сконцентрироваться на работе с zero.data, не отвлекаясь на другие детали реализации, которые возникают при создании, например, сложного wiki-приложения. Во-вторых, wiki может служить в качестве хорошего фундамента, позволяющего в будущем расширять возможности приложения, демонстрируя более сложные функции zero.data и других компонентов Project Zero.

Что такое wiki?

wiki – это приложение, позволяющее легко и быстро создавать и редактировать Web-страницы, а также связывать их между собой. Сам термин произошел от гавайского слова, означающего быстрый или простой.

Требования к wiki

Как уже упоминалось выше, приложение wiki должно поддерживать такие базовые операции, как создание, получение и редактирование wiki-страниц. Одной из общих черт большинства реализаций wiki является то, что страницы создаются путем их связывания с уже существующей страницей. Иначе говоря, пользователь нажимает на ссылку, в результате чего открывается окно с предложением создать новую страницу. Если же связанная страница была создана ранее, то она просто отображается вместе со ссылкой для перехода в режим редактирования. Форма для редактирования выглядит аналогично форме для создания новой страницы.

При создании прототипа wiki мы будем использовать возможности Project Zero для работы со скриптами и шаблонами, а также некоторые приемы, применяющиеся при реализации принципов MVC. В частности, мы поместим скрипты контроллера в открытый каталог приложения так, что они будут доступны через URI – как это обычно принято в приложениях на PHP. При этом структура каталогов и файлов на диске должна соответствовать использующимся URI. Страницы, относящиеся к уровню представления, будут находиться в каталоге /app/views. Поскольку сама реализация будет на Groovy, скрипты контроллера будут иметь суффикс .groovy, а страницы представления - .gt.

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


Рисунок 6. Структура приложения Project Zero после выполнения описанных выше шагов
Project Zero application folder structure after completing the steps

Хватит введения. Пора переходить к реализации.

Инициализация таблиц

Перед тем, как переходить к реализации слоев контроллера и представления, необходимо создать модель, к которой они будут обращаться для получения, отображения и манипулирования данными. Сами страницы wiki будут храниться в таблице базы данных. Для простоты модель нашего приложения будет представлять собой объект Map, связанный со строками в таблице (в противном случае это уже не была бы статья о zero.data). В целом приложение предъявляет очень скромные требования к хранилищу данных: все, что будет храниться в таблице – это заголовок страницы и ее содержимое. Для этого достаточно фрагмента SQL, приведенного в листинге 7, который будет размещаться в файле setup.sql.


Листинг 7. Содержимое файла setup.sql
        
CREATE TABLE pages (
  id int NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
  name varchar(20) NOT NULL,
  content varchar(3000),
  updated timestamp,
  PRIMARY KEY  (id)
);

Запуск приложения

В отличие от других артефактов, рассмотренных выше, setup.sql не является стандартной составляющей приложения. Операторы создания объектов базы данных, содержащиеся в данном файле, будут выполнены специальным обработчиком. Создавая подобный обработчик, вы явно указываете, какая часть приложения Project Zero должна быть выполнена в момент его запуска.

Сначала мы создадим Groovy-скрипт, который будет вызывать в момент старта приложения Project Zero. Данный скрипт будет выполнять операторы, содержащиеся в файле setup.sql, в случае отсутствия базы данных. При этом мы будем использовать временное решение, которые не должно применяться при эксплуатации реального приложения. На данный момент наше приложение не может изменять уже существующую схему базы данных, поэтому при изменении модели необходимо физически удалять базу данных с диска при помощи обработчика запуска приложения. Мы пошли на этот шаг исключительно в целях упрощения изложения материала. Простой, если не сказать наивной, реализации модели, приведенной в листинге 8, вполне достаточно для иллюстрации использования API zero.data.


Листинг 8. Содержимое файла app/scripts/startup.groovy
        
import zero.data.groovy.Manager

//Не запускайте скрипт, если база данных Derby уже существует
def db_dir = new File('db/wiki')
if (!db_dir.isAbsolute())
  db_dir = new File(config.root[], 'db/wiki')

if (!db_dir.exists()) {
  def buffer = new StringBuffer()
  new File('setup.sql').text.split('\n').each() { line ->
    line = line.trim()
    if (line && !line.startsWith("--") && !line.toLowerCase().startsWith("connect"))
      buffer << line << '\n'
  }
  def statements = buffer.toString().split(';')
  def data = Manager.create('wiki')
  try {
    data.inTransaction() {
      statements.each() { statement ->
        statement = statement.trim()
        if (statement)
        data.update(statement)
      }
    }
  } catch (Throwable error) {
    throw new RuntimeException("Setup database error: ${error.message}", error);
  }
}

Необходимо явно указать приложению, что скрипт, приведенный в листинге 8, должен быть выполнен в момент запуска. Это делается путем регистрации данного скрипта в качестве обработчика запуска в файле config/zero.config. Пример показан в листинге 9.


Листинг 9. Добавьте следующие строки в файл config/zero.config
        
/config/handlers += {
  "events" : "start",
  "handler" : "startup.groovy"
}

Это означает, что среда выполнения Project Zero будет вызывать скрипт startup.groovy в момент наступления события 'start'. Таким образом, при запуске приложения будет выполнен оператор CREATE TABLE. База данных еще не существует на момент первого запуска, поэтому встроенная СУБД Derby создаст ее на диске автоматически (в соответствии с тем, как мы задали параметры соединения).

Реализация приложения

Не останавливайте пока работу приложения. Project Zero – это динамическая среда, способная на лету подхватывать большинство изменений. Теперь, создав таблицу, можно переходить к реализации контроллера и представления. Начнем с отображения страницы.

Динамическое отображение HTML

Для отображения страницы необходимо создать процедуру, которая будет вызываться средой Project Zero в момент передачи управления нашему приложению. Мы реализуем ее в виде контроллера приложения, который назовем 'view.groovy' и поместим в каталог app/public. Контроллеру будет необходим экземпляр Manager для выполнения запроса касательно данной страницы. Далее действия контроллера будут зависеть от того, была ли выбрана строка из таблицы базы данных. Данная строка соответствует сохраненной странице. Если она существует, то будет вызвано представление для отображения страницы. Код контроллера показан в листинге 10.


Листинг 10. Реализация view.groovy
        
def name = request.params.name[]
def data = new zero.data.Manager('wiki')
def page = data.queryFirst("SELECT * FROM pages WHERE name=$name")
if (page) {
  request.page.name = page.name
  request.page.content = page.content
  request.view = 'view.gt'
} else {
  request.page.name = name
  request.view = 'create.gt'
}
render()

Далее необходимо создать две страницы представления 'view.gt' и 'create.gt', которые будут вызываться контроллером. Обе страницы просто отображают данные, хранящиеся в области видимости запроса. При этом используются шаблоны Groovy, как показано в листингах 11 и 12.


Листинг 11. Реализация view.gt
        
<html>
 <head>
  <title><%= request.page.name[] %></title>
 </head>
 <body>
  <h1><%= request.page.name[] %></h1>
  <%= request.page.content[] %>
  <hr/>
  <a href="<%= "${getRelativeUri('/edit.groovy')}?page=${request.page.name[]}" %>">
    Edit this page?
  </a>
 </body>
</html>


Листинг 12. Реализация create.gt
        
<html>
 <head>
  <title><%= request.page.name[] %> - Create</title>
 </head>
 <body>
  <h1><%= request.page.name[] %></h1>
   This page does not exist.
 <a href="<%= "${getRelativeUri("/edit.groovy")}?name=${request.page.name[]}" %>">
   Create?
 </a>
 </body>
</html>

Изменение записей в базе данных

Выше мы создали два представления: для отображения существующей страницы wiki и для отображения формы добавления новой страницы. Реализация этих представлений будет опираться на дополнительные контроллеры и представления. В частности, view.gt будет использовать контроллер edit.groovy, а create.gt будет отправлять введенные данные контроллеру save.groovy по протоколу HTTP методом POST. edit.groovy отвечает за выборку данных и отображение формы редактирования. Данная форма обладает интерфейсом, схожим с формой для создания страницы, но при этом отображает содержимое ранее сохраненной страницы. Скрипт save.groovy либо добавляет новую, либо изменяет существующую запись в таблице базы данных. Реализации edit.gt, edit.groovy и save.groovy приведены в листингах с 13-го по 15-ый.


Листинг 13. Реализация edit.groovy
        
def name = request.params.name[]
def data = zero.data.groovy.Manager('wiki')
def page = data.queryFirst("SELECT COUNT(*) FROM pages WHERE name=$name")

if (page) {
  request.page.content = page.content
} else {
  request.page.content = ""
}
request.page.name = name
request.view = 'edit.gt'
render()


Листинг 14. Реализация edit.gt
        
<html>
 <head>
  <title><%= request.page.name[] %> - Editing</title>
 </head>
 <body>
  <h1>Editing <%= request.page.name[] %></h1>
  <form method="POST"
  	action="<%= "${getRelativeUri('/save.groovy')?name=${request.page.name[]}" %>">
   <textarea name="content" rows="20" cols="60"><%= request.page.content[] %></textarea>
   <input type="submit" value="Save Page"/>
  </form>
 </body>
</html>


Листинг 15. Реализация save.groovy
        
def name = request.params.name[]
def data = zero.data.groovy.Manager('wiki')
def page data.queryFirst("SELECT * FROM pages WHERE name=${name}")
def content = request.params.content[]

if (page) {
  data.update("UPDATE pages SET content=${content}")
} else {
  data.update("INSERT INTO pages (name,content) VALUES ($page_name,$content")
}

uri = "${getAbsoluteUri('/view.groovy')}?name=${name}"
request.headers.out.Location = uri
request.status = HttpURLConnection.HTTP_MOVED_TEMP

Тестирование приложения

В итоге получилось приложение, обладающее базовой функциональностью wiki. Оно настолько примитивное, что приходится задавать адрес несуществующей страницы для того, чтобы начать работу с приложением. Например, можно ввести URI http://localhost:8080/view.groovy?name=HomePage, как показано на рисунке 7.


Рисунок 7. Несуществующая страница HomePage
Missing HomePage

Подобное поведение говорит о том, что данная страница еще не создана (что хорошо, так как означает, что приложение работает). Мы могли задать любой URI в начале работы, но вполне логично использовать "HomePage" для первой wiki-страницы. Далее необходимо создать саму страницу. Для этого в форму редактирования можно ввести любой фрагмент HTML, например, создать ссылку на другую страницу (пусть даже мы знаем, что та еще не существует). Пример показан на рисунке 8.


Рисунок 8. Форма редактирования страницы HomePage
Edit HomePage

Теперь остается только нажать на кнопку Save Page, что приведет к сохранению страницы в базе данных. При этом приложение переходит в режим просмотра только что отредактированной страницы, как показано на рисунке 9.


Рисунок 9. Отображение ранее созданной страницы HomePage
Found HomePage

Если добавленная выше ссылка указывает на несуществующую страницу (этого следует ожидать, потому что пока только одна страницы была сохранена в базе данных), то после нажатия на нее вам опять будет предложено ввести содержимое новой страницы. Разумеется, вы можете добавить еще одну страницу в приложение (см. рисунок 10).


Рисунок 10. Несуществующая страница CodingTips
Missing CodingTips

Пока это все возможности нашего приложения. При этом они могут быть значительно расширены, в частности, можно использовать языки разметки наподобие Markdown или Textile для упрощения создания и связывания страниц (вы можете попробовать сделать это в качестве упражнения).

Заключение

Project Zero – это платформа для упрощенного создания ПО, ориентированная на быструю разработку приложений Web 2.0 в соответствии с архитектурой SOA. В арсенал библиотек Project Zero входит простой в использовании API для выполнения запросов SQL. В данной статье рассказывалось об работе с данным API при создании простого wiki-приложения.

В статье обсуждались вопросы дизайна API zero.data, в том числе использование pureQuery в качестве базового API. Мы также подробно рассмотрели класс zero.data.Manager, пояснив на примерах некоторые из основных отличий версий API для Java и Groovy. Затем мы перешли непосредственно к практическим вопросам использования API zero.data, создав простое приложение wiki. Процесс разработки заключался в проектировании wiki, инициализации таблиц и итоговой реализации приложения. Надеемся, что этот опыт окажется для вас полезным в будущем при создании приложений Zero. В этом вам также поможет активное сообщество разработчиков Project Zero.



Загрузка

ОписаниеИмяРазмерМетод загрузки
Проект Eclipse для демонстрационного приложенияwa-pz-wiki.zip10KБHTTP

Информация о методах загрузки


Ресурсы

Научиться

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

  • Загрузите Project Zero и начните работу над приложением wiki. (EN)

Обсудить

Об авторах

Brandon Smith

Брэндон Смит (Brandon Smith) работает над проектом Project Zero в IBM, курируя широкий круг вопросов. Он имеет степень магистра из университета Карнеги-Меллон. С ним можно связаться на сайте 16cards.com, а также по адресу brandon+dW@16cards.com.

Hanumanth Kanthi photo

Ханумант Канти (Hanumanth Kanthi) занимает должность IT-архитектора в группе «IBM Software Services for WebSphere». Он имеет степень магистра компьютерных наук Технологического университета Виктории, Австралия. С ним можно связаться по адресу kanthi@us.ibm.com.

Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Спасибо. Эта запись была помечена для модератора.


Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Сообщение о нарушении не было отправлено. Попробуйте, пожалуйста, позже.


developerWorks: вход


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


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

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

 


При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Выберите ваше отображаемое имя

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

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

(Должно содержать от 3 до 31 символа.)


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

 


Оценить эту статью

Комментарии

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Information Management
ArticleID=471769
ArticleTitle=Создание простого Wiki-приложения при помощи Project Zero и API для доступа к данным среды WebSphere sMash
publish-date=03052010
author1-email=brandon+dW@16cards.com
author1-email-cc=
author2-email=kanthi@us.ibm.com
author2-email-cc=ruterbo@us.ibm.com

Теги

Help
Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Используйте ползунок, чтобы отразить больше или меньше тегов.

КнопкаПопулярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere).

Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).

Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Кнопка Популярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere). Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).