最近看见网上有不少基于Struts2+spring分页的东西,自己感觉都不是很适合,许多都只是对一个列表进行了分页,而没有考虑到查询条件等。个人认为,分页就是从前台把查询条件输入进去然后返回查询结果列表。这个问题的难点就是查询条件的传递,因为第一次查询时候需要输入查询条件,而以后点下一页时候,就不需要再次输入查询条件了。所以,第一次查询时候,需要把查询条件保存到某个地方,再次查询时候,把条件取出来,同时,这些要做的通用,等有许多查询页面时候,能最大限度的重用代码,好了,废话少说,下面展示我的分页代码
首先写一个Pages类,用来保存分页的一些信息,包括当前页码、记录总数、总页数、每页显示的记录数、查询条件等。代码如下:
public class Pages { private int pageNo = 1; // 当前页码 private int totalNum = -1;// 记录总数 private int totalPage = -1; // 总页数 int perPageNum = 10; // 每页显示记录数 private String queryParames;// 查询条件 public String getQueryParames() { return queryParames; } public void setQueryParames(String queryParames) { this.queryParames = queryParames; } public Pages() { } public Pages(int pageNo, int totalNum, int perPageNum) { this.pageNo = pageNo; this.totalNum = totalNum; this.perPageNum = perPageNum; this.executeCount(); } public void executeCount() { this.totalPage = (int) Math.ceil((this.totalNum + this.perPageNum - 1) / this.perPageNum); if (this.totalPage <= 0) { this.totalPage = 1; } int intPage = this.pageNo; if (intPage > this.totalPage) { this.pageNo = this.totalPage; } else { this.pageNo = intPage; } } public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } public int getPerPageNum() { return perPageNum; } public void setPerPageNum(int perPageNum) { this.perPageNum = perPageNum; } public int getTotalNum() { return totalNum; } public void setTotalNum(int totalNum) { this.totalNum = totalNum; } public int getTotalPage() { return totalPage; } public void setTotalPage(int totalPage) { this.totalPage = totalPage; } public Map transQueryCondition() { Map<String, String> map = new HashMap<String, String>(); if (StringUtils.isNull(queryParames)) { return map; } String[] condtions = queryParames.split(";"); for (int i = 0; i < condtions.length; i++) { if (StringUtils.isNull(condtions[i])) { continue; } map.put(condtions[i].split(",")[0], condtions[i].split(",")[1]); } return map; }
下面写一个通用的Action类,用来初始化查询参数:
public abstract class ListAction extends ActionSupport { protected static final String LIST = "list"; Logger logger = Logger.getLogger(ListAction.class); /* * 当前页 */ private int pageNo = 1; /* * 总页数 */ private int totalPage = -1; /* * 总记录数 */ private int totalNum = -1; /* * 查询参数 */ private String queryParames; private PageList pageList; public final String execute() { initQuerycondition(); Pages pages = new Pages(); pages.setPageNo(this.getPageNo()); pages.setPerPageNum(10); pages.setTotalNum(totalNum); pages.executeCount(); this.setTotalPage(pages.getTotalPage()); pages.setQueryParames(queryParames); queryPageList(pages); this.setTotalPage(pages.getTotalPage()); this.setTotalNum(pages.getTotalNum()); return LIST; } /** * 实现每个查询结果列表,依据查询结果的不同而不同 * @param pages */ protected abstract void queryPageList(Pages pages); /** * 初始化查询参数的配置 */ protected void initQuerycondition() { /* *如果不是第一次查询,直接返回,否则设置查询参数,拼装成 queryParames */ if (totalNum >= 0) { return; } Map map = ActionContext.getContext().getParameters(); Iterator iter = map.keySet().iterator(); StringBuffer query = new StringBuffer(); while (iter.hasNext()) { String key = (String) iter.next(); Object keyValue = ((Object[]) map.get(key))[0]; String value = ""; if (!StringUtils.isObjNull(keyValue)) { query.append(";").append(key); if (keyValue instanceof Date) { value = DateUtils.trunsDateToString((Date) keyValue); } else { value = String.valueOf(keyValue); } query.append(",").append(value); } } this.setQueryParames(query.toString()); } //get.....set...方法 }
再写一个Page类,继承Component,用来获取ValueStack中的参数值。
public class Page extends Component { private static final Log logger = LogFactory.getLog(Page.class); public Page(ValueStack stack) { super(stack); } private String pageNo; // 当前页码 private String totalPage; // 总页数 private String totalNum; // 总记录数 private String styleClass; // 分页的样式 private String theme; // 分页的主题 private String url; // action的路径 private String urlType; // 路径的类型,主要用于URL重写的扩展 private String queryParames; public String getQueryParames() { return queryParames; } public void setQueryParames(String queryParames) { this.queryParames = queryParames; } public boolean start(Writer writer) { boolean result = super.start(writer); Object obj = this.getStack().findValue(pageNo); pageNo = String.valueOf((Integer) obj); obj = this.getStack().findValue(totalPage); totalPage = String.valueOf((Integer) obj); obj = this.getStack().findValue(totalNum); totalNum = String.valueOf((Integer) obj); StringBuilder str = new StringBuilder(); Map cont = this.getStack().getContext(); StrutsRequestWrapper req = (StrutsRequestWrapper) cont .get(StrutsStatics.HTTP_REQUEST); if (url == null || "".equals(url)) { url = (String) req .getAttribute("javax.servlet.forward.request_uri"); } String pageStr = "?totalNum=" + totalNum + "&pageNo="; if ("dir".equals(urlType)) { pageStr = ""; if ("1".equals(pageNo)) {// 第一页时 if (url.lastIndexOf("/") != url.length() - 1) { if (url.lastIndexOf("1") == url.length() - 1) {// 如果有页码1,则去掉1 url = url.substring(0, url.length() - 1); } else if (url.lastIndexOf("/") != url.length() - 1) {// 如果没有页码1,并且最后不是'/'时,加上'/' url = url + "/"; } } } else { url = url.substring(0, url.lastIndexOf("/") + 1); } } // 下面这段处理主要是用来处理动态查询的参数,并拼接成url StringBuffer perUrl = new StringBuffer(""); obj = this.getStack().findValue(queryParames); if (!StringUtils.isObjNull(obj)) { perUrl.append("&").append("queryParames").append("=").append( StringUtils.decode((String) obj)); } //当前页 Integer cpageInt = Integer.valueOf(pageNo); str.append("<span> "); // 文本样式 if (theme == null || "text".equals(theme)) { // 当前页与总页数相等 if (pageNo.equals(totalPage)) { // 如果total = 1,则无需分页,显示“[第1页] [共1页]” if ("1".equals(totalPage)) { str.append("[第 " + pageNo + " 页]"); str.append(" [共 " + totalPage + " 页]"); } else { // 到达最后一页,显示“[首页] [上一页] [末页]” str.append("<a href='" + url + pageStr + "1" + perUrl + "'>[首 页]</a> "); str.append("<a href='" + url + pageStr + (cpageInt - 1) + perUrl + "'>[上一页]</a>"); str.append("[下一页]"); str.append(" <a href='" + url + pageStr + totalPage + perUrl + "'>[末 页]</a> "); } } else { // 当前页与总页数不相同 if ("1".equals(pageNo)) { // 第一页,显示“[首 页] [下一页] [末页]” str.append("<a href='" + url + pageStr + "1" + perUrl + "'>[首 页]</a>"); str.append("[上一页]"); str.append("<a href='" + url + pageStr + (cpageInt + 1) + perUrl + "'>[下一页]</a>"); str.append("<a href='" + url + pageStr + totalPage + perUrl + "'>[末 页]</a>"); } else { // 不是第一页,显示“[首页] [上一页] [下一页] [末页]” str.append("<a href='" + url + pageStr + "1" + perUrl + "'>[首 页]</a>"); str.append("<a href='" + url + pageStr + (cpageInt - 1) + perUrl + "'>[上一页]</a>"); str.append("<a href='" + url + pageStr + (cpageInt + 1) + perUrl + "'>[下一页]</a>"); str.append("<a href='" + url + pageStr + totalPage + perUrl + "'>[末 页]</a>"); } } } else if ("number".equals(theme)) { // 数字样式 [1 2 3 4 5 6 7 8 9 10 > // >>] Integer totalInt = Integer.valueOf(totalPage); // 如果只有一页,则无需分页 str.append("[ "); if (totalInt == 1) { str.append("<strong>1</strong> "); } else { //当前页 if (cpageInt > 1) { // 当前不是第一组,要显示“<< <” // <<:返回前一组第一页 // <:返回前一页 str.append("<a href='" + url + pageStr + "1" + perUrl + "'> << </a> "); str.append("<a href='" + url + pageStr + (cpageInt - 1) + perUrl); str.append("'><</a> "); } else { str.append("<< < "); } int v = (cpageInt - 4) > 0 ? (cpageInt - 4) : 1; int v1 = (cpageInt + 4) < totalInt ? (cpageInt + 4) : totalInt; if (v1 == totalInt) { v = totalInt - 10; v = (v <= 0 ? 1 : v); // 如果为负数,则修改为1 } else if (v == 1 && v1 < totalInt) { v1 = totalInt > 10 ? 10 : totalInt; } // 10个为一组显示 for (int i = v; i <= v1; i++) { if (cpageInt == i) { // 当前页要加粗显示 str.append("<strong>" + i + "</strong> "); } else { str.append("<a href='" + url + pageStr + i + perUrl + "'>" + i + "</a> "); } } // 如果多于1组并且不是最后一组,显示“> >>” if (cpageInt < totalInt) { // >>:返回下一组最后一页 // >:返回下一页 str.append("<a href='" + url + pageStr + (cpageInt + 1) + perUrl); str.append("'>></a> "); str.append("<a href='" + url + pageStr + totalInt + perUrl); str.append("'> >> </a> "); } else { str.append("> >> "); } } str.append("]"); } str.append("</span>"); try { writer.write(str.toString()); } catch (IOException e) { logger.error(e); } return result; } //get set 方法区 }
PageTag类,继承Struts2标签的 ComponentTagSupport。
public class PageTag extends ComponentTagSupport { private static final long serialVersionUID = -5371048231966321759L; private String pageNo; private String totalPage; private String totalNum; private String styleClass; private String theme; private String url; private String urlType; private String queryParames; @Override protected void populateParams() { super.populateParams(); Page page = (Page) component; page.setPageNo(pageNo); page.setTotalPage(totalPage); page.setTotalNum(totalNum); page.setStyleClass(styleClass); page.setTheme(theme); page.setUrl(url); page.setUrlType(urlType); page.setQueryParames(queryParames); } @Override public Component getBean(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { return new Page(stack); } // get set 方法....... }
自定义分页的tld文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>2.2.3</tlib-version> <jsp-version>1.2</jsp-version> <short-name>fly</short-name> <uri>/fly</uri> <display-name>"fly Tags"</display-name> <tag> <name>pages</name> <tag-class>com.fly.web.taglib.PageTag</tag-class> <body-content>jsp</body-content> <description>分页标签</description> <attribute> <name>pageNo</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>totalPage</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description>总页数</description> </attribute> <attribute> <name>totalNum</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description>总记录数。</description> </attribute> <attribute> <name>styleClass</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description>分页标签的样式,不配置此项将采用默认的样式</description> </attribute> <attribute> <name>theme</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description>分页的主题,现支持number|text两种主题</description> </attribute> <attribute> <name>url</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description>分页提交的路径,默认不用配置该项,自动获取系统访问路径。</description> </attribute> <attribute> <name>urlType</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>queryParames</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <description> 查询参数 </description> </attribute> </tag> </taglib>
我们在jsp页面直接写
<td align="center" nowrap> 记录总数 <s:property value="%{totalNum}" />条 每页显示10条 第<s:property value="pageNo" />页 <fly:pages pageNo="pageNo" totalPage="totalPage" totalNum="totalNum" styleClass="page" theme="text" queryParames="queryParames"> </fly:pages> </td>
就这样简单一个通用的分页框架就完成了。