hibernate分頁

本文介紹一種分頁組件的完整代碼,最後封裝了一個簡單的jsp自定義標籤

分頁效果如下:



沒有加頁面效果,只是意思一下。這個分頁的功能比較簡單,不過更復雜的分頁功能,原理也是差不多的

首先是Page對象

Java代碼
1.public class Page {
2.
3. private static final int DEFAULT_PAGE_SIZE = 10;
4.
5. private static final int DEFAULT_CURRENT_PAGE = 1;
6.
7. private int currentPage;// 當前頁數,通常在Action層設置
8.
9. private int pageSize;// 每頁記錄數,通常在Action層設置
10.
11. private int totalCount;// 總記錄數,在DAO層設置
12.
13. public Page(int currentPage, int pageSize) {
14. this.currentPage = currentPage;
15. this.pageSize = pageSize;
16. }
17.
18. public Page(int currentPage) {
19. this.currentPage = currentPage;
20. this.pageSize = DEFAULT_PAGE_SIZE;
21. }
22.
23. public Page() {
24. this.currentPage = DEFAULT_CURRENT_PAGE;
25. this.pageSize = DEFAULT_PAGE_SIZE;
26. }
27.
28. public int getFirstIndex() {
29. return pageSize * (currentPage - 1);
30. }
31.
32. public boolean hasPrevious() {
33. return currentPage > 1;
34. }
35.
36. public boolean hasNext() {
37. return currentPage < getTotalPage();
38. }
39.
40. public int getTotalPage() {
41.
42. long remainder = totalCount % this.getPageSize();
43.
44. if (0 == remainder) {
45. return totalCount / this.getPageSize();
46. }
47.
48. return totalCount / this.getPageSize() + 1;
49. }
50.}
public class Page {

private static final int DEFAULT_PAGE_SIZE = 10;

private static final int DEFAULT_CURRENT_PAGE = 1;

private int currentPage;// 當前頁數,通常在Action層設置

private int pageSize;// 每頁記錄數,通常在Action層設置

private int totalCount;// 總記錄數,在DAO層設置

public Page(int currentPage, int pageSize) {
this.currentPage = currentPage;
this.pageSize = pageSize;
}

public Page(int currentPage) {
this.currentPage = currentPage;
this.pageSize = DEFAULT_PAGE_SIZE;
}

public Page() {
this.currentPage = DEFAULT_CURRENT_PAGE;
this.pageSize = DEFAULT_PAGE_SIZE;
}

public int getFirstIndex() {
return pageSize * (currentPage - 1);
}

public boolean hasPrevious() {
return currentPage > 1;
}

public boolean hasNext() {
return currentPage < getTotalPage();
}

public int getTotalPage() {

long remainder = totalCount % this.getPageSize();

if (0 == remainder) {
return totalCount / this.getPageSize();
}

return totalCount / this.getPageSize() + 1;
}
}

省略了必須的getter和setter方法。這裏主要有3個字段currentPage、pageSize、totalCount,分別表示當前頁、每頁記錄數、總記錄數。基本上所有的分頁組件,都需要這些字段

其實總頁數totalPage也是必須的,但是這個字段是由pageSize和totalCount算出來的,所以即時計算得到比較好,如果也作爲一個字段的話,那麼和另外2個字段就不正交

getFirstIndex()方法也很重要,因爲後面查詢數據庫的時候,需要作爲第一條記錄的標識,作爲參數傳給查詢數據庫的方法

下面是DAO的寫法

Java代碼
1.public interface IBookDAO extends IGenericDAO<Book> {
2.
3. public Book queryByIsbn(String isbn);
4.
5. public List<Book> queryByNameWithPage(String name, Page page);
6.
7. public List<Book> queryByNameWithoutPage(String name);
8.
9.}
public interface IBookDAO extends IGenericDAO<Book> {

public Book queryByIsbn(String isbn);

public List<Book> queryByNameWithPage(String name, Page page);

public List<Book> queryByNameWithoutPage(String name);

}

