Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Распределенные сервис-ориентированные системы..pdf
Скачиваний:
16
Добавлен:
05.02.2023
Размер:
9.2 Mб
Скачать

.build();

}

}

Этим кодом мы завершаем разработку проекта lab9, соотвествующего Web-службе поставщика сервиса.

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

6.3.3 Шаблон реализации потребителя сервиса

Полная реализация RESTful-сервиса требует размещение функционала потребителя сервиса на сервере приложений.

Поскольку браузеры ориентированы только на HTTP-запросы GET и POST, нам необходимо серверное приложение, которое бы обеспечивало полную функциональность потребителя RESTful-сервиса.

В качестве основы такого приложения можно взять проект labs, рассмотренный во второй главе и реализующий прототип учебного приложения по всем лабораторным работам данной дисциплины (см. подраздел 2.4). Хотя полная реализация этого проекта была отложена по причине очевидного усложнения учебных примеров, реализуемых в главах 3 - 5, тем не менее, для демонстрации агента потребителя сервиса Web-службы в стиле REST этот проект вполне подходит.

Напомню, что проект labs обеспечивает доступ к серверу приложений посредством адресации XHTML-файла соответствующей лабораторной работы (см. последний вариант реализации, описанный в пункте 2.4.8 и показанный на рисунке 2.32). В частности, работе №9 соответствует файл lab9.xhtml. Если за начальное представление этого файла взять содержимое листинга 6.12, то, после запуска проекта и авторизации пользователем upk, внешний вид окна браузера будет отображен рисунком 6.11.

Листинг 6.12 — Исходное содержимое файла lab9.xhtml проекта labs

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:f="http://xmlns.jcp.org/jsf/core" xml:lang="ru">

<ui:composition template="/WEB-INF/templates/lab3Templ.xhtml">

<!-- Переопределение контекстной страницы context -->

272

<ui:define name="context">

<div align="left" style="color:black;padding:10px"> <b>lab9.xhtml - работа с сервисом: http://localhost:8080/lab9/letter</b>

<hr/> </div>

</ui:define>

</ui:composition>

</html>

Рисунок 6.11 — Начальное отображение файла lab9.xhtml

Обратите внимание, что XHTML-ресурс lab9.xhtml не имеет активных элементов и еще не использует никакую компонету-подложку. Другими словами

— это всего лишь «заглушка» для будущей реализации соответствующего проекта.

Вполне разумно для реализации шаблона потребителя сервиса использовать компонент-подложку с именем Lab9.java, что создаст нужную семантическую ассоциацию при описании проекта.

Следующим шагом необходимо решить: какой функционал и область действия должна обеспечивать эта подложка Lab9.java.

273

Чтобы правильно ответить на данный вопрос, студенту рекомендуется перечитать подраздел 2.4 второй главы. Особое внимание здесь необходимо обратить на пункт 2.4, где на рисунке 2.26 (см. стр. 114) представлена схема взаимодействия браузера и компонент-подложек JSF проекта labs.

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

Браузер

клиента

<Web-ресурс>

 

<Web-ресурс>

 

<Web-ресурс>

auth3.xhtml

 

subheader3.xhtml

 

menus3.xhtml

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<Запрос>

 

<Запрос>

 

<Запрос>

Auth3.class

 

SubHeader3.class

 

Menus3.class

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<Сессия>

 

 

 

 

 

 

RSOS.class

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<Приложение>

 

 

 

 

 

 

Users.class

 

 

 

Рисунок 6.12 — Повторное отображение рисунка 2.26 главы 2, стр. 114

Хорошо видно, что все представленные XHTML-ресурсы имеют ком- поненты-подложки с областью действия @RequestScoped. Это связано с тем, что они обслуживают локальные запросы к данным, которые храняться в CDIкомпоненте RSOS.class c областью действия @SessionScoped.

Особенность создаваемой здесь компоненты-подложки Lab9.class состоит в необходимости доступа к удаленным данным, реализуемым поставщиком сервиса в виде проекта lab9, и сохранении этих данных для отображения их с помощью XHTML-ресурса lab9.xhtml.

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

274

а) resMsg — текстовое сообщение, соответствующее полученному объекту типа Response;

б) list — список прочитанных сообщений типа List<Letter>;

в) id — целочисленный идентификатор запроса объекта типа Letter; г) text — текстовое сообщение запроса для объекта типа Letter;

д) rsos — инъекция сессионного объекта типа RSOS для получения данных о пользователе, выполняемой работе и результате авторизации;

е) address — текстовая константа http://localhost:8080/lab9/letter, соответствующая базовому адресу удаленного ресурса, который представлен сервером проекта lab9.

Естественно, что компонента Lab9.class должна иметь соответствующий набор методов (геттеров и сеттеров), обслуживающих доступ к данным из XHTML-ресурса lab9.xhtml.

Клиентская часть потребителя сервиса должна иметь описания классов Letter и ListLets.

