AddThis Feed Button

GWT-PF, GWT Pleso Framework

GWT Pleso framework

GWT Pleso Framework - это высокоуровневый framework основанный на GWT для создания пользовательских AJAX интерфейсов фронтэндов баз данных

 

pleso odb-ui prototype

ODB-UI prototype

Прототип интерфейса пользователя к объектным базам данных


Туториал 1. Написание первого GWT-PF приложения.

Содержание:

Часть 1. Создание простого справочника

  1. Создание проекта
  2. Общий подход
  3. Создание набора данных
  4. Создание класса-справочника
  5. Визуализация справочника

Часть 2. Создание форм манипуляции с данными: вставка, редактирование, удаление

  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()
	};
}

Запускаем проект и получаем рабочий справочник банков с вставкой, редактированием и удалением:

 

Комментарии: 0