s
Sesiya.ru

Проектирование Web-приложений

Информация о работе

Тема
Проектирование Web-приложений
Тип Методические указания
Предмет Web-программирование
Количество страниц 42
Язык работы Русский язык
Дата загрузки 2019-09-24 02:19:27
Размер файла 63.51 кб
Количество скачиваний 7
Скидка 15%

Поможем подготовить работу любой сложности

Заполнение заявки не обязывает Вас к заказу


Скачать файл с работой

Помогла работа? Поделись ссылкой

МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ

ФЕДЕРАЦИИ

ФГАОУ ВО «Крымский федеральный университет

им В.И.ВЕРНАДСКОГО»

Физико-технический институт

Кафедра компьютерной инженерии и моделирования









Методические указания по выполнению лабораторных работ

Для направлений подготовки

09.03.04 «Программная инженерия» (курс «Проектирование Web-приложений»)















Симферополь

2019

  1. Лабораторная работа № 1

    1. Цель работы

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

    1. Теоретическая часть

Любое интернет-приложение работает через сокеты. Для создания интернет-приложения на Java обычно используются два класса java.net.Socket и java.net.ServerSocket, с помощью которых и осуществляется передача данных по сети.

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

1.2.1. Описание класса Socket

Этот класс реализует клиентские сокеты. Сокета является конечной точкой для передачи данных между двумя машинами. Основные конструкторы класса Socket: — Socket (InetAddressaddress, intport) — создает экземпляр класса Socket с входящими параметрами IP-адресом и портом той машины, с которой мы связываемся. — Socket (Stringhost, intport, InetAddresslocalAddr, intlocalPort) — более точная настройка сокета, создает экземпляр класса Socket с входящими данными о IР-адресе и порте локальной и удаленной машины. — Socket (InetAddresshost, intport, booleanstream) — позволяет настроить сокету на передачу данных по протоколу TCP/IP (stream = true) или UDP (stream = false), создает экземпляр класса Socket с входящими параметрами IP-адресом и портом той машины, с которой мы связываемся, и параметром stream.

1.2.2. Основные методы класса Socket

getInputStream() — метод, который возвращает экземпляр класса InputStream, отвечает за входящий поток данных сокета.

getOutputStream() — метод, который возвращает экземпляр класса OutputStream, отвечает за исходящий поток данных сокета.

close()— метод завершения работы сокеты, после выполнения этого метода дальнейшее взаимодействие с объектом Socket невозможно.

1.2.3. Описание класса ServerSocket

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

ServerSocket (intport)— создает экземпляр класса ServerSocket, с входным параметром порт (локальной машины), при этом порт должен быть свободен, иначе произойдет событие ошибки.

ServerSocket (intport, intbacklog, InetAddressbindAddr) — создает экземпляр класса ServerSocket, с входными параметрами и порт, IP-адрес (bindAddr) и количеством возможных подключений (backlog), при этом порт должен быть свободен, иначе произойдет событие ошибки.

1.2.4. Основные методы класса ServerSocket

accept () — возвращает экземпляр класса Socket, с которым в дальнейшем будет работа по обмену данными. Данный метод ожидает подключения к созданной ServerSocket (к открытому порту, описанному при создании ServerSocket), пока подключение не произошло, находится в состоянии ожидания.

close() — метод завершения работы серверной сокеты, после выполнения этого метода дальнейшее взаимодействие с объектом ServerSocket невозможно.

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

Сервер:

ServerSocket serverSocket = new ServerSocket(12345);

Socket socket = serverSocket.accept();

Клиент:

Socket socket = new Socket ("localhost", 12345);

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

1.2.5. Работа с входящим и исходящим потоком байт

Основные методы, необходимые для сокетов — это передача данных, то есть получение и отправление потока данных:

для получения потока входящих данных нужно использовать метод getInputStream(). InputStream — абстрактный класс, задающий используемую в Java модель входных потоков;

для отправки исходящего потока данных нужно использовать метод getOutputStream(). OutputStream — абстрактный класс. Он задает модель выходных потоков Java.

getInputStream() и getOutputStream() возвращают поток байт, с которыми не очень удобно, для этого существует множество стандартных классов, которые помогают представить входящий (исходящий) поток в более удобном для нас формате, например, в виде String, class,.. Перечислим основные классы, которые могут использоваться для преобразования потока байт в другой формат и выступать в качестве обертки: ObjectInputStream и ObjectOutputStream позволяют передавать/получать ранее сериализованные объекты, то есть мы можем передавать ранее сформированный экземпляр класса и получить его на другой стороне как структурированный объект.

Пример:

Листинг класс Student, который хранит два значения: имя, возраст; и метод getTitle(), возвращает некоторую структурированную информацию о содержании класса. Данный класс реализует интерфейс Serializable.Serialization, предоставляет стандартный механизм для создания сериализуемых объектов. Сериализация — это процесс сохранения состояния объекта в последовательность байт.

Пример POJO-класса Student:

1. public class Student implements Serializable {

2. private String name; //Имя

3. private Integer age; //Возраст

4. public String getName() {

5. return name;

6. }

7. public void setName(String name) {

8. this.name = name;

9. }

10. public Integer getAge() {

11. return age

12. }

13. public void setAge (Integer age) {

14. this.age = age;

15. }

16. public String getTitle() {

17. return getName()+" "+getAge();

18. }

19. }

Действия отправителя объекта через сокет.

При отправке объекта изначально его необходимо создать и заполнить данными. Для этого создается экземпляр класса Student и заполняется данными.

1. Student student = new Student();

2. student.setAge(18);

3. student.setName("Mr.Smith");

После того как экземпляр класса будет создан, его можно будет отправлять, для этого используем класс ObjectOutputStream. Этот класс позволяет отправлять данные объектом, который реализуют интерфейс java.io.Serializable. Создание переменой, присвоенной экземпляру класса ObjectOutputStream, с помощью которой в дальнейшем будет осуществляться передача данных. ObjectOutputStream использует в качестве ресурса выходной поток данных ранее созданной сокеты.

  1. ObjectOutputStream out = new ObjectOutputStream (socket. getOutputStream());

  2. out.writeObject (student);//происходит отправление объекта

Действия принятия объекта через сокет.

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

1. ObjectInputStream in = new ObjectInputStream (socket. getInputStream());

2. try {

3. Student student = (Student)in.readObject(); //получение объекта Student

4. System.out.println (student.getTitle()); //использование метода getTitle() класса Student, для вывода результатов на консоль

5. } catch (ClassNotFoundException e) {

6. e.printStackTrace();

7. }

В результате выполнения данных операций на экране принимающей стороны должна появиться надпись “Mr.Smith 18”.

Работа с входным потоком данных как со строками.

InputStreamReader является мостом между потоком байт и потоком символов. Несет в себе информацию о кодировке (сам производит кодировку и декодировку, например, UTF-8). Для создания экземпляра класса InputStreamReader на вход необходимо подать класс InputStream, например, System.in или socket.getInputStream.

BufferedReader буферизует символы и позволяет извлекать из потока как сформированные строки, так и просто символы. Для создания экземпляра класса необходимо поместить в него любой класс, реализующий абстрактный класс Reader. Например, InputStreamReader, StringReader. Пример:

1. InputStreamReader isr = new InputStreamReader (System. in); //преобразование входного потока байт

2. BufferedReader br = new BufferedReader(isr); //буферизация символов

