Примечание редактора: 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 для доступа к реляционным данным
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, инициализировать таблицы и закончить реализацию приложения. Весь процесс в целом будет состоять из следующих основных шагов:
- Работа с данными
- Рассмотрение интерфейсов Java и Groovy
- Проектирование приложения
- Создание простой страницы 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 принимает замыкание в качестве параметра и выполняет его для каждого из результатов запроса. Внутри него, как видите, вызывается другое замыкание, которое просто перебирает записи ассоциативного массива, печатая ключи и значения.
В оставшейся части статьи мы продемонстрируем мощь zero.data на примере создания простого wiki-приложения в соответствии с принципами архитектуры «модель-представление-контроллер». На рисунке 2 показана общая схема реализации данной архитектуры в приложениях Zero; технические особенности написания кода, диктуемые инфраструктурой Zero, будут приведены ниже.
Архитектура «модель-представление-контроллер»
Взгляните на рисунок 2, на котором показано, как архитектура «модель-представление-контроллер» реализуется в приложениях Project Zero.
Рисунок 2. Реализация архитектуры "модель-представление-контроллера" в приложениях Project Zero
Первым делом создадим проект для будущего приложения 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
На первой странице мастера надо ввести название приложение. В качестве названия может выступать любая строка, но стоит выбрать говорящее само за себя имя, например, mywiki (рисунок 4).
Рисунок 4. Указание имени нового приложения Project Zero
В результате в вашем рабочем пространстве Eclipse будет создан проект, включающий в себя стандартную структуру каталогов приложения Project Zero, а также некоторых автоматически генерируемых артефактов. Проект mywiki должен выглядеть как на рисунке 5.
Рисунок 5. Структура каталогов приложения Project Zero
Добавление в проект 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"/>
|
Добавьте в проект необходимые библиотеки в соответствие с инструкциями, приведенными в статье "Введение в Project Zero, часть 1", а затем продолжим.
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 для демонстрации работы с API zero.data? Во-первых, это достаточно простое приложение, поэтому можно сконцентрироваться на работе с zero.data, не отвлекаясь на другие детали реализации, которые возникают при создании, например, сложного wiki-приложения. Во-вторых, wiki может служить в качестве хорошего фундамента, позволяющего в будущем расширять возможности приложения, демонстрируя более сложные функции zero.data и других компонентов Project Zero.
Как уже упоминалось выше, приложение wiki должно поддерживать такие базовые операции, как создание, получение и редактирование wiki-страниц. Одной из общих черт большинства реализаций wiki является то, что страницы создаются путем их связывания с уже существующей страницей. Иначе говоря, пользователь нажимает на ссылку, в результате чего открывается окно с предложением создать новую страницу. Если же связанная страница была создана ранее, то она просто отображается вместе со ссылкой для перехода в режим редактирования. Форма для редактирования выглядит аналогично форме для создания новой страницы.
При создании прототипа wiki мы будем использовать возможности Project Zero для работы со скриптами и шаблонами, а также некоторые приемы, применяющиеся при реализации принципов MVC. В частности, мы поместим скрипты контроллера в открытый каталог приложения так, что они будут доступны через URI – как это обычно принято в приложениях на PHP. При этом структура каталогов и файлов на диске должна соответствовать использующимся URI. Страницы, относящиеся к уровню представления, будут находиться в каталоге /app/views. Поскольку сама реализация будет на Groovy, скрипты контроллера будут иметь суффикс .groovy, а страницы представления - .gt.
После создания всех необходимых компонентов структура каталогов примет вид, подобно показанному на рисунке 6. Данный рисунок должен помочь вам разобраться со структурой приложения.
Рисунок 6. Структура приложения Project Zero после выполнения описанных выше шагов
Хватит введения. Пора переходить к реализации.
Перед тем, как переходить к реализации слоев контроллера и представления, необходимо создать модель, к которой они будут обращаться для получения, отображения и манипулирования данными. Сами страницы 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 – это динамическая среда, способная на лету подхватывать большинство изменений. Теперь, создав таблицу, можно переходить к реализации контроллера и представления. Начнем с отображения страницы.
Для отображения страницы необходимо создать процедуру, которая будет вызываться средой 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
Подобное поведение говорит о том, что данная страница еще не создана (что хорошо, так как означает, что приложение работает). Мы могли задать любой URI в начале работы, но вполне логично использовать "HomePage" для первой wiki-страницы. Далее необходимо создать саму страницу. Для этого в форму редактирования можно ввести любой фрагмент HTML, например, создать ссылку на другую страницу (пусть даже мы знаем, что та еще не существует). Пример показан на рисунке 8.
Рисунок 8. Форма редактирования страницы HomePage
Теперь остается только нажать на кнопку Save Page, что приведет к сохранению страницы в базе данных. При этом приложение переходит в режим просмотра только что отредактированной страницы, как показано на рисунке 9.
Рисунок 9. Отображение ранее созданной страницы HomePage
Если добавленная выше ссылка указывает на несуществующую страницу (этого следует ожидать, потому что пока только одна страницы была сохранена в базе данных), то после нажатия на нее вам опять будет предложено ввести содержимое новой страницы. Разумеется, вы можете добавить еще одну страницу в приложение (см. рисунок 10).
Рисунок 10. Несуществующая страница 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.zip | 10KБ | HTTP |
Научиться
- Оригинал статьи: “Use Project Zero and WebSphere sMash’s data access APIs to build a simple wiki” (Брэндон Смит и Ханумант Канти, developerWorks, январь 2008 г.). (EN)
- Статья “Введение в Project Zero, часть 1: создание REST-сервисов для вашего Web-приложения” (developerWorks, октябрь 2007 г.) содержит вводный, практически-ориентированный обзор инновационных возможностей Project Zero для создания, сборки и разворачивания многофункциональных Web-приложений. (EN)
- В статье “Обеспечение безопасности приложений Project Zero, часть 1: аутентификация и авторизация” (developerWorks, октябрь 2007 г.) рассказывается о том, как Project Zero позволяет упросить управление доступом к ресурсам приложения. (EN)
- Ознакомьтесь со статьей “Использование активной фильтрации контента для обеспечения безопасности приложений Project Zero”, в которой описываются способы защиты от наиболее распространенных атак на приложения Web 2.0, например, межсайтового выполнения сценариев. Использование активного фильтрования контента поможет значительно повысить безопасность ваших приложений Project Zero. (EN)
- Обратите внимание на среду выполнения pureQuery в IBM Data Studio, состоящую из средств разработки, API времени выполнения и системы для управления жизненным циклом создания Java-приложений, работающих с базами данных. Последние два компонента используются в Project Zero для предоставления гибких возможностей для разработки приложений Web 2.0. (EN)
- В документации по замыканиям в Groovy описываются практические способы использования этих конструкций. (EN)
- В статье “Шаблонный метод” (Wikipedia, ноябрь 2007 г.) обсуждается данный паттерн, а также рассказывается, как его применение при проектировании API дает пользователям возможность расширять функциональности без необходимости внесения изменений в существующие сервисы. (EN)
- Прочитайте статью “Оптимальное конфигурирование базы данных и зависимостей в приложениях Project Zero”, в которой освещаются вопросы использования единой конфигурации базы данных, используемой несколькими приложениями Project Zero. (EN)
- Присоединившись к сообществу Project Zero, вы сможете больше узнать о данном проекте. (EN)
- Прочитав вводное руководство под названием “ Приступаем к работе с Project Zero и PHP ”, вы сможете уже сегодня начать создавать приложения Project Zero. (EN)
- В разделе Web-разработки на сайте developerWorks содержится большой набор библиотек, примеров кода и других ресурсов, которые помогут вам быстро начать разрабатывать приложения Web 2.0.
- В центре материалов по Ajax на сайте developerWorks содержится большой объем информации для разработчиков с любым опытом. Данные материалы помогут вам начать использовать Ajax, значительно улучшив интерфейс ваших Web-приложений.
Получить продукты и технологии
- Загрузите Project Zero и начните работу над приложением wiki. (EN)
Обсудить
- Примите участие в обсуждении материала на форуме.
- Зайдите на портал Project Zero developerWorks Space, на котором представлены статьи, форумы и блоги на предмет Project Zero и технологий Web 2.0 от IBM. (EN)
- Примите участие в обсуждениях в форуме Project Zero. (EN)
- Читайте
блоги developerWorks
blogs и становитесь членом нашего сообщества. (EN)

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

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