Файл: Модель клиент-сервер (Применение модели «клиент-сервер» в разработке web-приложения).pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 26.04.2023

Просмотров: 477

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

- GET /widget/show – инициализирует виджет на странице, на которой установлен

- POST /widget/get – возвращает данные виджета в виде заполненного шаблона

- GET /widget/delete – удаляет виджет из базы даных

Для отображения контента страниц и виджета нам понадобятся pug html шаблоны, они содержат:

- layout.pug – общие для всех страниц элементы

- main.pug –элементы главной страницы

- addwidget.pug – форма добавления виджета

- editwidget.pug – форма редактирования виджета

- widgetlistitem.pug – элемент списка виджета на для главной страницы

- widgetview.pug – содержит заголовок контента виджета

- widgetviewday.pug – содержит контент виджета с погодой за один день

Для стилизации html тегов интерфейса будем использовать библиотеку bootstrap, также нам понадобится файл widget.css для реализации нужного отображения элементов виджета.

2.4. Создание и настройка проекта

Для начала работы на компьютере должны быть установлены nodejs и redis для веб-сервера и базы данных соответственно. Для начала создадим папку weatherapp. Запустим терминал и перейдем в эту папку. Затем инициализируем проект через npm и добавим в него зависимости:

mkdir weatherapp

cd weatherapp

npm init

npm install express body-parser request pug redis

В созданном package.json в поле scripts добавим строку, указывающую на основной скрипт сервера, а также создадим и сам этот файл:

// выдержка из package.json:

"scripts": {

"start": "node app" // необходимая строка

}

// команда для создания файла app.js

touch app.js

Наконец, создадим папку для шаблонов и публичных файлов веб-сервера (мы разместим в ней css стили):

mkdir views

mkdir public

Итак, мы закончили с настройкой проекта. У нас есть файл основного скрипта сервера, необходимые библиотеки для работы и нужная структура папок. Теперь можно запустить в новом окне терминала сервер redis с помощью команды redis-server и перейти к написанию кода серверной части нашего приложения.

2.5. Реализация серверной части

Откроем app.js (программный код вынесен в приложение А) и перейдем к написанию серверной части приложения. Первым делом сделаем импорт зависимостей. Затем объявим константы: учетные данные api погодного сервиса, города для которых будет возможность получать погоду в виджетах, временные диапазоны прогнозов, имена месяцев и порт, на котором будет запущено приложение.


Теперь создадим переменную app веб-сервера express и настроим его: добавим возможность парсинга body приходящих запросов, установим движок pug для работы шаблонов страниц, откроем доступ к директории public, откроем прослушивание на выбранном порту. Затем создадим в переменной client подключение к хранилищу Redis. Мы получили минимально настроенное express веб-приложение – переходим к написанию функциональной части.

Напишем функцию addUpdateWidget которая получает данные виджета на вход и сохраняет их (с заменой при совпадении id) в базе данных Redis при помощи client. Мы задействуем эту функцию для создания и редактирования виджетов далее.

Перейдём к написанию обработчиков запросов. Начнём с «GET /» запроса. В его обработчике установим тип контента, получим из базы данные виджетов. Если виджеты найдены, отрендерим их с помощью шаблона widgetlistitem.pug и отправим ответ, используя шаблон main.pug. Если виджеты не найдены, отправим ответ, используя шаблон main.pug с соответствующим сообщением.

Для «GET /widget/add» установим тип контента и отправим ответ, используя шаблон addwidget.pug, содержащий форму создания виджета.

Для «POST /widget/add» и «POST /widget/edit» выполним функцию addUpdateWidget и сделаем редирект на главную страницу.

Для «GET /widget/edit» установим тип контента, проверим есть ли в базе виджет с указанным в параметрах запроса id. Если виджет не найден, отправим в ответ соответствующее сообщение. Если найден ¬отправим ответ, используя шаблон editwidget.pug и данные виджета, полученные из базы.

Для «GET /widget/show» установим тип контента и в качестве ответа вернём js-код, который дожидается загрузки библиотеки jQuery после чего добавляет на страницу файл стилей виджетов widget.css, затем получает данные виджета и отображает их на странице в соответствующем блоке.

Для «POST /widget/get» установим тип контента, затем проверим есть ли в базе виджет с указанным в параметрах запроса id. Если виджет не найден, отправим в ответ соответствующее сообщение. Если найден, то пробуем получить ответ от api сервиса прогнозов погоды. В случае ошибки получения данных погоды отправим в ответ сообщение о том, что запросы на получение погоды отправляются слишком часто и порекомендуем повторить попытку позже. Если же данные погоды пришли, то вернем ответ, используя шаблоны widgetviewday.pug и widgetview.pug.

Для «GET /widget/delete» удалим виджет с указанным в параметрах запроса id и сделаем редирект на главную страницу. На этом запросе завершаем работу над серверной частью приложения и переходим к клиентской.


2.6. Реализация клиентской части

В данном разделе мы будем работать в директориях public и views, в которых будут размещены файл стилей widget.css и файлы html шаблонов соответственно. Листинг файлов приведён в приложении Б. Для начала добавим в widget.css отступы и стиль отображения для css-класса card, чтобы элементы виджета (день с данными о погоде) могли выстраиваться в горизонтальный ряд.

Перейдём к написанию html шаблонов. В коде будем по возможности использовать синтаксис шаблонизатора pug. Для стиллизации будем использовать классы библиотеки bootstrap.

В файле layout.pug объявим теги html, head и body, добавим link на файл стилей bootstrap, теги script со ссылками на скрипты jquery и bootstrap, а главное – тег h1 для вывода в него заголовка и блок content для содержимого страниц.

В файле main.pug унаследуем шаблон layout.pug, в блоке content разместим ссылку на страницу добавления виджета и тег div для вывода списка виджетов. Также можно разместить полученный в приложении код виджета для встраивания, чтобы проверить его работу.

В файле addwidget.pug унаследуем шаблон layout.pug, в блоке content разместим ссылку на главную страницу и форму добавления виджета с полями id (уникальный идентификатор), name (название), city (город), days (количество дней, за которые будет отображаться прогноз), type (тип отображения – вертикальный или горизонтальный).

В файле editwidget.pug унаследуем шаблон layout.pug, в блоке content разместим ссылку на главную страницу и форму редактирования виджета с полями, аналогичными заданным в форме добавления.

В файле widgetlistitem.pug разместим тег h5 состоящий из названия виджета, его типа и количества дней за которые будет отображаться прогноз. Ниже разместим код для встраивания, ссылки на редактирование и удаление.

В файле widgetview.pug разместим тег h4 состоящий из слов «Weather in» и названия города для которого будет показан прогноз погоды. Ниже разместим тег div с классом, который зависит от type виджета и кодом прогноза погоды по дням.

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

2.7. Проверка и запуск решения

Для проверки решения на соответствие задаче необходимо произвести запуск приложения. Для этого воспользуемся приведенной ниже инструкцией (система macOS с установленным пакетным менеджером brew).


1. Установить сервер nodejs: `brew install node`

2. Устновить и запустить redis: `brew install redis` для установки, `redis-server` для запуска

3. Установить зависимости проекта через npm: `npm install`

4. Запустить проект и открыть в браузере: `npm start` для запуска, `http://localhost:3033` страница приложения в браузере

Рис. 2.7.1. Главная страница, база виджетов пуста

Откроем главную страницу, убедимся, что у нас есть кнопка «Add widget» для добавления виджетов. Нажимаем на неё.

Рис. 2.7.2. Страница добавления виджета

Должна открыться страница с формой добавления виджета. Вводим в ней данные виджета: «Widget ID» – 1, «Name» – MSC, «City» – Moscow, «Days count» – 3 days, «View type» – Horizontal. Нажимаем кнопку «Save».

Рис. 2.7.3. Главная страница, в базе есть виджет

Мы видим главную страницу, но теперь на ней виден список созданных виджетов, а также установленный виджет с id=1. Нажмём на кнопку «EDIT».

Рис. 2.7.4. Страница редактирования виджета

На экране отображена страница редактирования виджета, данные введены в поля и доступны для изменения.

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

ЗАКЛЮЧЕНИЕ

Подробное рассмотрение модели «клиент-сервер» в теоретическом и практическом ключе в этой работе даёт уверенное понимание работы приложений, реализующих такую архитектуру.

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

