Простой модульный web проект с maven. Часть 2. DataSource и JPA: добавляем postgres и hibernate

Следующим шагом добавим к нашему проекту поддержку БД. Подключение будем осуществлять через DataSource. Это поможет нам не беспокоится о подключении к БД во время разработки от слова совсем.

Первым делом скачаем postgres. Так же нам облегчит жизнь PgAdmin (если вы качали пакет для Windows то он по умолчанию ставится за компанию, для Linux ставим отдельно). PgAdmin при входе спросит пароль для суперпользователя postgres. Как только подключение наладится вы, скорее всего, увидите тестовую БД postgres. Добавляем новую БД (я назвал ее demo). При добавлении достаточно указать имя и владельца (postgres), остальное в нашем примере роли не играет. Все эти махинации, конечно, можно провернуть и без всяких pgAdmin, а просто в консоли, но пойдем простым путем.

Теперь создадим DataSource. Это делается проще чем кажется. Первым делом необходимо прокинуть jdbc драйвер в Wildfly. Один из способов  – просто задеплоить jar драйвера, а второй – добавить драйвер как модуль WildFly. Пойдем более надежным – вторым способом (первый пригодится нам в следующих частях).

Скачиваем любую версию jdbc драйвера postgres.  Опять же, есть несколько способов добавить модуль: копированием jar и настройкой xml, через web интерфейс Wildfly или через командную строку (CLI). Разнообразия ради, будем добавлять последним способом. Чтобы не возиться с путями я просто закинул jar в директорию bin. Теперь стартуем Wildfly (bin/standalone.bat). Открываем новый терминал, и запускаем скрипт bin/jboss-cli.bat. Вводим connect и цепляемся к нашему Wildfly. Добавляем модуль:

module add --name=org.postgresql --slot=main --resources=postgresql-9.4-1206-jdbc4.jar --dependencies=javax.api,javax.transaction.api

И регистрируем драйвер:

/subsystem=datasources/jdbc-driver=postgres:add(driver-name="postgres",driver-module-name="org.postgresql",driver-class-name=org.postgresql.Driver)

Драйвер готов. Дело за DataSource. Добавить его можно все теми же тремя путями. На сей раз добавим через web интерфейс. Заходим на localhost:9990 и Wildfly с порога заявляет нам, что неплохо бы создать пользователя. К счастью, инструкция как это сделать будет на той же странице в виде картинки. Достаточно (не выключая Wildfly) стартануть из папки bin скрипт add-user.bat и далее следовать инструкции. Так как сервер у нас локальный, то можно добавлять просто admin/admin, хоть скрипт и будет ругаться что имя слишком простое.

Снова заходим в консоль, вводим имя и пароль и проходим данным маршрутом до голубой кнопки Add:

3

Далее в списке выбираем PostgreSQL Datasource. На следующей странице Name – Demo, JNDI соответственно – java:/Demo. Следующая страница предлагает выбрать драйвер. Переходим в Detected Driver и выбираем наш postgres. На следующей странице правим connection url, а конкретно добавляем имя нашей БД jdbc:postgresql://localhost:5432/demo. Username и password соответственно postgres и пароль который вводили при входе в pgAdmin. На последней странице жмем на Test Connection и если все в шоколаде, то получим сообщение Successfully created JDBC connection. С datasource закончили, настало время JPA.

Первым делом добавляем в проект hibernate (в pom проекта и в pom’ы модулей):

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.1.Final</version>
    <scope>provided</scope>
</dependency>

Далее неплохо бы его настроить. Снова идем в Project Structure -> Modules. Выделяем server и жмем сверху плюс. Выбираем JPA. Нажимаем на плюс справа и выбираем persistance.xml. Ну снизу еще можно до кучи выбрать провайдер Hibernate. Тем самым в модуле server появилась директория META-INF с persistance.xml внутри. Перейдем в src/main и создадим там директорию resources (так же можно в контекстном меню выбрать Mark Directory As -> Resources Root, если она автоматически не стала такой), и переносим WEB-INF туда. Получаем примерно следующее:

5

Содержимое persistance.xml будет следующим:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="DemoIt" transaction-type="JTA">
        <jta-data-source>java:/Demo</jta-data-source>
        <properties>
            <property name="hibernate.connection.characterEncoding" value="UTF-8"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.transaction.flush_before_completion" value="true"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL9Dialect"/>
            <property name="hibernate.connection.useUnicode" value="true"/>

            <!-- FIXME: comment out before production releases -->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            
        </properties>
    </persistence-unit>
</persistence>

Тут нужно обратить внимание на две вещи: во-первых, jta-data-source должен совпадать с указанным JNDI нашего DataSource, во-вторых, три строчки после комментария FIXME. Эти строчки помогут нам развернуть базу основываясь на Entity классах, то есть вообще без запросов create table и прочее. Но важно понимать, что оно также и пересоздаст уже существующие таблицы после каждого запуска приложения. Так что на этапе разработки раскомментируем, а затем закомментируем. На практике так можно создать начальный каркас БД. Однако все последующие обновления уже делаются скриптами, так как БД уже содержит боевые данные.

Самое сложное позади. Теперь пишем Entity. Добавляем новый класс (я назвал его SomeEntity, так как в фантазию не могу) рядом с нашей EJB:

package ru.alexkulikov;

import javax.persistence.*;

@Entity
@Table(name = "values")
public class SomeEntity {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "value")
    private String value;

    public SomeEntity() {
    }

    public SomeEntity(String value) {
        this.value = value;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

Подробно останавливаться на этом не будем. Теперь немного модифицируем наш EJB:

package ru.alexkulikov;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;

@Path("/")
@Stateless
public class MainEJB {

    @PersistenceContext
    private EntityManager entityManager;

    @Path("/save")
    @POST
    public Response doSave(@FormParam("value") String value) {
        SomeEntity entity = new SomeEntity(value);
        entityManager.persist(entity);

        return Response.ok(String.valueOf(entity.getId())).build();
    }

    @Path("/echo")
    @GET
    public Response doEcho(@QueryParam("id") Long id) {
        SomeEntity entity = entityManager.find(SomeEntity.class, id);
        return Response.ok(entity.getValue()).build();
    }
}

Тут тоже не будем заострять внимания на работу EntityManager’a. Возможно, в будущем, я напишу по этой теме отдельную статью. Итак, наш бин теперь может сохранить какое то значение в базе и вернуть его сгенерированный id. По этому id затем мы модем посмотреть это значение. Вот и все. Тестируем. Стартуем wildfly, после деплоя у нас должна создаться таблица values (можно проверить в pgAdmin, или можно настроить datasource прямо из IDEA, с правой стороны есть вкладка Database).

Берем любой REST клиент и прогоняем запрос:

45

По порядку: дергаем POST запрос, передаем параметр value, и получаем ответ – id созданной записи в базе. Проверяем GET запрос:

7

 

Leave a Reply

Your email address will not be published. Required fields are marked *