displaytag數(shù)據(jù)庫(kù)分頁(yè)方法及導(dǎo)出數(shù)據(jù)的問(wèn)題處理
文章分類: Java編程
最近在使用 springside 配合 struts2 + spring2.5 + hibernate3 做項(xiàng)目,為了不重復(fù)發(fā)明輪子(其實(shí)是懶,而且項(xiàng)目時(shí)間有限),使用到了 displaytag 作為頁(yè)面顯示的組件。 displaytag 具有分頁(yè)顯示,導(dǎo)出報(bào)表,頁(yè)面排序等功能。與其相似的還有另外一個(gè)工具叫做 extremecomponent 。雖然 displaytag 功能很多,但是也有很多問(wèn)題:第一就是他的默認(rèn)分頁(yè)和排序是基于內(nèi)存分頁(yè)的,這個(gè)在實(shí)際項(xiàng)目中是不太可行的,所以需要修改。第二就是他的導(dǎo)出報(bào)表的功能,他主要能導(dǎo)出 5 種格式 csv , xls , xml , pdf , rtf (主要是 pdf 和 excel ),其中默認(rèn)的 pdf 和 excel 導(dǎo)出都有亂碼問(wèn)題。
?
本文主要是講述如何解決這 2 個(gè)問(wèn)題。
displaytag 官網(wǎng): http://displaytag.sourceforge.net/1.2/
基本的配置和使用你可以從官網(wǎng)上了解到,本文不做說(shuō)明。
本文的解決方法一部分是來(lái)自于網(wǎng)絡(luò)其他文章。
好了首先是第一個(gè)分頁(yè)問(wèn)題,我們要使 displaytag 能夠用數(shù)據(jù)庫(kù)分頁(yè),而不僅僅是內(nèi)存分頁(yè)。 displaytag 其實(shí)已經(jīng)提供了 2 種方法讓你實(shí)現(xiàn)數(shù)據(jù)庫(kù),在其官網(wǎng)中有介紹
http://displaytag.sourceforge.net/1.2/tut_externalSortAndPage.html
我使用的是第一種實(shí)現(xiàn),實(shí)現(xiàn) displaytag 的 PaginatedList 接口:
?
- import ?java.util.List; ??
- ??
- import ?org.displaytag.pagination.PaginatedList; ??
- import ?org.displaytag.properties.SortOrderEnum; ??
- import ?org.springside.modules.orm.Page; ??
- ??
- /** ?
- ?*?實(shí)現(xiàn)displaytag的數(shù)據(jù)庫(kù)的分頁(yè)接口 ?
- ?*?并集成springside的Page類, ?
- ?*?這樣可以同時(shí)使用?springside的數(shù)據(jù)庫(kù)分頁(yè)功能及displaytag的分頁(yè)顯示功能 ?
- ?*?@author?tianjl ?
- ?* ?
- ?*?@param?<T> ?
- ?*/ ??
- public ? class ?DBPaginatedList<T>? extends ?Page<T>? implements ?PaginatedList?{ ??
- ??
- ???? private ?SortOrderEnum?sortDirection?=?SortOrderEnum.ASCENDING; ??
- ???? private ?String?sortCriterion; ??
- ??
- ???? //?--?構(gòu)造函數(shù)?--// ??
- ???? public ?DBPaginatedList()?{ ??
- ???????? super (); ??
- ????} ??
- ??
- ???? public ?DBPaginatedList( int ?pageSize)?{ ??
- ???????? super (pageSize); ??
- ????} ??
- ??
- ???? public ? int ?getFullListSize()?{ ??
- ???????? return ?( int )?totalCount; ??
- ????} ??
- ??
- ???? public ?List<T>?getList()?{ ??
- ???????? return ?result; ??
- ????} ??
- ??
- ???? public ? int ?getObjectsPerPage()?{ ??
- ???????? return ?pageSize; ??
- ????} ??
- ??
- ???? public ? int ?getPageNumber()?{ ??
- ???????? return ?pageNo; ??
- ????} ??
- ??
- ???? public ? void ?setSortCriterion(String?fieldN)?{ ??
- ???????? this .sortCriterion?=?(fieldN?==? null ?||? "null" .equals(fieldN))??? "1" ??
- ????????????????:?fieldN; ??
- ????} ??
- ??
- ???? public ?String?getSortCriterion()?{ ??
- ???????? return ? this .sortCriterion; ??
- ????} ??
- ??
- ???? public ? void ?setSortDirection(String?dir)?{ ??
- ???????? if ?(dir?==? null ?||? "null" .equals(dir)?||? "asc" .equalsIgnoreCase(dir))?{ ??
- ????????????sortDirection?=?SortOrderEnum.ASCENDING; ??
- ????????}? else ?{ ??
- ????????????sortDirection?=?SortOrderEnum.DESCENDING; ??
- ????????} ??
- ????} ??
- ???? ??
- ???? public ? void ?setSortDirection(SortOrderEnum?sortDirection)?{ ??
- ???????? this .sortDirection?=?sortDirection; ??
- ????} ??
- ??
- ???? public ?String?getSortDirectionStr()?{ ??
- ???????? if ?(sortDirection?==?SortOrderEnum.ASCENDING) ??
- ???????????? return ? "ASC" ; ??
- ???????? else ??
- ???????????? return ? "DESC" ; ??
- ????} ??
- ??
- ???? public ?SortOrderEnum?getSortDirection()?{ ??
- ???????? return ?sortDirection; ??
- ????} ??
- ??
- ???? public ?String?getSearchId()?{ ??
- ???????? return ?Integer.toHexString(pageSize?*? 10000 ?+?pageNo); ??
- ????} ??
- ??
- }??
import java.util.List; import org.displaytag.pagination.PaginatedList; import org.displaytag.properties.SortOrderEnum; import org.springside.modules.orm.Page; /** * 實(shí)現(xiàn)displaytag的數(shù)據(jù)庫(kù)的分頁(yè)接口 * 并集成springside的Page類, * 這樣可以同時(shí)使用 springside的數(shù)據(jù)庫(kù)分頁(yè)功能及displaytag的分頁(yè)顯示功能 * @author tianjl * * @param <T> */ public class DBPaginatedList<T> extends Page<T> implements PaginatedList { private SortOrderEnum sortDirection = SortOrderEnum.ASCENDING; private String sortCriterion; // -- 構(gòu)造函數(shù) --// public DBPaginatedList() { super(); } public DBPaginatedList(int pageSize) { super(pageSize); } public int getFullListSize() { return (int) totalCount; } public List<T> getList() { return result; } public int getObjectsPerPage() { return pageSize; } public int getPageNumber() { return pageNo; } public void setSortCriterion(String fieldN) { this.sortCriterion = (fieldN == null || "null".equals(fieldN)) ? "1" : fieldN; } public String getSortCriterion() { return this.sortCriterion; } public void setSortDirection(String dir) { if (dir == null || "null".equals(dir) || "asc".equalsIgnoreCase(dir)) { sortDirection = SortOrderEnum.ASCENDING; } else { sortDirection = SortOrderEnum.DESCENDING; } } public void setSortDirection(SortOrderEnum sortDirection) { this.sortDirection = sortDirection; } public String getSortDirectionStr() { if (sortDirection == SortOrderEnum.ASCENDING) return "ASC"; else return "DESC"; } public SortOrderEnum getSortDirection() { return sortDirection; } public String getSearchId() { return Integer.toHexString(pageSize * 10000 + pageNo); } }
?
?
這里要講一下, Page 類是 springside 提供的對(duì)分頁(yè)功能的封裝。這里你應(yīng)該去掉繼承 Page 類,并配合你自己的數(shù)據(jù)庫(kù)分頁(yè)功能。在 Page 類中,有一個(gè)內(nèi)部的 List 對(duì)象,存放著真實(shí)的結(jié)果集數(shù)據(jù)。 displaytag 在分析時(shí),會(huì)判斷你傳給他的對(duì)象是否實(shí)現(xiàn)了 PaginatedList 接口,如果實(shí)現(xiàn)了,它會(huì)從該對(duì)象中調(diào)用 getList() 方法,獲取結(jié)果集。所以在你的使用中,你應(yīng)該注意你的數(shù)據(jù)庫(kù)分頁(yè)代碼和 PaginatedList 接口的實(shí)現(xiàn)類的配合。
- public ? interface ?PaginatedList{ ??
- ???? /** ?
- ?????*?獲取分頁(yè)的結(jié)果集 ?
- ?????*/ ??
- ????List?getList(); ??
- ??
- ???? /** ?
- ?????*?獲取當(dāng)前頁(yè)數(shù) ?
- ?????*/ ??
- ???? int ?getPageNumber(); ??
- ??
- ???? /** ?
- ?????*?獲取每頁(yè)的個(gè)數(shù) ?
- ?????*/ ??
- ???? int ?getObjectsPerPage(); ??
- ??
- ???? /** ?
- ?????*?獲取整個(gè)結(jié)果集的個(gè)數(shù) ?
- ?????*/ ??
- ???? int ?getFullListSize(); ??
- ??
- ???? /** ?
- ?????*?獲取根據(jù)哪一列排序 ?
- ?????*/ ??
- ????String?getSortCriterion(); ??
- ??
- ???? /** ?
- ?????*?升序還是降序 ?
- ?????*/ ??
- ????SortOrderEnum?getSortDirection(); ??
- ??
- ???? /** ?
- ?????*?返回一個(gè)查詢的id ?
- ?????*/ ??
- ????String?getSearchId(); ??
- }??
public interface PaginatedList{ /** * 獲取分頁(yè)的結(jié)果集 */ List getList(); /** * 獲取當(dāng)前頁(yè)數(shù) */ int getPageNumber(); /** * 獲取每頁(yè)的個(gè)數(shù) */ int getObjectsPerPage(); /** * 獲取整個(gè)結(jié)果集的個(gè)數(shù) */ int getFullListSize(); /** * 獲取根據(jù)哪一列排序 */ String getSortCriterion(); /** * 升序還是降序 */ SortOrderEnum getSortDirection(); /** * 返回一個(gè)查詢的id */ String getSearchId(); }
?
?
這里請(qǐng)注意,你的數(shù)據(jù)庫(kù)分頁(yè)代碼和 displaytag 的分頁(yè)其實(shí)是 2 個(gè)不同的實(shí)現(xiàn),也就是說(shuō),你在之后的使用中,要同時(shí)為你數(shù)據(jù)庫(kù)分頁(yè)的代碼設(shè)置分頁(yè)值,排序值,并且也要為 PaginatedList 接口的實(shí)現(xiàn)類設(shè)置分頁(yè)值及排序值。 當(dāng)然你如果設(shè)計(jì)的好,能將 2 者柔和在一起,你可以只設(shè)置一次。我這里還是設(shè)置 2 次值的。 我這里寫(xiě)了個(gè)工具類還是設(shè)置 2 次值的。他從request中獲取分頁(yè)參數(shù),放到 PaginatedList 的實(shí)現(xiàn)類中,實(shí)際的數(shù)據(jù)庫(kù)分頁(yè)參數(shù)由struts2自動(dòng)封裝到action中的Page對(duì)象中,其實(shí)這個(gè)類寫(xiě)的有些多余,完全可以在 PaginatedList 的實(shí)現(xiàn)類內(nèi)部解決問(wèn)題,根本不需要引入HttpServletRequest 。
- /** ?
- ?*?分頁(yè)工具類 ?
- ?*? ?
- ?*?@author?tianjl ?
- ?*? ?
- ?*/ ??
- public ? class ?PaginationUtil?{ ??
- ??
- ???? /** ?
- ?????*?該方法用于displaytag的參數(shù)到springside的page的分頁(yè)參數(shù)做轉(zhuǎn)換 ?
- ?????*? ?
- ?????*?@param?request ?
- ?????*????????????(HttpServletRequest)?用于獲取請(qǐng)求參數(shù) ?
- ?????*?@param?page ?
- ?????*????????????(DBPaginatedList)?springside的Page對(duì)象 ?
- ?????*/ ??
- ???? public ? static ? void ?pageInfoPopulate(HttpServletRequest?request, ??
- ????????????DBPaginatedList?page)?{ ??
- ???????? if ?(request?==? null ?||?page?==? null ) ??
- ???????????? return ; ??
- ???????? else ?{ ??
- ????????????String?pagestr?=?request.getParameter( "page" ); ??
- ????????????String?sort?=?request.getParameter( "sort" ); ??
- ????????????String?dir?=?request.getParameter( "dir" ) ??
- ???????????? if ?(!StringUtils.isBlank(pagestr))?{ ??
- ????????????????page.setPageNo(NumberUtils.toInt(pagestr)); ??
- ????????????} ??
- ???????????? if ?(!StringUtils.isBlank(sort))?{ ??
- ????????????????page.setOrderBy(sort); ??
- ????????????????page.setSortCriterion(sort); ??
- ????????????} ??
- ???????????? if ?(!StringUtils.isBlank(dir))?{ ??
- ???????????????? if ?(StringUtils.equals(Page.ASC,?dir))?{ ??
- ????????????????????page.setOrder(Page.ASC); ??
- ????????????????}? else ?{ ??
- ????????????????????page.setOrder(Page.DESC); ??
- ????????????????} ??
- ????????????????page.setSortDirection(dir); ??
- ????????????} ??
- ????????} ??
- ????} ??
- }??
/** * 分頁(yè)工具類 * * @author tianjl * */ public class PaginationUtil { /** * 該方法用于displaytag的參數(shù)到springside的page的分頁(yè)參數(shù)做轉(zhuǎn)換 * * @param request * (HttpServletRequest) 用于獲取請(qǐng)求參數(shù) * @param page * (DBPaginatedList) springside的Page對(duì)象 */ public static void pageInfoPopulate(HttpServletRequest request, DBPaginatedList page) { if (request == null || page == null) return; else { String pagestr = request.getParameter("page"); String sort = request.getParameter("sort"); String dir = request.getParameter("dir") if (!StringUtils.isBlank(pagestr)) { page.setPageNo(NumberUtils.toInt(pagestr)); } if (!StringUtils.isBlank(sort)) { page.setOrderBy(sort); page.setSortCriterion(sort); } if (!StringUtils.isBlank(dir)) { if (StringUtils.equals(Page.ASC, dir)) { page.setOrder(Page.ASC); } else { page.setOrder(Page.DESC); } page.setSortDirection(dir); } } } }
?然后頁(yè)面中寫(xiě)上displaytag的標(biāo)簽:
- <display:table?id= "content" ?name= "pageList" ?requestURI= "/security/user.do" ? ??
- ????size= "totalCount" ?pagesize= "${pageList.pageSize?}" ?partialList= "true" > ??
- ????<display:column?property= "id" ?sortable= "true" ?style= "width:2%" /> ??
- ????<display:column?property= "name" ?title= "姓名" ?sortable= "true" ?/> ??
- ????<display:column?property= "loginName" ?title= "登錄名" ?sortable= "true" ?/> ??
- ????<display:column?property= "email" ?title= "郵箱" ?sortable= "true" ?/> ??
- </display:table>??
<display:table id="content" name="pageList" requestURI="/security/user.do" size="totalCount" pagesize="${pageList.pageSize }" partialList="true"> <display:column property="id" sortable="true" style="width:2%"/> <display:column property="name" title="姓名" sortable="true" /> <display:column property="loginName" title="登錄名" sortable="true" /> <display:column property="email" title="郵箱" sortable="true" /> </display:table>
?
?
這里有幾個(gè)點(diǎn)要注意, size 屬性中必須指定一個(gè)總頁(yè)數(shù),而且必須是 int 型的, springside 中 Page 類的總頁(yè)數(shù)是 long 型的,所以我又自己定義了個(gè) totalCount ,將值給 size 屬性。 partialList 屬性必須指定為 true ,這樣 displaytag 才會(huì)使用你的分頁(yè)。
到這里已經(jīng)可以使 displaytag 使用你提供的數(shù)據(jù)庫(kù)分頁(yè)了。
然后,我們來(lái)解決導(dǎo)出數(shù)據(jù)的問(wèn)題。導(dǎo)出數(shù)據(jù)是個(gè)很常用的功能,基本上是個(gè)系統(tǒng)都要這個(gè)功能。 displaytag 是提供了該功能的,但是問(wèn)題太多。一個(gè)是當(dāng)你讓 displaytag 使用了數(shù)據(jù)庫(kù)分頁(yè)后,只能導(dǎo)出當(dāng)前頁(yè)的數(shù)據(jù);另一個(gè)問(wèn)題是導(dǎo)出數(shù)據(jù)中文亂碼的問(wèn)題。
第一個(gè)問(wèn)題需要修改源代碼,給與實(shí)際解決方案文章在此:
http://superwing.iteye.com/blog/427407
你需要在 org.displaytag.tags.TableTag.java 中,將 1065 以及 1066 兩行進(jìn)行替換:
將
- PaginationHelper?paginationHelper?=? new ?PaginationHelper(pageNumber,?pagesize); ??
- this .tableIterator?=?paginationHelper.getIterator( this .list);???
PaginationHelper paginationHelper = new PaginationHelper(pageNumber, pagesize); this.tableIterator = paginationHelper.getIterator(this.list);
?替換為:
- if (MediaTypeEnum.HTML.equals( this .currentMediaType)){ ??
- ????PaginationHelper?paginationHelper?=? new ?PaginationHelper(pageNumber,?pagesize); ??
- ???? this .tableIterator?=?paginationHelper.getIterator( this .list); ??
- } else ?{ ??
- ???? this .tableIterator?=?IteratorUtils.getIterator( this .list); ??
- }???
if(MediaTypeEnum.HTML.equals(this.currentMediaType)){ PaginationHelper paginationHelper = new PaginationHelper(pageNumber, pagesize); this.tableIterator = paginationHelper.getIterator(this.list); }else { this.tableIterator = IteratorUtils.getIterator(this.list); }
?
在你的 action 種的代碼中,你需要知道用戶是否點(diǎn)擊了導(dǎo)出超鏈接,通過(guò)以下代碼可以獲取該值:
?
- String?exportValue?=?request.getParameter(TableTagParameters.PARAMETER_EXPORTING);??
String exportValue = request.getParameter(TableTagParameters.PARAMETER_EXPORTING);
?
?
如果該值不為空,則表示用戶按了導(dǎo)出,否則就是沒(méi)有。你應(yīng)該根據(jù)此值來(lái)選擇是查詢部分內(nèi)容還是全部?jī)?nèi)容。比如:
- if ?(exportValue?==? null ?||?exportValue.equals( "" ))?{ ??
- ???? //非導(dǎo)出,根據(jù)查詢條件filters進(jìn)行分頁(yè)查詢 ??
- ????pageList?=?securityEntityManager.searchUser(pageList,?filters); ??
- }? else ?{ ??
- ???? //導(dǎo)出,根據(jù)查詢條件filters查詢出所有結(jié)果集 ??
- ????List<User>?userList?=?securityEntityManager.getAllUser(pageList,?filters); ??
- ????pageList.setResult(userList); ??
- }??
if (exportValue == null || exportValue.equals("")) { //非導(dǎo)出,根據(jù)查詢條件filters進(jìn)行分頁(yè)查詢 pageList = securityEntityManager.searchUser(pageList, filters); } else { //導(dǎo)出,根據(jù)查詢條件filters查詢出所有結(jié)果集 List<User> userList = securityEntityManager.getAllUser(pageList, filters); pageList.setResult(userList); }?
好,第一個(gè)導(dǎo)出問(wèn)題解決完畢。
接下去是亂碼問(wèn)題,我這里只說(shuō)明 excel 和 pdf 的處理。解決方法也是來(lái)自于網(wǎng)絡(luò)。
excel 的導(dǎo)出處理相對(duì)簡(jiǎn)單,在你項(xiàng)目的 classpath 中加入 displaytag.properties 文件,加入以下代碼即可。
- export.excel. class =org.displaytag.export.excel.ExcelHssfView??
export.excel.class=org.displaytag.export.excel.ExcelHssfView
? 注意該屬性表示使displaytag使用poi導(dǎo)出excel,所以你需要加入displaytag-export-poi-1.2.jar和poi的jar包,而且只能使用poi3.2版本的jar包,其他版本都會(huì)報(bào)錯(cuò)說(shuō)NoSuchMethod,但是我看poi源碼,明明是有該方法的,不知道什么原因。(我使用過(guò)poi3.5和poi3.0都報(bào)了該錯(cuò))
pdf的亂碼處理,需要下載iTextAsian.jar,然后加入你的classpath,再修改源代碼org.displaytag.export.PdfView的115行處:
- //將 ??
- smallFont?=?FontFactory.getFont(FontFactory.HELVETICA,? 7 ,?Font.NORMAL,? new ?Color( 0 ,? 0 ,? 0 )); ??
- //替換為: ??
- smallFont?=?FontFactory.getFont( "STSong-Light" , "UniGB-UCS2-H" ,?Font.DEFAULTSIZE);??
//將 smallFont = FontFactory.getFont(FontFactory.HELVETICA, 7, Font.NORMAL, new Color(0, 0, 0)); //替換為: smallFont = FontFactory.getFont("STSong-Light","UniGB-UCS2-H", Font.DEFAULTSIZE);
?這樣pdf亂碼也可以解決了。
最后再引申幾個(gè)我遇到的其他問(wèn)題:
excel導(dǎo)出的內(nèi)容標(biāo)題看不清,這個(gè)需要修改源碼,找到org.displaytag.export.excel.ExcelHssfView的101到107行處是設(shè)置標(biāo)題樣式的,主要是把102行:
- //將 ??
- headerStyle.setFillPattern(HSSFCellStyle.FINE_DOTS); ??
- //替換為: ??
- headerStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);??
//將 headerStyle.setFillPattern(HSSFCellStyle.FINE_DOTS); //替換為: headerStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
?這樣,導(dǎo)出的標(biāo)題就不會(huì)看不清了。
另外一個(gè)問(wèn)題,是因?yàn)閐isplaytag和struts2一起使用導(dǎo)致的,由于displaytag生成的參數(shù)中帶“-”,而struts2中接受的參數(shù)中默認(rèn)又不允許有“-”,控制臺(tái)會(huì)報(bào)錯(cuò),但是卻不影響使用。不過(guò)控制臺(tái)老報(bào)錯(cuò),看著也不爽。
在 http://hi.baidu.com/j2ee_cn/blog/item/688a03db5a48846cd1164e66.html
說(shuō)修改xwork源碼可以解決該問(wèn)題,我照做確實(shí)解決了,但是又出現(xiàn)了其他問(wèn)題,struts2不會(huì)替我自動(dòng)封裝參數(shù)到action的對(duì)象中了,所以我又改了回來(lái)。大家如果用的也是struts2可以試試,是不是有這樣的問(wèn)題。
另一個(gè)方法是只要將,devMode設(shè)置為false就不會(huì)報(bào)這個(gè)錯(cuò)了,這個(gè)的確可以解決該問(wèn)題。
displaytag數(shù)據(jù)庫(kù)分頁(yè)方法及導(dǎo)出數(shù)據(jù)的問(wèn)題處理
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