Клиенты в виде веб-браузеров, мобильных приложений и серверы в виде компьютеров установленных в дата-центрах в настоящее время составляют большую часть сети Интернет также обширно используют многоуровневую модель клиент-серверной архитектуры. Работа различных процессов, таких как обработка изображений и видео, хранение и передача текстовых сообщений, аудио и видео трансляции и многих других, обеспечивается группами специализированных серверов: файловые хранилища, кеш-хранилища, базы данных, поисковые движки и другие виды. Данная модель несомненно будет применяться в будущем, развиваться и решать сложные проблемы работы с данными, передаваемыми между ноутбуками, пк, планшетами, смартфонами, устройствами «Умного дома», самолетами, самоуправляемыми автомобилями и многими другими, в том числе совершенно новыми.


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

  1. Д.Васкевич Стратегии клиент/сервер. Диалектика, Киев, 1997.
  2. Валерий Коржов. Многоуровневые системы клиент-сервер. (https://www.osp.ru/nets/1997/06/142618/) Издательство Открытые системы (17 июня 1997)
  3. http://www.glossary.ru
  4. http://www.nadprof.ru/school/client-server.shtml
  5. http://mrivkin.narod.ru/Publ/CLSERV1.htm
  6. http://www.intuit.ru/department/se/crosspl/1/2.html

Приложение А

app.js

const express = require('express');

const bodyParser = require('body-parser');

const pug = require('pug');

const path = require('path');

const redis = require('redis');

const request = require("request");

// Config OpenWeatherMap

const openWeatherMapApiKey = 'bbf89a2ce7b2d36edaac82d86df3ca8e';

const openWeatherMapApiUri = 'http://api.openweathermap.org/data/2.5/forecast/daily?';

// Setup widget options values

const cityNames = {

"524901": "Moscow",

"498817": "Saint Petersburg",

"520555": "Nizhniy Novgorod"

}

const forecastDurations = {

1: "Today",

3: "3 days",

7: "Week"

}

const widgetTypes = {

"vertical": "Vertical",

"horizontal": "Horizontal"

}

var monthNames = ["January", "February", "March", "April", "May", "June",

"July", "August", "September", "October", "November", "December"

];

// Create redis client

let client = redis.createClient();

client.on('connect', function () {

console.log('Connected to Redis ...');

})

// Set port

const port = 3033;

// Init app

const app = express();

// body parser

app.use(bodyParser.urlencoded({ extended: false }));

app.use(bodyParser.json());

// View engine

app.set('view engine', 'pug')

// Add public static files access

app.use(express.static(__dirname + '/public'));

app.listen(port, function () {

console.log('Server started on port ' + port);

})

// add/update widget function

function addUpdateWidget(req,callback) {

let id = 'widget_'+req.body.id;

let name = req.body.name;

let city = req.body.city;

let days = req.body.days;

let type = req.body.type;

client.hmset(id, [

'name', name,

'city', city,

'city_name', cityNames[city],

'days', days,

'type', type

], function (err, reply) {

if (err) {

console.log(err);

}

callback(reply);

})

}

app.get('/', function (req, res) {

res.set('Content-Type', 'text/html');

var widgets = [];

var widgets_code = "";

// get widgets ids SCAN 0 MATCH widget* COUNT 100

client.scan(0, 'MATCH', 'widget*', 'COUNT', 100, function (err, reply) {

if (err) {

res.render('main', { title: 'Widget app', message: 'Manage widgets', error: err })

}

if(reply[1].length>0) {

// loop to render them

let promise = new Promise(function (resolve) {

reply[1].map(function (val, index, arr) {

client.hgetall(val, function (err, obj) {

obj.id = val;

pug.renderFile('views/widgetlistitem.pug', {

id: obj.id,

name: obj.name,

city: cityNames[obj.city],

type: obj.type,

days: obj.days,

code: '<div id="weatherwidget_'+obj.id+'"></div><script type="text/javascript" src="http://localhost:3033/widget/show?id='+obj.id+'"></script>'

}, function (empty, res) {

widgets += obj;

widgets_code += res;

if (index == arr.length - 1) resolve(true);

});

});

});

});

promise

.then(function (value) {

res.render('main', { title: 'Widget app', message: 'Manage widgets', widgets_code: widgets_code });

return "widgets load success"