Сервис электронного кафе

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    3,79 Мб
  • Опубликовано:
    2015-07-19
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Сервис электронного кафе

СОДЕРЖАНИЕ

Введение

1. Описание сервиса электронного кафе и определение требований к системе

.1 Описание сервиса электронного кафе

.2 Определение требований к системе

. Постановка задачи и обзор методов её решения

. Модели представления системы и их описание

.1 Модель вариантов использования

.2 Модель состояний

.3 Модель последовательности

.4 Модель классов

.5 Модель компонентов

.6 Модель развертывания

. Информационная модель системы и ее описание

.1 Информационная модель

.2 Доказательство приведения информационной модели к 3-ей нормальной форме

. Обоснование оригинальных решений по использованию технических и программных средств

. Описание алгоритмов реализующих бизнес-логику серверной части

. Руководство пользователя

. Результаты тестирования разработанной системы и оценка выполнения задач

Выводы и заключения

Списки использованных источников

Приложения

ВВЕДЕНИЕ

В настоящее время большое количество ресторанов использует автоматические системы учета и контроля на производстве. Уходят времена ручного учета, рукописных чеков и многочисленной бухгалтерии, что позволяло допускать «выгодные» ошибки использовать разные ситуации для личного обогащения.

На сегодняшний день остро стал вопрос о повышении работы ресторанов, как неотъемлемой части сферы услуг. На рынке услуг, а конкретней «ресторанном» рынке конкуренция растёт огромными темпами, и это в свою очередь заставляет владельцев задуматься о рациональном использовании трудовых, а также материальных ресурсов, что в рациональной комбинации обеспечивают процветание бизнеса. Помимо расстановки материальных и трудовых ресурсов, можно воспользоваться инвестициями, направив их в механизм работы бизнеса.

В последнее время широко используются электронные средства для заработка дополнительных средств ресторанами, для рекламы организаций, не имеющих реальных кафе - представителей. Электронные кафе и рестораны - это удобство, как для потребителей, так и для поставщиков продукции.

Преимущества использования сервиса электронного кафе:

Недопущение ошибок при составлении заказа, т.к. посетитель составляет заказ сам (добавляя блюда и т.д.).

Полный контроль процесса, начиная от момента получения заказа и заканчивая его исполнением.

Повышение качества сервиса и скорости обслуживания клиентов.

Быстрота работы (удобство для клиента, эффективно для владельца).

Целью данной работы является разработка такой программы, которая бы позволила людям, не выходя из дома, покупать любимую еду и напитки.

Для достижения данной цели было необходимо исследовать данную систему, как с точки зрения функциональной модели, так и информационной.

Была разработана функциональная и информационная модели, в результате разработки и реализации, которых было получено данное приложение.

1.ОПИСАНИЕ СЕРВИСА ЭЛЕКТРОННОГО КАФЕ И ОПРЕДЕЛЕНИЕ ТРЕБОВАНИЙ К СИСТЕМЕ

.1 Описание сервиса электронного кафе

В предприятиях общественного питания в наше время происходит внедрение новых современных технологий, способствующих повышению качества кулинарной продукции. Однако, в последнее время, наряду с современными технологиями, стали внедряться такие системы, как электронный заказ блюд и напитков.

Общественное питание одной из первых отраслей народного хозяйства встало на рельсы преобразования, приняв груз острейших проблем переходного периода на рыночные отношения. Быстрыми темпами прошла приватизация предприятий, изменилась организационно-правовая форма предприятий общественного питания.

На начальной стадии разработки данной системы был поэтапно составлен процесс обслуживания клиентов работниками ресторана, а также их работы с меню и заказами. Для графического описания модели был использован стандарт IDEF0 (Integration Definition for Function Modeling - методология функционального моделирования, предназначенная для описания бизнес-процессов)[2]. Графический язык IDEF0 удивительно прост.

Функциональный блок графически изображается в виде прямоугольника и олицетворяет собой некоторую конкретную функцию в рамках рассматриваемой системы. Причём на первом уровне данный блок или контекстная диаграмма представляет основную цель, в моём случае - “Автоматизация работы ресторана по приёму клиентов”.

Каждая из четырех сторон функционального блока имеет своё определенное значение (роль), при этом:

верхняя сторона имеет значение “Управление” (Control);

левая сторона имеет значение “Вход” (Input);

правая сторона имеет значение “Выход” (Output);

нижняя сторона имеет значение “Механизм” (Mechanism)[2].

В данной работе главной целью было ”Разработать сервис электронного кафе” на “реальном” примере и показать какая информация для этого нужна, кто этим управляет и как это осуществляется (приложение А рисунок А.1).

Входной информацией являются денежные средства, которые необходимо для построения данной системы в реальном мире. Далее происходит создание самой системы, а также построение способов её функционирования. Управляющими механизмами являются правила составления заказа, а также нормативные документы (о составлении договоров, доставке блюд и т.д.). Механизм выполняется с помощью клиентов и персонала. Дальнейшие декомпозиции контекстной диаграммы были сделаны до того уровня вложенности, чтобы можно было рассмотреть элементарные функции (приложение А рисунок А.1 - А.5).

.2 Определение требований к системе

Основными требованиями к данной работе являются:

Информационная система должна быть реализована в видеприложения на языке Java с использованием технологий JSP, Servlet, RMI, XSLT.

Бизнес-логика системы должна быть реализована в методах, удаленно вызываемых сервлетами, с использованием технологии RMI. Все методы классов реализующих бизнес-логику, возвращают сервлету данные в формате XML. Сервлет производит трансформацию XML данных в xHTML с помощью XSL данных, загружаемых из файлов расположенных на стороне сервлета.

Доступ к данным в СУБД должен осуществляться через драйвер, поставляемый производителем СУБД. Использование интерфейса ODBC запрещено. Разрешается использовать Java Persistence API.

Приложение поставляется в виде двух архивов: war-архива (сервлет) и jar-архива (удаленные методы).

База данных должна генерироваться sql-скриптом под

пользователем вида Strakh_O_V .

