Web-приложение с использованием EJB3 + Glassfish и JPA2

В данном уроке хочу вам показать как создать web-приложение используя возможности Glassfish и EJB3.

В этом уроке хочу вас научить работать с EJB, почему сервер Glassfish, во первых мне с ним удобней работать, ну и в Glassfish мы будем хранить все настройки в нашем случае — это настройки доступа к базе данных.

Шаг 0

1. Скачиваем Glassfish.

Glassfish скачать

Теперь создаем проект в Intellij IDEAFile -> New Project -> Maven Module

2. Скачиваем MySQL Server скачать

После скачивания устанавливаем, ставим пароль root. И создаем базу, называем её devcolibri.

Шаг 1

Добавляем зависимости в pom.xml

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.25</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.2.1.Final</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.0-api</artifactId>
        <version>1.0.1.Final</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>3.0-alpha-1</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>javaee</groupId>
        <artifactId>javaee-api</artifactId>
        <version>5</version>
    </dependency>

    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>6.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

mysql — нужен для получения доступа к базе данных;

org.hibernate — будет использоваться с его контейнера entitymanager, который обеспечит удобную работу с БД;

org.hibernate.javax.persistence — будет использоваться в связке с hibernate;

javax.servlet — этим, мы даем возможность приложению создавать Servlet-ы;

javaee — даст возможность реализовать клиент-сервер приложение;

javaee-web-api — эта зависимость обеспечит возможность сделать наше приложение Web-приложением используя необходимые API;

entitymanager — используется для работы с одной бизнес операцией, и без необходимости не открывает connection.

Пример работы с Hibernate Mapping можно посмотреть в этом уроке  ‘Как работать с MySQL в Java — Hibernate XML Mapping

И еще нам потребуется два maven plugin-а:

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.5</source>
            <target>1.5</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
    </plugin>
</plugins>

Шаг 2

Теперь давайте создадим Entity (сущность) для работы с базой данных.

Создаем класс User.java

package com.devcolibri.entity;

import javax.persistence.*;

@Entity(name = "users")
@NamedQuery(name = "User.getAll", query = "SELECT u from User u")
public class User {

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

    @Column(name = "first_name", nullable = false)
    private String name;

    @Column(name = "last_name", nullable = false)
    private String lastName;

    @Column(name = "age", nullable = false)
    private int age;

    public User() {
    }