3. while (true){

4. String st = br.readLine(); //чтение из буфера строку

5. if (st==null)

6. {

7. break;

8. }

9. }

Работа с исходящим потоком данных как со строками.

PrintWriter позволяет введенный печатный текст представить к байтовому потоку вывода. Для создания экземпляра класса необходимо иметь входные параметры наследников абстрактного класса Writer (например, OutputStreamWriter) или классов, реализующих интерфейсы Closeable, Flushable (например, OutputStream). Пример:

1. PrintWriter printWriter = new PrintWriter (socket.getOutput Stream(), true);

2. printWriter.println("Введите значение а:";

1.3. Порядок выполнения работы

1.3.1. Подготовка рабочего места:

1. На компьютере, на котором будет проходить лабораторный практикум, необходимо установить следующие средства разработки:

1.1. Java Development Kit (jdk);

1.2. IntelliJIDEA (CommunityEdition, свободно распространяемый вариант);

1.3.СУБД на выбор: MS SQL Server, MySQL, PostgreSQL, Oracle.

2. Создать новый пустой проект (File — NewProject…). Записать его в каталог, название которого соответствует вашей фамилии.

2.1. При создании проекта необходимо указать, какое JDK вы будете использовать, если его не будет в предложенном меню, то вручную укажите путь до него. Например, C:\Program Files\Java\jdk1.7.0_15.

3. Создать пустой класс, содержащий статический метод выполнения (JavaApplication). Реализация метода может быть примерно следующей:

public static void main (String arg[]) {

System.out.println (“Hello, World!”);

}

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

1.3.2. Первая часть лабораторной работы

Требования к выполнению индивидуального задания.

Индивидуальное задание должно быть оформлено в отдельном классе.

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

Все входные параметры должны поступать в класс с помощью перегрузок конструкторов и должны совпадать с индивидуальным заданием (пример: в задании 1 должно быть описано три перегруженных конструктора, которые будут принимать String, Double [], List).

В классе должно быть описано поле, в котором будут храниться распарсенные значения (пример: в задание 1 в конструктор класса поступает обычная строка «11, 32, 1, 22, 14», конструктор должен разбить данную строку по запятой на массив чисел и заполнить поле, с которым в дальнейшем мы будем работать для вычисления максимального значения).

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

Варианты индивидуального задания.

1. Найти максимальное значение среди множества чисел (без использования класса Math). Числа должны поступать в виде: строки с некоторым разделителем (пример: «11, 32, 1, 22, 14»); в массиве; списком чисел.

2. Сортировка списка слов, без использования сторонних классов сортировки, например, Collections метод sort(). Слова должны поступать сплошным текстом с разделителем; списком; отдельными значениями данных.

3. Подсчет одинаковых слов. Слова должны поступать сплошным текстом и с разделителем; списком; отдельными значениями данных.

4. Подсчет четных и нечетных символов. Числа должны поступать в виде строки с некоторым разделителем (пример: «11, 32, 1, 22, 14»); в массиве; списком чисел.

5. Конвертер систем счисления. На вход поступает число, которое мы хотим конвертировать; система счисления конвертируемого числа; система счисления, в которую мы хотим преобразовать число. Числа должны поступать в виде строки с некоторым разделителем; в массиве; списком чисел.

6. Вывести уравнение прямой, проходящей через две точки. На вход поступает 4 числа: х1, у1, х2, у2. Числа должны поступать в виде строки с некоторым разделителем; в массиве; списком чисел.

7. Дан текст. Определите процентное отношение строчных и прописных букв к общему числу символов в нем. На вход поступает текст в виде строки.

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

9. Подсчет одинаковых символов. Символы должны поступать сплошным текстом с разделителем; списком; отдельными значениями данных.

10. Наибольший общий делитель (НОД) чисел (например, 3430 и 1365 — это 35. Другими словами, 35 — наибольшее число, на которое и 3430, и 1365 делятся без остатка). Числа должны поступать в виде строки с некоторым разделителем; в массиве; списком чисел.

11. Для каждого натурального числа в промежутке от m до n вывести все делители. Числа должны поступать в виде строки с некоторым разделителем; в массиве; отдельными значениями данных.

12. Перевод римских чисел в арабские (например, XIIV — 13). Поступает в виде строки.

1.3.3. Вторая часть лабораторной работы

1. Используя класс java.net.ServerSocket, написать простейший echo сервер. Технические требования, предъявляемые к серверу:

1.1. Порт, на котором запускается сервер — 12345. Транспортный протокол — TCP.

1.2. Количество одновременно подключенных клиентов — 1. То есть использование потоков (экземпляров класса Thread) на первом этапе не предусматривается.

1.3. Сервер должен обеспечивать echo-функционал, то есть просто передавать обратно клиенту, полученный буквенный символ.

1.4. На консоль (с помощью метода System.out.println ()) должны выводиться основные этапы работы программы (клиент установил соединение, был получен и передан обратно символ, соединение разорвано).

2. Изменить написанный класс echo-сервера. Сервер должен производить вычисления в соответствии с индивидуальным заданием, выполненным в пункте 1.3.2. В ответ клиент должен получить результат выполненной операции.

3. Написать клиентскую часть Socket:

3.1. Клиент должен будет подключиться к созданному ранее серверу.

3.2. Клиенту нужно передать данные параметров в соответствии с индивидуальным заданием, в ответ получить результат действий.

4. Произвести сборку серверной и клиентской части в jar файл.

5. Запустить jar-файлы серверной и клиентской части.



2. Лабораторная работа № 2

2.1. Цель работы

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

2.2. Теоретическая часть

2.2.1. HyperText Transfer Protocol

Для создания интернет-приложений все чаще и чаще используют протокол прикладного уровня (модели OSI), который готовит компьютеры к обмену информацией: HyperText Transfer Protocol, или HTTP. HTTP — протокол прикладного уровня поверх коммуникационного протокола TCP/IP. Изначально HTTP рассматривался как протокол передачи гипертекста, сейчас он широко используется и для передачи файлов. HTTP оперирует запросами, на сайтах вы встретите чаще всего только два основных запроса: — GET — запрос документа. Наиболее часто употребляемый метод; в HTTP/0.9 он был единственным. — POST — этот метод применяется для передачи данных CGI скриптам. Сами данные идут в следующих строках запроса в виде параметров. У всех запросов (Request) и ответов (Response) используется одна и та же структура: строка запроса/ответа, заголовки, пустая разделительная строка и тело сообщения. При этом обязательной является только строка запроса.

        1. Структура HTTP-запросов и ответов

Посмотрим структуру входящего GET-запроса на сервер и разберем его (табл. 2–3):

Таблица 2. Пример GET-запроса страницы сайта yandex.ru

Строка запроса (Request Line)

1. GET/index.html HTTP/1.1

Заголовки (Message Headers)

2. Host: yandex.ru

3. Connection: keep-alive

4. Cache-Control: max-age=0

5. Accept: text/html, application/xhtml+xml, application/xml; q=0.9, image/webp,*/*; q=0.8

6. User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36

7. Referer: http://yandex.ru/…

8. Accept-Encoding: gzip, deflate, sdch

9. Accept-Language: ru-RU, ru; q=0.8, en-US; q=0.6, en; q=0.4

10. Cookie: z=…

Пустая строка разделитель


Тело сообщения (EntityBody) — необязательный параметр

Например: файл





Таблица 3. Пример GET-ответа сайта yandex.ru

Строка ответа (Response Line)

1. HTTP/1.1200 OK

Заголовки (Message Headers)

2. Server: nginx

3. Date: Mon, 29 Sep 2018 08:04:48 GMT

4. Connection: close

5. Cache-Control: no-cache, no-store, max-age=0, must-revalidate

6. Content-Length: 5073

7. Content-Type: text/html; charset=utf-8

8. Content-Encoding: gzip

Пустая строка разделитель


Тело сообщения (EntityBody) — необязательный параметр

HTML-документ



Строка запроса (Request Line)

Указывает метод передачи, URL-адрес, к которому нужно обратиться, и версию протокола HTTP. В примере используется метод GET, адрес index.html, что позволяет серверу определить требуемый ресурс клиенту и версию HTTP.

Строка ответа (Response Line):

Указывает версию HTTP и код состояния запроса.

Коды состояния запроса HTTP

200 ОК — запрос был получен и обработан

301 Ресурс перемещен постоянно

302 Ресурс перемещен временно

400 Неверный запрос — сообщение с запросом имеет некорректный формат

401 Несанкционированный доступ — у пользователя нет прав для доступа к запрошенному документу

402 Ресурс доступен за плату

408 Тайм-аут запроса

500 Внутренняя ошибка сервера — ошибка помешала HTTP серверу обработать запрос

        1. Заголовки HTTP-запросов и ответов

Заголовки (Message Headers)

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

Connection: может принимать значения Keep-Alive и close. KeepAlive (оставить в живых) означает, что после выдачи данного документа соединение с сервером не разрывается, и можно выдавать еще запросы. Большинство браузеров работает именно в режиме KeepAlive, так как он позволяет за одно соединение с сервером скачать html-страницу и рисунки к ней. Будучи однажды установленным, режим Keep-Alive сохраняется до первой ошибки или до явного указания в очередном запросе Connection: close. close (закрыть) — соединение закрывается после ответа на данный запрос.

Cache-Control: срок годности содержимого в секундах:

no-cache. Сервер не должен использовать кэшированный ответ.

no-store. Ответ на этот запрос не должен кэшироваться.

max-age=delta-seconds. Клиент допускает кэшированный ответ, если его возраст не превышает delta-seconds секунд; клиент не требует его валидации.

max-stale=delta-seconds. Клиент допускает кэшированный ответ, если его возраст не превышает delta-seconds секунд.

min-fresh=delta-seconds. Клиент допускает кэшированный ответ, если он будет оставаться действительным не менее deltaseconds секунд от момента запроса.

no-transform. К запрашиваемому документу не должны применяться преобразования

only-if-cached. Допускается только кэшированный ответ. Если подходящего ответа нет в кэше, то не нужна ни валидация старого ответа, ни получение нового.

Accept: список поддерживаемых браузером типов содержимого в порядке их предпочтения данным браузером, например, для Google Chrome она будет выглядеть следующим образом:

text/html, application/xhtml+xml, application/xml; q=0.9, image/webp,*/*; q=0.8

Эти данные необходимы тогда, когда сервер может выдавать один и тот же документ в разных форматах.

User-Agent— значением является «кодовое обозначение» браузера. Например, Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36

Этот заголовок несет в себе несколько видов информации:

название браузера и его версию;

название операционной системы и ее версию;

язык системы по умолчанию.

Referer: Позволяет клиенту указать адрес (URI) ресурса, из которого получен запрашиваемый URI. Этот заголовок дает возможность серверу сгенерировать список обратных ссылок на ресурсы для будущего анализа, регистрации, оптимизированного кэширования и т. д. Он также позволяет прослеживать с целью последующего исправления устаревшие или введенные с ошибками ссылки.

Accept-Encoding: Большинство современных браузеров поддерживает метод сжатия Gzip, о чем они и сообщают в заголовке Accept-Encoding. Сервер может отправить страницу в сжатом виде. При этом объем трафика может уменьшиться до 80%, что довольно неплохо разгружает интернет-канал сайтов. Server: Информация о программном обеспечении сервера, отвечающего на запрос (это может быть как веб-, так и прокси-сервер).

Date: Дата и время формирования сообщения.

Accept-Language: поддерживаемый язык. Имеет значение для сервера, который может выдавать один и тот же документ в разных языковых версиях.

Content-Type: MIME тип возвращаемого документа.

Content-Length: размер возвращаемого документа. Пустая строка-разделитель необходима для разделения частей сообщения заголовков и тела сообщения.

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

      1. Управление потоками

В настоящее время пользователей интернета становится все больше и больше, и все больше вероятность того, что одновременно к серверу может обратиться несколько клиентов. Для решения данной задачи используются потоки, которые позволяют параллельно обрабатывать нескольких клиентов. Потоки — это независимые последовательности операций. Существует два пути создания потока. Первый — наследование от класса java.lang.Thread и переопределение его метода run. Второй— реализация интерфейса java.lang.Runnable и создание потока на основе этой реализации. В принципе, эти методы эквивалентны, разница в деталях. Наследование от java.lang.Thread делает его единственным родителем класса, что не всегда удобно. Таким образом, простейший поток может быть реализован так:

1. public class SampleThread extends Thread {

2. Integer counter = 0;

3. public SampleThread (Integer integer) {

4. counter=integer;

5. }

6. @Override

7. public void run () {

8. Integer result = counter*counter;

9. System.out.println (result);

10. }

11. public static void main (String [] args) {

12. for (int i = 10; i > 0; i —) {

13. new Thread (new SampleThread(i)).start ();

14. }

15. }

16. }

При этом результат всегда будет выводиться в разной очередности, например, 81;100;64;49;36;4;16;9;25;1.

    1. Порядок выполнения работы

Технические требования к разрабатываемому серверу.

1. Порт, на котором запускается сервер — 8080.

2. Количество одновременно обрабатываемых клиентских запросов — не ограничено (создание многопоточности).

3. Сервер должен распознавать метод запроса и реагировать только на метод GET. Реакция на все остальные методы (POST, PUT, DELETE и др.) не оговаривается и может быть реализована по желанию, но при этом, если будет реализован только один метод GET, на другие методы ваш сервер не должен срабатывать.

4. В заголовке выдаваемого ответа нужно указать корректный тип (text/html) и длину тела сформированного сообщения.

5. В ответ на любой запрошенный ресурс сервер должен выдавать HTML-страницу с возможностью отображения русских слов.

Примечание к выполнению работы

1. Написать процедуру распознавания окончания запроса (наличия пустой строки, в которой есть символ возврата каретки, но нет ни одного значащего текстового символа).

2. По окончании запроса провести анализ полученного метода. Если это GET — перейти к формированию корректного ответа клиенту.

3. Сформировать ответ и выдать его клиенту. Корректно завершить соединение с клиентом. При следующем запросе клиент установит новое соединение.

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

Результат выполнения лабораторной работы

  1. В ответ на любой запрос к серверу ответ должен содержать одну и ту же HTML-страницу, состоящую из надписи: Работу выполнял: Иванов Иван Иванович

2. Сервер должен работать по принципу echo-сервера, то есть то, что мы запрашиваем в адресной строке, то и отображаем на странице. Ответ должен приходить в виде HTML-страницы и должен содержать заполненные данные предыдущего этапа работы и сформированный ответ адресной строки, при этом ответ не должен содержать адреса сервера. Пример сформированного ответа адресной строки: Запрос: http://localhost:8080/display_the_entered_value Ответ: HTML-страница: <h1>display the entered value </h1>

3. Сервер должен принимать данные и выполнять вычисления в соответствии с индивидуальным заданием (лабораторная работа № 1), и отправлять результат клиенту в виде HTML-страницы. HTML-страница должна содержать ранее выполненные этапы лабораторной работы, а также информацию о произведенных вычислениях. Пример: при выполнении лабораторной работы было выбрано индивидуальное задание № 1 «Найти максимальное значение среди множества чисел…», значит, у нас в адресную строку в качестве ресурса должна быть введена цепочка чисел через разделительный символ: «11, 32, 1, 22, 14», сервер должен разбить строку, произвести вычисления и вернуть результат клиенту (браузеру).


3. Лабораторная работа № 3

3.1. Цель работы

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

3.2. Теоретическая часть

3.2.1. Создание клиентской части

Далее будет описан процесс взаимодействия разных технологий на примерах, таких, как HTML, CSS, JavaScript, JQuery, AJAX. Основным, конечно же является HTML, то есть сам наш документ, а CSS и JavaScript — вспомогательные аппараты для упрощения оформления и интерактивности страницы, AJAX же позволяет обмениваться информацией с сервером асинхронными запросами. Объединяет все эти технологии HTML, то есть ссылки на них (css-файлы и js-файлы) будут находиться в самом документе в виде следующих строк:

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

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

В фалах с расширением js обычно содержатся код JavaScript и элементы AJAX и JQuery.

В файлах с расширением css содержатся таблицы каскадных стилей.

Приведем простой пример применения этих технологий на практике. Пример HTML-файла:

1. <html>

2. <head>

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

4. <script type="text/javascript" src="jquery-1.6.2.min.js"></script>

5. <script type="text/javascript" src="example.js"></script>

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

7. <title>HardSite</title>

8. </head>

9. <body>

10. <input type="text" id="text" name="text" class="panda-searchfield">

11. <div class="b-top"><input type="submit" value="Перейти" onclick="sendTextJQuery()" class="b-top-but"></div>

12. <div class="b-top"><input type="submit" value="Перейти" onclick="sendText()" class="b-top-but"></div>

13. </body>

14. </html>

На 4–5 строках листинга представлено подключение js-файлов.

Один из них — это библиотека JQuery, другой — это созданный файл.

Строка 6 содержит подключение файла — таблицы каскадных стилей. Изначально, когда обращаются в адресной строке, к определенному сайту, отправляется HTTP get-запрос, после принятия от сервера HTML-документа браузер смотрит на информацию, отмеченную в теге HEAD, там обычно указывается служебная информация, по ней браузер понимает, какие еще файлы необходимо запросить от сервера, и будет поочередно отправлять запросы на сервер, требуя сначала файл jquery-1.6.2.min.js, затем example.js и заканчивая файлом каскадных стилей example.css. Изображения, которые могут использоваться в HTML-документе, также будут запрашиваться у сервера отдельными запросами.

3.2.2. Таблицы каскадных стилей

Существует три способа добавления стилей в документ.

1. Внутренние стили определяются атрибутом style в тегах. Пример: <p style = "color: blue">Абзац с текстом синего цвета</p>

2. Глобальные стили располагаются в контейнере <style>…</style>, который в свою очередь находится в теге <head>…</head>.

Пример:

1. <html>

2. <head>

3. … ….

4. <style type="text/css">

5. p {color:#808080;}

6. </style>

7. </head>

8. <body>

9. <p>Серый цвет текста во всех абзацах Web-страницы</p>

10. <p>Серый цвет текста во всех абзацах Web-страницы</p>

11. </body>

12. </html>

3. Внешние стили содержатся в отдельном файле с расширением css. Внешние стили позволяют всем страницам сайта использовать одни и те же стили, тем самым позволяя страницам выглядеть единообразно.

Для связи с файлом стилей используется тег <link>, расположенный в теге <head>…</head>. В нем задается два атрибута: rel=«stylesheet» и href, определяющий адрес файла стилей.

Пример:

1. <html>

2. <head>

3. … ….

4. <link rel="stylesheet" href="style.css">

5. … ….

6. </head>

7. <body>

8. … ….

9. </body>

10. </html>

Подключение стилей

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

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

1. p {

2. text-indent: 30px;

3. font-size: 14px;

4. color: #666;

5. }

Объявление стиля — это пара свойство CSS: значение CSS.

Например, color: red

color свойство CSS, определяющее цвет текста;

red значение CSS, определяющее красный цвет.

Существует несколько типов селекторов: селекторы CSS, селекторы тегов, селекторы идентификаторов и селекторы классов.

Селекторы тегов

В качестве селектора может выступать любой html-тег, для которого определяются правила стилевого оформления. Например,

h1 {color: red; text-align: center;}

Селекторы идентификаторов

HTML предоставляет возможность присвоить уникальный идентификатор любому тегу. Идентификатор задается атрибутом id. Например:

<div id="a1">…</div>

В CSS-коде селектор идентификатора обозначается знаком «решетка» (#). Так как идентификатор id применяется только к уникальным элементам, название тега перед знаком «решетка» (#) обычно опускают. Пример:

#a1 {color: green;}

Селекторы классов

Для стилевого оформления чаще всего используются селекторы классов. Класс для тега задается атрибутом class. Например:

<div class="c1">…</div>

Если атрибут id применяется для уникальной идентификации, то при помощи атрибута class тег относят к той или иной группе.

В CSS-коде селектор класса обозначается знаком «точка» (.). Разные теги можно отнести к одному классу. В таком случае имя тега перед знаком «точка» (.) опускают:

i.green {color: #008000;}

b.red {color: #f00;}

.blue {color: #00f;}

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

<div class="left w100">…</div>

Если некоторые из этих классов содержат одинаковые свойства стиля, но с разными значениями, то будут применены значения стиля класса, который в CSS-коде расположен ниже.

Селекторы CSS

Имеется набор стандартных селекторов, предоставляемый css. Например, E: focus; E: hover и т.д. Также он позволяет воспринимать структуры вида E#myid и E.myclass, которые позволяют более точно настроить стили. E#myid позволяет применить стили к элементу с id равным myid который обязательно должен находиться в теге E. E.myclass позволяет применить стили к элементам класса myclass, но только те, которые находятся в теге E.

3.2.3. Отправка HTTP-запросов с помощью языка JavaScript

JavaScript позволяет разработчикам:

изменять страницу, писать на ней текст, добавлять и удалять теги, менять стили элементов;

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

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

устанавливать и считывать cookie, валидировать данные, выводить сообщения и многое другое.

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

В данном примере будет показано, как можно отправить POST запрос на сервер с помощью JavaScript.

Пример использования объекта XMLHttpRequest:

1. function sendText () {

2. var text = document.getElementById("text").value;

3. var xmlhttp = new XMLHttpRequest();

4. xmlhttp.open ('POST', '/xhr/test.html', false);

5. xmlhttp.send(text);

6. xmlhttp.onreadystatechange = function(e) {

7. if (this.readyState == 4 && this.status == 200) {

8. …

9. }

10. }

11. }

Пример использования объекта XMLHttpRequest:

1. function sendTextJQuery ()

2. {

3. var text = $ ("#text").val ();

4. $.ajax ({

5. url: "/form.php",

6. type: "post",//тип запроса

7. data: text//отправляемые данные, в данный момент это простой текст

8. success: function (data, textStatus) {

9. …

10. }

11. });

12. }

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

В листинге показаны способы отправления запросов с данными на сервер с помощью компонента XMLHttpRequest и AJAX.

Функция sendText осуществляет общение с сервером через объект XMLHttpRequest. Для того что бы с ней работать, необходимо описать с кем и как необходимо соединиться, это позволяет сделать метод open с входными параметрами: тип запроса, url, асинхронной или синхронный тип запроса. После чего нужно послать сформированный HTTP-запрос, делает это функция send, входным параметром являются данные, которые необходимо передать серверу. Далее необходимо ожидать ответа от сервера, это позволяет осуществлять метод onreadystatechange.

Функция sendTextJQuery отправляет данные серверу с помощью технологий AJAX. Выполняется это функцией $.ajax, в которой указываются необходимые параметры: url, тип запроса и данные. Функция success позволяет получать ответ от сервера, который в дальнейшем необходимо обрабатывать.

XMLHttpRequest — это объект JavaScript, содержащий API, который обеспечивает клиентский скрипт функциональностью для обмена данными между клиентом и сервером. Может работать как асинхронно, так и синхронно с серверным приложением. Использует запросы HTTP или HTTPS напрямую к серверу и загружает данные ответа сервера напрямую в вызывающий скрипт. Позволяет осуществлять HTTP-запросы к серверу без перезагрузки страницы.

В основе работы AJAX лежит объект XMLHttpRequest. Только в отличие от XMLHttpRequest требует еще и библиотеку JQuery, но и имеет более гибкий функционал и более простое взаимодействие с сервером.

3.3. Порядок выполнения работы

Описание выполнения работы:

1. Описание HTML-страниц (не менее трех страниц):

1.1. Первая страница «О себе» содержит информацию:

Работу выполняли: Иванов Иван Иванович

1.2. Вторая страница — реализация индивидуального задания.

На странице отображены следующие элементы:

1.2.1. Поля для занесения информации, необходимой для вычисления.

1.2.2. Кнопка для отправки результатов на сервер.

1.2.3. Поле, в котором будет выводиться результат вычислений.

1.3. Третья страница— работа с таблицей, студент выбирает некоторую узкую тему, с которой он дальше будет работать. Например, таблица студенты. На странице отображается информация о студентах, при этом дана возможность добавлять нового студента, удалять и изменять данные уже существующего студента.

2. Изменения сервера в соответствии с требованиями.

2.1. Сервер должен обрабатывать запросы и в соответствии с ним возвращать необходимую клиенту информацию.

2.2. От клиента будут запросы на загрузку данных о css, js и других файлах, используемых страницей. Пример: все страницы используют файл каскадных стилей (css), в HTML-документе ссылка на него. При загрузке страницы браузером он обнаруживает, что данная страница использует css-файл и начинает автоматически требовать его с сервера. Сервер должен в итоге отправить ему этот файл.

2.3. Для сохранения данных третьей страницы необходимо:

2.3.1. Создать структуру таблицы. Например, таблица студенты содержит информацию: Имя, Фамилия, Отчество, Год рождения. Для этого мы создаем новый класс под названием Student с описанием полей Id, Name, LastName, FirstName, YearBirth и их геттеры и сеттеры (getName (), setName ()…).

2.3.2. Для хранения данных создаем список со структурой таблицы (Пример: List<Student>). Сохранение в файл или БД не требуется. То есть при каждом перезапуске сервера у нас будут обнуляться записи.

3. Технические требования:

3.1. Требования к серверу:

3.1.1. Все страницы должны храниться как html-страницы на сервере.

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

3.1.3. Все поля ввода информации должны иметь проверку входных значений (с помощью JavaScript).

3.2. Требования к оформлению HTML-страниц:

3.2.1. Общие требования:

3.2.1.1. У каждой группы студентов должен быть уникальный стиль сайта и уникальная тема для третьей страницы.

3.2.1.2. Все страницы должны быть красиво оформлены, стили описаны в отдельном css-файле.

3.2.1.3. У каждой страницы должно быть реализовано единое меню, у которого будет минимум три ссылки (переход на каждую созданную страницу).

3.2.2. Индивидуальные требования к страницам:

3.2.2.1. Первая страница: вывод статической информации.

3.2.2.2. Вторая страница: для выполнения вычислений мы должны использовать возможность отправки данных на сервер POST запросом и получать от сервера ответ, который должен помещаться в специально отведенное для этого поле. Данная функция должна быть реализована с помощью JavaScript и храниться отдельном js-файле.

3.2.2.3. Третья страница: при запуске сервера и при обращении к этой странице у нас будет отображаться пустая таблица (то есть сервер сохраненные данные не хранит постоянно, а только временно держит их в оперативной памяти). Данная страница должна позволять:

добавлять строки и сохранять их на сервере;

изменять строки и сохранять изменение на сервере;

удалять строки и удалять информацию с сервера.

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

3.2.2.3.2. Операция удаления: напротив каждой строки должен быть значок удаления, после нажатия на который строка должна пропасть (удалиться и со страницы, и с сервера).

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

3.2.2.3.4. Операция изменения: напротив каждой строки должен быть значок, нажатие которого должно работать по аналогии операции создания. Только все поля должны быть заполнены данными изменяемой строки.





4. Лабораторная работа № 4

4.1. Цель работы

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

4.2. Теоретическая часть

Существует множество реализаций технологии ORM на языке Java. Одна из этих реализаций - это Hibernate. Для того, чтобы использовать функционал Hibernate, необходимо иметь:

библиотеку ORM Hibernate, ее можно скачать с официального сайта производителя;

JDBC (Java Data Base Connectivity) — это библиотека, позволяющая взаимодействие с различными СУБД. JDBC основан на концепции драйверов, позволяющих получить соединение с БД по специальному URL. Каждая БД имеет свою JDBC библиотеку, которую можно загрузить с официального сайта используемой БД.

4.2.1. Создание конфигурации подключения к БД.

Основным классом Hibernate-технологии, позволяющей читать, изменять, добавлять или удалять данные из СУБД, является Session. Для получения сессии необходимо изначально установить конфигурацию соединения с БД и получить с помощью созданной конфигурации фабрику сессий (SessionFactory), которая в итоге будет нам поставлять сессии. Конфигурацию соединения можно прописать двумя способами:

через файл hibernate.cfg.xml;

через класс org.hibernate.cfg.Configuration.

Сейчас рассмотрим эти два способа на примерах:

Файл hibernate.cfg.xml

1. <! DOCTYPE hibernate-configuration SYSTEM

2. "http://www.hibernate.org/dtd/hibernateconfiguration-3.0.dtd">

3. <hibernate-configuration>

4. <session-factory>

5. < propertyname = " connection.url" > jdbc : sqlserver://localhost:1433; database=data_base</property>

6. <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>

7. <property name="connection.username">sa</property>

8. <property name="connection.password">1</property>

9. <property name="connection.pool_size">1</property>

10. <property name="current_session_context_class">thread</property>

11. <property name="hbm2ddl.auto">update</property>

12. <property name="show_sql">true</property>

13. <property name="dialect">org.hibernate.dialect.SQLServerDialect</property>

14. </session-factory>

15. </hibernate-configuration>

Первые две строчки — подключение спецификации (шаблона), с его помощью мы не ошибемся в синтаксисе и будем точно знать, где какой тег должен будет находиться и какие атрибуты он может иметь. Необходимая информация содержится в строчках с 5 по 13, в них прописаны непосредственно свойства подключения в БД:

connection.url - url-строка подключения к БД. В данном примере осуществляется подключение к MS SQL Server. Разберем строчку детально: jdbc: sqlserver: — это некоторая спецификация, через что мы подключаемся и к какому серверу;: //localhost:1433— указываем ip-адрес или доменное имя компьютера с портом, к которому мы будем подключаться; database=data_base - указание, к какой базе мы будем подключаться;

connection.driver_class — указание, какой драйвер будет использоваться в качестве связующего звена с СУБД. Здесь указывается класс JDBC-драйвера, который подключен к проекту, в примере указан драйвер MS SQL Server;

connection.username — логин зарегистрированного пользователя СУБД;

connection.password — пароль;

connection.pool_size — данное свойство показывает, сколько соединений к БД может быть одновременно открыто;

hbm2ddl.auto — свойство, указывает что нужно сделать со схемой БД при инициализации. Может принимать такие значения:

update — сверяет схему БД с имеющимися конфигурациями классов, если были внесены какие-то изменения, они автоматически занесутся в БД. При этом данные, которые были занесены в базу, не изменятся;

create — каждый раз при запуске приложения схема БД будет создаваться заново. Все данные, которые были занесены раньше, будут удалены;

create-drop — каждый раз при запуске приложения схема БД будет создаваться заново, а при завершении — удаляться. Все данные, которые были занесены во время работы приложения, будут удалены по завершению приложения;

validate — при инициализации будет совершена проверка соответствия конфигурации классов и схемы БД. Если мы внесли изменение в конфигурацию какого-то класса, а схема в БД не была изменена, сработает исключение;

show_sql — данное свойство указывает, будут ли выводится SQL запросы на консоль, которые отправляются на СУБД. В процессе отладки это бывает очень удобно;

dialect — hibernate может работать с разными БД, и каждая имеет свои особенности (генерация первичного ключа, страничный вывод, функции), нужно указать какой диалект будем использовать для создания запросов. В данном случае — диалект MS SQL Server.

Класс org.hibernate.cfg.Configuration используется для подготовки данных соединения к СУБД.

1. public static Configuration getConfiguration (){

2. Configuration cfg = new Configuration ();

3. cfg.setProper ty ("hiber nate.connection.url", "jdbc: sqlserver://localhost:1433; database=data_base");

4. cfg.setProperty ("hibernate.connection.driver_class", "com.microsoft.sqlserver.jdbc.SQLServerDriver");

5. cfg.setProperty ("hibernate.connection.username","sa");

6. cfg.setProperty ("hibernate.connection.password","1");

7. cfg.setProperty ("hibernate.connection.pool_size","1");

8. cfg.setProperty ("hibernate.current_session_context_class","thread");

9. cfg.setProperty ("hibernate.hbm2ddl.auto","update");

10. cfg.setProperty ("hibernate.show_sql","true");

11. cfg.setProperty ("hibernate.dialect","org.hibernate.dialect.SQLServerDialect");

12. return cfg;

13. }

Класс подключения к БД.

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

1. private static SessionFactory sessionFactory = buildSessionFactory();

2. private static SessionFactory buildSessionFactory () {

3. try {

4. if (sessionFactory == null) {

5. Configuration configuration = new Configuration ().configure(“HibernateUtil/hibernate.cfg.xml”);

6. St a n d a r d S e r v i c e R e g i s t r y B u i l d e r b u i l d e r = n e w

StandardServiceRegistryBuilder ().applySettings (configuration.getProperties ());

7. sessionFactory = configuration.buildSessionFactory (builder.build());

8. }

9. return sessionFactory;

10. } catch (Throwable ex) {

11. System.err.println (“Initial SessionFactory creation failed.” + ex);

12. throw new ExceptionInInitializerError (ex);

13. }

14. }

15. public static Session getSession () {

16. return sessionFactory.openSession ();

17. }

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

5. Configuration configuration = getConfiguration();

Метод getSession создает сессию, с помощью которой и будет происходить общение с БД.

4.2.2. Создание класса-сущности

БД позволяет хранить информацию в таблицах, для того чтобы это осуществить, у hibernate существует специальный механизм — mapping. Mapping-проецирование (сопоставление) Java классов с таблицами базы данных. Реализация маппинга возможна через использование конфигурационных файлов XML, либо через аннотации. Так как описание маппинга через файлы XML неудобно и уже устаревает, в примере использованы аннотации. Пример:

1. import javax.persistence.*;

2. @Entity

3. @Table (name = "people")

4. public class People {

5. @Id

6. @GeneratedValue (strategy = GenerationType.IDENTITY)

7. @Column (name = "id", unique = true, nullable = false)

8. private Integer id;

9. @Column (name = "firstName")

10. private String firstName;

11. @Column (name = "lastName")

12. private String lastName;

13. @Column (name = "middleName")

14. private String middleName;

15. @Column ()

16. private int year;

17.

18. public Integer getId () {

19. return id;

20. }

21. public void setId (Integer id) {

22. this.id = id;

23. }

24. …

25. }

Для того чтобы созданный класс воспринимался hibernate как некоторая сущность бизнес-модели, необходимо пометить аннотацией @Entity. Аннотация @Table позволяет задать имя, под которым данная сущность будет существовать в БД (позволяет задать имя таблицы), а также другие конфигурационные параметры. Если имя таблицы совпадает с именем класса, аннотацию можно не использовать.

В каждой сущности должен быть указан первичный ключ, который помечается @Id. Аннотация @GeneratedValue указывает, что данное поле будет генерироваться автоматически при создании нового элемента в таблице. @Column — один из основных аннотаций, который указывает, что поле, описанное после него, будет храниться в БД. Поле, над которым стоит аннотация Id, GeneratedValue, Column, должно быть либо примитивом, либо оберткой над этим примитивом: String; java.util.Date; java.sql.Date; java.math.BigDecimal; java.math.BigInteger.

По правилам хорошего тона класс нужно оформлять как просто POJO-объект, то есть поля должны иметь спецификатор доступа private. А доступ к этим полям осуществляется с помощью геттеров и сеттеров, как показано в примере, строчки 18–23.

4.2.3. Регистрация классов-сущностей

Для того чтобы hibernate при создании SessionFactory учитывала новую сущность, ее необходимо указать в конфигурации. Пример для файла hibernate.cfg.xml:

1. <hibernate-confi guration>

2. <session-factory>

3. …

4. <mapping class="Entity.People"/>

5. </session-factory>

6. </hibernate-confi guration>

Тег mapping позволяет указать, какие классы-сущности мы должны учитывать при создании SessionFactory.

Пример для конфигурационного класса org.hibernate.cfg.

Configuration:

1. Configuration cfg = new Configuration ();

2. cfg.addAnnotatedClass (People.class);

Взаимодействие с БД: создание, удаление, чтение и изменение сущностей.

4.2.4. Создание объекта в БД

Пример создания объекта (строки) в БД.

1. public static void create (Object o)

2. {

3. try {

4. Session session = HibernateUtil.getSession ();

5. session.beginTransaction ();

6. session.save (o);

7. session.getTransaction ().commit ();

8. session.close ();

9. } catch (HibernateException e) {

10. e.printStackTrace ();

11. }

В третьей строке мы обращаемся к созданному классу для получения сессии. Четвертая строчка— начало транзакции, шестая— конец транзакции или просто коммит, то есть те запросы, которые были между этими командами описаны, отправятся на сервер БД, и там появятся данные. Пятая строчка отвечает за генерацию кода, обеспечивающую создание объекта, при этом запрос будет выглядеть примерно следующим образом:

Hibernate: insert into people (firstName, lastName, middleName, year) values (?,?,?,?).

Пример сохранения объекта:

1. People people = new People ();

2. people.setFirstName ("Иванов");

3. people.setLastName ("Иван");

4. people.setMiddleName ("Иванович");

5. people.setYear (21);

6. create (people);

В БД появится запись.

4.2.5. Удаление объекта из БД.

Существует два распространенных способа удаления объектов из БД: через объект или через id. Через объект метод будет в точности такой же, как и при создании, только вместо save будет delete:

5. session.beginTransaction ();

6. session.delete (o);

7. session.getTransaction ().commit ();

Удаление с помощью HQL-запросов по id:

1. public static void delete (int id){

2. try {

3. Session session = HibernateUtil.getSession();

4. String stringQuery = "delete from People where id =: id";

5. Query query = session.createQuery (stringQuery);

6. query.setParameter ("id", id);

7. query.executeUpdate();

8. session.close();

9. } catch (HibernateException e) {

10. e.printStackTrace();

11. }

12. }

В примере прописывается строка HQL-запроса (Hibernate Query Language— язык запросов Hibernate), и на его основе формируется сам запрос, в который мы передаем параметры через метод setParameter. Метод executeUpdate непосредственно выполняет запрос, после его выполнения в БД будет произведено удаление объекта.

4.2.6. Изменение объекта в БД

Изменение объекта ничем не отличается от метода создания объекта, только в место save будет использоваться метод update:

5. session.beginTransaction ();

6. session.update (o);

7. session.getTransaction ().commit ();

4.2.7. Чтение из БД

Есть два основных способа чтения данных из БД— это чтение списком и чтение по id. Для чтения из базы данных используется специальный вид запросов под названием Criteria. Пример вызова списка без фильтрации по параметрам:

List<People> peoples = session.createCriteria(People.class).list();

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

Если же нам нужен поиск по идентификатору, то нужно использовать некоторую фильтрацию:

1. People people = (People) session.createCriteria (People.class)

2. .add (Restrictions.eq (“id”, id)).uniqueResult ();

Как и в прошлый раз, мы указываем, к какой таблице обращаемся. Дальше используется метод add, в который прописываются условия отбора, это сделать нам позволяет класс Restrictions. Метод же eq означает, что будет осуществляться сравнение с объектом, который мы в него поместим. Метод uniqueResult позволяет вернуть результат объектом, но у него есть и недостатки: если объект не будет найден или по каким-то причинам объектов будет больше одного, произойдет ошибка. Для обхода ошибки рекомендуется прописывать немного другой код:

1. People people = null;

2. List peoples = session.createCriteria (People.class)

3. .add (Restrictions.eq ("id", id)).list();

4. if (peoples!=null&&peoples.size()==1)

5. {

6. people = peoples.get(0);

7.} Весь результат будет собираться в список, если не будет найдено ни одного элемента или элементов списка будет больше 1, то if не сработает, но и не произойдет ошибки.

4.2.8. Связи между таблицами

Обычно при создании проектов необходимо связывать таблицы между собой, это нужно для логической связи объектов между собой. Так как реляционная база данных представляет собой множество взаимосвязанных таблиц, то необходимо уделить отдельное внимание описанию отношений между сущностями с помощью технологии hibernate. Всего существует три основных типа связи: one-toone, one-to-many, many-to-one; существует также связь many-to-many, но она может быть решена как специальной аннотацией @many-tomany, так и промежуточной таблицей.

4.2.9. Связь many-to-one

Разберем пример. Есть сущность people, которая связана с phone, то есть две таблицы: люди и телефоны. У одного человека может быть несколько телефонов, но не наоборот. Для этого мы создаем связь many-to-one, при этом в таблице phone появится новое поле, ссылающееся на элемент таблицы people, в нем будет храниться идентификатор. Класс people был уже описан ранее, в данном случае он остается неизменным. Класс phone выглядит следующим образом:

1. @Entity

2. @Table (name = "phones")

3. public class Phone {

4. @Id

5. @GeneratedValue (strategy = GenerationType.IDENTITY)

6. @Column (name = "id")

7. private int id;

8. @Column (name = "number")

9. private String number;

10. @ManyToOne (targetEntity = People.class, fetch = FetchType.LAZY)

11. @JoinColumn (name = "id_ people")

12. private People people;

13. … (описываем геттеры и сеттер)

14. }

Аннотация @ManyToOne позволяет создать связь между двумя таблицами. Также при использовании связи many-to-one автоматически создается вторичный ключ. Свойство targetEntity указывает, с какой сущностью будет происходить соединение по внешнему ключу. Свойство fetch (очень важное свойство) может иметь два состояния: LAZY или EAGER — по умолчанию это EAGER. В случае если параметром будет выступать EAGER, связанный элемент будет сразу же подгружаться автоматически. LAZY — пока не обратятся к элементу people, данные не будут загружены.

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

При запросе к БД:

1. Phone phone = (Phone) session.createCriteria (Phone.class).add

(Restrictions.eq ("id", 1)).uniqueResult ();

2. People people = phone.getPeople ();

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

fetch = FetchType.LAZY

При выполнении первой строчки будет сформирован запрос на получение данных только о таблице Phone, и только когда идет обращение к связанному объекту People, формируется новый запрос.

1. Hibernate: select this_.id as id1_1_0_, this_.number as number2_1_0_, this_.id_poeple as id_poepl3_1_0_ from phones this_ where this_.id=?

2. Hibernate: select people0_.id as id1_0_0_, people0_.firstName as firstNam2_0_0_, people0_.lastName as lastName3_0_0_, people0_.middleName as middleNa4_0_0_, people0_.year as

year5_0_0_ from people people0_ where people0_.id=?

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

Hibernate.initialize (phone.getPeople());

fetch = FetchType.EAGER

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

Пример сформированного запроса:

Hibernate: select this_.id as id1_1_1_, this_.number as number2_1_1_, this_.id_poeple as id_poepl3_1_1_, people2_.id as id1_0_0_, people2_. firstName as firstNam2_0_0_, people2_.lastName as lastName3_0_0_, people2_.middleName as middleNa4_0_0_, people2_.year as year5_0_0_ from phones this_ left outer join people people2_ on this_.id_poeple=people2_.id where this_.id=? Аннотация @JoinColumn в данном случае является не обязательной, она просто содержит параметр, в котором можно указать название колонки.

Связь one-to-many.

Часто требуется делать и обратную связь, то есть, имея объект people, получать список связанных с ним телефонов.

1. @Entity

2. @Table (name = "people")

3. public class People {

4. …

5. @OneToMany (targetEntity = Phone.class, mappedBy = "people",

fetch = FetchType.LAZY)

6. private List<Phone> phones;

7. …

8. }

Аннотация @OneToMany позволяет осуществить эту мнимую связь, которая обеспечивается hibernate, но не БД. Параметр targetEntity указывает, с какой сущностью идет связь. В параметре mappedBy прописывается имя связующего поля с аннотацией @ManyToOne, то есть его имя people. Параметр fetch был ранее описан, в данном случае он играет ту же самую функцию.

4.3. Порядок выполнения работы

Постановка задачи:

1. Разобраться с ORM-технологией и Hibernate библиотекой, а также с JDBC концепцией.

2. Опираясь на наработки предыдущей лабораторной работы, реализовать подключение к базе данных с помощью библиотек JDBC (для каждой базы данных своя JDBC-библиотека), дальнейшее взаимодействие с базой данных должно осуществляться с помощью Hibernate. (Определение используемой базы данных на выбор студента, но желательно PostgreSQL).

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

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

3. Создание таблицы в базе данных:

3.1. Структура таблицы берется из предыдущей лабораторной работы.

3.2. Создать класс, соответствующий структуре таблицы, с элементами аннотаций для взаимодействия с базой данных через библиотеку Hibernate.

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













5. Лабораторная работа № 5

5.1. Цель работы

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

5.2. Теоретическая часть

Про технологии MVC было подробно рассказано в теоретической части учебно-методического пособия. А сейчас мы подробно рассмотрим тему библиотеки FreeMarker.

FreeMaker — это написанная на Java библиотека, предназначенная для реализации механизма шаблонов. Шаблоны работают с текстом, подставляя в текст значения переменных. Цепочка следующая. Есть исходный текст, он представляет собой HTML с особыми тэгами (выражениями — не HTML, а именно шаблонизатора; язык FreeMaker называется FTL, FreeMaker Template Language). Далее этот текст проходит через некоторый процесс, называемый рендерингом. Выходом является текст. Но в нем воспринимаемые шаблонизатором тэги уже заменены на конкретные значения. На этом этапе обычно остается «чистый» HTML — страница в том виде, в каком она будет передана клиенту.

Наиболее часто шаблонизатор применяется следующим образом.

Создается класс, в котором собирается вся необходимая для отображения информация (изъятая из model MVC). И этот класс используется в качестве основы (контекста) для работы шаблонизатора, для получения HTML из заготовки (шаблона).

Рассмотрим следующий пример. Есть шаблон, текстовый файл с именем ourTemplate.html, содержащий следующую строку.

<h1>Здравствуйте, ${userName}!</h1>

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

В Java-классе необходимо выполнить следующие действия.

1. HashMap renderContext = new HashMap ();

2. renderContext.put ("userName", getCurrentUser ().getName ());

3. Template template = fmConfig.getTemplate ("ourTemplate.html");

4. StringWriter writer = new StringWriter ();

5. template.process (renderContext, writer);

6. String html = writer.toString ();

7. sendToClient (html);

Создается словарь (HashMap). В элемент с именем userName помещается ФИО текущего пользователя, полученное вызовом функций getCurrentUser().getName(). Дальше создается объект-шаблон (template) основанный на ранее сформированной конфигурации (fmConfig) из файла outTemplate.html, и к нему применяем операцию process.

На выходе получаем текстовую строку, которая будет содержать примерно следующее: <h1>Здравствуйте, Иванов Иван Иванович!</h1>

Мы оживили страницу, заменив шаблон на реальное значение переменной. Такую HTML-строку можно отправлять.

FreeMaker способен заменять шаблоны на реальное значение переменных — это значит сильно упрощать ситуацию. FreeMaker имеет достаточно развитый язык, позволяющий создавать списки, производить условные переходы и т.д. Кроме того, если чего-то не хватило в самом FTL, можно определить и свои собственные директивы (практически это вряд ли понадобится, но такая возможность есть). Пример списка, сделанного при помощи механизма шаблонов.

Пример шаблона:

1. <table>

2. <#list Users as u >

3. <tr>

4. <td>${u.getLastName ()}</td>

5. <td>${u.getFirstName ()}</td>

6. </tr>

7. </#list>

8. </table>

Строка в таблице фигурирует один раз. Класс контекста мог бы выглядеть следующим образом:

1. HashMap context = new HashMap ();

2. //Собираем всех пользователей, которых мы хотим получить

3. //в таблице на экране — в вектор.

4. Vector Users = new Vector ();

5. User u = new User ("Иванов", "Иван", "Иванович"); Users.add (u1);

6. User u2 = new User ("Петров", "Петр", "Петрович"); Users.add (u2);

7. User u3 = new User ("Николаев", "Николай", "Николаевич");

Users.add (u3);

8. //Теперь в контекст в качестве именованной переменной помещаем сам вектор.

9. context.put ("Users", Users);

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

1. <table>

2. <tr>

3. <td>Иванов</td>

4. <td>Иван</td>

5. </tr>

6. <tr>

7. <td>Петров</td>

8. <td>Петр</td>

9. </tr>

10. <tr>

11. <td>Николаев</td>

12. <td>Николай</td>

13. </tr>

14. </table>

Отметим две вещи:

1) строк в таблице стало столько, сколько элементов в коллекции Users в контексте. Если их будет 100, значит, директива FreeMaker <#list> выполнится 100 раз, и получаем HTML с таблицей, состоящей из 100 строк;

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

FreeMaker работает с текстом. У него текст на входе и текст на выходе. HTML - это частный случай применения механизма шаблонов.

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

5.3. Порядок выполнения работы

Постановка задачи:

1. Разобраться с технологией MVC и библиотекой FreeMarker. Используя библиотеку FreeMarker, изменить структуру вашего сайта, результата предыдущей лабораторной работы.

1.1. Отделить одинаковую (статичную) часть от всех страниц (одна из которых обязательно является меню) в отдельный HTML-файл.

1.2. Все созданные ранее страницы изменить в соответствии с требованиями работы с библиотекой FreeeMarker.

2. При организации ответа нужно объединить страницы меню и запрашиваемую страницу с помощью FreeMarker.

2.6. Защита лабораторных работ

Результаты каждой выполненной лабораторной работы:

1) сформированный проект, выполненный по заданию лабораторной работы;

2) оформленный отчет, содержащий все этапы выполненной работы.

Защита лабораторной работы:

1) продемонстрировать разработанное приложение, выполненное в соответствии с заданием;

2) предоставить отчет по лабораторной работе в печатном виде;

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













































Библиографический список

1. Аншина М. Л. Технологии создания распределенных систем / А.А. Цимбал, М.Л. Аншина.— СПб. : Питер, 2003.

2. Браун Л. Программирование для Web / Л. Браун, М. Холл. — Sun Microsystems, 2002.

3. Дейтел Х.М. Технологии программирования наJava/ Х.М. Дейтел, П. Дж. Дейтел, С.И. Сантри.— М. : ООО «Бином-Пресс», 2003.

4. Таненбаум Э. Распределенные системы. Принципы и парадигмы / Э. Таненбаум, М. Ван Стеен.— СПб. : Питер, 2003.

5. Тузовский А. Ф. Проектирование интернет-приложений /А.Ф. Тузовский — Томск : Изд-во Томского политехнического университета, 2010.

6. Java Hibernate. Часть 1 — Введение [Электронный ресурс]. URL: http://javaxblog.ru/article/java-hibernate-1/(дата обращения: 05.07.15). Заголовок с экрана.

7. HIBERNATE— Relational Persistence forIdiomatic Java [Электронный ресурс]. URL: http://samsonych.com/lib/hibernate/index.

© Copyright 2012-2020, Все права защищены.