Интерфейс программы и данные должны быть только на русском

(белорусском) языке.

Построение программного кода должно соответствовать правилам,

определенным в документе «Code Conventions for the JavaTM Programming Language».

Минимальные системные требования данного проекта:

Windows XP/7 CPU x32.5.1.

Сервлет-контейнер: Tomcat 6.0.26.6/ JRE6.

2. ПОСТАНОВКА ЗАДАЧИ И ОБЗОР МЕТОДОВ ЕЁ РЕШЕНИЯ

Целью данной работы было создание приложения, которое поможет работникам общепита, в частности ресторана, в обслуживании клиентов, работе с меню и заказами, а также поможет получить потребителям, то, что они хотят за короткое время и без особых усилий.

Приложение должно представлять собой сайт, на котором люди могли бы просмотреть блюда по категориям, добавлять блюда в корзину, редактировать свою корзину, оформлять заказ и просматривать новости и дополнительную информацию о портале.

В данном приложении вход в систему может осуществляться как посетителями ресторана, так и его работниками, поэтому некоторые функции доступные работникам сервиса будут недопустимы для посетителей.

В наши дни существует большое количество подобных сайтов, например Eda.by, Pokushat.by и многие другие. Они заключают договор с ресторанами и кафе, например ’Гараж’, и уже представляют продукции этого заведения. Также существует большое количество заведений, так называемых ‘Take away’, которые предназначены для того, чтобы люди брали там еду на вынос. Такие заведения также имеют свои сайты, например ‘sushivesla.by’.

В данном курсовом проекте необходимо сформулировать и решить ряд задач:

Данное приложение должно быть реализовано на языке программирования Java, с использованием сервлетов, JSP страниц, удалённых методов.

Необходимо построить информационную модель системы в.

Необходимо построить функциональную модель системы в IDEF0.

Необходимо смоделировать информационную систему с помощьютандарта UML.

Также в программе также должны быть реализованы основные функции и действия. Пользователь должен иметь возможность просмотра подробной информации о блюде и заказе (просмотр данных осуществляется с помощью таблиц). Пользователь (работник сервиса) должен иметь возможность редактирования данных, таких как наименование, вес и цену блюда, также осуществлять работу с заказами. В программе необходимо предусмотреть корректность ввода данных.

3. МОДЕЛИ ПРЕДСТАВЛЕНИЯ СИСТЕМЫ И ИХ ОПИСАНИЕ

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

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

.1 Диаграмма вариантов использования

Диаграмма вариантов использования состоит из актеров, для которых система производит действие и собственно действия Use Case, которое описывает то, что актер хочет получить от системы[3].

В данной диаграмме вариантов использования в роли актёров выступают пользователи сайта и работник (администратор). Посетитель может просмотреть информацию о блюде, а также сформировать заказ: добавить понравившееся блюда в корзину, введя количество, и ввести свои личные данные (фамилию, имя, контактный телефон, адрес).

Работник ресторана может осуществлять работу с заказами, а также с меню, как видно из диаграммы (приложение Б рисунок Б.1).

.2 Диаграмма состояний

Диаграмма состояний предназначена для отображения состояний объектов системы, имеющих сложную модель поведения. Она показывает пространство состояний системы или ее элементов, события, которые влекут переход из одного состояния в другое, действия, которые происходят при изменении состояния.Объекты меняют своё состояние в ответ на происходящие события и стечением времени. Диаграмма состояний представляет состояния объекта и переходы между ними, а также начальное и конечное состояние объекта[3].

Диаграмма состояния данной системы приведена в приложении В на рисунке В.1

.3 Диаграмма последовательностей

Для моделирования взаимодействия объектов во времени в языке UML используются диаграммы последовательностей. Для демонстрации диаграммы последовательностей рассмотрим диаграмму, представленную в приложении Г на рисунке Г.1.

Действие начинается с того, что клиент запрашивает какую-либо информацию. Программа обращается к удалённым методам (RMI), которые обращаются к соответствующим сервисам, которые вызывают соответствующие методы из dao - уровня. Последние методы обращаются к базе данных, формируют информацию для отправки и возвращают на уровень выше.

Изъяном данной диаграммы является то, что в программе Enterprise Architect данный тип диаграммы выполняется, не совсем точно, т.к. линия жизни каждого блока должна заканчиваться после того, как была проведена стрелка от этого объекта, но в программе линия жизни ещё продлевается.

.4 Диаграммы классов

Диаграмма классов описывает структуру системы, показывая её классы, их атрибуты и операторы, а также взаимосвязи этих классов[3].

В приложении Д на рисунке Д.1 изображена диаграмма классов и интерфейсов уровней rmi-service-dao.

.5 Диаграмма компонентов

Диаграмма компонентов показывает разбиение программной системы на структурные компоненты и связи между компонентами[3].

В приложении Е на рисунках Е.1 и Е.2 приведены диаграммы компонентов клиентской и серверной частей данного приложения с пакетами и входящими в них классами, а также зависимость между данными классами.

.6 Диаграмма развёртывания

Диаграмма развёртывания предназначена для визуализации элементов и компонентов программы, существующих лишь на этапе ее исполнения[3].

В приложении Ж на рисунке Ж.1 приведена диаграмма развёртывания данной системы.

4. ИНФОРМАЦИОННАЯ МОДЕЛЬ СИСТЕМЫ И ЕЁ ОПИСАНИЕ

.1 Информационная модель

- средство разработки структуры базы данных. ERwin создает визуальное представление для данного проекта. Это представление может использоваться для детального анализа, уточнения и распространения как части документации, необходимой разработки.

Процесс построения информационной модели состоит из следующих шагов:

определение сущностей;

определение зависимостей между сущностями;

задание первичных и альтернативных ключей;

определение атрибутов сущностей;

составление логической (logical) модели;

переход к физическому (physical) описанию модели.

Логический уровень означает прямое отображение фактов из реальной жизни. На логическом уровне не рассматривается использование конкретной СУБД, не определяются типы данных и не определяются индексы для таблиц.