    public User(String name, String lastName, int age) {

        this.name = name;
        this.lastName = lastName;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Дальше нам нужно создать EntityManager, но для начало настроим Glassfish.

Шаг 3

Что именно мы будем настраивать в glassfish?

Мы будем настраивать JDBC Connection.

Если вы только установили Glassfish, то он у вас уже запущен, нам нужно его остановить. Для этого идем туда где он установлен, если вы ничего не меняли, то он должен лежать в корне диска C:/glassfish4, и после в папку bin там есть файл asadmin.bat запускайте его. Появится консоль, там вы должны написать следующую команду, чтобы остановить glassfish:

stop-domain domain1

Как проверить запущен ли сервер? 

Для этого откройте браузер и просто напишите в URL -> localhost:4848, если вы увидите вход в админку glassfish то сервер запущен.

После того как вы остановили сервер идем в папку C:\glassfish4\glassfish\domains\domain1\lib\ext и копируем туда MySQLJDBCDriver, его можно найти в

C:\Users\devcolibri\.m2\repository\mysql\mysql-connector-java\5.1.25\mysql-connector-java-5.1.25.jar

Это нужно Glassfish для того чтобы получать connection к базе данных, так как за все транзакции будет отвечать glassfish то ему нужен данный драйвер.

Дальше открываем asadmin.bat и запускаем сервер следующей командой:

start-domain domain1

После этого идем в браузер по URL -> localhost:4848 и логинимся admin, пароль admin.

Открываем в пункте меню вкладку JDBC -> JDBC Connection Pool.

Теперь добавляем JDBC Resources на основе созданного Pool:

Внимание!

Или вместо этого, что мы настраивали выше можно добавить в консоли asadmin.bat следующей командой эти данные.

Для JDBC Connection Pool эта (все в одну строку):

create-jdbc-connection-pool 
      --datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlDataSource 
      --property user=root:password=root:DatabaseName=devcolibri:ServerName=localhost:port=3306:Encoding=UTF-8 MySQL-Pool

и для JDBC Resources:

create-jdbc-resource --connectionpoolid MySQL-Pool jdbc/devcolibri

На этом настройка законченна!

Шаг 4

В проекте заходим в папку src/resources/ и создаем там новую папку META-INF и добавляем туда файл persistence.xml, теперь мы настроим наш персистенс на контейнер Glassfish-а.

<?xml version="1.0" encoding="UTF-8" ?>
<persistence version="1.0" 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">

    <persistence-unit name="DEVMODE" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/devcolibri</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

в строке 9 есть атрибут name=’DEV’ — это имя persistence-unit по этому имени будет фабрика будет создавать EntityManager.

В уроке ‘JPA работа с базой данных‘ уже рассматривалась работа с JPA.

Шаг 5

Создаем Bean для этого создадим класс UserBean.java и проаннотируем его аннотацией @Stateless.

Аннотация @Stateless указывает, что это будет бин без сохранения состояния между вызовами методов.

package com.devcolibri.bean;

import com.devcolibri.entity.User;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.util.List;

@Stateless
public class UserBean {

    // Будет инициализирован контейнером Glassfish
    // unitName = "DEVMODE" - это имя persistence-unit
    // EntityManager дает возможность выполнять CRUD запросы в БД
    @PersistenceContext(unitName = "DEVMODE")
    private EntityManager em;

    // Добавляем User-а В базу данных
    public User add(User user){
        return em.merge(user);
    }

    // Получаем пользователя по id
    public User get(long id){
        return em.find(User.class, id);
    }

    // обновляем пользователя
    // если User которого мыпытаемся обновить нет,
    // то запишется он как новый
    public void update(User user){
        add(user);
    }

    // удаляем User по id
    public void delete(long id){
        em.remove(get(id));
    }

    // Получаем все пользователей с БД
    public List<User> getAll(){
        TypedQuery<User> namedQuery = em.createNamedQuery("User.getAll", User.class);
        return namedQuery.getResultList();
    }

}

Шаг 6

Создаем Servlet который будет работать с данным бином, который мы создали выше.

Назовем его MainServlet.java он будет выводить все пользователей:

package com.devcolibri.servlet;

import com.devcolibri.bean.UserBean;
import com.devcolibri.entity.User;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/list")
public class MainServlet extends HttpServlet{

    // Аннотация говорит о том,
    // что данный объект будет инициализирован
    // контейнером Glassfish DI
    @EJB
    private UserBean userBean;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
                                                 throws ServletException, IOException {
        // Получаем список пользователей
        List<User> allUser = userBean.getAll();

        // добавляем полученный список в request,
        // который отправится на jsp 
        req.setAttribute("users", allUser);

        // отправляем request на jsp
        req.getRequestDispatcher("/list.jsp").forward(req, resp);

    }

}

И теперь создадим jsp страницу которая будет выводить полученный список пользователей на Servlet-е.

Создадим list.jsp тут src\main\webapp\list.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Список пользователей</title>
</head>
<body>

    <h3>Все пользователи:</h3>(<a href="add">добавить</a>)
    <ol>
        <c:forEach items="${users}" var="user">
            <li>
                ${user.name} ${user.lastName} - ${user.age}
                <a href="add?edit=${user.id}">редактировать</a> | <a href="delete?id=${user.id}">удалить</a>
            </li>
        </c:forEach>
    </ol>

</body>
</html>

Шаг 7

Добавим сервлет, который будет добавлять новых пользователей, а также он будет редактировать пользователей.

Создадим сервелет AddAndEditUserServlet.java:

package com.devcolibri.servlet;

import com.devcolibri.bean.UserBean;
import com.devcolibri.entity.User;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/add")
public class AddAndEditUserServlet extends HttpServlet {

    @EJB
    private UserBean userBean;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
                                            throws ServletException, IOException {
        resp.setContentType("text/html");
        req.setCharacterEncoding("UTF-8");

        // если параметр null, то пользователь
        // пришел на страницу, чтобы создать нового, иначе
        // будет выполнятся редактирование существующего пользователя
        if(req.getParameter("edit") != null){
            long id = Long.valueOf(req.getParameter("edit"));
            User user = userBean.get(id);

            req.setAttribute("user", user);
        }

        req.getRequestDispatcher("/add.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
                                             throws ServletException, IOException {
        resp.setContentType("text/html");
        req.setCharacterEncoding("UTF-8");

        String name = req.getParameter("name");
        String lastName = req.getParameter("lastName");
        int age = Integer.valueOf(req.getParameter("age"));

        // если id есть, то выполняется редактирование
        // а если нет id, то - это значит, что создается новый пользователь
        if(req.getParameter("id") != ""){
            long id = Long.valueOf(req.getParameter("id"));
            User user = userBean.get(id);
            user.setAge(age);
            user.setLastName(lastName);
            user.setName(name);

            // обновляем пользователя
            userBean.update(user);
        } else{
            // добавляем нового
            userBean.add(new User(name, lastName, age));
        }

        // перенаправляем на сервлет, который выводит все пользователей
        resp.sendRedirect("list");
    }
}

и JSP для этого сервлета:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Добавление | Редактирование</title>
</head>
<body>

    <form action="add" method="post">
        <label for="name">Введите имя:
            <input type="text" id="name" value="${user.name}" name="name" />
        </label>  <br />
        <label for="last-name">Введите фамилию:
            <input type="text" id="last-name" value="${user.lastName}" name="lastName" />
        </label>  <br />
        <label for="age">Введите возвраст:
            <input type="text" id="age" value="${user.age}" name="age" />
        </label>  <br />
        <input type="hidden" name="id" value="${user.id}" />
        <input type="submit" value="Сохранить" />
    </form>

</body>
</html>

Шаг 8

И последний сервлет это для удаления пользователя, и назовем его DeleteUser.java:

package com.devcolibri.servlet;

import com.devcolibri.bean.UserBean;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/delete")
public class DeleteUser extends HttpServlet {

    @EJB
    private UserBean userBean;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
                                            throws ServletException, IOException {
        if(req.getParameter("id") != null && req.getParameter("id") != ""){
            long id = Long.valueOf(req.getParameter("id"));
            userBean.delete(id);
        }
        resp.sendRedirect("list");
    }
}

Шаг 9

Теперь собираем проект с помощью Maven:

После этого в папке проекта появится папка target и там будет собранный проект с расширением *.war

Шаг 10

Теперь деплоим (Deploy).

Deploy — это развертывание проекта на сервере приложений.

Заходим в glassfish http://localhost:4848/ потом в меню Application -> Deploy

После удачного деплоя вы можете зайти на свое приложение:

http://localhost:8080/EJBGlassfishJPA-1.0/list

В результате получится это:

P.S. Спасибо за внимание! Надеюсь я вам помог.

Урок создан: 20 июня 2013 | Просмотров: 29997 | Автор: Александр Барчук | Правила перепечатки


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

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

Ваш e-mail не будет опубликован.

Комментарии:

  • 26 июня 2013 в 16:37

    Sergey

    В idea довольно объемная инфраструктура для создания ear приложений, было бы очень интересно почитать про концепцию работы с такими проектами в этой ide, принятый порядок подключения модулей, сборки, работу с встроенными вайзардами, инкрементное обновление ear архива и т.д. Сама ide, с не привычки немного не очевидна :) родная их дока довольно скромна на примеры, а все сторонние статьи в основном больше про мавен чем про идею, а с мавеном проблем то как раз нет, по нему книг и статей написано немерено :) Да если можно, выложите пожалуйста собранный правильно с вашей точки зрения ear проект в idea на что-нибудь вроде гитхаба, было бы интересно посмотреть :)

  • 02 июля 2013 в 00:41

    Ang

    Есть неточность в связке между Шагом 4 и 5. Не правильно указанно имя PersistenceContext.

  • 19 сентября 2013 в 11:02

    Sergey

    А куда, делся урок по сборке модульного ear архива? :)

    • 19 сентября 2013 в 12:04

      Александр Барчук

      Автор который его делал решил уйти и забрал урок :) Скоро мы напишем урок по данной теме!

  • 15 декабря 2013 в 15:26

    Dima

    Отличная статья. Очень помогла мне.

  • 11 июня 2014 в 10:23

    Buba

    req.getParameter(«id») != «» а может .equals() ? Скачал проект кроме добаления

    • 11 июня 2014 в 12:35

      yernar

      primer ne rabotaet na glassfish4.0

  • 13 июня 2014 в 11:18

    Revver

    Очень интересная статья, я не знаком с EJB, поэтому читал интересом, но к сожалению у меня запустить не получилось, и при написании своего приложения «по инструкции» и запуск ваших исходников. Сервер выдает ошибку javax.ejb.EJBException. Как считаете возможно в чем может быть проблема.

    • 13 июня 2014 в 14:02

      Александр Барчук

      Я не тестировал на Glassfish 4 попробуйте на Glasfish 3

      • 16 июня 2014 в 12:16

        Revver

        Да вы правы, на версии 3.1.2 все прекрасно работает, несопоставимость сервера и EJB возможно связанна с версиями данных зависимостей?

        javaee
        javaee-api
        5

        javax
        javaee-web-api
        6.0
        provided

  • 22 мая 2015 в 15:11

    Василий

    »
    MySQLJDBCDriver, его можно найти в

    C:\Users\devcolibri\.m2\repository\mysql\mysql-connector-java\5.1.25\mysql-connector-java-5.1.25.jar
    »
    исправьте ссыль, ведь на моём компьютере нет пользователя «devcolibri»

  • 14 марта 2016 в 00:06

    Константин

    В строчке @Column(name = «user_ID») — user_id подчеркиваеться красным, что за?
    Весь гугл перелопатил, не найдк=у ошибку(

  • 28 апреля 2016 в 15:14

    Алексей

    Пример не работает на базе postgrisql.
    Внес корректировки в сущность User:

    @Entity
    @Table(name = «users»)
    и только тогда заработало

  • 18 мая 2016 в 18:03

    Николай

    Проблема с glassfish решена тут
    https://coderwall.com/p/e5fxrw/use-hibernate-4-3-x-with-jta-on-glassfish-4
    нужно поменять версию

    org.hibernate
    hibernate-entitymanager
    4.3.0.Final

    в persistence.xml указано новое значение в поле provider
    org.hibernate.jpa.HibernatePersistenceProvider
    и добавить в properties

  • 27 мая 2016 в 15:54

    Max

    *.war
    может *.jar ?

  • 27 мая 2016 в 16:11

    Max

    Деплой падает с ClassNotFoundException: org.hibernate.ejb.HibernatePersistence
    Glassfish 3.1.2

  • 09 ноября 2016 в 08:24

    Сергей

    Делаю всё в точности с инструкцией, но при деплое валится с ошибкой: Error occurred during deployment: Exception while preparing the app : java.lang.ClassNotFoundException: org.hibernate.ejb.HibernatePersistence. В чем может быть дело?

  • 16 декабря 2016 в 05:13

    defneo

    Все работает, но при сохранении пользователя в базу данных выдает java.lang.NumberFormatException: For input string: «».