Рейтинг@Mail.ru

Apache Cayenne: создаём веб-приложение и работаем с СУБД ЛИНТЕР

Автор: Alex. Опубликовано в Программирование . просмотров: 12506

Рейтинг:  0 / 5

Звезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активна
 

В первой статье мы познакомились с Apache Cayenne и создали простое работающее приложение. В этой статье мы конвертируем это приложение в веб-приложение, а затем научим его работать с СУБД ЛИНТЕР.

Если вы не читали первую статью, то вот она: "Apache Cayenne: знакомимся и создаём простое приложение".

Apache Cayenne: создаём веб-приложение и работаем с СУБД ЛИНТЕР

Конвертация проекта в веб-приложение

Типичное веб-приложение с Cayenne работает следующим образом:

      • Конфигурация Cayenne загружается при старте контекста приложения, с помощью специального фильтра сервлетов.
      • Пользовательские запросы перехватываются фильтром, и DataContext привязывается к потоку, который обрабатывает запрос. Таким образом, приложение может получить доступ к DataContext в любом месте.
      • Тот же экземпляр DataContext может быть использован внутри простой пользовательской сессии. Разные сессии используют разные экземпляры DataContexts (и, соответственно, разные наборы объектов). Контекст может применяться по-разному в зависимости от специфики приложения. Здесь мы будем использовать контекст ограниченный сессией.

Итак, приступим к созданию веб-приложения:

      • В Eclipse в папке нашего тестового проекта создайте новую папку «src/main/webapp/WEB-INF».
      • В папке «WEB-INF» создайте файл «web.xml» (стандартное описание веб-приложения) со следующим содержанием:

