GWT Pleso framework
GWT Pleso Framework - это высокоуровневый framework основанный на GWT для создания пользовательских AJAX интерфейсов фронтэндов баз данных
ODB-UI prototype
Прототип интерфейса пользователя к объектным базам данных
Туториал 1. Написание первого GWT-PF приложения.
Содержание:
Часть 1. Создание простого справочника
- Создание проекта
- Общий подход
- Создание набора данных
- Создание класса-справочника
- Визуализация справочника
Часть 2. Создание форм манипуляции с данными: вставка, редактирование, удаление
- Модификация набора данных для возможности вставки, редактирования и удаления
- Разработка форм манипуляций с даными
Часть 2. Создание форм манипуляции с данными: вставка, редактирование, удаление (часть 1).
В предыдущей части мы создали простой справочник, способный загружать и отображать в удобном для пользователя виде данные о банках. Теперь сделаем доступным изменение этих данных с помощью форм манипулирования данными.
Модификация набора данных для возможности вставки, редактирования и удаления
Для того, чтобы дать пользователю возможность вставлять, редактировать и удалять банки, нужно добавить к набору данных все эти возможности:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | public void add(Bank bank, AsyncCallback callback) { try { bank.setBank_id(new Integer(this.counter++)); banks.add(bank); callback.onSuccess(new Integer(1)); } catch (Exception e){ e.printStackTrace(); callback.onFailure(new FrameworkRuntimeException(e.getMessage(), e)); } } public void update(Bank bank, AsyncCallback callback) { try { for(int i = 0; i < this.banks.size(); i++) { if (((Bank)this.banks.get(i)).getBank_id() == bank.getBank_id()) { this.banks.set(i, bank); callback.onSuccess(new Integer(1)); } } throw new IllegalArgumentException("No such bank."); } catch (Exception e){ e.printStackTrace(); callback.onFailure(new FrameworkRuntimeException(e.getMessage(), e)); } } public void get(Integer bank_id, AsyncCallback callback) { try { for(int i = 0; i < this.banks.size(); i++) { if (((Bank)this.banks.get(i)).getBank_id() == bank_id) { callback.onSuccess(this.banks.get(i)); return; } } throw new IllegalArgumentException("No such bank."); } catch (Exception e){ e.printStackTrace(); callback.onFailure(new FrameworkRuntimeException(e.getMessage(), e)); } } public void delete(Integer bank_id, AsyncCallback callback) { try { for(int i = 0; i < this.banks.size(); i++) { if (((Bank)this.banks.get(i)).getBank_id() == bank_id) { this.banks.remove(i); callback.onSuccess(new Integer(1)); return; } } throw new IllegalArgumentException("No such bank."); } catch (Exception e){ e.printStackTrace(); callback.onFailure(new FrameworkRuntimeException(e.getMessage(), e)); } } |
Логика работы методов понятна из вышеизложенного кода. Это просто манипуляции с массивом даных. В реальном приложении даные методы будут взаимодействовать с серверной стороной, где находиться база данных или другое хранилище. Метод get здесь нужен для загрузки данных в форму редактирования.
Разработка форм манипуляций с даными
GWT-PF предоставляет возможность построения разных типов форм для манипуляции и просмотра данных. Это такие формы: вставки, редактирования, просмотра, поиска, параметров отчета и т.д. Интерфейсы форм находятся в пространстве имен: net.pleso.framework.client.bl.forms. Базовый интерфейс всех форм - IForm. В нем предусмотрены два метода: для получения заголовка формы и для получения массива групп элементов формы. Единственным элементом в нашем случае будет компонент редактирования поля bank_name. Логика фреймворка принуждает нас делать два отдельных класса для формы вставки и редактирования записи, которые реализуют интерфейсы IAddForm и IEditForm соответственно. Но при этом мы можем сделать общий для них класс-предок, который реализует логику создания элемента редактирования названия банка.
Элементы форм в GWT-PF представлены интерфейсами IFormItemsGroup и IFormItem. IFormItem представляет собой любой элемент формы (например TextBox). В GWT-PF есть несколько наследников интерфейса IFormItem для представления манипуляций с разными типами данных, а также read-only элементов. Они поддерживают валидацию значений, а также проверку на обязательность заполнения. Для поля bank_name мы используем простой TextBox с названием колонки. Для этого нужно использовать интерфейс IEditColumnFormItem и его реализацию по-умолчанию - EditFormItem.
IFormItemsGroup представляет собой группу (набор) из нескольких IFormItem. К примеру, в форме редактирования клиента есть личные данные клиента и информация о его счетах. Эти поля можно разбить на группы и разместить в нужной последовательности на форме. Форма должна иметь хотя бы одну группу. Мы используем реализацию группы по-умолчанию - FormItemsGroup.
Создадим клас BankForm в пространстве имен net.pleso.tutorials.tutorial1.client.bl.forms:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package net.pleso.tutorials.tutorial1.client.bl.forms; import net.pleso.framework.client.bl.forms.items.IFormItem; import net.pleso.framework.client.bl.forms.items.IFormItemsGroup; import net.pleso.framework.client.bl.forms.items.impl.EditFormItem; import net.pleso.framework.client.bl.forms.items.impl.FormItemsGroup; import net.pleso.tutorials.tutorial1.client.dal.Bank; public class BankForm { protected static IFormItemsGroup[] groups; static { IFormItem[] items = { new EditFormItem(Bank.Columns.bank_name) }; groups = new IFormItemsGroup[] { new FormItemsGroup(null, items) }; } } |
Как видно из вышеизложенного кода, мы сформировали одну группу без названия, а также один элемент формы в этой группе, который привязан к колонке bank_name класса Bank из уровня DAL. Используем даный класс, как базовый, для создания форм вставки и редактирования банка. Первым создадим класс AddBankForm, который реализует интерфейс IAddForm:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package net.pleso.tutorials.tutorial1.client.bl.forms; import com.google.gwt.user.client.rpc.AsyncCallback; import net.pleso.framework.client.bl.forms.IAddForm; import net.pleso.framework.client.bl.forms.items.IFormItemsGroup; import net.pleso.framework.client.dal.IDataRow; import net.pleso.tutorials.tutorial1.client.bl.BankRB; import net.pleso.tutorials.tutorial1.client.dal.Bank; public class AddBankForm extends BankForm implements IAddForm { public AddBankForm() { } public IDataRow createEmptyRow() { return new Bank(); } public void addRow(IDataRow row, AsyncCallback callback) { BankRB.getBankDataSet().add((Bank) row, callback); } public String getCaption() { return "Add Bank"; } public IFormItemsGroup[] getGroups() { return groups; } } |
Фреймворк вызовет тетод createEmptyRow тогда, когда построит форму вставки нового значения. Именно в эту пустую строку он вставит данные, которые введет пользователь. Метод addRow будет вызван, когда пользователь нажмет Ok на форме и нужно будет записывать данные уже в источник даных. Форма обращается к источнику данных и вызывает написаный нами метод add. Метод getCaption возвращает название формы. А метод getGroups возвращает группы из предка BankForm.
Вторым создадим класс EditBankForm, который реализует интерфейс IEditForm:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | package net.pleso.tutorials.tutorial1.client.bl.forms; import com.google.gwt.user.client.rpc.AsyncCallback; import net.pleso.framework.client.bl.forms.IEditForm; import net.pleso.framework.client.bl.forms.items.IFormItemsGroup; import net.pleso.framework.client.dal.IDataRow; import net.pleso.tutorials.tutorial1.client.bl.BankRB; import net.pleso.tutorials.tutorial1.client.dal.Bank; public class EditBankForm extends BankForm implements IEditForm { private Integer bank_id = null; public EditBankForm(Integer bank_id) { this.bank_id = bank_id; } public void updateRow(IDataRow row, AsyncCallback callback) { BankRB.getBankDataSet().update((Bank) row, callback); } public void GetData(AsyncCallback callback) { BankRB.getBankDataSet().get(this.bank_id, callback); } public String getCaption() { return "Edit Bank"; } public IFormItemsGroup[] getGroups() { return groups; } } |
Представим себе логику работы формы редактирования. Она получает идентификатор строки даных, которую нужно редактировать. Это она и делает в конструкторе. Далее она по даному идентификатору запрашивает всю строку з данными, чтобы показать старые значения пользователю и дать возможность их редактировать. Это и делает метод GetData. После того, как пользователь отредактировал данные, их нужно сохранить. Вызывается метод updateRow, в который передается уже отредактированная строка с данными. Бизнес-логика вызывает соответствующий метод источника данных. Методы getCaption и getGroups аналогичны форме вставки.
Теперь привяжем готовые формы к справочнику, чтобы пользователь мог их вызывать непосредственно из справочника. Справочник, в свою очередь, должен знать, как эти формы создавать. Формы необязательно могут быть привязаны к справочнику, но и использоваться отдельно. Для того, чтобы справочник мог показать у себя слайдеры доступа к формам, кнопки или вообще исполнить любое действие с данными он должен реализовать интерфейс IActionProviders. Этот интерфейс возвращает массив интерфейсов IActionProvider. IActionProvider - это абстрактный провайдер действия с данными. Создадим реализации необходимых провайдеров, т.е. действий по работе с формами редактирования и вставки. Для этого существуют интерфейсы-наследники IAddFormProvider и IEditFormProvider:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | private class AddRowAction implements IAddFormProvider { public IAddForm getAddForm(IDataRow row) { return new AddBankForm(); } public String getActionCaption() { return null; } } private class EditRowAction implements IEditFormProvider { public IEditForm getEditForm(IDataRow row) { if (row instanceof Bank && row != null) return new EditBankForm(((Bank)row).getBank_id()); else return new EditBankForm(null); } public String getActionCaption() { return null; } } public IActionProvider[] getActionProviders() { return new IActionProvider[] { new AddRowAction(), new EditRowAction() }; } |
Осталось добавить действие удаления с помощью интерфейсов IDeleteRowProvider и IDeleteRowExecutor. IDeleteRowExecutor - это логическая сущность, представляющая собой средство удаления строки данных. Простота работы IDeleteRowProvider и IDeleteRowExecutor позволяет реализовать их в одном классе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private class DeleteRowAction implements IDeleteRowProvider, IDeleteRowExecutor { public IDeleteRowExecutor getDeleteRowExecutor() { return this; } public String getActionCaption() { return "Delete"; } public void deleteRow(IDataRow row, AsyncCallback callback) { dataSource.delete(((Bank) row).getBank_id(), callback); } } public IActionProvider[] getActionProviders() { return new IActionProvider[] { new AddRowAction(), new EditRowAction(), new DeleteRowAction() }; } |
Запускаем проект и получаем рабочий справочник банков с вставкой, редактированием и удалением:



