Статьи

Ленивая JSF Primefaces Datatable Pagination — Часть 1

Сегодня мы сделаем пагинацию данных в JSF с помощью Lazy List с управляемым бином в виде области видимости. Что означают все эти слова / выражения?

Сегодня существует несколько сред JSF, которые предоставляют таблицам данных готовую нумерацию страниц, сортировщик столбцов и другие функциональные возможности. Сегодня мы будем использовать данные Primefaces.

Обычно таблицы данных помещают отображаемый Список с сущностями в пользовательский http-сеанс. Увеличение объектов внутри пользовательской сессии будет иметь прямое влияние на производительность сервера; каждый пользователь, который отображает таблицу данных и хранит список в сеансе, будет выделять все больше и больше памяти на сервере.

Чтобы выглядеть как в реальной жизни, наша статья будет использовать JPA и HSQLDB в качестве базы данных, а мы будем использовать JPQL для запроса данных.

В конце этого поста вы найдете ссылку для скачивания исходного кода.

Мы будем использовать:

  • JSF 2.0 — реализация JBoss 7
  • JBoss 7.1 — код этого поста должен применяться ко всем серверам
  • Затмение Индиго
  • JPA 2.0 — реализация JBoss 7
  • HSQLDB (2.2.8) — HSQL — это база данных памяти, ее будет проще запускать.
  • Primefaces 3.2

Этот пост не о хороших методах разработки и не о добавлении слоев классов моделирования проекта. Я просто собираюсь показать, как сделать нумерацию страниц без управляемого сессионного компонента.

У нас будет только одна сущность, которая будет сохраняться, класс Player. Ниже код класса:

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
package com.model;
 
import java.io.Serializable;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
 
@Entity
public class Player implements Serializable{
 
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
 
    private String name;
    private int age;
 
    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 int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public int hashCode() {
        return getId();
    }
 
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Player){
            Player player = (Player) obj;
            return player.getId() == getId();
        }
 
        return false;
    }
}

Нам нужно будет создать файл persistence.xml внутри папки «src / META-INF»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
 
<persistence version="2.0"
 
    <persistence-unit name="JSFPU" transaction-type="JTA">
        <jta-data-source>java:/JSFDS</jta-data-source>
 
        <properties>
            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
            <property name="hibernate.connection.shutdown" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        </properties>
    </persistence-unit>
</persistence>

Чтобы абстрагировать транзакцию базы данных, мы будем использовать класс MyTransaction:

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
package com.connection;
 
import java.io.Serializable;
 
import javax.persistence.EntityManager;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
 
public class MyTransaction implements Serializable {
 
    /**
     *
     */
    private static final long serialVersionUID = 1L;
 
    private Connection connection = new Connection();  
 
    public void begin() throws NotSupportedException, SystemException {
        connection.begin();
    }
 
    public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException,
            SystemException {
        connection.commit();
    }
 
    public int getStatus() throws SystemException {
        return connection.getStatus();
    }
 
    public void rollback() throws IllegalStateException, SecurityException, SystemException {
        connection.rollback();
    }
 
    public void setRollbackOnly() throws IllegalStateException, SystemException {
        connection.setRollbackOnly();
    }
 
    public void setTransactionTimeout(int timeout) throws SystemException {
        connection.setTransactionTimeout(timeout);
    }
 
    public static MyTransaction getNewTransaction() {
        return new MyTransaction();
    }
 
    public EntityManager getEntityManager() {
        return connection.getEntityManager();
    }
}

В приведенном выше коде вы можете видеть, что класс является просто абстракцией для соединения с базой данных; это поможет нам с запросами к базе данных. Вы можете использовать любой тип соединения или даже EJB, чтобы избежать ручного управления соединением.

Проверьте код класса соединения:

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
package com.connection;
 
import java.io.Serializable;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
 