<?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
      <display-name>Cayenne Example</display-name>
      <!-- Этот фильтр загружает ServerRuntime и обеспечивает каждый поток своим DataContext.
             Обратите внимание на то, что имя фильтра должно совпадать с именем конфигурационного файла.
      -->
      <filter>
            <filter-name>cayenne-project</filter-name>
            <filter-class>org.apache.cayenne.configuration.web.CayenneFilter</filter-class>
      </filter>
      <filter-mapping>
            <filter-name>cayenne-project</filter-name>
            <url-pattern>/*</url-pattern>
      </filter-mapping>
      <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
</web-app>

      • Создайте страничку для просмотра художников «src/main/webapp/index.jsp» со следующим содержимым:

<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<%@ page import="ru.proghouse.cayenne.persistent.*" %>
<%@ page import="org.apache.cayenne.*" %>
<%@ page import="org.apache.cayenne.query.*" %>
<%@ page import="org.apache.cayenne.exp.*" %>
<%@ page import="java.util.*" %>
 
<% 
      SelectQuery query = new SelectQuery(Artist.class);
      query.addOrdering(Artist.NAME_PROPERTY, SortOrder.ASCENDING);
 
      ObjectContext context = BaseContext.getThreadObjectContext();
      List<Artist> artists = context.performQuery(query);
%>
<html>
      <head>
            <title>Главная страница</title>
      </head>
      <body>
            <h2>Художники:</h2>
<%
if(artists.isEmpty())
{
%>
            <p>Художники не найдены</p>
<%
}
else
{ 
       for(Artist a : artists)
       {
%>
            <p><a href="detail.jsp?id=<%=Cayenne.intPKForObject(a)%>"> <%=a.getName()%> </a></p>
<%
      }
}
%>
            <hr>
            <p><a href="detail.jsp">Добавить нового художника...</a></p>
      </body>
</html>

      • Создайте страничку для редактирования художника «src/main/webapp/detail.jsp» со следующим содержимым:

<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<%@ page import="ru.proghouse.cayenne.persistent.*" %>
<%@ page import="org.apache.cayenne.*" %>
<%@ page import="java.util.*" %>
<%@ page import="java.text.*" %>
 
<% 
      ObjectContext context = BaseContext.getThreadObjectContext();
      String id = request.getParameter("id");
 
      //Ищем художника по id
      Artist artist = null;
      if(id != null && id.trim().length() > 0)
            artist = Cayenne.objectForPK(context, Artist.class, Integer.parseInt(id));
 
      if("POST".equals(request.getMethod()))
      {
            //Если id не сохранён в скрытом поле,
            //то создаём нового художника.
            if(artist == null)
                  artist = context.newObject(Artist.class);
 
            //В реальном приложении здесь нужно делать ряд проверок,
            //но в примере будем считать, что всё введено правильно.
            artist.setName(request.getParameter("name"));
            artist.setDateOfBirthString(request.getParameter("dateOfBirth"));
 
            context.commitChanges();
 
            response.sendRedirect("index.jsp");
      }
 
      if(artist == null)
       //Создаём временный объект для создания формы.
            artist = new Artist();
 
      String name = artist.getName() == null ? "" : artist.getName();
      String dob = artist.getDateOfBirth() == null
                  ? "" : new SimpleDateFormat("yyyyMMdd").format(artist.getDateOfBirth());
%>
<html>
      <head>
            <title>Информация о художнике</title>
      </head>
      <body>
            <h2>Информация о художнике</h2>
            <form name="EditArtist" action="detail.jsp" method="POST">
                  <input type="hidden" name="id" value="<%= id != null ? id : "" %>" />
                  <table border="0">
                        <tr>
                              <td>Имя:</td>
                              <td><input type="text" name="name" value="<%= name %>"/></td>
                        </tr>
                        <tr>
                              <td>Дата рождения (yyyyMMdd):</td>
                              <td><input type="text" name="dateOfBirth" value="<%= dob %>"/></td>
                        </tr>
                        <tr>
                              <td></td>
                              <td align="right"><input type="submit" value="Сохранить" /></td>
                        </tr>   
                  </table>
            </form>
      </body>
</html>

Теперь запустим наше веб-приложение с помощью «maven-jetty-plugin». Чтобы сделать это выполните следующие действия:

      • Добавьте следующий кусок текста в файл «pom.xml» после секции «dependencies» и сохраните изменения:

<build>
      <plugins>
            <plugin>
                  <groupId>org.mortbay.jetty</groupId>
                  <artifactId>maven-jetty-plugin</artifactId>
                  <version>6.1.22</version>
            </plugin>
      </plugins>
</build>

      • Вызовите меню «Run -> Run Configurations...», выберите в списке слева «Maven Build», щёлкните правой кнопкой мышки и выберите «New».
      • Убедитесь, что поля «Name», «Base directory» и «Goals» заполнены так, как показано на рисунке снизу:

Добавление плагина Jetty в Eclipse

      • Щёлкните «Apply» и «Run». При первом запуске плагина Jetty может уйти несколько минут на загрузку всех зависимостей, но в конечном итоге вы увидите подобные сообщения в консоли:

[INFO] Scanning for projects...
...
[INFO] ------------------------------------------------------------------------
[INFO] Building example 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO] Configuring Jetty for project: example
[INFO] Webapp source directory = C:\workspace\example\src\main\webapp
[INFO] Reload Mechanic: automatic
[INFO] Classes = C:\workspace\example\target\classes
[INFO] Logging to org.slf4j.impl.SimpleLogger(org.mortbay.log) via org.mortbay.log.Slf4jLog
[INFO] Context path = /example
[INFO] Tmp directory = determined at runtime
[INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml
[INFO] Web overrides = none
[INFO] web.xml file = C:\workspace\example\src\main\webapp\WEB-INF\web.xml
[INFO] Webapp directory = C:\workspace\example\src\main\webapp
[INFO] Starting jetty 6.1.22 ...
[INFO] jetty-6.1.22
[INFO] No Transaction manager found - if your webapp requires one, please configure one.
[INFO] Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server

      • Это значит, что Jetty контейнер стартовал.
      • Теперь откройте ссылку http://localhost:8080/example/ в браузере. Вы должны увидеть сообщение «Художники не найдены» в вашем браузере и следующий текст в консоли Eclipse:

INFO: Loading XML configuration resource from file:/C:/workspace/example/target/classes/cayenne-project.xml
INFO: Loading XML DataMap resource from file:/C:/workspace/example/target/classes/datamap.map.xml
INFO: loading user name and password.
INFO: Created connection pool: jdbc:derby:memory:testdb;create=true
 Driver class: org.apache.derby.jdbc.EmbeddedDriver
 Min. connections in the pool: 1
 Max. connections in the pool: 1
INFO: setting DataNode 'datanode' as default, used by all unlinked DataMaps
INFO: Opening connection: jdbc:derby:memory:testdb;create=true
 Login: null
 Password: *******
INFO: +++ Connecting: SUCCESS.
INFO: Detected and installed adapter: org.apache.cayenne.dba.derby.DerbyAdapter
INFO: --- transaction started.
INFO: No schema detected, will create mapped tables
INFO: CREATE TABLE ARTIST (DATE_OF_BIRTH DATE NOT NULL, ID INTEGER NOT NULL, NAME VARCHAR (200) NOT NULL, PRIMARY KEY (ID))
INFO: CREATE TABLE GALLERY (ID INTEGER NOT NULL, NAME VARCHAR (200) NOT NULL, PRIMARY KEY (ID))
INFO: CREATE TABLE PAINTING (ARTIST_ID INTEGER NOT NULL, GALLERY_ID INTEGER, ID INTEGER NOT NULL, NAME VARCHAR (200) NOT NULL, PRIMARY KEY (ID))
INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (ARTIST_ID) REFERENCES ARTIST (ID)
INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (GALLERY_ID) REFERENCES GALLERY (ID)
INFO: CREATE TABLE AUTO_PK_SUPPORT ( TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, PRIMARY KEY(TABLE_NAME))
INFO: DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ('ARTIST', 'GALLERY', 'PAINTING')
INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('ARTIST', 200)
INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('GALLERY', 200)
INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('PAINTING', 200)
INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 ORDER BY t0.NAME - prepared in 57 ms.
INFO: === returned 0 rows. - took 77 ms.
INFO: +++ transaction committed.

      • Вы можете щёлкнуть по ссылке «Добавить нового художника...», чтобы добавить художников. Существующих художников можно редактировать.

Веб-приложение созданное с помощью Apache Cayenne

Создание схемы базы данных в СУБД ЛИНТЕР с помощью CayenneModeler

Наш пример, который мы сделали выше, работает с базой данных хранящейся в памяти. Чтобы при остановке приложения все данные не пропадали, давайте попробуем создать скрипт на создание таблиц для реальной СУБД с помощью моделера Cayenne. Практика использования Cayenne с СУБД MySQL и IBM DB2 у меня уже есть, а вот попробовать, как Cayenne будет работать с СУБД ЛИНТЕР, мне было бы интересно.

Для корректного взаимодействия с различными СУБД в Cayenne предусмотрены так называемые адаптеры, которые позволяют учитывать различные диалекты SQL. По умолчанию, в Cayenne уже есть адаптеры для всех распространённых СУБД, за исключением СУБД ЛИНТЕР. Есть правда универсальный адаптер «org.apache.cayenne.dba.JdbcAdapter», но через него Cayenne отказался работать с СУБД ЛИНТЕР – происходят ошибки при записи изменений.

Но выход есть. Я обратился к разработчикам, и они любезно предоставили мне архив с исходниками пакета диалекта СУБД ЛИНТЕР, в котором реализован адаптер «org.apache.cayenne.dba.linter.LinterAdapter». Поддерживаются разные версии Cayenne. Скачать этот архив можно здесь:

Файлы:
Пакет диалекта СУБД ЛИНТЕР для работы с Apache Cayenne Версия:От 14.08.2015

Пакета диалекта СУБД ЛИНТЕР для работы с Apache Cayenne к статье "Apache Cayenne: создаём веб-приложение и работаем с СУБД ЛИНТЕР".

Дата 14.08.2015 Размер файла 49.36 KB Закачек 1525

Для сборки пакета диалекта используется Apache Maven (скачать можно здесь). Для установки Maven, просто распакуйте архив и пропишите в переменную среды путь к папке bin (в которой лежит файл mvn.cmd). Проверьте также, чтобы была добавлена переменная среды JAVA_HOME, в которой хранится путь к JDK (у меня – это «C:\Program Files\Java\jdk1.7.0_25»). Для проверки установки вызовите в консоли команду «mvn –v».

Итак, чтобы собрать пакет диалекта СУБД ЛИНТЕР, сделайте следующее:

      • Распакуйте архив с исходниками. Я распаковал архив в папку «C:\linter».
      • Выберите версию пакета, в зависимости от версии Cayenne. Для Cayenne 3.1 – это папка «cayenne/v3» (у меня это папка «C:\linter\cayenne\v3»).
      • Из консоли выполните для выбранной папки команду «mvn clean install».
      • После выполнения команд в папке «cayenne/v3/target» создастся файл «linter-cayenne3-1.0.1.jar» (у меня это папка «C:\linter\cayenne\v3\target») и, кроме того, пакет будет зарегистрирован в локальном хранилище Maven (это нужно для использования в Eclipse).

Также для работы с базой данных вам понадобится JDBC-драйвер (в нашем примере для JDK 1.5 – это файл linjdbc-1.4.jar). Найти его можно в папке «jdbc» в месте установки СУБД ЛИНТЕР (если при установке вы выбрали соответствующую опцию).

После того как у нас есть драйвер (файл linjdbc-1.4.jar) и адаптер (файл linter-cayenne3-1.0.1.jar) можно приступать к настройке Cayenne.

Сначала познакомим моделер Cayenne с JDBC-драйвером СУБД ЛИНТЕР (это нужно для того, чтобы выполнять скрипт на создание таблиц прямо из моделера) и адаптером (это нужно для генерации скриптов с учётом диалекта СУБД ЛИНТЕР).

      • Щёлкните по пункту меню «Tools -> Preferences».
      • В диалоге настроек «Edit Preferences» выберите «ClassPath» в списке слева.
      • Щёлкните по кнопке «Add Jar/Zip» и выберите файл драйвера (linjdbc-1.4.jar).
      • Щёлкните по кнопке «Add Jar/Zip» ещё раз и выберите файл пакета диалекта (linter-cayenne3-1.0.1.jar).

Добавление драйвера СУБД ЛИНТЕР в моделер Apache Cayenne

      • Нажмите кнопку «Save», чтобы сохранить изменения (до того как эти изменения не сохранены, моделер Cayenne ничего не будет знать о драйвере и адаптере СУБД ЛИНТЕР).

Теперь создадим локальный источник данных Cayenne. Локальные источники данных используются только в моделере Cayenne для соединения с базами данных или быстрого создания новых узлов данных.

      • Щёлкните по пункту меню «Tools -> Preferences».
      • В диалоге настроек «Edit Preferences» выберите «Local DataSources» в списке слева.
      • Щёлкните по кнопке «New».
      • В очередном открывшемся диалоге «Create New Local DataSource» нужно задать имя источника данных. Введите в поле «Name» текст «LinterDataSource». В выпадающем списке адаптеров вы можете увидеть адаптеры для различных распространённых СУБД. Адаптеры позволяют генерировать SQL код специфичный для разных СУБД, а также автоматически заполняют поля «JDBC Driver» и «DB URL». Для СУБД ЛИНТЕР в этом списке адаптер не отображается, но это не страшно, мы зададим его чуть позже. Оставьте в этом поле значение «Custom / Undefined».

Добавление локального источника даных в моделер Apache Cayenne

      • Нажмите «Create».
      • Теперь в поле «JDBC Driver» пропишите «com.relx.jdbc.LinterDriver», а в поле «DB URL» пропишите «jdbc:linter:linapid:localhost:1070:local» (я буду соединяться с демонстрационной базой данных, которая была создана на моём компьютере при установке СУБД ЛИНТЕР). В полях «User Name» и «Password» задайте имя пользователя и пароль для подключения к базе данных. В поле «Adapter» пропишите «org.apache.cayenne.dba.linter.LinterAdapter».

Добавление локального источника данных СУБД ЛИНТЕР в моделер Apache Cayenne

      • Проверьте подключение, нажав на кнопку «Test...». Если вы всё настроили правильно, то вы увидите сообщение «Connected Successfully». Обратите внимание, что для работы JDBC-драйвера нужно запустить JDBC-сервер ЛИНТЕР.

Успешная проверка соединения с СУБД ЛИНТЕР из моделера Apache Cayenne

Теперь создадим и выполним скрипт на создание таблиц:

      • Выделите «datamap» в дереве слева и щёлкните по пункту меню «Tools -> Generate Database Schema». После этого поднимется диалог «Generate DB Schema: Options».
      • На закладке «SQL Options» вы можете выбрать, что нужно удалять и создавать и здесь же задаётся адаптер. Поскольку, нужных таблиц в базе данных у нас ещё нет, проставьте только галки на создание объектов, как показано на картинке. Также в поле «Adapter» пропишите «org.apache.cayenne.dba.linter.LinterAdapter» и нажмите клавишу «Enter», чтобы SQL-скрипт перестроился.

Генерация скрипта на создание таблиц в СУБД ЛИНТЕР в моделере Apache Cayenne

      • На закладке «Tables» вы можете выбрать нужные таблицы (нам нужно выбрать все таблицы).
      • Нажмите «Generate».
      • После этого появляется диалог «Generate DB Schema: Connect to Database», в котором выберите созданный выше локальный источник данных и нажмите «Continue».

Подключение к СУБД ЛИНТЕР из Apache Cayenne для создания таблиц

      • После того как скрипт выполнится, вы увидите сообщение «Schema Generation Complete».

Сообщение об успешной генерации базы данных в Apache Cayenne

После этого вы можете с помощью рабочего стола ЛИНТЕР удостовериться, что таблицы в базе данных действительно создались.

Просмотр, созданных с помощью Apache Cayenne в СУБД ЛИНТЕР таблиц

Перенастройка веб-приложения на работу с СУБД ЛИНТЕР

Для начала создадим новый узел данных (мы не будем удалять или изменять узел данных, который был сделан для in-memory базы данных, а просто добавим ещё один).

      • Щёлкните по кнопке «Create DataNode».
      • Выберите локальный источник данных, который мы создали выше, из выпадающего списка «Local DataSource» и нажмите кнопку «Sync with Local» (синхронизировать с локальным источником данных). Как видите все поля JDBC-конфигурации после нажатия на кнопку «Sync with Local» заполнились из выбранного локального источника данных.

Создание узла данных в Apache Cayenne для работы с СУБД ЛИНТЕР

      • Перейдите на закладку «Adapter», введите в поле «Custom Adapter» текст «org.apache.cayenne.dba.linter.LinterAdapter» и нажмите «Enter».

Настройка адаптера в Apache Cayenne для работы с СУБД ЛИНТЕР

После того как новый узел данных создан, щёлкните по карте данных «datamap» и выберите из выпадающего списка «DataNode» наш новый узел данных «datanode1» и сохраните изменения.

Выбор другого узла данных в Apache Cayenne

Перед тем как идти дальше, нам ещё нужно добавить JDBC-драйвер СУБД ЛИНТЕР в локальное хранилище Maven. Иначе мы не сможем прописать зависимости Maven и наше веб-приложение не увидит драйвер. Делать это вручную приходится потому, что никаких JAR-файлов ЛИНТЕР в хранилище Maven я не обнаружил.

Итак, чтобы добавить файл linjdbc-1.4.jar в локальное хранилище Maven перейдите в папку с этим файлом (у меня это папка «C:\Program Files (x86)\Linter\jdbc\») и выполните следующую команду из консоли:

mvn install:install-file -Dfile=linjdbc-1.4.jar -DgroupId=com.relx.jdbc -DartifactId=linjdbc -Dversion=1.4 -Dpackaging=jar

Теперь возвращаемся в Eclipse. Остановите наше веб-приложение, если оно выполняется (кнопка «Terminate» в панели инструментов консоли) и обновите наш проект (пункт контекстного меню «Refresh»).

Затем добавьте в файл «pom.xml» внутрь секции «dependencies» следующий кусок текста и сохраните изменения:

<dependency>
   <groupId>com.relx.jdbc</groupId>
   <artifactId>linjdbc</artifactId>
   <version>1.4</version>
</dependency>
<dependency>
   <groupId>ru.relex.lintersql</groupId>
   <artifactId>linter-cayenne3</artifactId>
   <version>1.0.1</version>
</dependency>

Теперь, когда всё готово, запустите наш веб-проект снова, для этого щёлкните правой кнопкой мышки по названию проекта и выберите «Run As -> Maven Build». После запуска приложения опять откройте в браузере страничку http://localhost:8080/example/ и опять добавьте художников.

После добавления убедитесь с помощью рабочего стола ЛИНТЕР, что данные сохранились в базе данных.

Просмотр данных в таблице СУБД ЛИНТЕР

Как видите, теперь данные сохраняются реальной в СУБД и после остановки приложения наши труды не пропадут. Можете остановить приложение, запустить его снова и убедиться, что добавленные художники остались в базе данных.

Подведём итог

Итак, из этих двух статей вы узнали, что такое Cayenne и научились использовать его основной функционал. Конечно, эта платформа даёт ещё много возможностей, которые не описаны в этих статьях, но те основы, которые описаны здесь, помогут вам начать правильно использовать мощный инструмент под названием Apache Cayenne.

Tags: Apache Cayenne Обзоры инструментов для программирования Учебники по программированию ЛИНТЕР

Добавить комментарий