其中涉及到分頁查詢的就是queryByNameWithPage()方法,這個Page對象是從Action傳遞下來的

Java代碼
1.@Repository
2.public class BookDAO extends GenericDAO<Book> implements IBookDAO {
3.
4. public BookDAO() {
5. super(Book.class);
6. }
7.
8. @Override
9. public Book queryByIsbn(String isbn) {
10. String hql = "from Book b where b.isbn = ?";
11. return queryForObject(hql, new Object[] { isbn });
12. }
13.
14. @Override
15. public List<Book> queryByNameWithPage(String name, Page page) {
16. String hql = "from Book b where b.name = ?";
17. return queryForList(hql, new Object[] { name }, page);
18. }
19.
20. @Override
21. public List<Book> queryByNameWithoutPage(String name) {
22. String hql = "from Book b where b.name = ?";
23. return queryForList(hql, new Object[] { name });
24. }
25.
26.}
@Repository
public class BookDAO extends GenericDAO<Book> implements IBookDAO {

public BookDAO() {
super(Book.class);
}

@Override
public Book queryByIsbn(String isbn) {
String hql = "from Book b where b.isbn = ?";
return queryForObject(hql, new Object[] { isbn });
}

@Override
public List<Book> queryByNameWithPage(String name, Page page) {
String hql = "from Book b where b.name = ?";
return queryForList(hql, new Object[] { name }, page);
}

@Override
public List<Book> queryByNameWithoutPage(String name) {
String hql = "from Book b where b.name = ?";
return queryForList(hql, new Object[] { name });
}

}

這裏調用的是GenericDAO裏的方法queryForList()

Java代碼
1.@SuppressWarnings("unchecked")
2. protected List<T> queryForList(String hql, Object[] params, Page page) {
3.
4. generatePageTotalCount(hql, params, page);
5.
6. Query query = sessionFactory.getCurrentSession().createQuery(hql);
7. setQueryParams(query, params);
8. query.setFirstResult(page.getFirstIndex());
9. query.setMaxResults(page.getPageSize());
10. return query.list();
11. }
12.
13. /**
14. * 該方法會改變參數page的totalCount字段
15. *
16. * @param originHql
17. * 原始hql語句
18. * @param params
19. * 原始參數
20. * @param page
21. * 頁面對象
22. */
23. private void generatePageTotalCount(String originHql, Object[] params,
24. Page page) {
25. String generatedCountHql = "select count(*) " + originHql;
26. Query countQuery = sessionFactory.getCurrentSession().createQuery(
27. generatedCountHql);
28. setQueryParams(countQuery, params);
29. int totalCount = ((Long) countQuery.uniqueResult()).intValue();
30. page.setTotalCount(totalCount);
31. }
@SuppressWarnings("unchecked")
protected List<T> queryForList(String hql, Object[] params, Page page) {

generatePageTotalCount(hql, params, page);

Query query = sessionFactory.getCurrentSession().createQuery(hql);
setQueryParams(query, params);
query.setFirstResult(page.getFirstIndex());
query.setMaxResults(page.getPageSize());
return query.list();
}

/**
* 該方法會改變參數page的totalCount字段
*
* @param originHql
* 原始hql語句
* @param params
* 原始參數
* @param page
* 頁面對象
*/
private void generatePageTotalCount(String originHql, Object[] params,
Page page) {
String generatedCountHql = "select count(*) " + originHql;
Query countQuery = sessionFactory.getCurrentSession().createQuery(
generatedCountHql);
setQueryParams(countQuery, params);
int totalCount = ((Long) countQuery.uniqueResult()).intValue();
page.setTotalCount(totalCount);
}

這段代碼關鍵有2點

一個是調用Page對象的getFirstIndex()方法和getPageSize()方法,確定查詢結果的範圍