Действительно, поставщик сервиса, представленный Web-сервисом класса LetsRestService (см. листинг 6.11, стр. 272-276), возвращает объекты типа Letter и ListLets в формате JSON. Соответственно, клиентская сторона в виде класса Lab9 должна восстанавливать эти объекты. Поэтому описания этих классов должны присутствовать в проекте labs, но в клиентском исполнении, как это показано на листингах 6.13 - 6.14.

Листинг 6.13 — Клиентское описание класса Letter.java проекта labs

package asu.rsos;

import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date;

import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;

import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType;

/**

*Клиентская часть базовой сущности Letter.

*Добавляются: обязательная аннотация @XmlRootElement

*и @XmlType(...)

*/

@XmlType(propOrder={"id", "date", "name", "text"}) @XmlRootElement

public class Letter implements Serializable

{

275

// Идентификатор сериализации

private static final long serialVersionUID = 1L;

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;

private Date date; private String name; private String text;

/** * Конструкторы, геттеры, сеттеры и другие бизнес-методы */

public Letter() {

}

public Letter(Date date, String name, String text) { this.date = date;

this.name = name; this.text = text;

}

// Геттеры и сеттеры POJO-класса /**

*Аннотация @XmlElement для публичного метода

*getId()

*/

@XmlElement

public int getId() { return id;

}

public void setId(int id) { this.id = id;

}

/**

*Аннотация @XmlElement для публичного метода

*getDate()

*/

@XmlElement

public Date getDate() { return this.date;

}

public void setDate(Date date) { this.date = date;

}

/**

*Аннотация @XmlElement для публичного метода

*getName()

*/

@XmlElement

public String getName() { return name;

}

public void setName(String name) { this.name = name;

276

}

/**

*Аннотация @XmlElement для публичного метода

*getText()

*/

@XmlElement

public String getText() { return text;

}

public void setText(String text) { this.text = text;

}

// Дополнительные функции форматирования public String toString() {

return Integer.toString(id) + " " + date.toString() + " " + name + " " + text;

}

public String getDateString() { SimpleDateFormat sdf =

new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); return sdf.format(this.date);

}

}

Листинг 6.14 — Клиентское описание класса ListLets.java проекта labs

package asu.rsos;

import java.io.Serializable; import java.util.ArrayList; import java.util.List;

import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement;

/**

*Корневая аннотация для всего класса, задающая

*имя списка объектов типа Letter.

*/ @XmlRootElement(name="letters")

public class ListLets implements Serializable

{

private static final long serialVersionUID = 1L;

// Приватная переменная класса

private List<Letter> list = new ArrayList<>(); /**

* Конструкторы, геттеры, сеттеры и другие бизнес-методы */

public ListLets() {}

public ListLets(Letter letter) { if(letter != null)

list.add(letter);

}

277

public ListLets(List<Letter> list) { this.list = list;

}

/**

*Аннотация для публичного метода getList(), задающая имя для

*описания объекта типа Letter и допускающая пустой список. */

@XmlElement(name="letter", nillable = true) public List<Letter> getList() {

return list;

}

}

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

 

 

 

 

 

 

Браузер

 

 

 

 

 

 

 

 

 

 

 

 

клиента

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Запросы-

 

 

 

 

 

 

 

 

 

 

 

 

 

Ответы

 

 

 

 

 

 

 

 

 

HTTP

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<Web-ресурс>

 

 

 

 

 

 

 

Проверка

 

lab9.xhtml

 

 

 

 

 

 

 

авторизации

 

 

 

 

 

 

 

 

Сервер приложений

геттеры

 

сеттеры

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Проект lab9

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<Сессия>

 

 

 

<Сессия>

 

 

 

 

 

 

 

 

 

 

 

RSOS.class

 

 

 

Lab9.class

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рисунок 6.13 — Схема взаимодействия потребителя с поставщиком сервиса

Как видно из рисунка, сессионная компонента Lab9.class должна обеспечивать функционал трех видов:

1)isAuth() — метод запрашивающий результат авторизации пользователя и выбор работы - «Работа №9»;

2)геттеры/сеттеры — стандартные методы, обслуживающие запросы Web-ресурса lab9.xhtml;

3)mGetList(), mGetLetter(), mPostLetter(), mDeleteLetter() и mPutLetter()

методы, осуществояющие распросы к удаленному серверу приложений и возвращающие строку «lab9», что означает переход к Web-ресурсу lab9.xhtml.

Сучетом введенных ограничений, шаблон реализуемой компоненты Lab9.class представлен на листинге 6.15.

278

Листинг 6.15 — Шаблон файла Lab9.java проекта labs

package asu.rsos;

import java.io.Serializable; import java.util.ArrayList; import java.util.List;

import javax.enterprise.context.SessionScoped; import javax.inject.Inject;

import javax.inject.Named;

import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget;

/**

*Компонент-подложка ресурса lab9.xhtml, обеспечивающая

*CRUD-операции потребителя сервиса, посредством запросов

*GET, POST, DELETE и PUT к Web-сервису проекта lab9.

*/

@Named

@SessionScoped public

class Lab9 implements Serializable

