Теперь после небольшого рассказа о данном фреймворке, можно «ринуться в бой» и рассмотреть фичи ADF более конкретно. Данная статья будет об ADF Business Components. О том как работать с ними декларативно и программно.
Общие понятия
ADF Business Components (далее BC) – это часть фреймворка для работы с БД, предоставляющая визуальную и декларативную разработку. Конфигурация BC хранится в XML файлах, но при желании можно сгенерировать Java классы и добавить и/или переопределить логику.
BC делятся на 5 основных частей:
- Entity Objects (EO)
- View Objects (VO)
- Associations
- View Links
- Application Module
EO представляет собой таблицу из БД, и, соответственно, экземпляр EO – это строка из таблицы.
Данный компонент инкапсулирует в себе данные, правила валидации и логику персистентности.
EO associations определяют связи между двумя сущностями (таблицами)
VO – компонент, ответственный за чтение данных из data source, а также включает в себя операции по их обновлению.
View Links – определяют связи между VO (по аналогии с associations)
Application Module – это уровень сервиса, предоставляющий работу с бизнес компонентами (а именно с VO и View Links). Также в него можно добавить дополнительные методы и вкладывать другие Application Modules. В конечном счете Application Module используется, как Data Control.
IDE time
Для тестовых БД данных я буду использовать employees таблицу из oracle HR схемы.
После прохождения визарда «Business Components from tables», в результате получим следующий набор файлов.
Здесь Employees – EO, EmployeesView – VO, EmployeesAppModule – Application Module, EmpManagerFkAssoc – ассоциация между работниками и их менеджерами, EmpManagerFkLink – View link для аналогичной связи, но для VO, Business Components Diagram — диаграмма компонентов.
А на панели Data Controls создастся соответствующий data control.
Взглянем на диаграмму.
Можно увидеть, что EmployeesView создан на основе Employees EO. А в ApplicationModule попали два инстанса EmployeesView. Один отвечает за менеджера, а второй за его работников.
Краткий обзор сгенерированных файлов.
Employees
В сгенерированном EO можно посмотреть какие атрибуты в него входят, отредактировать, добавить свои или удалить.
Также можно управлять правилами валидации данных.
EmployeesView
Из атрибутов VO видно, что они берутся из Employees EO.
Можно посмотреть запрос VO, его переменные и критерии (named where clauses)
EmployeesAppModule
Application Module, как мы видели раньше, содержит два экземпляра EmployeesView
EmpManagerFkAssoc
Связь между сущностями.
EmpManagerFkLink
Одинаковые Source и Destination, говорят о том, что View Link построена на базе Associations.
CRUD
Да-да. CRUD будет реализован полностью декларативным путем, мною не будет написано ни одной строчки кода.
Посмотрим какой будет результат.
Вначале будет показана таблица с сотрудниками.
При нажатии на Create employee, произойдет переход на создание нового сотрудника.
При нажатии на Save новый сотрудник добавится в БД, и мы вернемся к таблице.
При нажатии на Update employee, произойдет переход на редактирование информации сотрудника.
После сохранения изменений, снова возврат к таблице.
Ну и наконец при нажатии на Delete employee, сотрудник испарится.
Ходом операций управляет bounded task flow. О том, как работать с task flows, будет отдельная статья. Пока просто посмотрим на диаграмму.
ViewEmployees, createEmployee и updateEmployee это view activities с JSFF, отвечающие за отображение таблицы и форм.
Для отображения сотрудников в таблице, нужно перенести EmployeeView из Data Control на страницу и выбрать в опциях создания – нужный вид таблицы (в моем случае – это read only)
Для вывода форм на страницах createEmployee и updateEmployee нужно сделать аналогичную операцию, но выбрать из категории Form (в моем случае – это ADF Form)
Все остальные activities – это операции над DataControl’ом. Перенесены эти операции также с Data Controls панели.
CreateInsert создает в итераторе новую строку и переводит курсор итератора на нее.
Delete удаляет строку в итераторе, на которой в данный момент находится курсор.
Чтобы действия CreateInsert и Delete вступили в силу, необходимо вызвать операцию Commit, а для того, чтобы откатить изменения – Rollback.
На этом реализация CRUD’а завершена.
CRUD v2
Теперь рассмотрим случай, когда мы не отказываемся полностью от декларативного пути, но операции хотим вызывать в каком-либо managed bean’e.
Для простоты рассмотрим только реализацию вставки, так как остальные выполняются аналогично.
Первым шагом необходимо создать managed bean.
Код bean’a рассмотрим в самом конце.
Я создам новую страницу и перенесу на нее таблицу, чтобы можно было увидеть новые данные, и форму для добавления нового сотрудника.
В input компонентах проставлю связи value на managed bean. И в конце добавлю кнопку, используя в качестве action listener’a метод managed bean’а.
В итоге разметка jspx выглядит следующим образом:
<af:form id="f1"> <af:table value="#{bindings.EmployeesView1.collectionModel}" var="row" rows="#{bindings.EmployeesView1.rangeSize}" emptyText="#{bindings.EmployeesView1.viewable ? 'No data to display.' : 'Access Denied.'}" fetchSize="#{bindings.EmployeesView1.rangeSize}" rowBandingInterval="0" id="t1"> <af:column sortProperty="#{bindings.EmployeesView1.hints.FirstName.name}" sortable="false" headerText="#{bindings.EmployeesView1.hints.FirstName.label}" id="c1"> <af:outputText value="#{row.FirstName}" id="ot1"/> </af:column> <af:column sortProperty="#{bindings.EmployeesView1.hints.LastName.name}" sortable="false" headerText="#{bindings.EmployeesView1.hints.LastName.label}" id="c2"> <af:outputText value="#{row.LastName}" id="ot2"/> </af:column> <af:column sortProperty="#{bindings.EmployeesView1.hints.Email.name}" sortable="false" headerText="#{bindings.EmployeesView1.hints.Email.label}" id="c3"> <af:outputText value="#{row.Email}" id="ot3"/> </af:column> <af:column sortProperty="#{bindings.EmployeesView1.hints.PhoneNumber.name}" sortable="false" headerText="#{bindings.EmployeesView1.hints.PhoneNumber.label}" id="c4"> <af:outputText value="#{row.PhoneNumber}" id="ot4"/> </af:column> <af:column sortProperty="#{bindings.EmployeesView1.hints.JobId.name}" sortable="false" headerText="#{bindings.EmployeesView1.hints.JobId.label}" id="c5"> <af:outputText value="#{row.JobId}" id="ot5"/> </af:column> </af:table> <af:panelFormLayout id="pfl1"> <af:inputText value="#{backingBeanScope.employeeBean.employeeId}" label="#{bindings.EmployeeId.hints.label}" required="#{bindings.EmployeeId.hints.mandatory}" columns="#{bindings.EmployeeId.hints.displayWidth}" maximumLength="#{bindings.EmployeeId.hints.precision}" shortDesc="#{bindings.EmployeeId.hints.tooltip}" id="it1"> <f:validator binding="#{bindings.EmployeeId.validator}"/> <af:convertNumber groupingUsed="false" pattern="#{bindings.EmployeeId.format}"/> </af:inputText> <af:inputText value="#{backingBeanScope.employeeBean.firstName}" label="#{bindings.FirstName.hints.label}" required="#{bindings.FirstName.hints.mandatory}" columns="#{bindings.FirstName.hints.displayWidth}" maximumLength="#{bindings.FirstName.hints.precision}" shortDesc="#{bindings.FirstName.hints.tooltip}" id="it2"> <f:validator binding="#{bindings.FirstName.validator}"/> </af:inputText> <af:inputText value="#{backingBeanScope.employeeBean.lastName}" label="#{bindings.LastName.hints.label}" required="#{bindings.LastName.hints.mandatory}" columns="#{bindings.LastName.hints.displayWidth}" maximumLength="#{bindings.LastName.hints.precision}" shortDesc="#{bindings.LastName.hints.tooltip}" id="it3"> <f:validator binding="#{bindings.LastName.validator}"/> </af:inputText> <af:inputText value="#{backingBeanScope.employeeBean.email}" label="#{bindings.Email.hints.label}" required="#{bindings.Email.hints.mandatory}" columns="#{bindings.Email.hints.displayWidth}" maximumLength="#{bindings.Email.hints.precision}" shortDesc="#{bindings.Email.hints.tooltip}" id="it4"> <f:validator binding="#{bindings.Email.validator}"/> </af:inputText> <af:inputText value="#{backingBeanScope.employeeBean.phoneNumber}" label="#{bindings.PhoneNumber.hints.label}" required="#{bindings.PhoneNumber.hints.mandatory}" columns="#{bindings.PhoneNumber.hints.displayWidth}" maximumLength="#{bindings.PhoneNumber.hints.precision}" shortDesc="#{bindings.PhoneNumber.hints.tooltip}" id="it5"> <f:validator binding="#{bindings.PhoneNumber.validator}"/> </af:inputText> <af:inputDate value="#{backingBeanScope.employeeBean.hireDate}" label="#{bindings.HireDate.hints.label}" required="#{bindings.HireDate.hints.mandatory}" columns="#{bindings.HireDate.hints.displayWidth}" shortDesc="#{bindings.HireDate.hints.tooltip}" id="id1"> <f:validator binding="#{bindings.HireDate.validator}"/> <af:convertDateTime pattern="#{bindings.HireDate.format}"/> </af:inputDate> <af:inputText value="#{backingBeanScope.employeeBean.jobId}" label="#{bindings.JobId.hints.label}" required="#{bindings.JobId.hints.mandatory}" columns="#{bindings.JobId.hints.displayWidth}" maximumLength="#{bindings.JobId.hints.precision}" shortDesc="#{bindings.JobId.hints.tooltip}" id="it6"> <f:validator binding="#{bindings.JobId.validator}"/> </af:inputText> <af:commandButton text="Create Employee" id="cb1" actionListener="#{backingBeanScope.employeeBean.createEmployee}"/> </af:panelFormLayout> </af:form>
А описание страницы будет выглядеть так.
Код managed bean’a (get’ры и set’ры опустим).
Поля:
private int employeeId; private String firstName; private String lastName; private String email; private String phoneNumber; private Timestamp hireDate; private String jobId; private BindingContainer bindings;
Метод вставки, использующийся кнопкой на странице:
public void createEmployee(ActionEvent actionEvent) { // Получаем binding контейнер BindingContainer bindings = getBindings(); // Выполняем операцию создания новой строки OperationBinding createOperation = bindings.getOperationBinding("CreateInsert"); createOperation.execute(); // Забиваем атрибуты данными AttributeBinding employeeId = (AttributeBinding)bindings.getControlBinding("EmployeeId"); employeeId.setInputValue(this.employeeId); AttributeBinding firstName = (AttributeBinding)bindings.getControlBinding("FirstName"); firstName.setInputValue(this.firstName); AttributeBinding lastName = (AttributeBinding)bindings.getControlBinding("LastName"); lastName.setInputValue(this.lastName); AttributeBinding phoneNumber = (AttributeBinding)bindings.getControlBinding("PhoneNumber"); phoneNumber.setInputValue(this.phoneNumber); AttributeBinding email = (AttributeBinding)bindings.getControlBinding("Email"); email.setInputValue(this.email); AttributeBinding hireDate = (AttributeBinding)bindings.getControlBinding("HireDate"); hireDate.setInputValue(this.hireDate); AttributeBinding jobId = (AttributeBinding)bindings.getControlBinding("JobId"); jobId.setInputValue(this.jobId); // Коммитим и тем самым сохраняем новую строку OperationBinding commitOperation = bindings.getOperationBinding("Commit"); commitOperation.execute(); }
Проверим работу managed bean’a, убедившись, что в таблицу попала новая запись.
CRUD v3
И последний пример, в котором будет только использование кода.
Для начала нужно подготовить классы у Business Components.
Для этого откроем EmployeeView перейдем на вкладку Java и сгенерируем следующие классы.
EmployeesViewImpl необходим для работы с запросами, а EmployeesViewRowImpl будет представлять из себя строку с атрибутами.
Таким же путем сгенерируем класс для Application Module.
Осталось написать новый метод для добавления строки в БД в EmployeesAppModuleImpl, создать TO класс для передачи данных в этот метод, и вызвать данный метод в managed bean’e.
Метод в Application Module:
public void createEmployee(EmployeeInfo employeeInfo) { // Получаем ViewObject EmployeesViewImpl employeeView = getEmployeesView1(); // Готовим новую строку. EmployeesViewRowImpl employee = (EmployeesViewRowImpl)employeeView.createRow(); employee.setEmployeeId(employeeInfo.getEmployeeId()); employee.setEmail(employeeInfo.getEmail()); employee.setPhoneNumber(employeeInfo.getPhoneNumber()); employee.setFirstName(employeeInfo.getFirstName()); employee.setLastName(employeeInfo.getLastName()); employee.setHireDate(new Timestamp(employeeInfo.getHireDate())); employee.setJobId(employeeInfo.getJobId()); // Производим операцию вставки. employeeView.insertRow(employee); // Коммитим getDBTransaction().commit(); }
Новый метод bean’a:
public void createEmployee2(ActionEvent actionEvent) { // Получаем application module String applicationModuleClass = "com.matim.forhabr.model.EmplyeesAppModuleImpl"; String config = "EmplyeesAppModuleLocal"; EmplyeesAppModuleImpl appModule = (EmplyeesAppModuleImpl) Configuration.createRootApplicationModule(applicationModuleClass, config); // Забиваем данными TO EmployeeInfo employeeInfo = new EmployeeInfo(); employeeInfo.setEmail(this.email); employeeInfo.setEmployeeId(this.employeeId); employeeInfo.setFirstName(this.firstName); employeeInfo.setHireDate(this.hireDate); employeeInfo.setJobId(this.jobId); employeeInfo.setLastName(this.lastName); employeeInfo.setPhoneNumber(this.phoneNumber); // Вызываем метод по созданию нового сотрудника appModule.createEmployee(employeeInfo); // Освобождаем ресурсы Configuration.releaseRootApplicationModule(appModule, false); // Так как вставка идет на стороне AppModule, // то только для целей, обновления таблицы // выполним операцию Execute BindingContainer bindings = getBindings(); OperationBinding executeIterator = bindings.getOperationBinding("Execute"); executeIterator.execute(); }
Проверяем работу:
На этом сегодня все. Много всего еще осталось за бортом по этой теме, поэтому оставлю ссылку на дополнительную информацию здесь.
P.S. Следующая статья будет о task flows.
ссылка на оригинал статьи http://habrahabr.ru/post/173059/
Добавить комментарий