- •Обозначения и сокращения
- •введение
- •1. Установка и настройка инструментальных средств
- •1.1. Установка и подготовка к работе операционной системы
- •1.2. Установка программного обеспечения
- •1.3. Создание таблиц в базе данных
- •2. Основы Java EE 6
- •2.1. Распределенные многоуровневые приложения
- •2.2. Контейнеры Java EE
- •2.3. Сервер GlassFish v3
- •2.4. Структура приложения
- •2.5. Конфигурирование приложений
- •2.6. Задание ссылок на ресурсы
- •4. Введение в компоненты Facelets
- •4.1. Веб-страницы
- •4.2. Разработка простого приложения Facelets
- •4.3. Использование шаблонов
- •5. Унифицированный язык записи выражений
- •6.1. Добавление компонент библиотеки HTML на страницу
- •6.2. Использование компонент для таблиц баз данных
- •6.3. Использование тегов библиотеки Core
- •7. Использование конвертеров, слушателей и проверок
- •7.1. Использование стандартных преобразователей
- •7.2. Регистрация слушателей для компонентов
- •8. Внешние объекты (JavaBeans)
- •8.1. Создание класса внешних объектов
- •8.2. Описание свойств бинов
- •8.3. Написание методов внешних бинов
- •8.4. Проверка бинами
- •9.1. Файл конфигурации ресурсов приложения
- •9.2. Упорядочение ресурсов конфигурации приложения
- •9.3. Конфигурирование состояния проекта
- •9.4. Выбор конфигурации бина
- •9.5. Регистрация сообщений об ошибках как пакет ресурса
- •9.7. Конфигурирование правил навигации (Navigation Rules)
- •9.8. Основные требования приложения JavaServer Faces
- •10. Технология Java Servlet
- •11. Введение в Java Persistence API
- •11.1. Требования к классам сущностей
- •11.3. Внедряемые классы в сущностях
- •11.4. Наследование сущностей
- •11.5. Стратегии наследования сущностей с отображением
- •11.6. Управление сущностями
- •11.7. Запросы сущностей
- •12. Примеры хранимых сущностей
- •12.1. Приложение order
- •12.2. Пример получения схемы отношений на основе таблиц БД
- •13.1. Терминология языка запросов
- •13.3. Упрощенный синтаксис языка запросов
- •13.4. Примеры запросов
- •13.5. Запросы с навигацией связанных сущностей
- •13.6. Запросы с другими условными выражениями
- •13.7. Изменение и удаление группы сущностей
- •13.8. Полный синтаксис языка запросов
- •14. Язык запросов Criteria API
- •14.3. Корни запроса
- •14.4. Использование объединения в запросе
- •14.5. Навигация путей в запросах
- •14.6. Ограничения на результаты запроса
- •14.7. Управление результатами запросов
- •14.8. Исполнение запросов
- •15. Связывание ресурсов
- •15.1. Ресурсы и служба имен JNDI
- •15.2. Объекты DataSource и пулы соединений (Connection Pools)
- •15.3. Внедрение ресурсов
- •15.4. Адаптеры ресурсов
- •15.5. Аннотации метаданных
- •16. Безопасность веб-приложений
- •16.1. Краткий обзор
- •16.2. Механизмы обеспечения безопасности
- •16.3. Безопасность сервера предприятия
- •16.4. Использование защищенного соединения SSL
- •18. Пример приложения
- •18.1. Создание проекта веб-приложения
- •18.3.Структура приложения JavaEE 6
- •18.4. Программирование вида для объектов
- •18.5. Дизайн главной страницы
- •18.6. Страница просмотра записей таблицы городов
- •18.7. Страница добавления записей о городах
- •18.8. Страница редактирования записей о городах
- •18.9. Страница удаления записей о городах
- •19. Обработка связей внешних ключей
- •19.1. Разработка класса для вида сущности
- •19.2. Доработка вида для городов
- •19.3. Разработка обзорной страницы
- •19.5. Страница для редактирования записей с внешними ключами
- •20. Дополнительные функции
- •20.1. Сортировка записей таблицы
- •20.2. Контроль за удалением связанных записей
- •20.3. Контроль ввода наименований
- •20.4. Запросы к БД на языке Java Persistence Query Language
- •20.5. Управление страницами при просмотре таблицы
- •20.6. Создание и просмотр отчетов
- •20.7. Использование шаблонов и стилей
- •20.8. Защита приложения паролем
- •Заключение
- •Библиографический список
19. Обработка связей внешних ключей
Используемое в технологии Java EE 6 отображение (mapping) полей записей
на свойства объектов сущностей позволяет легко решать задачи доступа к свойствам объекта внешней таблицы при связывании их внешними ключами. Вместо ключа за-
писи внешней таблицы, хранимого в записи БД, объект имеет свойство, содержащее
экземпляр сущности из внешней таблицы. В то же время экземпляр сущности внеш-
ней таблицы содержит список ссылающихся на него объектов.
Посмотрите внимательно на фрагмент объявления свойства personsList и методов доступа к этому свойству в сущности класса Cities:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "cityId") private List<Persons> personsList;
public List<Persons> getPersonsList() { return personsList;
}
public void setPersonsList(List<Persons> personsList) { this.personsList = personsList;
}
Аннотация @OneToMany объявляет следующее за ним свойство связью «один-
ко-многим» между сущностями Cities и Persons через свойство cityId. Это свойство
задаётся при отображении записи БД в объект сущности подсистемой хранилища и поддерживается в актуальном состоянии при всех манипуляциях с сущностями и с записями БД.
Симметрично свойство связи внешнего ключа в описании класса Persons вы-
глядит так:
@JoinColumn(name = "city_id", referencedColumnName = "id_city") @ManyToOne(optional = false)
private Cities cityId;
а методы доступа — как:
public Cities getCityId() { return cityId;
}
public void setCityId(Cities cityId) { this.cityId = cityId;
}
Эта согласованная пара свойств обеспечивает потребности программиста и дизайнера при разработке приложения. Причина, по которой выбрано имя свойства cityId, заключается в том, что администратором базы данных так было названо поле
внешнего ключа при создании таблицы персон. Там это поле имело смысл ключа
внешней таблицы. Здесь это имя просто копируется без изменения для того, чтобы не вносить путаницы в имена, но свойство содержит уже сам связываемый объект.
232
19.1. Разработка класса для вида сущности
Кроме стандартных методов доступа к данным и обработчикам команд для дизайнера вид должен обеспечивать выбор имени города из выпадающего списка. Для
этого требуется создать виртуальное свойство-конвертор ключа записи в таблице го-
родов в объект сущности «город». Это вызвано тем, что используемый нами стан-
дартный компонент выбора из выпадающего списка возвращает ключ, а не объект с
таким ключом.
Для получения объекта-города с заданным ключом приходится обращаться
к услугам фасада городов, для чего его необходимо объявить в тексте класса вида
для персоны (смотрите п. 1.4.4.3: клик правой кнопкой после заголовка класса –
«Вставить код» – Call Enterprise Bean – выбор из списка имени фасада). Должны
быть вставлены строки:
@EJB
private CitiesFacade citiesFacade;
Метод Long getId_City() возвращает ключ объекта города персоны (если он не
был задан, то 1L — длинное целое).
public Long getId_City() {
return (this.person.getCityId() == null) ? 1L
: this.person.getCityId().getIdCity();
}
Метод setId_City(Long id) устанавливает значение свойства cityId персоны как объект с ключом, заданным параметром.
public void setId_City(Long id) { this.person.setCityId(citiesFacade.find(id));
}
Файл PersonsView.java package Views;
import Entities.Persons; import Facades.CitiesFacade; import Facades.PersonsFacade; import java.util.Date; import java.util.List; import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped; import javax.faces.bean.ManagedBean;
/**
*
* @author cyx */
@ManagedBean(name = "personsView") @RequestScoped
public class PersonsView { @EJB
private CitiesFacade citiesFacade;
@EJB
private PersonsFacade personsFacade; private Persons person;
233
/** Creates a new instance of PersonsView */ public PersonsView() {
this.person = new Persons(null, "", "", "", new Date(1990, 01, 31));
}
public Persons getPerson() { return this.person;
}
public int getNumberOfPersons() { return personsFacade.findAll().size();
}
public List<Persons> getAllOfPersons() { return personsFacade.findAll();
}
public String savePerson() { this.personsFacade.create(person); return “personsPage”;
}
public String modPerson(Persons person) { this.person = person;
return “person_mod”;
}
public String mod_yes_Person() { this.personsFacade.edit(this.person); return “personsPage”;
}
public String delPerson(Persons person) { this.person = person;
return “person_del”;
}
public String del_yes_Person() { this.personsFacade.remove(this.person); return “personsPage”;
}
// Виртуальное свойство-конвертор id <--> City для выбора из списка Default 1L
public Long getId_City() {
return (this.person.getCityId() == null) ? 1L : this.person.getCityId().getIdCity();
}
public void setId_City(Long id) { this.person.setCityId(citiesFacade.find(id));
}
}
234
Упражнения
1.Как в текст класса попало объявление объекта citiesFacade?
2.Почему потребовалось объявлять виртуальное свойство id_City?
19.2. Доработка вида для городов
Для работы компонента выбора из выпадающего списка необходимо подгото-
вить свойство в классе вида для городов, содержащее форматированный специаль-
ным образом список элементов. Для этого вставим в файл класса CitiesView.java опи-
сание поля citiesSelector:
private ArrayList citiesSelector;
и метод getCitiesSelector() для вычисления свойства citiesSelector (не забывайте ис-
правлять выражения импорта).
public ArrayList getCitiesSelector() { citiesSelector = new ArrayList();
List<Cities> allCities = this.citiesFacade.findAll(); for (int i = 0; i < (allCities.size()); i++) {
Cities cit = allCities.get(i);
citiesSelector.add(new SelectItem(cit.getIdCity(), cit.getName(), cit.getName()));
}
return citiesSelector;
}
Список выбора представляет собой набор компонент класса SelectItem, содержащих ключ, название и описание элемента выбора. Проанализируйте текст метода.
19.3. Разработка обзорной страницы
Структура файла personsPage.xhtml для генерации обзорной таблицы персон не сильно отличается от таблицы городов. Существенным отличием является поле
города для персоны. Для его визуализации используется выражение
“#{person.cityId.name}”,
в котором для показа названия города использовано свойство name города, на который ссылается поле cityId для person.
Обратите внимание на форматирование дат с использованием тега convertDateTime, вложенного в тег outputText. Это позволяет видеть дату в формате dd.mm.YY, который часто употребляется в деловой переписке. Изменяя значение атри-
бута dateStyle на default, short, medium, long и full, можно получить нужный формат.
<h:outputText value="#{person.bday}"> <f:convertDateTime dateStyle="short" />
</h:outputText>
235
Файл personsPage.xhtml
<?xml version="1.0" encoding="UTF-8"?> <html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Просмотр таблицы персон</title> </head>
<body>
<f:view>
<table border="1" width="100%"> <tr>
<td><h:outputLabel value="Персоны. Всего записей "/> <h:outputText value="#{personsView.numberOfPersons}"/> </td>
</tr>
<tr>
<td>
<h:form>
<h:dataTable value="#{personsView.allOfPersons}" var="person" border="1">
<h:column>
<f:facet name="header"> <h:outputText value="Ключ"/>
</f:facet>
<h:outputText value="#{person.idPerson}"/> </h:column>
<h:column>
<f:facet name="header"> <h:outputText value="Фамилия"/>
</f:facet>
<h:outputText value="#{person.family}"/> </h:column>
<h:column>
<f:facet name="header"> <h:outputText value="Имя"/>
</f:facet>
<h:outputText value="#{person.name}"/> </h:column>
<h:column>
<f:facet name="header"> <h:outputText value="Отчество"/>
</f:facet>
<h:outputText value="#{person.father}"/> </h:column>
<h:column>
<f:facet name="header">
236
<h:outputText value="Дата рождения"/> </f:facet>
<h:outputText value="#{person.bday}"> <f:convertDateTime dateStyle="short" />
</h:outputText>
</h:column>
<h:column>
<f:facet name="header"> <h:outputText value="Город"/>
</f:facet>
<h:outputText value="#{person.cityId.name}"/> </h:column>
<h:column>
<f:facet name="header"> <h:outputText value="Операции"/>
</f:facet>
<h:commandLink action="#{personsView. modPerson(person)}">
<h:outputText value="Заменить" /> </h:commandLink>
<h:commandLink action="#{personsView. delPerson(person)}">
<h:outputText value="Удалить" /> </h:commandLink>
</h:column>
</h:dataTable>
</h:form>
</td>
</tr>
<tr>
<td>
<h:form>
<h:commandLink action="personAddPage"> <h:outputText value="Добавить" />
</h:commandLink>
</h:form>
<br/>
<h:form>
<h:commandLink action="index"> <h:outputText value="На главную" />
</h:commandLink>
</h:form>
</td>
</tr>
</table>
</f:view>
</body>
</html>
237
Упражнения
1.Проследите путь информации о названии города для персоны.
2.Проверьте различные форматы вывода дат.
19.4.Страница для добавления записей
свнешними ключами
Особенность страницы ввода заключается в наличии поля внешнего ключа, ко-
торое нужно задавать клиенту выбором из списка записей справочной таблицы. Для
этого используется компонент selectOneMenu, атрибут value которого ссылается на
виртуальное(вычисляемое)свойствоid_CityэкземпляравидадляперсонpersonsView.
Напомним, что это свойство-конвертор «ключ – объект» описано в виде для персоны.
Вложенный тег selectItems задаёт своим атрибутом value ссылку на виртуальное свойство citiesSelector экземпляра вида для городов citiesView, которое и вычисляет необ-
ходимый список элементов выбора для селектора.
<h:selectOneMenu |
id="idCity" |
|
required |
= |
"true" |
value |
= |
"#{personsView.id_City}" > |
<f:selectItems value="#{citiesView.citiesSelector}" /> </h:selectOneMenu>
Файл personAddPage.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates and open the template in the editor.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Добавление персоны в таблицу</title> </head>
<body>
<f:view>
<table border="1" width="100%"> <tr>
<td>
<h:form>
<table>
<tr>
<td> <h:outputLabel value="Фамилия:"/> </td>
238
<td><h:inputText value="#{personsView.person.
family}"/> </td>
</tr>
<tr>
<td> <h:outputLabel value="Имя:"/> </td> <td><h:inputText value="#{personsView.person.
name}"/> </td>
</tr>
<tr>
<td> <h:outputLabel value="Отчество:"/> </td> <td><h:inputText value="#{personsView.person.
father}"/> </td>
</tr>
<tr>
<td> <h:outputLabel value="Рождение:"/> </td> <td><h:inputText value="#{personsView.person.
bday}">
<f:convertDateTime dateStyle="short" /> </h:inputText>
</td>
</tr>
<tr>
<td> <h:outputLabel value="Город:"/> </td> <td>
<h:selectOneMenu id="idCity" required = "true" value =
"#{personsView.id_City}" >
<f:selectItems value="#{citiesView.citiesSe-
lector}" />
<!--f:converter / --> </h:selectOneMenu>
</td>
</tr>
<tr>
<td>
<h:commandButton action="#{personsView.
savePerson}"
value="Добавить" /> <h:commandButton action="personsPage" value="Отменить" />
</td>
</tr>
</table>
</h:form>
</td>
</tr>
</table>
</f:view>
</body>
</html>
239