另一個是設置Page對象自身的totalCount字段,因爲Action裏持有該Page對象的引用,所以根據totalCount和pageSize計算出totalPage之後,就可以在前臺顯示出總頁數

接下來是Action層的寫法(中間的Service層只是起一個傳遞作用和事務控制作用,省略)

Java代碼
1.@Controller
2.@Scope("prototype")
3.public class BookAction extends ActionSupport {
4.
5. private static final long serialVersionUID = -4400311497910666205L;
6.
7. @Autowired
8. private IBookService bookService;
9.
10. private Page page;// 分頁組件
11.
12. private List<Book> books;// 查詢結果列表
13.
14. public String list() {
15. if (null == page) {
16. page = new Page();// 如果page對象爲空,說明不是通過點擊頁碼跳轉
17. }
18. books = bookService.getBooks(page);
19. return SUCCESS;
20. }
21.}
@Controller
@Scope("prototype")
public class BookAction extends ActionSupport {

private static final long serialVersionUID = -4400311497910666205L;

@Autowired
private IBookService bookService;

private Page page;// 分頁組件

private List<Book> books;// 查詢結果列表

public String list() {
if (null == page) {
page = new Page();// 如果page對象爲空,說明不是通過點擊頁碼跳轉
}
books = bookService.getBooks(page);
return SUCCESS;
}
}

這裏省略了與分頁無關的方法和字段,以及getter、setter方法

這裏重點是list()方法,如果是通過jsp頁面點擊“上一頁”、“下一頁”的鏈接進入此方法的,那麼struts2框架就會自動初始化Page對象。如果這個時候page對象爲空,那麼說明是用戶直接進入該頁面,就需要初始化一個Page對象(currentPage=1,表示是第一頁)

該Page對象此時的totalCount是0,在查詢之後,纔會根據查詢到的記錄總數,設置totalCount的值,由於Action持有此Page的引用,所以可以在前臺顯示出來

下面是前臺頁面的寫法

Jsp代碼
1.<div id="page_area">
2.
3. <s:if test="page.hasPrevious()">
4. <a href="list.action?page.currentPage=${page.currentPage-1}">上一頁</a>
5. </s:if>
6.
7. <span>第${page.currentPage}頁</span>
8. <span>共${page.getTotalPage()}頁</span>
9.
10. <s:if test="page.hasNext()">
11. <a href="list.action?page.currentPage=${page.currentPage+1}">下一頁</a>
12. </s:if>
13.
14. </div>
<div id="page_area">

<s:if test="page.hasPrevious()">
<a href="list.action?page.currentPage=${page.currentPage-1}">上一頁</a>
</s:if>

<span>第${page.currentPage}頁</span>
<span>共${page.getTotalPage()}頁</span>

<s:if test="page.hasNext()">
<a href="list.action?page.currentPage=${page.currentPage+1}">下一頁</a>
</s:if>

</div>

裏面用到了struts2的<s:if>標籤,還有${}表達式。我感覺${]表達式還是很方便的,struts2封裝的各種<s:>標籤我倒是不喜歡用,自己用html標籤開發,我覺得更靈活一點

這個分頁組件在各個頁面都可以用到,但是如果每個jsp都要拷貝這段代碼,就不好了,所以需要把它封裝成標籤

封裝後的效果是這樣的:

Jsp代碼
1.<wfm:page page="${page}" />
<wfm:page page="${page}" />

下面就介紹下這個自定義標籤的開發

首先需要在WEB-INF目錄下創建一個.tld文件,只要放在WEB-INF目錄下就可以了,所以一般會單獨建一個子目錄tld來保存



這個tld內容如下