{

/** * Стандартный идентификатор для сериализации */

private static final long serialVersionUID = 1L; /**

* Инъекция объекта класса RSOS */

@Inject

private RSOS rsos; /**

*Приватные переменные, обслуживаемые методами

*геттеров и сеттеров.

*/

//Текстовое сообщение, соответствующее ответу типа Response private String resMsg = "Вводите запросы...";

//Прочитанный список сообщений

private List<Letter> list = new ArrayList<>();

// Идентификатор обрабатываемого сообщения private int id;

//Текст обрабатываемого сообщения private String text;

//Адрес доступа к сервису ListRestService проекта lab9 private String address = "http://localhost:8080/lab9/letter"; /** * Пустой конструктор */

public Lab9() {} /**

* Публичные методы геттеров и сеттеров

*/

public String getResMsg() {return resMsg;}

public void setResMsg(String resMsg) {this.resMsg = resMsg;}

public List<Letter> getList() {return list;}

279

//

public void

setList(List<Letter>

list) {this.list = list;}

 

public int

getId() {return id;}

 

 

public void

setId(int id) {this.id = id;}

 

public String getText() {return text;}

 

public void

setText(String text)

{this.text = text;}

 

public String getAddress() {return

address;}

 

public void

setAddress(String address) {this.address = address;}

/** * Метод проверки авторизации */

public boolean isAuth()

{

if(rsos.getUser() == null || rsos.getWork() == null) return false;

if(rsos.getUser().length() > 0

|| "Работа №9".equals(rsos.getWork())) return true;

return false;

}

/**

*Шаблоны методов, реализующих запросы к поставщику сервисов.

*Все они должны возвращать строку "lab9", что возвращает

*запрос к ресурсу lab9.xhtml.

*/

//Получить список объектов типа Letter public String mGetList() {

resMsg = "Метод GET - не реализован"; return "lab9";

}

// Получить объект типа Letter по идентификатору id public String mGetLetter() {

resMsg = "Метод GET - не реализован"; return "lab9";

}

//Создать новый объект типа Letter public String mPostLetter() {

resMsg = "Метод POST - не реализован"; return "lab9";

}

//Удалить объект типа Letter по идентификатору id public String mDeleteLetter() {

resMsg = "Метод DELETE - не реализован"; return "lab9";

}

//Модифицировать объект типа Letter по идентификатору id public String mPutLetter() {

resMsg = "Метод PUT - не реализован"; return "lab9";

}

}

280

Обратите внимание, что на приведенном листинге шаблона компонентыподложки Lab9 нереализованными являются только пять последних методов, отвечающих за запросы к Web-сервису проекта lab9. Ими мы займемся в следующих пунктах данного подраздела, а сейчас преобразуем ресурс lab9.xhtml к виду, показанному на листинге 6.16.

Листинг 6.16 — Итоговое содержимое файла lab9.xhtml проекта labs

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:f="http://xmlns.jcp.org/jsf/core" xml:lang="ru">

<ui:composition template="/WEB-INF/templates/lab3Templ.xhtml">

<!-- Переопределение контекстной страницы context --> <ui:define name="context">

<div align="left" style="color:black;padding:10px"> <b>lab9.xhtml - работа с сервисом: http://localhost:8080/lab9/letter</b>

<hr/>

<h:outputText value="#{lab9.resMsg}" style="color:red"/> <hr/>

<h:form>

<h:panelGrid columns="2">

<h:outputText value="Идентификатор:"/> <h:inputText value="#{lab9.id}"/>

<h:outputText value="Введи текст:"/>

<h:inputTextarea value="#{lab9.text}" rows="5" cols="40"/> </h:panelGrid>

<h:commandButton value="GET-список" action="#{lab9.mGetList()}"/> <h:commandButton value="GET-письмо" action="#{lab9.mGetLetter()}"/> <h:commandButton value="POST-новое" action="#{lab9.mPostLetter()}"/> <h:commandButton value="DELETE-письмо" action="#{lab9.mDeleteLetter()}"/> <h:commandButton value="PUT-письмо" action="#{lab9.mPutLetter()}"/>

</h:form><hr/>

<table id="table1" cellspacing="0" cellpadding="5" border="0" > <thead><tr>

<th align="left" ></th> <th align="left" >Дата</th>

<th align="left" >Пользователь</th> <th align="left" >Сообщение</th>

</tr></thead>

<tbody>

<c:forEach items="${lab9.list}" var="letter">

281

<tr>

 

<td><h:outputText value="${letter.id}" default="*"

/></td>

<td><h:outputText value="${letter.dateString}"

/></td>

<td><h:outputText value="${letter.name}"

/></td>

<td><h:outputText value="${letter.text}"

/></td>

</tr>

 

</c:forEach>

 

</tbody>

 

</table>

 

</div>

 

</ui:define>

 

</ui:composition>

 

</html>

 

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

Рисунок 6.14 — Начальное изображение ресурса lab9.xhtml

Теперь перейдем к решению конкретных задач.

282