一、实现方式:
(1)添加 tld 配置文件。
在项目的WEB-INF下添加 mytag.tld 文件,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <description>JSTL 1.2 core library</description> <display-name>JSTL core</display-name> <tlib-version>1.0</tlib-version> <short-name>mt</short-name> <uri>/WEB-INF/mytag</uri> <tag> <name>pages</name> <tag-class>cn.guopeng.oa.tag.PagerTag</tag-class> <body-content>empty</body-content> <attribute> <name>currentPage</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>totalPage</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>path</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>params</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>hasSelect</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>java.lang.Boolean</type> </attribute> <attribute> <name>hasGoText</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>java.lang.Boolean</type> </attribute> </tag> </taglib>
(2)在cn.guopeng.oa.tag包中添加类:PagerTag 主要用来接收参数并传递给PagerImpl类
package cn.guopeng.oa.tag; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.components.Component; import org.apache.struts2.views.jsp.ComponentTagSupport; import com.opensymphony.xwork2.util.ValueStack; public class PagerTag extends ComponentTagSupport { private String currentPage; // 当前页 private String totalPage; // 总页数 private String path; // 请求地址 private String params; //其他参数 private boolean hasSelect;//是否有下拉列表 private boolean hasGoText; //是否有跳转文本框 省略get、set方法 @Override public Component getBean(ValueStack arg0, HttpServletRequest arg1, HttpServletResponse arg2) { return new PagerImpl(arg0); // 返回Pages Component,分页的逻辑处理都在这个Component中 } // 获得参数 @Override protected void populateParams() { super.populateParams(); PagerImpl pagrImpl = (PagerImpl) component; pagrImpl.setCurrentPage(currentPage); pagrImpl.setTotalPage(totalPage); pagrImpl.setPath(path); pagrImpl.setParams(params); pagrImpl.setHasGoText(hasGoText); pagrImpl.setHasSelect(hasSelect); } }
(3)在cn.guopeng.oa.tag包中添加类:PagerImpl。根据传过来的参数到值栈中获得相应值,并输出分页。
package cn.guopeng.oa.tag; import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.struts2.components.Component; import com.opensymphony.xwork2.util.ValueStack; public class PagerImpl extends Component { //接收参数 private String currentPage; private String totalPage; private String path; private String params; private boolean hasSelect;//是否有下拉列表 private boolean hasGoText; //是否有跳转文本框 private int _currentPage;//当前页面 private int _totalPage;//总页数 private Map<String, Object> _params;//其他参数 省略get、set方法 @Override public boolean start(Writer writer) { boolean result = super.start(writer); String pageParam = ""; // 保存传递页数的参数字符串 try { StringBuilder sb = new StringBuilder(); boolean isValid = true; Object temp; // 检查必须的参数 if (isValid) { if (path != null) { path = path.trim(); } else { isValid = false; } } if (isValid) { if (totalPage != null) { totalPage = totalPage.trim(); temp = this.getStack().findValue(totalPage); if(temp != null){ _totalPage = (Integer)temp; }else{ isValid = false; } } else { isValid = false; } } if (isValid) { if (currentPage != null) { currentPage = currentPage.trim(); temp = this.getStack().findValue(currentPage); if(temp != null){ _currentPage = (Integer)temp; pageParam = currentPage; } } else { isValid = false; } } if (isValid) { if (params != null) { params = params.trim(); temp = this.getStack().findValue(params); if(temp != null){ _params = (Map<String, Object>)temp; }else{ isValid = false; } } } if (isValid) { if (1 >= _currentPage) { sb.append("/n"); sb.append("首页"); sb.append("  "); sb.append("上一页"); sb.append(" "); } else { sb.append("/n"); // 输出带链接首页 sb.append("<a href=/""); sb.append(path); insertParams(sb); sb.append(pageParam); sb.append("="); sb.append("1"); sb.append("/""); sb.append(">"); sb.append("首页"); sb.append("</a>"); sb.append(" "); // 输出带链接上一页 sb.append("<a href=/""); sb.append(path); insertParams(sb); sb.append(pageParam); sb.append("="); sb.append(_currentPage - 1); sb.append("/""); sb.append(">"); sb.append("上一页"); sb.append("</a>"); sb.append(" "); } if (_totalPage <= _currentPage) { sb.append("/n"); // 源代码换行 sb.append("下一页"); sb.append("  "); sb.append("末页"); sb.append(" "); } else { sb.append("/n"); // 输出带链接下一页 sb.append("<a href=/""); sb.append(path); insertParams(sb); sb.append(pageParam); sb.append("="); sb.append(_currentPage + 1); sb.append("/""); sb.append(">"); sb.append("下一页"); sb.append("</a>"); sb.append(" "); // 输出带链接末页 sb.append("<a href=/""); sb.append(path); insertParams(sb); sb.append(pageParam); sb.append("="); sb.append(_totalPage); sb.append("/""); sb.append(">"); sb.append("末页"); sb.append("</a>"); sb.append(" "); } if (this.hasSelect) { sb.append("/n"); sb.append("<form action=/""); sb.append(path); insertParams(sb); sb.append("/" method=/"post/" style=/"display: inline;/">"); sb.append("/n"); sb.append("跳转到:"); sb.append("<select name=/""); sb.append(pageParam); sb .append("/" onchange=/"javascript:this.parentNode.submit()/">"); sb.append("/n"); for (int i = 1; i <= _totalPage; i++) { if (i == _currentPage) { sb.append("<option value=/""); sb.append(i); sb.append("/" selected=/"selected/">"); sb.append(i); sb.append("</option>"); } else { sb.append("<option value=/""); sb.append(i); sb.append("/" >"); sb.append(i); sb.append("</option>"); } } sb.append("/n"); sb.append("</select>"); sb.append("/n"); sb.append("</form>"); } if (hasGoText) { sb.append("/n"); sb.append("<form action=/""); sb.append(path); insertParams(sb); sb.append("/" method=/"post/" style=/"display: inline;/">"); sb.append("/n"); sb.append("跳转到:<input type=/"text/" size=/"3/" name=/""); sb.append(pageParam); sb.append("/"/>"); sb.append("/n"); sb.append("<input type=/"submit/" value=/"Go/"/>"); sb.append("/n"); sb.append("</form>"); } } writer.write(sb.toString()); } catch (IOException ex) { ex.printStackTrace(); } return result; } private void insertParams(StringBuilder sb) { sb.append("?"); if (_params != null) { Iterator<Entry<String, Object>> it = _params.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it .next(); String key = entry.getKey(); Object val = entry.getValue(); sb.append(key); sb.append("="); sb.append(val); sb.append("&"); } } } }
(4)请求的Action类
package cn.guopeng.oa.action; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import cn.guopeng.oa.model.Orgnization; import cn.guopeng.oa.service.IOrgMgr; import com.opensymphony.xwork2.ActionSupport; @Component("orgAction") @Scope("prototype") public class OrgAction extends ActionSupport { private IOrgMgr orgMgr; private int pid; private int currentPage = 1; private int totalPage; private int totalCount; private Orgnization org; private List<Orgnization> orgs; private Map<String, Object> params; 省略部分get、set方法 public IOrgMgr getOrgMgr() { return orgMgr; } @Resource public void setOrgMgr(IOrgMgr orgMgr) { this.orgMgr = orgMgr; } //列表 public String list(){ params = new HashMap<String, Object>(); params.put("pid", pid); totalPage = orgMgr.getTotalPage(pid); totalCount = orgMgr.getTotalCount(pid); orgs = orgMgr.loadOrgs(pid, currentPage); return "list"; } //添加 public String addInput(){ return "addInput"; } //删除 public String delete(){ if(orgMgr.delete(org.getId())); return "delete"; } }
(5)使用分页标签的jsp页面:
<mt:pages totalPage="totalPage" currentPage="currentPage" path="${webroot}/orgAction!list" params="params" hasSelect="true" hasGoText="false"/>
(6)测试请求链接:
<%=webroot %>/orgAction!list?pid=1
没有传递currentPage参数原因是在Action中默认为第一页。
(7)其他说明:
在传递的参数中params对应Action中的一个Map类型,用于传递其他的参数,比如上面链接可以写为<%=webroot %>/orgAction!list?pid=1¤tPage=1其中currentPage就是要请求的页数,pid是父类型的id。就如同只取出某一分类中的记录再分页。
二、Struts 自定义标签的执行原理 时序图(部分):