В конце этого поста вы найдете исходный код для скачивания. Вы можете использовать его как хотите. Просто перейдите на последнюю страницу и выполните загрузку. \ о /
Если вы скачали код и ничего не поняли, в этом посте я объясню каждую деталь, найденную в коде. Просто прочитайте тему в этом посте, который вы хотите.
Я перечислю ниже технологии, которые я буду использовать в этом посте:
- JSF 2.0 Mojarra — с ManagedBeans в качестве RequestScope и SessionScope.
- Интернационализация сообщений — файл, который будет содержать все сообщения нашей системы; вам будет легче переводить страницы.
- CSS-файл по умолчанию, который будет импортирован как библиотека.
- EJB 3 — Наши DAO и Фасады будут @Stateless.
- Универсальный DAO — универсальный DAO, в котором будут использоваться действия CRUD для облегчения нашей жизни.
- JPA 2 — Для отображения наших классов в БД
- JAAS — для контроля входа и доступа пользователей к страницам.
- MVC — я буду использовать этот шаблон с небольшими изменениями.
- Postgres как база данных, но я покажу, как настроить приложение для MySQL.
Я не буду использовать TDD-JUnit для тестирования наших View / Model / Classes, но по следующей ссылке вы можете увидеть методику использования JUnit для тестирования ваших ManagedBeans: JUnit с HSQLDB, JPA и Hibernate .
Инструменты, которые мы будем использовать:
- Eclipse Indigo — http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/indigor
- Я буду использовать JBoss 7 (некоторые читатели этого блога просили меня об этом) — http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-7.0.2.Final .zip версия: JBoss 7 Все (НЕ сертифицирован Java EE6) .
- Инструменты Indigo JBoss (версия Milestone) — https://www.jboss.org/tools/download/dev.html, если вы не знаете, как установить Инструменты JBoss, в этом посте я покажу, как ( Проверка регистрации пользователя с помощью JAAS). и JSF ). Помните, что в этом посте я покажу, как установить другую версию Eclipse, но разница заключается в URL; используйте этот URL вместо URL, использованного в ссылке выше: http://download.jboss.org/jbosstools/updates/development/indigo/
- Я буду использовать базу данных Postgres, но вы можете использовать любую базу данных; Вам потребуется только загрузить базу данных и драйвер JDBC. Здесь вы можете загрузить последнюю версию Postgres JDBC: http://jdbc.postgresql.org/download.html ; последняя версия на данный момент — 4: http://jdbc.postgresql.org/download/postgresql-9.1-901.jdbc4.jar .
Этот пост будет иметь несколько страниц; Эта первая страница просто для того, чтобы показать технические детали сегодняшнего поста.
Я не буду кодировать интерфейс моей модели / DAO, просто чтобы сэкономить место. Помните, что вы всегда должны кодировать интерфейсы ( Design Pattern — Strategy ) .
Прежде чем продолжить, убедитесь, что вы установили JBoss Tools и JBoss 7 именно в таком порядке.
Бизнес модель
Давайте создадим проект EJB, который будет поддерживать наш системный бизнес.
Нажмите на кнопку « Готово ».
Давайте создадим классы User и Dog, которые будут внутри пакета «com». Это будет иметь код ниже:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package com.model;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.NamedQuery;import javax.persistence.Table;@Entity@Table(name = 'USERS')@NamedQuery(name='User.findUserByEmail', query='select u from User u where u.email = :email')public class User { public static final String FIND_BY_EMAIL = 'User.findUserByEmail'; @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; @Column(unique = true) private String email; private String password; private String name; private String role; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } @Override public int hashCode() { return getId(); } @Override public boolean equals(Object obj) { if(obj instanceof User){ User user = (User) obj; return user.getEmail().equals(getEmail()); } return false; }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package com.model;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name = 'DOGS')public class Dog { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; private double weight; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } @Override public int hashCode() { return getId(); } @Override public boolean equals(Object obj) { if(obj instanceof Dog){ Dog dog = (Dog) obj; return dog.getId() == getId(); } return false; }} |
О коде выше:
- У класса User есть поле с именем «role», в котором будет храниться уровень роли пользователя. Я создал одно поле, и мы оставим все данные в одной таблице, чтобы их было легче понять. Если вы хотите получить более подробную информацию о JAAS, вы можете написать в этом посте: Проверка входа пользователя с помощью JAAS и JSF .
- Я позволю JPA обрабатывать таблицы Id поколений. Если вы хотите изменить способ создания идентификатора, вы можете проверить эти сообщения, чтобы увидеть, как это сделать: JPA SequenceGenerator , JPA TableGenerator — Простой ключ Primay .
- Электронная почта будет уникальной; это будет идентификатор входа в систему.
- Обратите внимание, что класс, который должен быть объявлен как Entity, нуждается только в следующих аннотациях: «@Entity» и «@Id». Класс не должен реализовывать интерфейс Serializable.
Бизнес — ДАО
Я буду использовать общий DAO для основных операций CRUD, а другие два DAO: один для пользователя и другой для собаки. Понять его использование будет очень легко:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
package com.dao;import java.util.List;import java.util.Map;import java.util.Map.Entry;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.persistence.Query;import javax.persistence.criteria.CriteriaQuery;public abstract class GenericDAO<T> { private final static String UNIT_NAME = 'CrudPU'; @PersistenceContext(unitName = UNIT_NAME) private EntityManager em; private Class<T> entityClass; public GenericDAO(Class<T> entityClass) { this.entityClass = entityClass; } public void save(T entity) { em.persist(entity); } public void delete(T entity) { T entityToBeRemoved = em.merge(entity); em.remove(entityToBeRemoved); } public T update(T entity) { return em.merge(entity); } public T find(int entityID) { return em.find(entityClass, entityID); } // Using the unchecked because JPA does not have a // em.getCriteriaBuilder().createQuery()<T> method @SuppressWarnings({ 'unchecked', 'rawtypes' }) public List<T> findAll() { CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); cq.select(cq.from(entityClass)); return em.createQuery(cq).getResultList(); } // Using the unchecked because JPA does not have a // ery.getSingleResult()<T> method @SuppressWarnings('unchecked') protected T findOneResult(String namedQuery, Map<String, Object> parameters) { T result = null; try { Query query = em.createNamedQuery(namedQuery); // Method that will populate parameters if they are passed not null and empty if (parameters != null && !parameters.isEmpty()) { populateQueryParameters(query, parameters); } result = (T) query.getSingleResult(); } catch (Exception e) { System.out.println('Error while running query: ' + e.getMessage()); e.printStackTrace(); } return result; } private void populateQueryParameters(Query query, Map<String, Object> parameters) { for (Entry<String, Object> entry : parameters.entrySet()) { query.setParameter(entry.getKey(), entry.getValue()); } }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
package com.dao;import javax.ejb.Stateless;import com.model.Dog;@Statelesspublic class DogDAO extends GenericDAO<Dog> { public DogDAO() { super(Dog.class); }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.dao;import java.util.HashMap;import java.util.Map;import javax.ejb.Stateless;import com.model.User;@Statelesspublic class UserDAO extends GenericDAO<User> { public UserDAO() { super(User.class); } public User findUserByEmail(String email){ Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put('email', email); return super.findOneResult(User.FIND_BY_EMAIL, parameters); }} |
О коде выше:
- Я скрыл некоторые предупреждения, потому что код JPA еще не «понимает» дженерики.
- Метод findOneResult имеет защищенный доступ только для предотвращения внешнего доступа из других классов; этот метод требует логики для заполнения параметров, как мы видим в UserDAO.
- Класс GenericDAO имеет полные методы CRUD плюс метод, который возвращает один объект с заданным NamedQuery.
- У класса UserDAO есть метод (findUserByEmail), который принадлежит только классу; но он имеет все методы CRUD по наследству. С этим шаблоном DAO мы получили более гибкий код.
- В DogDAO нет никакого метода, а есть только методы CRUD; Вы можете реализовать любой метод в классе без проблем.
- Вместо того, чтобы использовать метод для «сохранения» и другой для «обновления» ваших объектов, вы можете использовать один метод «entityManager.merge ()». У вас будет тот же результат, но вам нужно будет обратить внимание на параметры каскада.
- Я не использовал интерфейсы, потому что EJB 3.1 позволяет нам иметь Локальные Сессионные Компоненты без Состояния без интерфейса. Если вы используете более старую версию EJB, вам необходимо реализовать интерфейс (как реализовать EJB с интерфейсами, мы увидим в этом посте на странице «Фасады»). Я не буду разрабатывать интерфейсы моей DAO / Model только для экономии места в этом посте. Помните: «Всегда программируйте на интерфейс» ( Design Pattern — Strategy ).
- Если вы используете JBoss 4.2, вы можете использовать аннотации org.jboss.annotation.ejb.LocalBinding или org.jboss.annotation.ejb.RemoteBinding; в этой аннотации вы можете написать имя, которое будет отображено и передано EJB.
Бизнес — Фасады
Я создам Фасады, которые станут «мостом» между View и DAO. На Фасаде мы оставим все бизнес-правила, оставив в DAO только функции / транзакции «базы данных», например, CRUD и запросы.
Давайте посмотрим, какими будут наши классы UserFacade и DogFacade:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.facade;import java.util.List;import javax.ejb.Local;import com.model.Dog;@Localpublic interface DogFacade { public abstract void save(Dog dog); public abstract Dog update(Dog dog); public abstract void delete(Dog dog); public abstract Dog find(int entityID); public abstract List<Dog> findAll();} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
package com.facade;import java.util.List;import javax.ejb.EJB;import javax.ejb.Stateless;import com.dao.DogDAO;import com.model.Dog;@Statelesspublic class DogFacadeImp implements DogFacade { @EJB private DogDAO dogDAO; @Override public void save(Dog dog) { isDogWithAllData(dog); dogDAO.save(dog); } @Override public Dog update(Dog dog) { isDogWithAllData(dog); return dogDAO.update(dog); } @Override public void delete(Dog dog) { dogDAO.delete(dog); } @Override public Dog find(int entityID) { return dogDAO.find(entityID); } @Override public List<Dog> findAll() { return dogDAO.findAll(); } private void isDogWithAllData(Dog dog){ boolean hasError = false; if(dog == null){ hasError = true; } if (dog.getName() == null || ''.equals(dog.getName().trim())){ hasError = true; } if(dog.getWeight() <= 0){ hasError = true; } if (hasError){ throw new IllegalArgumentException('The dog is missing data. Check the name and weight, they should have value.'); } }} |
|
01
02
03
04
05
06
07
08
09
10
|
package com.facade;import javax.ejb.Local;import com.model.User;@Localpublic interface UserFacade { public User findUserByEmail(String email);} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
package com.facade;import javax.ejb.EJB;import javax.ejb.Stateless;import com.dao.UserDAO;import com.model.User;@Statelesspublic class UserFacadeImp implements UserFacade { @EJB private UserDAO userDAO; public User findUserByEmail(String email) { return userDAO.findUserByEmail(email); }} |
О коде выше:
- Класс DogFacadeImp выполняет всю работу по защите DogDAO от представления. Он может иметь бизнес-правила и избегать доступа к базе данных, если некоторые данные отсутствуют или любое другое бизнес-правило нарушено.
- У UserFacade есть только один метод, потому что в этом посте у нас не будет User crud; bean-компонент будет искать пользователя только в том случае, если представление не находит его в HttpSession.
- Если вы используете JBoss 4.2, вы можете использовать аннотации org.jboss.annotation.ejb.LocalBinding или org.jboss.annotation.ejb.RemoteBinding; в этой аннотации вы можете написать имя, которое будет отображено и передано EJB.
- Я делаю проверку в DogFacadeImp, чтобы убедиться, что у собаки есть только действительные данные. Помните, что каждый может отправить вам неверные данные, и проверка вашего представления может работать не так, как вы ожидаете. Данные вашего заявления очень важны, и двойная проверка всегда стоит.
Интерфейсы аннотированы @Local, но я помню, что эта аннотация не является обязательной. Если вы не напишите аннотацию @Local, ваш сервер будет считать, что ваш EJB является локальным по умолчанию.
Бизнес — Источник данных (по модулям)
Нам также нужно настроить наш источник данных.
Сначала я попытался создать источник данных, следуя этому руководству http://community.jboss.org/wiki/JBossAS7-DatasourceConfigurationForPostgresql (я следую учебным пособиям, как и любой другой человек), но после развертывания с использованием нескольких ошибок началось EJB и JBoss не смогли найти банку Postgres.
Если вы используете JBoss 6 или любую другую версию, вам не нужно создавать модуль; просто поместите файл в папку «default / lib». Если у вас есть какие-либо сомнения по поводу настройки источника данных, я покажу, как это сделать, в JBoss 6 или другой версии под ним, здесь: Проверка входа пользователя с помощью JAAS и JSF .
Давайте создадим модуль Postgres. Внутри вашего JBoss 7 создайте каталог: « YOUR_JBOSS / modules / org / postgresql / main ». Скопируйте банку в созданный каталог и создайте файл с именем «module.xml»; скопируйте код ниже внутри файла «module.xml»:
|
1
2
3
4
5
6
7
|
<?xml version='1.0' encoding='UTF-8'?><module xmlns='urn:jboss:module:1.0' name='org.postgresql'> <resources> <resource-root path='postgresql-9.1-901.jdbc4.jar'/> </resources> <dependencies><module name='javax.api'/></dependencies></module> |
Обратите внимание, что внутри файла «module.xml» написано имя файла jar, имя должно совпадать с именем файла jar Postgres.
Для создания модуля MySQL создайте следующую папку « YOUR_JBOSS / modules / com / mysql / main » . Скопируйте банку в созданный каталог и создайте файл с именем «module.xml»; скопируйте код ниже внутри файла «module.xml»:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<?xml version='1.0' encoding='UTF-8'?><!-- ~ JBoss copyrights --><module xmlns='urn:jboss:module:1.0' name='com.mysql'> <resources> <resource-root path='mysql-connector-java-5.1.15.jar'/> </resources> <dependencies> <module name='javax.api'/> </dependencies></module> |
Давайте отредактируем файл « YOUR_JBOSS / standalone / configuration / standalone.xml ». Внутри ключа «<источники данных>» добавьте код ниже:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<datasources> <!-- Add this config: begin --> <datasource jndi-name='CrudDS' pool-name='CrudDS_Pool' enabled='true' jta='true' use-java-context='true' use-ccm='true'> <connection-url>jdbc:postgresql://localhost:5432/CrudDB</connection-url> <driver-class>org.postgresql.Driver</driver-class> <driver>postgresql-jdbc4</driver> <pool> <min-pool-size>2</min-pool-size> <max-pool-size>20</max-pool-size> <prefill>true</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <user-name>postgres</user-name> <password>postgres</password> </security> <validation> <check-valid-connection-sql>SELECT 1</check-valid-connection-sql> <validate-on-match>false</validate-on-match> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </datasource> <!-- Add this config: end --> <drivers> <!-- Add this config: begin --> <driver name='postgresql-jdbc4' module='org.postgresql'/> <!-- Add this config: end --> </drivers> |
Чтобы настроить источник данных с MySQL, посмотрите здесь:
http://community.jboss.org/wiki/DataSourceConfigurationInAS7
Бизнес — XML-конфигурации
Давайте посмотрим, каким будет наш файл persistence.xml (этот файл должен находиться внутри папки src / META-INF):
|
01
02
03
04
05
06
07
08
09
10
|
<?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='CrudPU' transaction-type='JTA'> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/CrudDS</jta-data-source> <properties> <property name='hibernate.hbm2ddl.auto' value='update'/> </properties> </persistence-unit></persistence> |
Мы получили очень простой код; он просто указывает на источник данных и возможность генерировать все таблицы базы данных с помощью «update».
Добавьте проект EJB в JBoss.
Создайте базу данных в Postgres и запустите JBoss; после того, как вы запустили его, JPA создаст таблицы.
Проверьте изображение ниже, чтобы увидеть таблицы / последовательности, которые JPA создал для нас.
Создайте файл с именем «jboss-web.xml» в папке WEB-INF и напишите в нем приведенный ниже код:
|
1
2
3
4
5
6
7
8
9
|
<?xml version='1.0' encoding='UTF-8'?><jboss-web> <!-- URL to access the web module --> <context-root>CrudJSF</context-root> <!-- Realm that will be used --> <security-domain>java:/jaas/CrudJSFRealm</security-domain></jboss-web> |
В приведенном выше файле мы настроили Царство, которое будет использовать наше приложение. Давайте вставим пользователей в базу данных, которая будет выполнять вход с помощью JAAS (если вы хотите увидеть более подробную информацию о JAAS, вы можете увидеть это здесь: Проверка входа пользователя с помощью JAAS и JSF ). Я не буду вдаваться в подробности JAAS, потому что вы можете найти каждый шаг, описанный в предыдущей ссылке.
Смотрите на изображении ниже данные, которые я вставил вручную в базу данных (вы должны сделать то же самое):
Перейдите ко второй части урока.
Ссылка: полное веб-приложение JSF EJB JPA JAAS от нашего партнера JCG Хеберта Коэльо в блоге uaiHebert .