public class Connection implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * Get the user transaction by JNDI
     *
     * @return the user transaction
     */
    public UserTransaction getUserTransaction() {
        UserTransaction ut = null;
        try {
            Context c = new InitialContext();
            ut = (UserTransaction) c.lookup("java:comp/UserTransaction");
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        return ut;
    }
 
    /**
     * Get the EntityManayger by JNDI
     *
     * @return the entity manager
     */
    public EntityManager getEntityManager() {
        EntityManager em = null;
 
        try {
            Context initCtx = new InitialContext();
            // The JSFPU must be written in the web.xml
            em = (EntityManager) initCtx.lookup("java:comp/env/JSFPU");
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        return em;
    }
 
    public void begin() throws NotSupportedException, SystemException {
        getUserTransaction().begin();
    }
 
    public void commit() throws SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException, SystemException {
        getUserTransaction().commit();
    }
 
    public int getStatus() throws SystemException {
        return getUserTransaction().getStatus();
    }
 
    public void rollback() throws IllegalStateException, SecurityException, SystemException {
        getUserTransaction().rollback();
    }
 
    public void setRollbackOnly() throws IllegalStateException, SystemException {
        getUserTransaction().setRollbackOnly();
    }
 
    public void setTransactionTimeout(int timeout) throws SystemException {
        getUserTransaction().setTransactionTimeout(timeout);
    }
}

Мы могли бы использовать введенную UserTransaction от JSF, но мы решили использовать поиск JNDI. Существует несколько вызовов Primefaces, которые вызываются вне контекста JSF, вы можете получить некоторое исключение NullPointerException, если попытаетесь получить доступ к ссылкам, которые должны быть введены. Есть несколько способов работать с этой проблемой, но мы будем использовать JNDI Lookup для EntityManager и UserTransaction.

Наш последний класс будет PlayerDAO:

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
package com.dao;
 
import java.io.Serializable;
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.Query;
 
import com.connection.MyTransaction;
import com.model.Player;
 
public class PlayerDAO implements Serializable {
 
    private static final long serialVersionUID = 1L;
    private MyTransaction myTransaction;
 
    public PlayerDAO(MyTransaction transaction) {
        this.myTransaction = transaction;
    }
 
    /**
     * Find players in the DB
     *
     * @param startingAt the first "row" db that the query will search
     * @param maxPerPage the amount of records allowed per "trip" in the DB
     * @return a players java.util.List
     */
    @SuppressWarnings("unchecked")
    public List<Player> findPlayers(int startingAt, int maxPerPage) {
        EntityManager em = myTransaction.getEntityManager();
 
        // regular query that will search for players in the db
        Query query = em.createQuery("select p from Player p");
        query.setFirstResult(startingAt);
        query.setMaxResults(maxPerPage);
 
        return query.getResultList();
    }
 
    /**
     * Creates 100 players in the DB
     */
    public void create100Players() {
        EntityManager em = myTransaction.getEntityManager();
 
        Player player;
 
        for (int x = 0; x < 100; x++) {
            player = new Player();
            player.setName("Player: " + x);
            player.setAge(x);
            em.persist(player);
        }
 
        em.flush();
    }
 
    /**
     * Sum the number of players in the DB
     *
     * @return an int with the total
     */
    public int countPlayersTotal() {
        EntityManager em = myTransaction.getEntityManager();
        Query query = em.createQuery("select COUNT(p) from Player p");
 
        Number result = (Number) query.getSingleResult();
 
        return result.intValue();
    }
}

В классе PlayerDAO у нас есть только 3 метода для работы с нумерацией страниц. Обратите внимание, что нет способа перечислить всех игроков в нашей базе данных.

Создайте папку «YOU_JBOSS / modules / org / hsqldb / main». Внутри этой папки создайте файл с именем «module.xml». Напишите код ниже в файле «module.xml»:

1
2
3
4
5
6
7
8
9
<module xmlns="urn:jboss:module:1.0" name="org.hsqldb">
    <resources>
        <resource-root path="hsqldb.jar" />
    </resources>
    <dependencies>
        <module name="javax.api" />
        <module name="javax.transaction.api" />
    </dependencies>
</module>

Скопируйте файл «hsqldb.jar» в папку «main», которую вы только что создали. Этот файл вы найдете внутри HSQLDB-файла, который вы скачали по пути «hsqldb-2.2.8.zip/hsqldb-2.2.8/hsqldb/lib».

Отредактируйте файл «YOU_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
<datasource jndi-name="java:/JSFDS" pool-name="JSFDS_POOL"
    enabled="true" jta="true" use-java-context="true" use-ccm="true">
    <connection-url>
        jdbc:hsqldb:mem:jsfinmemory
    </connection-url>
    <driver>
        hsqldb
    </driver>
    <pool>
        <prefill>false</prefill>
        <use-strict-min>false</use-strict-min>
        <flush-strategy>FailingConnectionOnly</flush-strategy>
    </pool>
    <security>
        <user-name>
            sa
        </user-name>
        <password>
        </password>
    </security>
</datasource>

В узле драйверов добавьте:

1
<driver name="hsqldb" module="org.hsqldb"/>

Ссылка: Ленивая JSF Datatable Pagination (Primefaces) от нашего партнера JCG Хеберта Коэльо в блоге uaiHebert .