Xml代碼
1.<?xml version="1.0" encoding="UTF-8" ?>
2.
3.<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5. xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
6. version="2.0">
7.
8. <description>Workforce Tag Lib</description>
9. <tlib-version>1.0</tlib-version>
10. <short-name>WorkforceTagLibrary</short-name>
11. <uri>/wfm-tags</uri>
12.
13. <tag>
14. <description>generate page bar</description>
15. <name>page</name>
16. <tag-class>com.huawei.inoc.framework.tag.PageTag</tag-class>
17. <body-content>empty</body-content>
18. <attribute>
19. <name>page</name>
20. <required>true</required>
21. <rtexprvalue>true</rtexprvalue>
22. </attribute>
23. </tag>
24.
25.</taglib>
<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">

<description>Workforce Tag Lib</description>
<tlib-version>1.0</tlib-version>
<short-name>WorkforceTagLibrary</short-name>
<uri>/wfm-tags</uri>

<tag>
<description>generate page bar</description>
<name>page</name>
<tag-class>com.huawei.inoc.framework.tag.PageTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>page</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

</taglib>

上面比較重要的元素是<uri>,後面在jsp頁面裏使用這個標籤的時候會用到,然後可以定義多個<tag>元素,每個都是一個標籤,命名都很清晰,就不用解釋了。其中<rtexprvalue>這個標籤,設置爲true之後,則此屬性支持變量

下面是標籤的實現類

Java代碼
1.public class PageTag extends SimpleTagSupport {
2.
3. private Page page;
4.
5. @Override
6. public void doTag() throws JspException, IOException {
7. String content = generateContent();
8. getJspContext().getOut().write(content);
9. }
10.
11. private String generateContent() {
12.
13. StringBuilder response = new StringBuilder();
14.
15. response.append("<div id=\"page_area\">");
16.
17. if (page.hasPrevious()) {
18. response.append("<a href=\"list.action?page.currentPage="
19. + (page.getCurrentPage() - 1) + "\">上一頁</a>");
20. }
21.
22. response.append("<span>第" + page.getCurrentPage() + "頁</span>");
23. response.append("<span>共" + page.getTotalPage() + "頁</span>");
24.
25. if (page.hasNext()) {
26. response.append("<a href=\"list.action?page.currentPage="
27. + (page.getCurrentPage() + 1) + "\">下一頁</a>");
28. }
29.
30. response.append("</div>");
31.
32. return response.toString();
33. }
34.
35. public Page getPage() {
36. return page;
37. }
38.
39. public void setPage(Page page) {
40. this.page = page;
41. }
42.
43.}
public class PageTag extends SimpleTagSupport {

private Page page;

@Override
public void doTag() throws JspException, IOException {
String content = generateContent();
getJspContext().getOut().write(content);
}

private String generateContent() {

StringBuilder response = new StringBuilder();

response.append("<div id=\"page_area\">");

if (page.hasPrevious()) {
response.append("<a href=\"list.action?page.currentPage="
+ (page.getCurrentPage() - 1) + "\">上一頁</a>");
}

response.append("<span>第" + page.getCurrentPage() + "頁</span>");
response.append("<span>共" + page.getTotalPage() + "頁</span>");

if (page.hasNext()) {
response.append("<a href=\"list.action?page.currentPage="
+ (page.getCurrentPage() + 1) + "\">下一頁</a>");
}

response.append("</div>");

return response.toString();
}

public Page getPage() {
return page;
}

public void setPage(Page page) {
this.page = page;
}

}

上面的代碼很簡單,jsp2.0之後,要實現自定義標籤是很容易的,繼承SimpleTagSupport類,實現doTag()方法即可,如果需要設置一些屬性的話,聲明爲字段,並添加getter和setter方法

最後是jsp頁面的引用方法

Jsp代碼
1.<%@ taglib prefix="wfm" uri="/wfm-tags"%>
<%@ taglib prefix="wfm" uri="/wfm-tags"%>


Jsp代碼
1.<wfm:page page="${page}" />
<wfm:page page="${page}" />

在比較早的版本里,還需要在web.xml裏增加tag-lib的配置,從某個版本的servlet規範之後(好像是3.0),就不需要了,容器會自動到WEB-INF目錄下加載所有的.tld文件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章