Форум: "Прочее";
Текущий архив: 2009.08.30;
Скачать: [xml.tar.bz2];
ВнизWEB <-> Настройки <-> БД Найти похожие ветки
← →
Пит (2009-06-30 18:04) [0]Давно терзают меня измышления на тему WEB-настроек программы, хранения их в БД и кажется, я готов хоть как-то более-менее грамотно описать ситуацию.
В целом, проблема как я понимаю давно рассматриваемая и в некоторых (C#) языках есть средства упрощения данного процесса, а некоторые так и созданы для таких вещей, но рассматривается именно Delphi.
Задача описывается достаточно кратко: в программе есть объекты (сущности, записи - как угодно), у них есть свойства. Хранить эти свойства офлайн нужно в БД. Со стороны пользователя данные сущности настраиваются через WEB.
Собственно, все.
А вот теперь о реализации. Общие проблемы такие:
I) неудобно постоянно разбирать / собирать HTML. Как-то надо автоматизировать, обегчить этот процесс, обеспечить расширяемость и так далее.
II) HTTP протокол текстовый, постоянные конвертации, нужно упрощать процесс.
Более подробно на техническом уровне в чем состоит задача:
1) со стороны сервера формируется HTML-страничка, позволяющая в браузере делать настройки объекта, данная страница пересылается клиенту
Вопрос номер один: кто будет формировать эти странички, позволяющие настраивать объекты?
Это может быть сам объект (его внутренний функционал), какой-то дополнительный внешний код, другие варианты?
2) клиент определенным образом использует предоставленный интерфейс. Он может делать элементарные вещи: добавлять объект, редактировать существующий объект, удалять объект.
Сделанные настройки отправляются POST-запросом на сервер. Допустим, серверу это доступно в виде TStrings, имя параметра и его значение (все параметры, напомню, текстовые)
Пример пересылаемых данных для удаления объекта:action=delete
id=54
Пример для редактирования:action=edit
id=54
name=Объект номер 54
number=3
...
[свойства объекта]
...
3) сервер обрабатывает полученную информацию: проверяет на корректность, делает соответствующие изменения в БД, изменяет свойства объектов (сущностей) в программе.
В общих чертах технология работы абсолютно понятна. Но есть нюансы, которые я лично не знаю как оптимальных образом можно обойти. Поэтому предлагаю на практике рассмотреть некоторые варианты работы, для многих это будет понятнее. Потому что проблема именно в конкретике.
Что должен уметь функционал - принимать WEB-запросы в виде набора "параметр=значение" и формировать ответ в HTML.
← →
Пит (2009-06-30 18:05) [1]Вариант 1. Примитивный.
Набор свойств в программе хранится в виде списка на структуры, "ручная" обработка всего и всяvar
List: TList; // список свойств
...
function WEBRequest(ParamList: TStrings): string;
var
id: int64;
begin
if ParamList["action"] = "add" then
begin
if not TryStrToInt64(ParamList["priority"], iPriority) then begin
Result := "Отсутствует параметр приоритет";
exit;
end;
if (iPriority < 0) or (iPriority > 100) then
begin
Result := "Параметр приоритет должен быть в диапазоне 0..100";
exit;
end;
.......
// сохранение в БД
INSERT INTO xxx Priority = [iPriority] ...
// получаем ID получившейся записи
ID := SELECT ... ;
// добавление новой сущности в работу
New(Param);
Param.ID := ID;
Param.Priority := iPriority ;
...
List.Add(Param);
end;
end;
Код ужасен. Приведена только часть кода, которая отвечает за создание нового объекта. А еще есть редактирование, удаление, другие объекты. Да и показана обработка только одного свойства.
Код будет очень избыточным. Проверка на допустимость Priority нужна и в секции редактирования объекта, и в секции добавления нового объекта. И так каждый раз, плюс конвертации постоянные текстовых параметров в нужные типы.
Более-менее сложная иерархия, кода будет килобайты, ну в общем что тут обсуждать.
← →
Пит (2009-06-30 18:05) [2]Вариант 2. Продвинутый.
Пишется некоторый класс, который обегчает работу с WEB-ом. Параллельно он вынужден инкапсулировать работу с хранилищем данных, иначе от него немного толку.
Для наглядности некоторое описание этого класса:THTMLDBConfig = class
...
procedure AddProperty(Name, Desc: string; TypeProp: TTypeProp;
DefValue: string; HTMLMaxLength:integer=-1; HTMLSize: integer=-1;
CheckBoxLabel:string="");
function AddRecord(ParamList: TStrings; ErrText: PString): boolean;
function EditRecord(ParamList: TStrings; PKValue: int64;
ErrText: PString): boolean;
procedure DeleteRecord(ParamList: TStrings); overload; virtual;
procedure DeleteRecord(PKValue: int64); overload; virtual;
function GetHTMLCodeRecord(PKValue: int64): string; overload; virtual;
Пример настройки такого класса:AddProperty("Name", "Название магазина", tpTextNotEmpty, "", 50, 20);
AddProperty("Priority", cParamRegCodeNum_desc, tpInt, "", 3, 3);
Дело улучшается. Имея такой класс, двумя строчками я даю понять о существовании двух полей. Задаю имена (это как имена POST-данных, так и имена полей в БД), задаю описание поля (по которому класс может генерировать текстовое описание WEB-ошибок), тип поля, другие характеристики, нужные классу.
Соответственно, пример 1 трансформируется:function WEBRequest(ParamList: TStrings): string;
begin
if ParamList["action"] = "add" then Result := HTMLDBConfig.AddRecord(ParamList);
end;
Соответственно, на основании заданной структуры (с помощью AddProperty) класс из переданного ParamList проверяет наличие всех нужных параметров, проверят их валидность, пишет их в базу, выдает ошибки в случае чего.
Процедура же GetHTMLCodeRecord в HTML табличном виде выдает форму настройки параметров данной сущности, опять же на основании заданой структуры через AddProperty.
Налицо инкапсуляция работы с WEB и с БД. Но при этом реальный код по работе с сущностью отделен от БД (плохо это? Хорошо?), конечно класс наносит определенные ограничения, а что поделать.
Зато сколько свойств у объекта, столько строчек кода нужно для определения формата вывода в HTML, редактирование, добавления объектов через HTML в БД.
Недостатки возможно в том, что сторонний класс "отнимает" работу с БД у собственно функционального кода.
И при этом получается, что WEB настраивает не сами сущности в программе, а сущности в БД. То есть, допустим, при редактировании объекта класс проверяет и записывает информацию в БД, откуда для применения изменений она уже должна быть считана в программу. Немного, наверное, порочная практика.
Также нужно обеспечивать синхронизацию между работой вспомогательного WEB-DB класса и той части кода, отвечающей за функционал объекта.
В случае использования такого вспомогательного класса вручную остается писать:
- загрузку свойств объекта из БД для работы (для загрузки при старте программы, для загрузки изменений из БД, которые туда сохранил вспомогательный класс)
- сохрание изменившихся свойств объекта в БД
← →
Пит (2009-06-30 18:05) [3]Дальнейшие улучшения
Видимо, надо копать в сторону интеграции функционала объекта с возможностью настройки через WEB, сохранение и загрузка свойств из БД.
То есть, каждый функциональный класс имеет метод аля:TClient = class
// функционал
...
// WEB
function WEBRequest(ParamList: TSTrings): string;
...
// property
property Priority: integer write SetPriority read FPriority;
...
end;
При этом не хочется вручную обрабатывать каждый параметр и свалиться в код примера 1.
Первоначальную проверку данных можно сделать аля как через класс THTMLConfig, но без функционала работы с БД, что-то типа:function TClient.WEBRequest(ParamList: TStrings): string;
begin
if ParamList["action"] = "edit" then
begin
Result := THTMLConfigCheck.Request(ParamList) ;
if Result <> "" then exit;
Self.Priority := StrToInt(ParamList["priority"]);
...
end;
end;
При этом класс THTMLConfigCheck настраивается аля:HTMLConfigCheck.AddProperty("priority", "Приоритет клиента", tpInteger);
тем самым он может производить первоначальные проверки и выдавать ошибки. Дополнительная проверка, возможна, допустим через исключения в сетерах. То есть:procedure TClient.SetPriority(Priority: integer);
begin
if (Priority < 0 ) or (Priority > 100) then EMy.Create("Ошибка такая то");
...
end;
Соответственно, тогда в WEBRequest должна быть "поимка" исключений при присвоении свойств.
Вся проблема усугубляется тем, что нужно соблюдение некоторых юзеро-ориентированных правил для веба:
- если форма заполнена неверно и отправлена - должен вернуться ПЕРЕЧЕНЬ ошибок (а не первая встретившаяся) заполнения формы с повторным выводом неправильно заполненной формы
Есть еще кое-какие фишки, забыл уже ((
В общем, проблема достаточно многогранная, думаю, у кого нет опыта работ таких связок на дельфи сразу во все проблемы просто не въедет. Описать полностью просто сил нету, статью надо писать. Хотелось бы обсудить, возможно кто-то имеет опыт, решал аналогичные проблемы. От мыслей пухнет голова, сделаешь в одном месте красиво - в другом не очень. А хочется красиво везде, без избыточности...
Если у кого идеи есть - высказывайте, я не все описал, по факту могу уже порассуждать чем плохо, хорошо, в чем затык...
← →
test © (2009-06-30 18:12) [4]В Java давно на этот счет сделали DAO DB суть в том что класс отвечает за таблицу(связку таблиц), ты оперируеш обьектами, обьектами уже сами занимаются SQL DML и Select"ом.
← →
test © (2009-06-30 18:13) [5]Там этот момент облегчен тем что удалять ничего не надо сервер сам узнает своих.))
← →
Пит (2009-06-30 18:32) [6]
> В Java давно на этот счет сделали DAO DB
круто
> класс отвечает за таблицу(связку таблиц), ты оперируеш обьектами,
> обьектами уже сами занимаются SQL DML и Select"ом.
какая пользова от этого в дельфи, можно повторить алгоритм? Как это реализовано все принципиально, очень хотелось бы на элементарном примере.
← →
sniknik © (2009-06-30 18:33) [7]много букв.., не осилил, но суть вроде уловил, про создание компонент для автоматизации http...
один вопрос по этому поводу, а у тебя есть в дельфи закладки с названиями начинающимися с IW ххх (Intra Web)? и что ты про них думаеш?
← →
Пит (2009-06-30 19:23) [8]
> про создание компонент для автоматизации http...
ну это очень приблизительное описание, ну что-то типа.
> а у тебя есть в дельфи закладки с названиями начинающимися
> с IW ххх (Intra Web)? и что ты про них думаеш?
никогда не работал. Почитал в вики: http://ru.wikipedia.org/wiki/IntraWeb
почитал статейку про IW... Сложилось мнение, что данная технология сильно ограничит возможности.
У нас, во-первых, свой HTTP-сервер (основанный на idHTTP). Свои стили CSS, подсказки, свой дизайн продукта, логика настроек и редактирования. Плюс приложение не использует форм, управляется только через WEB, работает в качестве сервиса... Боюсь, заточка IW под проект будет куда геморойнее, чем реализовать изложенную задачу.
Единственное, чую не встречу человека, который сможет детально понять проблемы ((( Сейчас копаю в сторону того, что сторонний универсальный вспомогательный класс может задавать свойства Delphi объектов через RTTI, ошибки генерировать через исключения в Set"ерах.
Но как конкретно это будет выглядеть. Как организовать редактирование, создание нового объекта... Как связать с сохранением в БД, не писать же в коде каждого set"ера сохранение этого свойства в БД отдельно...
Блин, просто голова пухнет. Писать все варианты и смотреть времени нету, изначально раставить по полочкам и выбрать оптимальный вариант не получается, не хватает опыта, памяти и мозгов ))
← →
DVM © (2009-06-30 20:40) [9]Мне тоже было бы интересно услышать кто как подходил к решению данной задачи, описанной Пит-ом.
← →
test © (2009-06-30 21:46) [10]Пит (30.06.09 18:32) [6]
DAO DB это просто требования к классам(программе) как оно должно фунциклировать, реализовать можно хоть на Бейсике.
← →
Пит (2009-06-30 21:49) [11]
> DAO DB это просто требования к классам(программе) как оно
> должно фунциклировать, реализовать можно хоть на Бейсике.
>
очень расплывчато. Можешь в терминах дельфи продемонстрировать подход, приблизительный, чтобы понять как это и что упрощает? Писать базовый класс, какие требования соблюдать, как это реализовано?
← →
test © (2009-06-30 21:55) [12]Пит (30.06.09 21:49) [11]
У тебя есть класс основной который занимается соединением и тд, есть соглашения как должен работать класс который таблицу перекрывает. Ты создаешь класс таблицы получаешь запись, меняеш его, сохраняеш состояние, сумбурно мал мало, посмотри в инете там толково расписано, как многие технологии Java они представляет собой описание реализацию делает каждый по своему. Сама технология описывает основные правила и требования к группе классов.
← →
Пит (2009-06-30 22:26) [13]Попытаюсь кратко подвести размышления, на которых я остановился.
У нас есть три аспекта:
- база данных, которая хранит настройки конфигурации
- некий функциональный код, реализующий нужное нам поведение на основе параметров объектов (свойства которого и хранятся в БД)
- WEB-интерфейс по управления и настройке свойств объектов
Все эти три аспекта должны быть реализованы. Сразу вопрос - где? Сам функционал объекта должен уметь работать с БД, с WEB-параметрами или это отдельный вспомогательный класс, как он будет интегрирован с конкретным объектом?
Грубо говоря у объекта есть:property Number: integer write xxx read yyy;
Где и кто должен сохранять / загружать это свойство из БД и управлять этим свойством через WEB?
Сохрание свойства. Можно сделать через сетер. То есть, присваиваем объекту новое значение свойство - оно тут же сохраняется в сетере в БД, присваивается или в случае неправильно заданного значения выдает исключение.
Такой вариант слишком геморный, в каждом сетере надо генерировать запрос к БД.
Можно сделать это в методе объекта, который по команде сбрасывает все значения свойств в базу. Другой метод из БД загружает свойства.
Плохо с точи зрения начальной инициализации. Допустим, при 100 объектах надо 100 раз вызвать метод загрузки свойств из БД, будет сгенерировано 100 запросов. Да и тот кто для 100 объектов будет вызывать эти методы загрузки сам должен уметь работать с БД, чтобы получить список всех объектов и для каждого вызвать метод загрузки.
Можно сделать внешний класс, который при инициализации сделает общий SELECT и по циклу инициализирует все объекты, одна запись в БД = один объект.
Опять же, проверка в сетерах на допустимость значений - это прекрасно. Но допустим нужно проверить не только разрешенный диапазон, но и проверить при загрузке / создания объекта со свойством CodeName равным CodeValue не существует ли уже другого такого объекта с таким же значением CodeName. Сетер класса должен знать о всех других экземплярах данного класса значит. или должен быть вышестоящий управляющий объект со списком всеъ экземпляров, тогда логично в него перенести функционал по работе с БД и WEB...
Блииин, короче я просто не в состоянии продумать адекватную логику. И так, и эдак всплывают подводные камни.
Лучшее, что я сейчас реализовал - это "Пример 2" из поста [2]
Некий универсальный класс, который первоначально нужно настроить на свойства объекта аля:Config.PKName = "ID";
Config.AddProperty("Name", "Название магазина", tpTextNotEmpty, "", 50, 20);
AddProperty("Priority", "Приоритет", tpInt, "", 3, 3);
Где Name название свойства в БД и в WEB-запросах. Далее идет описание свойства (для текстового описания ошибок), потом тип этого поля (в данном случае текстовое поле, которое не может быть пустым, потом его значение по-умолчанию для нового объекта, размер и максимальная длина в WEB-форме.
В результате этот класс на основании настроек умеет:
- по данным WEB / POST / GET запроса вычленять параметры и сохранять их в БД (редактирование объекта)
- ... создавать в БД новый объект
- ... удалять объект из БД по primary key
- выдавать настройки объекта в виде HTML таблицы
- выдавать HTML таблицу с настройками по-умолчанию для создания нового объекта
Но при этом этот универсальный физический класс спрягает работу WEB и БД, ничего естественно не зная о функциональном коде.
Поэтому плюс нужно уметь загружать настройки из БД.
И алгоритм немного порочный получается.
- При редактировании по WEB настроек объектов - через универсальный класс они сохраняются в БД
- далее вызывается функция, которая очищает список всех объектов из программы и загружает их всех заново скопом из БД
Минусы очевидны... Но что дальше делать - не знаю. ((
← →
antonn © (2009-06-30 23:46) [14]странно что в теме еще не прозвучало слово "xml" :)
← →
sniknik © (2009-07-01 01:42) [15]> странно что в теме еще не прозвучало слово "xml" :)
а это что, панацея от всего? или для всего, как бы это правильно выразить.
перечитал, и наконец то все. стало непонятно почему такой упор на дельфи и класс/компонент в дельфи.
"плясать" то тут, имхо, надо от клиента, т.е. html странички, и проверки все в ней яваскриптом делать, и введенное из нее посылать... (а там кстати xml формировать посложнее чем тот же json), на сервере же (в программе) только принять готовые данные и в базу(или ini, без разницы) положить. ну и послать сам html естественно, готовый, просто в нужные места дефоултные значения/старые настройки из базы подставлять.
зачем тут "пляски" с классами, не пойму.
← →
antonn © (2009-07-01 02:03) [16]
> а это что, панацея от всего? или для всего, как бы это правильно
> выразить.
а это хорошо бы вписалось в протокол обмена через html, и при должном следовании стандарту был бы неплохой независимый интерфейс обмена под разные клиенты, оформленный отдельным "звеном". А пока я почитал автора и какая то каша, точно не понять что не получается, что хочется.
И со стороны расширяемости все таки получше, в данном случае гораздо лучше ini-структуры, удобней описывать св-ва и значения.
Чтоб не делать всякие проверки в коде типа:if ParamList["action"] = "add" then
← →
test © (2009-07-01 05:25) [17]Пит (30.06.09 22:26) [13]
Поищи в интернете требования/описания/пояснения к Data Acess Objects там готовый вариант алгоритма на описанное тобой лежит, в том числе и с подводными камнями.
← →
test © (2009-07-01 09:33) [18]antonn © (01.07.09 02:03) [16]
И Ajax и DataMinig и SAX и ....
Не плоди сущности без надобности, бритва Аккамы.
← →
makvell (2009-07-01 10:32) [19]Послушай test, он дело говорит ;)
Почитать можно, например тут: http://javagu.ru/portal/dt?last=false&provider=javaguru&ArticleId=GURU_ARTICLE_81158&SecID=GURU_SECTION_ 80703
это жава, но проблем с пониманием сути быть не должно :)
← →
makvell (2009-07-01 10:36) [20]И кстати, по поводу XML, знаю что тут есть его большие "не любители" :) но суть не в этом, как раз тут оно может быть уместно в случае, когда веб морда должна/может меняться, при этом не хочется править код, который ее генерирует. Это, конечно, добавление еще одного звена но... допустим сервер генерит не html, а xml, после чего это xml при помощи xslt трансформируется в нужный нам html. Захотели что-то поменять, поправили трансформацию, ничего не компилим, в код не лезем. Но это просто так, вдруг тоже пригодится :)
← →
Пит (2009-07-01 12:08) [21]
> стало непонятно почему такой упор на дельфи
потому что программа на дельфи разрабатывается?!
> и класс/компонент
> в дельфи
о компоненте речи не шло. Что касается оформления в виде набора функций / классом - ну так вопрос не принципиальный. Но у нас же все таки ООП, так что наверное лучше оперировать объектами.
> "плясать" то тут, имхо, надо от клиента, т.е. html странички,
> и проверки все в ней яваскриптом делать
нуууу, братец... Ты сейчас сказанул.
Элементарно отключен JS в браузере и все. Браузер тебе пошлет какие угодно данные (это мы не рассматриваем примеры, когда насильно будут посылать неверные данные). Например, в качестве системного номера тебе прийдет строка:SysNum=Hi man
И что ты будешь делать? Сделаешь аля:INSERT INTO ... SysNum = :param1
Query.SetParamByName("param1").AsInteger := StrToInt(PostData["sysnum"]) ;
А там строка - получишь исключение. Клиенту максимум выведется на английском языке стандарный текст исключения об ошибке преобразования. А если параметра нету?
А если тебе нужно гарантировать, что данный SysNum уникальный, что ты там проверишь с помощью JS?
Ты все таки не въехал в проблему. Проблема лежит на НИЗКОМ уровне. Ты просто представь тот объем однотипного кода лишь по извлечению параметров из HTTP-запроса у разных классов (ну или частей кода в общем случае), проверка параметров, запись в БД.
Блин, ну я в общем подозревал, что это бесполезно. Кто реально не пытался такое писать и не понял всего гемора - так не поймет (((
← →
Пит (2009-07-01 12:12) [22]ну а про DAO почитал - это связь реляционной БД с ООП моделью. Ну это вообще о другом.
← →
test © (2009-07-01 12:13) [23]Пит (01.07.09 12:08) [21]
>>Блин, ну я в общем подозревал, что это бесполезно. Кто реально не пытался
такое писать и не понял всего гемора - так не поймет (((
makvell (01.07.09 10:32) [19]
Почитать можно, например тут: http://javagu.ru/portal/dt?last=false&provider=javaguru&ArticleId=GURU_ARTICLE_81158&SecID=GURU_SECTION_ 80703
это жава, но проблем с пониманием сути быть не должно :)
Какая разница на каком языке дока, главное что Тьюринговые языки, ты почитай ознакомься.
← →
Пит (2009-07-01 12:25) [24]
> ты почитай ознакомься
см [22]
← →
Sergey Masloff (2009-07-01 13:11) [25]Зачем весь этот геморрой с классами? Классы ради классов?
Вся эта задача решается элементарно процедурно на встроенном процедурном языке СУБД (если таковой имеется - я бы все остальные варианты просто не рассматривал).
На стороне клиента функции - трубы "записать параметр", "зачитать параметр", "зачитать все параметры определенного объекта"
Как все это работает можно посмотреть на сайте Ингоса если есть хоть один наш полис - зарегистрироваться и посмотреть свои настройки в личном кабинете ;-) Все работает именно так как я написал. Весь код несколько строчек на PL/SQL который может поддерживать человек слыхом не слыхавший про дельфи, джава и це с решеткой а прочитавший тонкую брошюрку по процедурному программированию ;-)
← →
test © (2009-07-01 13:16) [26]Пит (01.07.09 12:25) [24]
(*псевдокод похожий на Дельфи*)
TAbstractTable= class
(*тут DML и Select*)
.....
end;
TTable = class(TAbstractTable)
private
fNumber:integer;
procedure SetNumber(i:integer);
...
published
property Number: read fNumber write SetNumber;
...
end;
procedure TTable.SetNumber(i:integer);
begin
....
if i > 10000 then
RaiseException("Выход за диапазон");
....
end;
Ошибку обрабатывает твой личный обработчик но ему не надо возиться с открытием соединений с БД и запросами, логика на TTable, запросы на TAbstractTable.
← →
test © (2009-07-01 13:18) [27]Sergey Masloff (01.07.09 13:11) [25]
Каждому свое.
← →
Пит (2009-07-01 13:18) [28]Эх, попытка номер 5 )))
У нас фактически три сущности: WEB, БД, функционал
- WEB это совокупность действий, алгоритмов по приему и ответу на WEB / HTTP / POST /GET запросы и взаимодействие с функционалом
- БД это совокупность действий, связывающих функционал и базу данных
- сам функционал это то, что обеспечивает работу объекта )))
Возьмем функциональный класс, допустим который хранит информацию о ВСЕХ клиентахTClients = class
function AddClient(Name, Family, ...): boolean;
function GetClientByName(Name: string): TClientInfo;
function DeleteClientByID(ID: int64): boolean;
...
end;
Первые вопросы - где и кто будет реализовывать функционал по работе с WEB и БД?
Работа с WEB
Это может быть или частью функционала TClients:
>function TClients.WEBRequest(WebParams: TStrings): string;
Или реализовано во внешнем коде.
В первом случае мы сталкиваемся с записью аля из первого примера в посте [1]. Вручную обработка каждого параметра, выдача ошибок - ужасно. И каждый раз этот функционал нужно повторять в каждом классе: в TOperators, в TPlaces... и т.д.
Во втором случае (вынесено во внешний код) возможно написание некоего универсального класса. по обработке POST-запросов. Но без работы с БД от него мало толку.
Этот универсальный класс не может настраивать конкретные классы аля TClients, TOperators по понятным причинам (ну вот только если грамотно как-то приплести RTTI, но как...). Этот универсальный класс можно настраивать типа того:
>Config.AddProperty("Name", "Название магазина", tpTextNotEmpty, "", 50, 20);
>Config.AddProperty("Priority", "Приоритет", tpInt, "", 3, 3);
И вот он уже готов обрабатывать сущности, имеющие свойства Name и Priority. В смысле работы с WEB он можнт принимать набор параметров (не редактирование, удаление, добавление), вычленять их (по настройкам), проверять правильность. Как-то так:
>Error := Config.CheckParam(WebParams);
На основе заданного описания (AddProperty) он проверяет правильность HTTP параметров, выдает ошибки. Упрощает немного дело, но лишь очень частично.
Можно его завязать еще и на БД. Тогда помимо проверки он еще будет писать / извлекать данные из БД. Что-то вроде:
Config.AddRecord(WebParams) - после проверки добавляет новую запись на основании описания
Config.DeleteRecord(WebParams) - удаляет некую сущность из БД
Опять же на основании заданного описания может генерировать в HTML виде описания сущости из БД :
Config.GetHTMLView(PKValue: int64): string;
Это уже сильно упрощает дело. Но при этом разрывается связь между функционалом (классами TClients, TOperators) и базой данных. Фактически, такой вспомогательный класс TConfig становится провайдером по редактированию БД, без привязки к функциональным классам. У меня пока это обходится где-то так:
{ поступил WEB-запрос }
Config.AddRecord/EditRecord (WebRequest);
Clients.Clear;
Client.LoadAllFromDB;
То есть, фактически, например при добавлении нового экземпляра сущности через WEB - оно через настроенный элементарным образом TConfig пишется в БД с контролем ошибок, а далее идет приказ функциональному классу перезагрузить все из БД.
Минусы очевидны - далеко не всегда можно так поступить, только в случае примитивных сущностей возможна прозрачная перезагрузка всех данных из БД.
Вот именно на этом этапе я и остановился сейчас. Я не знаю как в описанном случае все связать с функциональными классами.
И в тоже время, если перенести работу с БД в функциональный класс, как упростить работу c WEB... Бррр...
Надеюсь, хоть немного прояснил.
← →
sniknik © (2009-07-01 13:24) [29]> Браузер тебе пошлет какие угодно данные
ничего он не пошлет, если "посылалка" будет на том же яваскрипте (а много данных посылать придется именно так). и кроме того раз он отключен то лучше выдать страницу с отказом работать без него чем бесполезную форму ввода параметров.
> (это мы не рассматриваем примеры, когда насильно будут посылать неверные данные).
кто? разве не ты пишешь обе стороны, и клиент и сервер?
> И что ты будешь делать? Сделаешь аля:
если там должно быть число, то так и буду работать с ним как с числом.
> А там строка - получишь исключение.
ну и что? нормальное поведение, по нему буду знать что сам где то в передаче напортачил, а исключение обработаю как обычно, сохраню в лог, и выдам его в ответ вместо данных (и вместо таблички например у меня на странице появится ошибка от базы, типа "неверное значение параметра" или "ошибка преобразования").
ничего страшного в этом нет.
ты не путай проверку всего и вся, всякой мелочи типа, входит ли число в диапазон, с нормальными исключениями.
> А если тебе нужно гарантировать, что данный SysNum уникальный, что ты там проверишь с помощью JS?
а почему нет? если нужно его генерить на клиенте то использую гуид. на крайний случай будет исключение. не проблема.
> Ты все таки не въехал в проблему.
я ее не вижу, в моем представлении как это реализовать.
> тот объем однотипного кода лишь по извлечению параметров из HTTP-запроса
вот весь однотипный объем -
JSONObject.Text:= ARequestInfo.Document;
для получения готового распаренного объекта со структурой как xml-документа (работал с xml?). это если передавать json-ом, как советовал, и использовать их компонент для дельфей. (в обратную сторону и этого не надо, стандартная функция eval делает стандартный "родной" обьект в яваскрипте (и да там можно сказать что ее использование небезопасно, но это решаемо, а для варианта когда и то и то свое попросту не нужно))
> Кто реально не пытался такое писать и не понял всего гемора - так не поймет (((
вообще то у меня есть что то подобное, не страница параметров, но похожее (формирует страничку, посылает туда сюда данные, работает с базой).
хотя ты прав я не пытался писать, а просто взял и написал, наверное поэтому и не понимаю проблем...
← →
Пит (2009-07-01 13:30) [30]
> Sergey Masloff (01.07.09 13:11) [25]
Сергей, не очень понятно. Можно на примере привести путь прохождения данных?
Допустим, со стороны клиента от заполненной формы мы получаем следующие WEB параметры типа:action=edit
id=45
Name=Sergey
Number=4574
Логически это означает отредактировать клиента с ID равным 45 и присвоить ему (поля в БД) имя сергей и номер 4574. Можешь описать всю цепочку прохождения и обработки данных?
> procedure TTable.SetNumber(i:integer);
> begin
> ....
> if i > 10000 then
> RaiseException("Выход за диапазон");
> ....
>
> end;
test, пример абсолютно понятный, но ЧТО идет в случае else? ))
Если больше 10000 - исключение, ок. А если параметр верный, какой код в else который по идее должен сохранить параметр в БД?
И еще раз, я тебе уже говорил - это ты говоришь о связи реляционной БД с ООП моделью. Но у меня задача иная, там еще сильно впрягается управление по WEB.
← →
test © (2009-07-01 13:31) [31](*Псевдо код похожий на Дельфи*)
TAbstractWeb=class
// Стандартная обработка
end;
TDEfaultPage=class(TAbstractWeb)
// Обработка Default Page
end;
TMailPage=class(TAbstractWeb)
// Обработка почты
end;
ИМХО Вот как то так
← →
Polevi © (2009-07-01 13:47) [32]Для каждого объекта создается набор хранимых процедур для создания, сохранения, удаления и выборке по ID
Пишется генератор, который используя информацию о метаданных базы через INFORMATION_SCHEMA генерирует классы-обертки, которые умеют эти процедуры вызывать.
Реализация ф-ии WebRequest сводится к поиску нужного типа, инстанцированию и вызова метода.
← →
Polevi © (2009-07-01 13:49) [33]Да, и генерируемый объект также имеет ф-ию Render, которая возвращает html представление
← →
makvell (2009-07-01 13:57) [34]
> test © (01.07.09 12:13) [23]
>
> makvell (01.07.09 10:32) [19]
> Почитать можно, например тут...
>
> Какая разница на каком языке дока, главное что Тьюринговые
> языки, ты почитай ознакомься.
Не совсем понял, к чему наезд на меня :) я сказал, что ты прав, и что близко к использованию ДАО, дал пример (описание) как оно в яве. Не думаю что мне стоит с чем-то еще знакомиться, уже знаком и вполне успешно использую ;) и вообще я не вижу проблемы у топик стартера, такое ощущение, что это обсуждение ради обсуждения, типа "вы все не правы, мне нужно что-то другое, а что я и сам не знаю".
← →
Пит (2009-07-01 13:59) [35]
> ничего он не пошлет, если "посылалка" будет на том же яваскрипте
нуу... Это значит система станет ненастраиваемой в браузерах с отключенным JS. Такой вариант неприемлим.
Да и вообще, это смена шила на мыло. Код по проверке параметров из программы перенесен на JS, ну там точно также надо будет писать проверки. А для упрощения проверок строить определенную иерархию кода, чтобы оптимизировать.
> а почему нет? если нужно его генерить на клиенте то использую
> гуид. на крайний случай будет исключение. не проблема
ты не понял. Допустим, есть список устройств. У каждого устройства есть номер, не ID из БД, а конкретно задаваемый номер, идентифицирующий устройство в транспортной сети. У каждого устройства допустим свой адрес, но при этом адреса не могут повторяться. Где ты будешь делать проверку, в JS? Тебе же нужен доступ к данным всех устройств, чтобы понять, что новый заданный номер не катит по причине уже наличия данного номера у другого устройства.
Нее, полностью переложить проверку на JS нереально, он не обладает данными для проверки. Только так, максимум контроль передаваемых параметров, число, строка, не пустая строка и подобное, на уровне типов.
> JSONObject.Text:= ARequestInfo.Document;
> для получения готового распаренного объекта со структурой
> как xml-документа
а что там парсить в HTTP-параметрах? ребенок справится.
Вопрос не в том, чтобы распарсить (у меня точно такие же распарсенные параметры в TStringList хранятся), а в том, чтобы присвоить эти значения функциональному коду.
← →
Sergey Masloff (2009-07-01 14:05) [36]Пит (01.07.09 13:30) [30]
Конечно. Только нужно на стороне сервера еще как-то отличить что это за команда (или писать по паре процедура сервера приложений -процедура в субд. Предлагаю вариант с одной процедурой на стороне веб-сервера. Назовем ее ApplyCommand
допустим с такой сигнатурой (абстрактно)
ApplyComand(inBuf, outBuf : string) : boolean;
Тогда примерно так
Клиент передает данные как строку через get или post
|
Сервер перехватывает строку и (возможно) приводит ее в нужный вид. После преобразования параметров вызывается функция ApplyCommand в которую как входной буфер отдаются параметры приехавшие с клиента. Этот код написан и отлажен 1 (один) раз и не меняется никогда
|
Процедурный код СУБД
Пусть процедура называется
ApplyCommandImp() она
- вызывает другую процедуру которая по буферу понимает что это за команда допустим GetCommandCode(inBuf : string) : integer;
тогда ApplyCommand() выглядит так
begin
case GetCommandCode(inBuf : string) of
0 : return SaveClientParams(inBuf, outBuf);
1 : return ReadClientParams(inBuf, outBuf);
2 : return SomeOtherUsefulInfo(inBuf, outBuf);
....
else
return StdErrorMsg(inBuf, outBuf);
end
а например SaveClientParams(inBuf, outBuf); выглядит так
begin
if AnalyzeInputParams(inBuf) then begin
update Client set Name=GetParam(inBuf,"name"), Number=(inBuf,"number") where id = GetParam(inBuf,"id")
if (ничего не проапдейтилось)
insert into Client(Name, Number, id) values (Params......
outBuf = (текст, HTML, XML о том что все в порядке)
return true;
else return ReportInvalidParams(outBuf) // в буфер запишем что там плохого - можно сразу как HTML (XML)
end;
Ну что-то в этом роде. На практике все несложно получается и каждая процедура примитивна - даже документировать не нужно
<>
← →
test © (2009-07-01 14:06) [37]makvell (01.07.09 13:57) [34]
Опечатка, хотел Питу отправить тебя целеком переписывать было лень скопировал. Немного криво получилось ))
← →
Пит (2009-07-01 14:12) [38]
> Для каждого объекта создается набор хранимых процедур для
> создания, сохранения, удаления и выборке по ID
> Пишется генератор, который используя информацию о метаданных
> базы через INFORMATION_SCHEMA генерирует классы-обертки,
> которые умеют эти процедуры вызывать.
> Реализация ф-ии WebRequest сводится к поиску нужного типа,
> инстанцированию и вызова метода.
это прекрасно, но я это уже сделал.
Это фактически провайдер по редактированию записей в БД. Он связывает WEB и БД, но он никоим образом не связывает это с функциональными классами!!! Вы каждый раз предлагая такой вариант выкидываете один компонент - сам функционал программы.
Я писал в постах [2] и [28] как это реализовано в моем случае. Тоже самое, что ты предложил, только прототип объекта (сущности) берется не из метаданных БД, а настраивается вручную аля:Config.AddProperty("Name", "Название магазина", tpTextNotEmpty, "", 50, 20);
Это и задает его отображение в WEB (функция Render), и задает способы записи в БД.
Вызов описанных тобой хранимок заменен у меня опять же на основании заданного прототипа сущности на исполнение запросов INSERT, UPDATE и DELETE. В используемой БД нету хранимок, да и не принципиально это. Такой функционал уже есть, он реализован.
Но он не связан с функциональным кодом! Грубо говоря, для твоей реализации представь ситуацию.
В WEB интерфейсе клиент УДАЛЯЕТ некий экземпляр сущности. Провайдер TConfig понимает это и удаляет из БД соответствующую запись. Но как это изменение скажется в программе? Грубо говоря класс TSomebodyCollection, который хранит информацию о всех сущностях - как узнает об изменениях?
← →
Polevi © (2009-07-01 14:24) [39]>класс TSomebodyCollection как узнает об изменениях?
а зачем он хранит эту информацию ? web приложение stateless по умолчанию
запросит броузер этот список - выдай ему свежие данные
а вся валидация на уровне базы - констрэйнтов и хранимых процедур
← →
Polevi © (2009-07-01 14:28) [40]если ты хочешь отобразить данные на объектную модель и в дальнейшем работать со списками и экземплярами связаных сущностей - тебе нужен ORM.. чтото вроде Hibernate
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2009.08.30;
Скачать: [xml.tar.bz2];
Память: 0.64 MB
Время: 0.006 c