На рисунке 4.1.1 представлена логическая модель данной системы

Рисунок 4.1.1 - Логическая модель системы

Проанализировав данную предметную область, в проекте было решено создать следующие сущности: Блюдо, Заказ, ТипБлюда, Корзина, Состав, Продукт, Скидка, Клиент, Администратор, и входящие в них атрибуты:

Блюдо содержит информацию о блюде в меню:

`idDish` - уникальный номер блюда (первичный ключ);

`nameDish` - название блюда;

`priceDish` - стоимость блюда;

`weightDish` - вес блюда;

`imagespath` - путь к картинке блюда.

Заказ содержит информацию о заказе:

`idOrder` - уникальный номер заказа (первичный ключ);

`dishCostOrder` - стоимость за блюда;

`secondaryCostOrder` - дополнительная стоимость (приборы, упаковка).

ТипБлюда содержит информацию о типе блюда :

`idDishType` - уникальный номер типа блюда (первичный ключ);

`nameDishType` - название типа блюда.

Продукт :

`idProduct` - уникальный номер продукта (первичный ключ);

`nameProduct` - название продукта;

`caloriesPer100grProduct` - калорийность продукта на 100 грамм.

Состав - сущность, хранящая данные о составе блюда:

`productWieghtInDishComposition` - вес продукта в блюде;

`caloriesComposition` - калорийность продукта.

Корзина:

`dshCountBasket` - количество выбранного блюда;

`dish_idDish` - код блюда;

`order_idOrder` - код заказа.

Скидка:

`iddiscount` - уникальный номер скидки (первичный ключ);

`amountdiscount` - сумма скидки;

`percentdiscount` - процент скидки.

Клиент - сущность, хранящая данные о клиенте:

‘idClient` уникальный номер клиента (первичный ключ);

`lastnameClient`- фамилия клиента;

`firstnameClient` - имя клиента;

`addressClient`- адрес клиента;

`phoneClient` - телефон клиента.

Администратор - сущность, хранящая данные об администраторе:

`idadmin` - уникальный номер администратора (первичный ключ);

`loginadmin`- логин;

`passwordadmin`- пароль.

Рисунок 4.1.2 - Физическая модель системы

.2 Доказательство приведения информационной модели к 3-ей нормальной форме

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


Рисунок 4.2.1 - Первая нормальная форма

Проанализировав данную систему сервиса электронного кафе, можно сказать, что данная модель находиться в первой нормальной форме.

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

Рисунок 4.2.2 - Вторая нормальная форма

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

Если сущность находиться во второй нормальной форме и отсутствуют функциональные зависимости между ее не ключевыми атрибутами, то такая сущность находиться в третьей нормальной форме.

Для приведения сущности к третьей нормальной форме необходимо:

выделить атрибуты, которые функционально зависят от одного и того же не ключевого атрибута;

поместить их в новую сущность;

установить с новой сущностью связь типа «один ко многим»;

повторить указанные выше операции, если это необходимо.

Проанализировав данную систему, можно сказать, что данная модель находится в третьей нормальной форме, т.к. есть такие сущности, как на рисунке 4.2.3.

Рисунок 4.2.3 - Третья нормальная форма

5. ОБОСНОВАНИЕ ОРИГИНАЛЬНЫХ РЕШЕНИЙ ПО ИСПОЛЬЗОВАНИЮ ТЕХНИЧЕСКИХ И ПРОГРАММНЫХ СРЕДСТВ

При реализации данной программы были использованы следующие, не включённые в требования, решения:

Использование шаблона MVC (Model-View-Controller),

реализация, которого позволила чётко и структурировано разграничить части программы, что способствует удобной и быстрой расширяемости[1].

Шаблон MVC позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента:

Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера), изменяя своё состояние.

Представление (View). Отвечает за отображение информации (пользовательский интерфейс).

Поведение (Controller). Интерпретирует данные, введённые пользователем, и информирует модель и представление о необходимости соответствующей реакции.

Важно отметить, что как представление, так и поведение зависят от модели. Однако модель не зависит ни от представления, ни от поведения. Это одно из ключевых достоинств подобного разделения. Оно позволяет строить модель независимо от визуального представления, а также создавать несколько различных представлений для одной модели.

Использование порождающего шаблона SingleTon, который

удобен тем, что класс контролирует наличие единственного экземпляра, и он же предоставляет при необходимости к нему доступ[1].

Использование шаблона DAO (Data Access Object), реализация

которого удобна для абстрагирования и инкапсулирования доступа к источнику данных. Он представляет собой объект, который предоставляет абстрактный интерфейс к какому-либо типу базы данных или механизму хранения. Определённые возможности предоставляются независимо от того, какой механизм хранения используется и без необходимости специальным образом соответствовать этому механизму хранения.

Использование библиотеки JSTL (стандартная библиотека тегов). Она является альтернативой такому виду встроенной в JSP логики, как скриптлеты, то есть прямые вставки Java кода. Использование стандартизованного множества тегов предпочтительнее, поскольку получаемый код легче поддерживать и проще отделять бизнес-логику от логики отображения.

Использование шаблона Command, реализация которого

позволила легко обрабатывать и разграничивать запросы, приходящие от котроллера. Позволяет создать структуру, в которой класс-отправитель и класс-получатель не зависят друг от друга напрямую. Организация обратного вызова к классу, который включает в себя класс-отправитель[1].

Использование пула соединений с базой данных, что позволяет

контролировать количество соединений и с лёгкостью управлять соединениями (добавлять новое, удалять все).

Использование сессий позволило обеспечить хранение данных во время нескольких запросов от клиента[1].

6. ОПИСАНИЕ АЛГОРИТМОВ РЕАЛИЗУЮЩИХ БИЗНЕС-ЛОГИКУ СЕРВЕРНОЙ ЧАСТИ ПРОЕКТИРУЕМОЙ СИСТЕМЫ

Бизнес-логика данного проекта, как было написано в требованиях, сосредоточена в серверной части. Там реализованы такие операции, как соединение с базой данных, добавление данных в базу, удаление записей из неё, чтение и редактирование данных. Когда пользователь выбирает определенную операцию, клиент вызывает соответствующие методы rmi-интерфейса, передавая в качестве параметров необходимые данные. После того, как клиент вызвал метод, сервер получит информацию, он обрабатывает данный запрос, связывается с базой данных, если ему это требуется, и посылает клиенту результат его работы.

.1 Добавление заказа в базу данных

Для того чтобы наглядно отобразить алгоритм, реализующий бизнес-логику северной части системы «Сервис электронного кафе», я рассмотрю пример добавления заказа в базу данных, блок-схема которого представлена в Приложении И на рисунке И.2, а листинг в Приложении Л.

После того как клиент выбирает операцию оформления заказа, он переходит на страницу, на которой ему необходимо вести свои данные, затем он нажимает на кнопку оформить и через rmi-интерфейс вызывается метод добавления заказа. Однако перед добавлением заказа необходимо добавить клиента. После добавления клиента будет вызван метод создания заказа:

Затем вызывается метод из уровня сервисов, который вызывает метод дабавления заказа из уровня dao. Для того, чтобы создать заказ необходимо соединиться с базой данных, через пул коннэкшионов.

6.2 Считывание списка блюд из базы данных

Считывание списка блюд из базы данных необходимо, когда пользователь захочет просмотреть меню по категориям блюд. Тогда будет вызван метод getDishesByDishType(String dishType), который вызовет метод из уровня сервисов. Данный метод вызывает метод selectDishesByDishType(String dishType) из dao-уровня, также в цикле вызывает метод selectDishCompositionByDishId(int dishId), который для каждого блюда возьмёт из базы данных его состав.Блок-схема представлена в Приложении И на рисунке И.1, а листинг в Приложении Л.

7. РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ

Приложение имеет простой, интуитивно-понятный интерфейс, доступный обычному пользователю. При запуске данного приложения вы увидите главную страницу (рисунок 7.1).

Рисунок 7.1 - Главная страница

Данная страница является главной для пользователей-клиентов данного приложения. Пользователь может просмотреть меню, совершить поиск по названию блюда и просмотреть свою корзину.

Для того, чтобы просмотреть меню по категориям, необходимо нажать на кнопку выбранной категории блюд, что позволит вам просмотреть список всех продуктов по выбранной категории , допустим ‘Салаты’(рисунок 7.2).

Рисунок 7.2 - Просмотр меню по категории ‘Салаты’

Для того, чтобы добавить блюдо в корзину, необходимо выделить его на checkbox, а также, если необходимо, ввести требуемое количество. Добавим ‘Салат из ростбифа’ в количестве 1 штука и нажать на кнопку ‘Добавить в корзину’(рисунок 7.3).

Рисунок 7.3 - Выбор блюда из списка

При нажатии кнопки ‘Добавить в корзину’, вы перейдёте на страницу, которая отобразит вам вашу корзину (рисунок 7.4).

Рисунок 7.4 - Корзина клиента

Также клиент может очистить содержимое своей корзины, нажав на кнопку ‘Удалить’.

Если клиент хочет оформить заказ, то ему необходимо нажать на кнопку ‘Оформить заказ’, что переведёт его на страницу оформления заказа(рисунок 7.5), где ему будет необходимо ввести свои данные, и где он может просмотреть сумму заказа общую , и сумму с учётом скидки и упаковки.

Рисунок 7.5 - Оформление заказа

Далее необходимо нажать на кнопку ‘Оформить’, что переведёт вас на следующую страницу с информацией (рисунок 7.6).

Рисунок 7.6 - Страница информации после совершения заказа

Клиент может осуществить поиск по меню, введя название блюда в поле под надписью ‘Поиск по меню’, нажав на кнопку ‘Найти’, пользователю будет предоставлена информация по данному запросу. Введём слово ‘курица’ в поле ввода, нажмём на кнопку ‘Найти’ и увидем информацию, предоставленную на рисунке 7.7.

Рисунок 7.7 - Результаты поиска по меню

Если пользователь является администратором, то для того, чтобы войти в систему, ему необходимо нажать на кнопку ‘Войти’ , что переведёт его на страницу логинации(рисунок 7.8). Введём логин -admin, пароль - admin.

Рисунок 7.8 - Вход в систему

После того, как администратор верно ввёл данные, он переходит на страницу ‘Админка’, на которой ему доступны следующие действия (рисунок 7.9):

удалить блюдо;

редактировать информацию о блюде;

добавить новое блюдо;

просмотреть список заказов;

а также все действия , доступные пользователю - клиенту .

Рисунок 7.9 - Администраторская деятельность

Для того, чтобы удалить блюдо, администратор должен нажать на кнопку ‘Удалить’, расположенную рядом с выбранным блюдом.

Для того, чтобы отредактировать блюдо. Необходимо нажать на кнопку ‘Редактировать’ рядом с блюдом, которое вы хотите отредактировать.Нажав, вы перейдёте на страницу редактирования, где сможете ввести и сохранить изменённые данные(рисунок 7.10).

Рисунок 7.10 - Редактирование блюда

Для того, чтобы добавить новое блюдо, администратору необходимо нажать на кнопку ‘Добавить блюдо’. Нажав, вы перейдёте на страницу добавления блюда, где будет необходимо ввести данные о блюде (рисунок 7.11).

Рисунок 7.11 - Добавление блюда

Также администратор может просмотреть список заказов и удалить определённый заказ. Для того, чтобы просмотреть все заказы, администратор должен нажать на кнопку ‘Просмотреть заказы ‘, после чего он перейдёт на страницу заказов, где можетудалить определённые заказы (рисунок 7.12).

Рисунок 7.12 - Просмотр заказов

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

8. РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ РАЗРАБОТАННОЙ СИСТЕМЫ И ОЦЕНКА ВЫПОЛНЕНИЯ ЗАДАЧ

Все основные моменты исполнения данного проекта были показаны в разделе 7 Руководство пользователя.

При разработке данного приложения были сформированы модульные тесты с помощью JUnit для некоторых методов класса, реализующего rmi-интерфейс: добавление блюда в базу данных, добавление клиента в базу данных, добавление заказа и подсчёт общей стоимости заказа, включая процент скидки. Т.к. эти методы являются одними из важнейших (без них невозможно нормальное функционирование приложения) для них я создала JUnit - тесты.

Оценивая каждый модуль изолированно и подтверждая корректность его работы, точно установить проблему значительно проще чем, если бы элемент был частью системы.

На рисунке 8.1 представлены результаты тестирования некоторых методов.

Рисунок 8.1 - Тестирование методов

Также в программе существуют проверки на ввод корректных данных, например при вводе данных, в поле ввода для поиска. Человек должен ввести не мене 3 символов и не более 10 (рисунок 8.2).

Рисунок 8.2 - Проверка вводимых данных при поиске блюд

ВЫВОДЫ И ЗАКЛЮЧЕНИЯ

В данной курсовой работе было разработано приложение, реализованное в архитектуре клиент - сервер, с использованием базы данных и доступом к ней через JDBC и драйвером поставщика базы данных на тему “Сервис электронного кафе”.

Приложение разработано как для пользователей-клиентов, так и пользователей-администраторов, что намного расширяет возможности приложений такого типа.

Были соблюдены все требования, предъявляемые к данному курсовому проекту, а также все задачи, которые были поставлены для разработки данной системы. электронное кафе тестирование программный

Была создана информационная и функциональная модель, приведённые выше, которые в полной мере позволяют оценить данное приложение и понять, как с точки зрения разработчика, так и с точки зрения пользователя.

Одним из достоинств разработанной системы является стильный и удобный для пользователя интерфейс. Таким образом, любой пользователь (работник ресторана, просто пользователь), когда-либо работавший в Internet, без труда сможет работать и с этой системой.

Для создания данного проекта был использован язык программирования Java, сервлеты, паттерны создания Singleton и Commnad.

Также использовался шаблон MVC, который позволил структурировать архитектуру приложения и сделать его удобным для расширяемости.

Также использовались шаблоны проектирования (Information Expert, Low Coupling, High Cohesion), которые позволяют построить правильную, легко модифицируемую систему.

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

[1] Блинов, Е.Н. , Романчик, В.С, Промышленное программирование - Мн.:УниверсалПресс, 2007. - 704 c.

[2] Леоненков, А. В. Самоучитель UML/ А. В. Леоненков - СПб. : BHV, 2002. - 304 с.

[3] Маркин, А. В. Построение запросов и программирование на SQL / А. В. Маркин - М. : Диалог-МИФИ, 2008. - 320 с.

[4] Ноутон, П. Java 2 / П. Ноутон, Г.Шилдт - СПб. : БХВ-Петербург, 2008. - 1072 с.

ПРИЛОЖЕНИЕ А

(обязательное)

Функциональная модель сервиса электронного кафе

Рисунок А.1 - Контекстная диаграмма функциональной модели

Рисунок А.2 - Общее функционирование системы

Рисунок А.3 - Декомпозиция создания меню

Рисунок А.4 - Декомпозиция обработки запросов клиента

Рисунок А.5 - Декомпозиция создания заказа

ПРИЛОЖЕНИЕ Б

(обязательное)

Диаграмма вариантов использования

Рисунок Б.1 - Диаграмма вариантов использования пользователь

Рисунок Б.2 - Диаграмма вариантов использования пользователь

ПРИЛОЖЕНИЕ В

(обязательное)

Диаграмма состояний

Рисунок В.1 - Диаграмма состояний

ПРИЛОЖЕНИЕ Г

(обязательное)

Диаграмма последовательностей

Рисунок Г.1 - Диаграмма последовательностей

 ПРИЛОЖЕНИЕ Д

(обязательное)

Диаграмма классов

Рисунок Д.1 - Диаграмма классов иерархии rmi-service-dao

 ПРИЛОЖЕНИЕ Е

(обязательное)

Диаграмма компонентов

Рисунок Е.1 - Диаграмма компонентов клиентской части

Рисунок Е.2 - Диаграмма компонентов серверной части

ПРИЛОЖЕНИЕ Ж

(обязательное)

Диаграмма развёртывания

Рисунок Ж.1 - Диаграмма развёртывания

ПРИЛОЖЕНИЕ И

(обязательное)

Блок-схемы работы приложения

Рисунок И.1 - Блок-схема алгоритма выборки блюд по категориям

Рисунок И.2 - Блок-схема алгоритма добавления блюда в корзину

ПРИЛОЖЕНИЕ К

(обязательное)

Листинг алгоритмов, реализующих бизнес-логику

Листинг 1. Удалённые методы RMI-интерфейса

public interface IRmiForAdmin extends Remote {Admin getAdminByLogin(String login) throws RemoteException;ArrayList<DishDO> getDishesByDishType(String dishType) throws RemoteException;List<DishDO> findDishesByName(String dishName) throws RemoteException;List<DishDO> selectAllDishes() throws RemoteException;boolean deleteDishById(int dishId) throws RemoteException;boolean editDish(Dish dish) throws RemoteException;boolean addDish(Dish dish) throws RemoteException;boolean addClient(Client client) throws RemoteException;boolean addOrder(Order order) throws RemoteException;int countTotalCostTakingIntoDiscount(int totalCost) throws RemoteException;int getClientMaxId() throws RemoteException;List<Order> selectOrders() throws RemoteException;boolean deleteOrder(Order order) throws RemoteException;Client getClientById(int clientId) throws RemoteException;List<DishType> selectDishType() throws RemoteException;Order getOrderById(int orderId) throws RemoteException;String selectDiscount() throws RemoteException;

}

Листинг 2. Реализация удалённых методовclass RmiForAdminImpl extends UnicastRemoteObject implements IRmiForAdmin{AdminService adminService; DishService dishService;DishTypeService dishTypeService;ClientService clientService;OrderService orderService;RmiForAdminImpl () throws RemoteException {= new AdminService();= new DishService();= new ClientService();= new OrderService();= new DishTypeService();

}

// метод ищет по логину и возвращает экземпляр класса Admin

public Admin getAdminByLogin(String login)throws RemoteException {adminService.getAdminByLogin(login);

}

// метод ищет и составляет список блюд по типу блюда и возвращает его

public ArrayList<DishDO> getDishesByDishType(String dishType) throws RemoteException {dishService.getDishByDishType(dishType);

}List<DishDO> findDishesByName(String dishName) throws RemoteException {dishService.findDishesByName(dishName);

}List<DishDO> selectAllDishes() throws RemoteException {dishService.selectAllDishes();

}boolean deleteDishById(int dishId) throws RemoteException {dishService.deleteDishById(dishId);

}boolean editDish(Dish dish) throws RemoteException {dishService.editDish(dish);

}boolean addDish(Dish dish) throws RemoteException {dishService.addDish(dish);

}boolean addClient(Client client) throws RemoteException{clientService.addClient(client);

}boolean addOrder(Order order) throws RemoteException {orderService.createOrder(order);

}int countTotalCostTakingIntoDiscount(int totalCost) throws RemoteException{orderService.countTotalCostTakingIntoDiscount(totalCost);

}boolean deleteOrder(Order order){orderService.deleteOrder(order);

}List<DishType> selectDishType(){dishTypeService.selectDishTypes();

}Order getOrderById(int orderId){orderService.getOrderById(orderId);

}String selectDiscount(){discountDao = new DiscountDaoImpl();xstream = new XStream();.alias("discount",Discount.class);xml = xstream.toXML(discountDao.selectAll());xml;

}}

Листинг 3. DishService.javaclass DishService {dishDao;DishService(){= new DishDaoImpl();

}ArrayList<DishDO> getDishByDishType(String dishType){<DishDO> dishDoList = new ArrayList<DishDO>();<Dish> dishList = dishDao.selectDishesByDishType(dishType);(Dish dish : dishList ){<DishComposition> productsList = dishDao.selectDishCompositionByDishId(dish.getId());.add(new DishDO(dish, productsList));

}dishDoList;

}List<DishDO> findDishesByName(String dishName){<DishDO> dishList = new ArrayList<DishDO>();(Dish dish : dishDao.selectDishes()){(dish.getName().toLowerCase().contains(dishName.toLowerCase())){<DishComposition> productsList = dishDao.selectDishCompositionByDishId(dish.getId());.add(new DishDO(dish, productsList));

} return dishDoList; }boolean deleteDishById(int dishId){dishDao.deleteDish(dishId);

} public boolean editDish(Dish dish){dishDao.editDish(dish);

} public boolean addDish(Dish dish){dishDao.addDish(dish); }}

Приложение Л

(обязательное)

Листинг основных элементов программы

Листинг 1. Discount.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">

<html>

<body>

<p >Наша компания может предложить вам следующую систему скидок:</p>

<table border="1" align="left">

<tr>

<td>Сумма*</td>

<td>Процент</td>

</tr>

<xsl:for-each select="list">

<xsl:for-each select="discount">

<tr>

<td>

<xsl:value-of select="amount"/>

</td>

<td>

<xsl:value-of select="percent"/>

</td>

</tr>

</xsl:for-each>

</xsl:for-each>

</table>

<p >* - сумма, после которой начинает действовать скидка</p>

</body>

</html>

</xsl:template>

</xsl:stylesheet>

Листинг 2. Dish.jsp

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Сервис онлайн кафе</title>

<link rel="stylesheet" type="text/css" href="main.css" />

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<script type="text/javascript" src="jsp/countCheck.js"></script>

</head>

<body>

<div>

<jsp:include page = "mainPages/header.jsp" flush = "true"/>

<jsp:include page = "mainPages/left.jsp" flush = "true"/>

<jsp:include page = "mainPages/right.jsp" flush = "true"/>

<div>

<form action="Controller" method="post" >

<table style="border-color: tomato;background-color: #ffffff; font-size: medium;" >

<c:if test = "${dish_data != 'Sorry, information was not found'}">

<c:forEach var = "dishDO" items = "${dish_data}">

<tr >

<td><input type="checkbox" name="checkBox${dishDO.dish.name}"/><br/>

<input type="text" maxlength="3" size="1" onmouseout="return check(count${dishDO.dish.name})" name="count${dishDO.dish.name}" value="1" />

</td>

<td align="center">

<img alt="не найдено" src="${dishDO.dish.imagePath}"/>

</td>

<td align="center" style="color: chocolate">

<c:out value="${dishDO.dish.name}"/>

</td>

<td align="center">

<c:out value="${dishDO.dish.weight}"/>

</td>

<td align="center">

<c:out value="${dishDO.dish.price}"/>

</td>

<td align="center">

<c:forEach var = "dishComp" items = "${dishDO.composition}">

<c:out value="${dishComp.productName}"/>

<c:out ="${dishComp.productWeight}"/><br/>

</c:forEach>

</td>

</tr>

</c:forEach>

</c:if>

</table>

<input type="submit" value="Добавить в корзину"/>

<input type="hidden" name="command" value="addToBasket"/>

</form>

</div>

<jsp:include page = "mainPages/footer.jsp" flush = "true"/>

</div></body> </html>

Листинг 3. IDishDao.javainterface IDishDao {boolean addDish(Dish dish); // метод создаёт идобавляет в БД новое блюдоboolean deleteDish(int dishId); //метод удаляет блюдо из БД по его номеруboolean editDish(Dish dish); // метод обновлиет информацию о блюде в бдList<Dish> selectDishes(); // метод находит все блюдаArrayList<Dish> selectDishesByDishType(String dishType);List<DishComposition> selectDishCompositionByDishId(int dishId);}

Листинг 4. DishDaoImpl.javaDishDaoImpl() {= new DBConnection(); } boolean addDish(Dish dish) {{= (PreparedStatement) dbConnection.connect().prepareStatement(Dish.getMap().get("addDish"));.setInt(1, dish.getId());.setString(2, dish.getName());.setDouble(3, dish.getWeight());.setDouble(4, dish.getPrice());.setLong(5, dish.getType().getId());(statement.executeUpdate() > 0);

} catch (SQLException e) {.printStackTrace();false;

} }boolean deleteDish(int dishId) {{= (PreparedStatement) dbConnection.connect().prepareStatement(Dish.getMap().get("deleteDish"));.setInt(1, dishId);(statement.executeUpdate() > 0);

} catch (SQLException ex) {.getLogger(DishDaoImpl.class.getName()).log(Level.SEVERE, null, ex); return false;

} }boolean editDish(Dish dish) {{ statement = (PreparedStatement) dbConnection.connect().prepareStatement(Dish.getMap().get("updateDish"));.setString(1, dish.getName());.setDouble(2, dish.getWeight());.setDouble(3, dish.getPrice());.setInt(4, dish.getId());(statement.executeUpdate() > 0);

} catch (SQLException ex) {.getLogger(DishDaoImpl.class.getName()).log(Level.SEVERE,

Продолжение приложения Л, ex);

return false;

}

}List<Dish> selectDishes() {theSet;<Dish> dishList = null;{ps = (PreparedStatement) dbConnection.connect().(Dish.getMap().get("selectAll"));= ps.executeQuery();= new ArrayList<Dish>();(theSet.next()) {dish = new Dish();(dish, theSet);.add(dish);

}dishList;

} catch (SQLException ex) {.getLogger(DishDaoImpl.class.getName()).log(Level.SEVERE, null, ex);null;

}

}ArrayList<Dish> selectDishesByDishType(String dishType) {theSet;<Dish> dishList = new ArrayList<Dish>();{ps = (PreparedStatement) dbConnection.connect().(Dish.getMap().get("selectByType"));.setString(1, dishType);= ps.executeQuery();(theSet.next()) {dish = new Dish();(dish, theSet);.add(dish);

}dishList;

} catch (SQLException ex) {.getLogger(DishDaoImpl.class.getName()).log(Level.SEVERE, null, ex);null;

}

}List<DishComposition> selectDishCompositionByDishId(int dishId) {theSet;<DishComposition> productsList = new ArrayList<DishComposition>();{ps = (PreparedStatement) .connect().(Dish.getMap().get("selectCompositionByDishId"));.setInt(1, dishId);= ps.executeQuery();(theSet.next()) {composition = new DishComposition();.setProductName(theSet.getString("nameProduct"));.setProductWeight(theSet.getInt("productWieghtInDishComposition"));.add(composition);

}

} catch (SQLException ex) {.getLogger(DishDaoImpl.class.getName()).log(Level.SEVERE, null, ex);

} return productsList; }}

Приложение М

(обязательное)

Листинг скрипта генерации базы данныхDATABASE IF NOT EXISTS `restaurant` TABLE IF NOT EXISTS `admin` (

`idadmin` int(11) NOT NULL AUTO_INCREMENT,

`loginadmin` varchar(45) NOT NULL,

`passwordadmin` int(11) NOT NULL,KEY (`idadmin`),KEY `loginAdmin_UNIQUE` (`loginadmin`),KEY `idadmin_UNIQUE` (`idadmin`)

) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;INTO `admin` (`idadmin`, `loginadmin`, `passwordadmin`) VALUES (1, 'admin', 92668751), (7, 'olya', 1450575459), (8, 'kostya', 1508416), (9, 'kolya', 1824529005);TABLE IF NOT EXISTS `basket` (

`dishCountBasket` int(11) NOT NULL,

`dish_idDish` int(11) NOT NULL,

`order_idOrder` int(11) NOT NULL,KEY (`dish_idDish`,`order_idOrder`),`fk_basket_order1` (`order_idOrder`),`fk_basket_dish` FOREIGN KEY (`dish_idDish`) REFERENCES `dish` (`idDish`) ON DELETE NO ACTION ON UPDATE NO ACTION,`fk_basket_order1` FOREIGN KEY (`order_idOrder`) REFERENCES `order` (`idOrder`) ON DELETE NO ACTION ON UPDATE NO ACTION

) ENGINE=InnoDB DEFAULT CHARSET=utf8;TABLE IF NOT EXISTS `client` (

`idClient` int(11) NOT NULL AUTO_INCREMENT,

`lastnameClient` varchar(45) NOT NULL,

`firstnameClient` varchar(45) NOT NULL,

`addressClient` varchar(45) NOT NULL,

`phoneClient` varchar(45) NOT NULL,KEY (`idClient`),KEY `idClient_UNIQUE` (`idClient`)

) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;INTO `client` (`idClient`, `lastnameClient`, `firstnameClient`, `addressClient`, `phoneClient`) VALUES (1, 'Страх', 'Ольга', 'Городецкая 58-110', '3070330'), (10, 'Страх', 'Наталья', 'Воронянского 23-89', '2456791'), (11, 'Сторук', 'Алексей', 'Кижевского 23-90', '1243546'), (13, 'Кожевников', 'Слава', 'Коренцова 34-123', '1234565'), (22, 'Дановский', 'Костя', 'Родная 7', '2345645');TABLE IF NOT EXISTS `composition` (

`productWieghtInDishComposition` int(11) NOT NULL,

`caloriesComposition` varchar(45) NOT NULL,

`dish_idDish` int(11) NOT NULL,

`product_idProduct` int(11) NOT NULL,KEY (`dish_idDish`,`product_idProduct`),`fk_composition_product1` (`product_idProduct`),`fk_composition_dish1` FOREIGN KEY (`dish_idDish`) REFERENCES `dish` (`idDish`) ON DELETE NO ACTION ON UPDATE NO ACTION,`fk_composition_product1` FOREIGN KEY (`product_idProduct`) REFERENCES `product` (`idProduct`) ON DELETE NO ON UPDATE NO ACTION

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INTO `composition` (`productWieghtInDishComposition`, `caloriesComposition`, `dish_idDish`, `product_idProduct`) VALUES (230, '50', 1, 1), (137, '345', 1, 2), (30, '120', 2, 3), (212, '234', 2, 4), (123, '234', 3, 1), (23, '32', 3, 2), (234, '43', 3, 4), (34, '23', 4, 1), (23, '234', 4, 4), (23, '24', 5, 2);TABLE IF NOT EXISTS `discount` (

`iddiscount` int(11) NOT NULL AUTO_INCREMENT,

`amountdiscount` int(11) NOT NULL,

`percentdiscount` double NOT NULL,KEY (`iddiscount`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;INTO `discount` (`iddiscount`, `amountdiscount`, `percentdiscount`) VALUES (1, 200000, 0.2), (2, 150000, 0.15), (3, 100000, 0.1);

/*!40000 ALTER TABLE `discount` ENABLE KEYS */;TABLE IF NOT EXISTS `dish` (

`idDish` int(11) NOT NULL AUTO_INCREMENT,

`nameDish` varchar(45) NOT NULL,

`priceDish` double NOT NULL,

`weightDish` double NOT NULL,

`dishtype_idDishType` int(11) DEFAULT NULL,

`imagespath` varchar(45) DEFAULT NULL,KEY (`idDish`),KEY `idProduct_UNIQUE` (`idDish`),`fk_dish_dishtype1` (`dishtype_idDishType`),`fk_dish_dishtype1` FOREIGN KEY (`dishtype_idDishType`) REFERENCES `dishtype` (`idDishType`) ON DELETE NO ACTION ON UPDATE NO ACTION

) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;INTO `dish` (`idDish`, `nameDish`, `priceDish`, `weightDish`,

`dishtype_idDishType`, `imagespath`) VALUES (1, 'Картофель фри', 2830, 120, 1, 'images/fri_patatoes.jpg'), (2, 'Спагетти со шпинатом', 15340, 260, 1, 'images/spagetti2.jpg'), (3, 'Спагетти Карбонара', 13830, 262, 1, 'images/spagetti1.jpg'), (4, 'Драники со сметаной', 6010, 155, 1, 'images/draniki_so_smetanoi.jpg'), (5, 'Куриная грудка с лисичками', 21250, 390, 1, 'images/chicken_rest.jpg'), (6, 'Омлет с беконом', 3780, 127, 3, 'images/breakfast1.jpg'), (7, 'Омлет с сыром', 2500, 127, 3, 'images/breakfast2.jpg'), (8, 'Салат \'Цезарь\' классический', 17540, 272, 2, 'images/salad_Cezar.jpg'), (10, 'Штрудель яблочный', 12900, 114, 4, 'images/apple_shtrudel.jpg'), (12, 'Пицца \'Курица с ананасами\'', 17820, 455, 6, 'images/checken_with_pineapple.jpg'), (13, 'Пицца \'Четыре сыра\'',

, 260, 6, 'images/pizza_4_cheezes.jpg'), (14, 'Пицца \'Овощная\'', 14890, 340, 6, 'images/pizza_vegatable.jpg'), (15, 'Имбирный чай', 7450, 170, 5, 'images/imb_tea.jpg'), (16, 'Сок апельсиновый', 2450, 250, 5, 'images/orange_juice.jpg'), (17, 'Штрудель твороженный', 3560, 130, 4, 'images/tvorog_shtrudel.jpg'), (18, 'Coca-Cola', 2970, 250, 5, 'images/cola.jpg'), (19, 'Бургер с курицей', 6880, 160, 3,

'images/chicken_burger.jpg'), (20, 'Fanta', 2970, 250, 5, 'images/fanta.jpg'), (21, 'Sprite', 2970, 250, 5, 'images/sprite.jpg'), (22,

'Свежий огурец', 1040, 30, 3, 'images/cucumber.jpg'), (23, 'Свежий помидор', 680, 30, 3, 'images/tomato.jpg'), (24, 'Салат из ростбифа', 24300, 190, 2, 'images/salad_from_rostbeaf.jpg'), (25, 'Салат от кролика Роджера', 6950, 177, 2, 'images/rabbit_salad.jpg');

/*!40000 ALTER TABLE `dish` ENABLE KEYS */;TABLE IF NOT EXISTS `dishtype` (

`idDishType` int(11) NOT NULL AUTO_INCREMENT,

`nameDishType` varchar(45) NOT NULL,KEY (`idDishType`),KEY `iddishType_UNIQUE` (`idDishType`)

) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;INTO `dishtype` (`idDishType`, `nameDishType`) VALUES (1, 'Гарниры'), (2, 'Салаты'), (3, 'Завтраки'), (4, 'Десерты'), (5, 'Напитки'), (6, 'Пицца');TABLE IF NOT EXISTS `order` (

`idOrder` int(11) NOT NULL AUTO_INCREMENT,

`dishCostOrder` int(11) NOT NULL,

`secondaryCostOrder` int(11) NOT NULL,

`client_idClient` int(11) NOT NULL,KEY (`idOrder`),KEY `idOrder_UNIQUE` (`idOrder`),`fk_order_client1` (`client_idClient`),`fk_order_client1` FOREIGN KEY (`client_idClient`) REFERENCES `client` (`idClient`) ON DELETE NO ACTION ON UPDATE NO ACTION

) ENGINE=InnoDB DEFAULT CHARSET=utf8;TABLE IF NOT EXISTS `product` (

`idProduct` int(11) NOT NULL AUTO_INCREMENT,

`nameProduct` varchar(45) NOT NULL,

`caloriesPer100grProduct` double DEFAULT NULL,KEY (`idProduct`),KEY `idProduct_UNIQUE` (`idProduct`),`composition` (`idProduct`)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;INTO `product` (`idProduct`, `nameProduct`, `caloriesPer100grProduct`) VALUES (1, 'Помидоры', 50), (2, 'Мука', 1), (3, 'Огурец', 20), (4, 'Свинина', 300), (5, 'Майонез', 89)

Похожие работы на - Сервис электронного кафе

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!