java web 通用的分页组件
通用的分页组件
有时候找到一个合适的web表格分页组件真是一件痛苦的事情,要么是没有完全封装的分页方法,使用起来比较麻烦,不够方便,要么使用方便,但很难同项目结合,也有许多开源分页组件,功能非常强大,但使用起来有很多问题,有些不好与系统结合,有些不好扩展,但总感觉有些浮肿,很多功能不够实用,也没多大意义,就此尝试写了一个分页组件,够用了,但也有不少问题,望大家共同修正.
1、 HTML元素java封装:
为了操作方便起见,
package commons.page;
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry;
public class HtmlElement { private String tagName; private Map<String, String> attributes = new HashMap<String, String>(); private List<HtmlElement> children = new ArrayList<HtmlElement>(); private String value = ""; private String text = "";
public HtmlElement(String tagName) { this.tagName = tagName; }
public void setValue(String value) { this.value = value; }
public List<HtmlElement> getChildren() { return children; }
public void addChild(HtmlElement element) { this.children.add(element); }
public void addAttribute(String name, String value) { this.attributes.put(name, value); }
public String getAttributeValue(String name) { return this.attributes.get(name); } @Override public String toString() { return this.toHtml(); } public String toHtml() { StringBuffer sb = new StringBuffer(); sb.append("<"); sb.append(this.tagName); sb.append(this.getAttr()); sb.append(">"); sb.append(this.value); for (HtmlElement e : this.children) { sb.append(e.toHtml()); } sb.append(this.text); sb.append("</"); sb.append(this.tagName); sb.append(">"); return sb.toString(); } protected String getAttr() { StringBuffer sb = new StringBuffer(); Set<Entry<String, String>> attr = this.attributes.entrySet(); for (Entry<String, String> entry : attr) { sb.append(" "); sb.append(entry.getKey()); sb.append("=/""); sb.append(entry.getValue()); sb.append("/""); } return sb.toString(); }
public void setText(String text) { this.text = text; } } |
例如:
HtmlElement div1 = new HtmlElement("div"); HtmlElement div2 = new HtmlElement("div"); HtmlElement span = new HtmlElement("span"); div1.addAttribute("class", "tuo"); div1.addAttribute("id", "dd1"); div1.addChild(div2); div1.addChild(span); div1.setValue("fds222222fds"); div1.setText("wwwwwwwww"); System.out.println(div1.toHtml()); |
生成:
<div id="dd1" class="tuo"> fds222222fds <div></div> <span></span> Wwwwwwwww </div> |
2、
数据表格类
package commons.page;
import java.util.Calendar; import java.util.List;
import commons.page.model.ArrayDataModel; import commons.page.model.DataModel; import commons.page.model.ListDataModel;
public class HtmlTable extends HtmlElement { private HtmlElement thead = new HtmlElement("thead"); private HtmlElement tbody = new HtmlElement("tbody"); private HtmlElement tfoot = new HtmlElement("tfoot"); private String[] header = null; private String[] footer = null; private DataModel dataModel = null; private int startRowIndex = -1;// 开始行索引 private int maxRowNum = -1;// 最大行数 private CellCallBack callBack;
public HtmlTable() { super("table"); } public void setCellCallBack(CellCallBack callBack) { this.callBack = callBack; } public void setMaxRowNum(int maxRowNum) { this.maxRowNum = maxRowNum; } public void setStartRowIndex(int startRowIndex) { this.startRowIndex = startRowIndex; } public void setHeader(String[] header) { this.header = header; } public void setHeader(String header) { this.header = header.split(","); } public void setFooter(String[] footer) { this.footer = footer; } public void setFooter(String footer) { this.footer = footer.split(","); } public void setDataModel(DataModel dataModel) { this.dataModel = dataModel; } public void setData(Object[][] data) { this.dataModel = new ArrayDataModel(); this.dataModel.setWrappedData(data); } public void setData(List data) { this.dataModel = new ListDataModel(); this.dataModel.setWrappedData(data); }
public void setTbody(HtmlElement tbody) { this.tbody = tbody; }
public void setTfoot(HtmlElement tfoot) { this.tfoot = tfoot; }
public void setThead(HtmlElement thead) { this.thead = thead; }
@Override public String toHtml() { String id = this.getAttributeValue("id"); if (id == null || "".equals(id)) { this.addAttribute("id", "table" + Calendar.getInstance().getTimeInMillis()); } this.process();
return super.toHtml(); } private void process() { if (this.header != null) { this.thead.getChildren().clear(); HtmlElement tr = new HtmlElement("tr"); for (String header : this.header) { HtmlElement th = new HtmlElement("th"); th.setText(header); tr.addChild(th); } this.thead.addChild(tr); this.addChild(this.thead); } if (this.dataModel != null) { if (this.callBack == null) { this.callBack = new CellCallBack() { public HtmlElement doCell(Object data) { HtmlRow tr = new HtmlRow(); if (data instanceof String[]) { String[] ds = (String[]) data; int len = ds.length; if (header != null) { if (len > header.length) { len = header.length; } } for (int i = 0; i < len; i++) { HtmlElement td = new HtmlElement("td"); td.setText(ds[i] == null ? "" : ds[i]); tr.addChild(td); } } else if (data instanceof Object[]) { Object[] os = (Object[]) data; int len = os.length; if (header != null) { if (len > header.length) { len = header.length; } } for (int i = 0; i < len; i++) { HtmlElement td = new HtmlElement("td"); td.setText(os[i] == null ? "" : os[i].toString()); tr.addChild(td); } } return tr; } }; } int startRow = 0; int endRow = 0; int j = this.dataModel.getRowCount(); if (this.startRowIndex > 0) { startRow = this.startRowIndex; } if (this.maxRowNum < 0) { endRow = this.dataModel.getRowCount(); } else { endRow = startRow + this.maxRowNum; } if (endRow > j) { endRow = j; } this.tbody.getChildren().clear();
for (int i = startRow; i < endRow; i++) { this.dataModel.setRowIndex(i); HtmlElement tr = this.callBack.doCell(this.dataModel.getRowData()); this.tbody.addChild(tr); } if (endRow - startRow < this.maxRowNum) { for (int i = 0; i < (this.maxRowNum - (endRow - startRow)); i++) { HtmlElement row = TableUtil.createRow(new String[this.header.length]); this.tbody.addChild(row); } } this.addChild(this.tbody); } if (this.footer != null) { this.tfoot.getChildren().clear(); HtmlElement tr = new HtmlElement("tr"); for (String footer : this.footer) { HtmlElement td = new HtmlElement("td"); td.setText(footer); tr.addChild(td); } this.tfoot.addChild(tr); this.addChild(this.tfoot); } } }
|
该类主要功能是将提供的表头,表尾数据及表格数据生成对应的HTML, 并且可以设置需要显示的数据内容(从某行开始到某行),并提供了多种数据模型供选择包括数组数据,List数据,并可以通过继承DataModel实现其中的方法来自定义.
3、 统一数据模型
package commons.page.model;
import java.util.ArrayList; import java.util.List;
public abstract class DataModel { private List _listeners; public void addDataModelListener(DataModelListener listener) { if (listener == null) throw new NullPointerException("listener"); if (_listeners == null) { _listeners = new ArrayList(); } _listeners.add(listener); } public DataModelListener[] getDataModelListeners() { if (_listeners == null) { return new DataModelListener[0]; } return (DataModelListener[]) _listeners.toArray(new DataModelListener[_listeners.size()]); } abstract public int getRowCount();
abstract public Object getRowData();
abstract public int getRowIndex();
abstract public Object getWrappedData(); abstract public boolean isRowAvailable();
public void removeDataModelListener(DataModelListener listener) { if (listener == null) throw new NullPointerException("listener"); if (_listeners != null) { _listeners.remove(listener); } } abstract public void setRowIndex(int rowIndex); abstract public void setWrappedData(Object data); }
|
DataModel来源于JSF中DataModel,并且有ArrayDataModel,ListDataModel, ResultDataModel, ScalarDataModel等多种实现,基本上有ArrayDataModel,ListDataModel就够用了,如果不够可以自己继承DataModel实现来实现.
4、 分页类
package commons.page;
import java.math.*;
/** * 分页操作类,该类来自于互联网,做了部分修改,以适应需求 * * @author life * */ public class Pager { private int totalRows; // 总行数 private int pageSize = 13; // 每页显示的行数 private int currentPage; // 当前页号 private int totalPages; // 总页数 private int startRow; // 当前页在数据库中的起始行
public Pager() { currentPage = 1; startRow = 0; }
private void process() { totalPages = totalRows / pageSize; int mod = totalRows % pageSize; if (mod > 0) { totalPages++; } if (this.currentPage <= 0) { currentPage = 1; } startRow = (currentPage - 1) * pageSize;
}
public int getStartRow() { return startRow; }
public int getTotalPages() { return totalPages; }
public int getCurrentPage() { return currentPage; }
public int getPageSize() { return pageSize; }
public void setTotalRows(int totalRows) { this.totalRows = totalRows; this.process(); }
// public void setStartRow(int startRow) { // this.startRow = startRow; // } // public void setTotalPages(int totalPages) { // this.totalPages = totalPages; // } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; this.process(); }
public void setPageSize(int pageSize) { this.pageSize = pageSize; this.process(); }
public int getTotalRows() { return totalRows; }
public void first() { currentPage = 1; startRow = 0; }
public void previous() { if (currentPage == 1) { return; } currentPage--; startRow = (currentPage - 1) * pageSize; }
public void next() { // System.out.print("next:"); if (currentPage < totalPages) { currentPage++; } startRow = (currentPage - 1) * pageSize; }
public void last() { currentPage = totalPages; startRow = (currentPage - 1) * pageSize; }
public void refresh(int _currentPage) { currentPage = _currentPage; if (currentPage > totalPages) { last(); } } }
|
Pager类来源于互联网,主要负责分页操作.
5、 最终分页类操作
package commons.page;
import javax.servlet.http.HttpServletRequest;
public class PageDataTable { private HtmlTable table = new HtmlTable();// 分页表格 private int operate = 0;// 操作,默认为第一页 private int gopage = 1;// 转到页码 private int cpage = 1;// 当前页 private int rowsize = 13;// 默认13行 private Pager pager = new Pager();// 分页操作类 private int mode = 0;// 模式0:内存分页,1:数据库查询分页 private PageDataCallBack callBack;// 适用于mode=1时(数据库查询分页),为HtmlTable提供DataModel数据模型回叫对象 private String id = "";// 分页表格ID,默认值为2098,该ID将在一个页面使用多个分页表格时作为唯一标识,标记正在操作的分页表格,如果有重复,将不能正常工作 private final static String DEFAULT_ID = "2098";
public PageDataTable(HttpServletRequest request, String id, int mode) { this.init(request, id, mode); }
public PageDataTable(HttpServletRequest request, int mode) { this.init(request, DEFAULT_ID, mode); }
public PageDataTable(HttpServletRequest request, String id) { this.init(request, id, 0); }
public PageDataTable(HttpServletRequest request) { this.init(request, DEFAULT_ID, 0); }
private void init(HttpServletRequest request, String id, int mode) { this.mode = mode; this.id = id; String op = request.getParameter("__OPERATE__" + this.id); String gopage = request.getParameter("__GOPAGE__" + this.id); String cpage = request.getParameter("__CPAGE__" + this.id); String maxsize = request.getParameter("__MAXROWSIZE__" + this.id);
// System.out.println("===" +op+"---"+gopage+"---"+cpage); this.operate = op == null ? 0 : ("".equals(op) ? 4 : Integer.parseInt(op)); this.gopage = gopage == null ? 1 : Integer.parseInt(gopage); this.cpage = cpage == null ? 1 : Integer.parseInt(cpage); this.rowsize = maxsize == null ? -1 : Integer.parseInt(maxsize);
}
public void setTable(HtmlTable table) { this.table = table; }
public void setPageSize(int pageSize) { this.pager.setPageSize(pageSize); }
public void setTotalRows(int totalRows) { this.pager.setTotalRows(totalRows); }
public void setPageDataCallBack(PageDataCallBack callBack) { this.callBack = callBack; }
public String render() { // 预分页操作处理 this.process(); // 内存分页设置其开始行索引为当前页开始索引,如果为数据库查询分页,则设置开始行索引为0 if (this.mode == 0) { this.table.setStartRowIndex(this.pager.getStartRow()); } else { this.table.setStartRowIndex(0); } // 设置表格最大显示行数 this.table.setMaxRowNum(this.pager.getPageSize()); // mode=1时,数据库查询分页设置分页表格DataModel对象,通常数据库查询也在此时执行 if (this.callBack != null) { this.table.setDataModel(this.callBack.doPage(this.pager.getStartRow(), this.pager.getPageSize())); } // 分页表格界面组织,容器DIV HtmlElement div = new HtmlElement("div"); div.addAttribute("class", "horse_data_page"); div.addAttribute("id", "horse_" + this.id); // 分页表格DIV HtmlElement div1 = new HtmlElement("div"); div1.addAttribute("class", "horse_page_table"); div1.addChild(this.table); div.addChild(div1); // 分页工具条 HtmlElement pageBar = new HtmlElement("Table"); pageBar.addAttribute("width", "100%"); HtmlElement row = new HtmlElement("tr"); row.addChild(this.getPageInfo1()); row.addChild(this.getPageInfo2()); row.addChild(this.getPageInfo3()); row.addChild(this.getPageInfo4()); pageBar.addChild(row); div.addChild(pageBar); // 操作用到的脚本 HtmlElement script = new HtmlElement("script"); script.addAttribute("language", "javascript"); script.setValue("function pageOperate" + this.id + "(value){var op=document.getElementById(/"__OPERATE__" + this.id + "/"); op.value=value; op.form.submit();}"); div.addChild(script); return div.toHtml(); }
/** * 处理翻页操作 */ private void process() { if (this.rowsize > 0) { this.pager.setPageSize(this.rowsize); } this.pager.setCurrentPage(this.cpage); if (this.operate == 0) { this.pager.first(); } else if (this.operate == 1) { this.pager.previous(); } else if (this.operate == 2) { this.pager.next(); } else if (this.operate == 3) { this.pager.last(); } else if (this.operate == 4) { this.gopage = (this.gopage > this.pager.getTotalPages()) ? this.pager.getTotalPages() : this.gopage; this.pager.setCurrentPage(this.gopage); }
}
/** * 分页信息1,输出记录信息,总共m页,n条记录 * * @return */ private HtmlElement getPageInfo1() { HtmlElement cell1 = new HtmlElement("td"); int st = this.pager.getStartRow() <= 0 ? 1 : this.pager.getStartRow(); st++; int ed = (this.pager.getStartRow() + this.pager.getPageSize()) > this.pager.getTotalRows() ? this.pager.getTotalRows() : (this.pager.getStartRow() + this.pager .getPageSize()); cell1.setValue("总共" + this.pager.getTotalPages() + "页," + this.pager.getTotalRows() + "条记录"); return cell1; }
/** * 分页信息2,输出 首页 上一页 下一页 末页 翻页信息 * * @return */ private HtmlElement getPageInfo2() {
HtmlElement cell = new HtmlElement("td"); HtmlElement a1 = new HtmlElement("a"); HtmlElement a2 = new HtmlElement("a"); HtmlElement a3 = new HtmlElement("a"); HtmlElement a4 = new HtmlElement("a"); a1.setValue(" 首页 "); a2.setValue(" 上一页 "); a3.setValue(" 下一页 "); a4.setValue(" 末页 ");
if (this.pager.getCurrentPage() > 1) { a1.addAttribute("href", "#"); a1.addAttribute("onclick", "pageOperate" + this.id + "('0')"); a2.addAttribute("href", "#"); a2.addAttribute("onclick", "pageOperate" + this.id + "('1')"); }
if (this.pager.getTotalPages() > this.pager.getCurrentPage()) { a3.addAttribute("href", "#"); a3.addAttribute("onclick", "pageOperate" + this.id + "('2')"); a4.addAttribute("href", "#"); a4.addAttribute("onclick", "pageOperate" + this.id + "('3')"); } cell.addChild(a1); cell.addChild(a2); if (this.pager.getTotalPages() >= 10) { int p = this.pager.getTotalPages() / 10; int st = (this.pager.getCurrentPage() - 5) > 0 ? (this.pager.getCurrentPage() - 5) : 1; int ed = ((this.pager.getCurrentPage() + 5) <= p) ? (this.pager.getCurrentPage() + 5) : p; for (int i = st; i < ed; i++) { HtmlElement a = new HtmlElement("a"); a.addAttribute("href", "#"); a.addAttribute("onclick", "pageOperate('5')"); cell.addChild(a); }
} cell.addChild(a3); cell.addChild(a4);
return cell; }
/** * 分页信息3 显示转到某一页 * * @return */ private HtmlElement getPageInfo3() { HtmlElement cell3 = new HtmlElement("td"); HtmlElement input = new HtmlElement("input"); input.addAttribute("id", "__GOPAGE__" + this.id); input.addAttribute("name", "__GOPAGE__" + this.id); input.addAttribute("type", "text"); input.addAttribute("size", "4");// input.addAttribute("onKeyUp", "this.value=this.value.replace(///D/g,'')"); input.addAttribute("value", this.pager.getCurrentPage() + ""); cell3.setValue("第" + input.toHtml() + "页"); HtmlElement b = new HtmlElement("button"); b.addAttribute("onclick", "pageOperate" + this.id + "('4')"); b.setValue("转到"); cell3.addChild(b); return cell3; }
/** * 分页栏信息列4 * * @return */ private HtmlElement getPageInfo4() { HtmlElement cell4 = new HtmlElement("td"); // 当前页隐藏域 HtmlElement input1 = new HtmlElement("input"); input1.addAttribute("id", "__CPAGE__" + this.id); input1.addAttribute("name", "__CPAGE__" + this.id); input1.addAttribute("type", "hidden"); input1.addAttribute("value", this.pager.getCurrentPage() + ""); // 操作隐藏域 HtmlElement input2 = new HtmlElement("input"); input2.addAttribute("id", "__OPERATE__" + this.id); input2.addAttribute("name", "__OPERATE__" + this.id); input2.addAttribute("type", "hidden"); // 当前最大显示数据行 HtmlElement input3 = new HtmlElement("input"); input3.addAttribute("id", "__MAXROWSIZE__" + this.id); input3.addAttribute("name", "__MAXROWSIZE__" + this.id); input3.addAttribute("value", (this.rowsize == -1 ? this.pager.getPageSize() : this.rowsize) + ""); input3.addAttribute("type", "hidden"); cell4.addChild(input1); cell4.addChild(input2); cell4.addChild(input3);
return cell4; } } |
这是最终操作分页的类,结合HtmlTable和Pager实现分页.
6、 例子:
package commons.page;
import java.util.ArrayList; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import commons.page.model.DataModel; import commons.page.model.ListDataModel;
public class TestPage { /** * 内存分页测试 * * @param request * @return */ public static String se(HttpServletRequest request) { int len = 125; String[][] data = new String[len][6]; for (int i = 0; i < data.length; i++) { data[i] = new String[] { "String列1-" + i, "String咧2-" + i, "String烈3-" + i, "String烈4-" + i, "String烈5-" + i, "String烈6-" + i }; } List<Object[]> d2 = new ArrayList<Object[]>(); for (int i = 0; i < len; i++) { Object[] o = new Object[] { "list列1-" + i, "list咧2-" + i, "list烈3-" + i, "list烈4-" + i, "list烈5-" + i, "list烈6-" + i }; d2.add(o); } HtmlTable t = new HtmlTable(); t.addAttribute("width", "100%"); t.addAttribute("border", "1"); // t.setData(data);//数组测试 t.setData(d2);// List测试 t.setHeader("标题1,标题3,标题4,标题6,标题5"); t.setCellCallBack(new CellCallBack() { public HtmlRow doCell(Object data) { // 数组测试 // String[] s = (String[] ) data; // HtmlRow row = TableUtil.createRow(new Object[] { // s[0],s[2],s[3],s[5],s[4]});
// List测试 Object[] s = (Object[]) data; HtmlRow row = TableUtil.createRow(new Object[] { s[0], s[2], s[3], s[5], s[4] });
return row; } });
PageDataTable p = new PageDataTable(request, 0); p.setPageSize(12); p.setTotalRows(len); p.setTable(t); return p.render(); }
/** * 查询分页测试 * * @param request * @return */ public static String se2(HttpServletRequest request) { final int len = 125; HtmlTable t = new HtmlTable(); t.setHeader("标题1,标题3,标题4,标题6,标题5"); PageDataTable p = new PageDataTable(request, "__my_2098_", 1); p.setPageSize(9); p.setTotalRows(len); p.setPageDataCallBack(new PageDataCallBack() { @Override public DataModel doPage(int startRow, int maxRow) { List<Object[]> d2 = new ArrayList<Object[]>(); // 下面为测试所用,模拟数据库查询,实际使用时将startRow,maxRow两个变量传入SQL语句查询数据库获取相应的记录 int endRow = (startRow + maxRow) > len ? len : (startRow + maxRow); for (int i = startRow; i < endRow; i++) { Object[] o = new Object[] { "list列1-" + i, "list咧2-" + i, "list烈3-" + i, "list烈4-" + i, "list烈5-" + i, "list烈6-" + i }; d2.add(o); } DataModel dataModel = new ListDataModel(); dataModel.setWrappedData(d2); return dataModel; } }); p.setTable(t); return p.render(); } }
JSP页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@page import="commons.page.TestPage"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <style type="text/css"> @IMPORT url("<%=request.getContextPath()%>/css/page_gird.css"); </style> </head> <body> <div onclick="op(1)">sadas</div> <form method="post"> <% out.print(TestPage.se(request)); %> <% out.print(TestPage.se2(request)); %> </form> </body> </html>
page_gird.css文件
@CHARSET "UTF-8"; .horse_data_page { height: auto; width: 100%; padding: 0px; margin: 0px; } .horse_data_page .horse_page_table { background-color: #FFFFFF; width: 100%; padding: 0px; margin: 0px; } .horse_data_page .horse_page_table table { width: 100%; border-collapse:collapse; border-spacing: 0px; empty-cells : show; table-layout:fixed; border-top-width: 4px; border-right-width: 0px; border-bottom-width: 4px; border-left-width: 0px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #3399CC; border-right-color: #CCCCCC; border-bottom-color: #3399CC; border-left-color: #CCCCCC; background-color: #FFFFFF; } .horse_data_page .horse_page_table table thead th { border: 1px solid #CCCCCC; padding: 4px; background-color: #E3E3E3; font-size:14px; text-align:center; white-space:nowrap; } .horse_data_page .horse_page_table table tbody td { border: 1px solid #CCCCCC; padding: 3px; font-size:12px; overflow:hidden; white-space:nowrap; text-overflow : ellipsis; }
.horse_data_page input { border: 1px solid #CCCCCC; background-color: #FFFFFF; font-size:12px; } .horse_data_page button { border: 1px solid #CCCCCC; background-color: #FFFFFF; font-size:12px; FILTER:progid:DXImageTransform.Microsoft.Gradient(gradientType=0,startColorstr='#EBEBEB', endColorstr='#CCCCCC'); } .horse_data_page table { border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-right-color: #CCCCCC; border-bottom-color: #CCCCCC; border-left-color: #CCCCCC; background-color: #EBEBEB; border-collapse:collapse; width: 100%; font-size:12px; } .horse_data_page table td { border: 0px solid #666666; font-size:12px; padding: 2px; margin: 0px; }.horse_data_page a:link { text-decoration: none; } .horse_data_page a:visited { text-decoration: none; } .horse_data_page a:hover { text-decoration: none; } .horse_data_page a:active { text-decoration: none; } |
最终效果图: