JSF中为DataTable增加翻页功能

初学JSF的大概都会遇到这么个问题,从Bean中将数据读取出来以后,用DataTable在页面上显示。是很常用的数据内容输出的方法,但是DataTable本身没有翻页的功能。如何给DataTable增加翻页呢?这里分享一下CoreJSF 3rd Edition中的pager demo来完成这个数据分页。其思路可以扩展到各种大量数据需要翻页的情况。

不想自己实现这个翻页的朋友,可以使用各种UI Framework中自带的翻页组件。比如Apache Tomahawk 中的 dataScroller 具体实现方法其实和这里要谈到的类似。

OK首先是JSF网页部分:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:corejsf="http://corejsf.com">
   <h:head>
      <h:outputStylesheet library="css" name="styles.css"/>
      <title>Pager Test</title>
   </h:head>
   <h:body>
      <ui:debug/>
      <h:form>
         <h:dataTable id="timezones" value="#{tz.data}" var="row" rows="10">
            <h:column>#{row}</h:column>
         </h:dataTable>
         <corejsf:pager dataTableId="timezones" showpages="20"
                        selectedStyleClass="currentPage"/>
      </h:form>
   </h:body>
</html>

tz这个bean的data是个String[],其中放了所有的timezone的名称。这里用DataTable将它输出到html页面上。这个表格将会很长,所以我们需要来将其分页化。

TimeZone bean的内容很简单:

package com.corejsf;
 
import javax.faces.bean.ManagedBean;
   // or import javax.inject.Named;
import javax.faces.bean.RequestScoped;
 
@ManagedBean(name="tz") // or @Named("tz")
@RequestScoped
public class TimeZoneBean {
   private String[] data = java.util.TimeZone.getAvailableIDs();
   public String[] getData() { return data; }
}

好直到这里都没什么,如果你已经留意前面第一个jsf页面,其中的<corejsf:pager dataTableId=”timezones” showpages=”20″
selectedStyleClass=”currentPage”/>部分,实际就是我们这里的重点了,这是一个定制的Renderer,用这个定制的renderer来控制翻页并且切换DataTable的数据显示。

这里我们的这个翻页Renderer叫“com.corejsf.Pager”该类属于javax.faces.Command。

具体实现方式:

package com.corejsf;
 
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;
 
@FacesRenderer(componentFamily="javax.faces.Command",
   rendererType="com.corejsf.Pager")
public class PagerRenderer extends Renderer {
   public void encodeBegin(FacesContext context, UIComponent component)
      throws IOException {
      String id = component.getClientId(context);
      UIComponent parent = component;
      while (!(parent instanceof UIForm)) parent = parent.getParent();
      String formId = parent.getClientId(context);
 
      ResponseWriter writer = context.getResponseWriter();    
 
      String styleClass = (String) component.getAttributes().get("styleClass");
      String selectedStyleClass
         = (String) component.getAttributes().get("selectedStyleClass");
      String dataTableId = (String) component.getAttributes().get("dataTableId");
      int showpages = toInt(component.getAttributes().get("showpages"));      
 
      // find the component with the given ID
 
      UIData data = (UIData) component.findComponent(dataTableId);
 
      int first = data.getFirst();
      int itemcount = data.getRowCount();
      int pagesize = data.getRows();
      if (pagesize <= 0) pagesize = itemcount;
 
      int pages = itemcount / pagesize;
      if (itemcount % pagesize != 0) pages++;
 
      int currentPage = first / pagesize;
      if (first >= itemcount - pagesize) currentPage = pages - 1;
      int startPage = 0;
      int endPage = pages;
      if (showpages > 0) {
         startPage = (currentPage / showpages) * showpages;
         endPage = Math.min(startPage + showpages, pages);
      }
      if (currentPage > 0)
         writeLink(writer, component, formId, id, "<", styleClass);
 
      if (startPage > 0)
         writeLink(writer, component, formId, id, "<<", styleClass);
 
      for (int i = startPage; i < endPage; i++) {
         writeLink(writer, component, formId, id, "" + (i + 1),
            i == currentPage ? selectedStyleClass : styleClass);
      }
 
      if (endPage < pages)
         writeLink(writer, component, formId, id, ">>", styleClass);
 
      if (first < itemcount - pagesize)
         writeLink(writer, component, formId, id, ">", styleClass);
 
      // hidden field to hold result
      writeHiddenField(writer, component, id);
   }
 
   private void writeLink(ResponseWriter writer, UIComponent component,
      String formId, String id, String value, String styleClass)
      throws IOException {
      writer.writeText(" ", null);
      writer.startElement("a", component);
      writer.writeAttribute("href", "#", null);
      writer.writeAttribute("onclick", onclickCode(formId, id, value), null);
      if (styleClass != null)
         writer.writeAttribute("class", styleClass, "styleClass");
      writer.writeText(value, null);
      writer.endElement("a");
   }
 
   private String onclickCode(String formId, String id, String value) {
      return new StringBuilder().append("document.forms['")
         .append(formId).append("']['")
         .append(id).append("'].value='").append(value).append("'; document.forms['")
         .append(formId).append("'].submit(); return false;").toString();
   }
 
   private void writeHiddenField(ResponseWriter writer, UIComponent component,
      String id) throws IOException {
      writer.startElement("input", component);
      writer.writeAttribute("type", "hidden", null);
      writer.writeAttribute("name", id, null);
      writer.endElement("input");
   }
 
   public void decode(FacesContext context, UIComponent component) {
      String id = component.getClientId(context);
      Map<String, String> parameters
         = context.getExternalContext().getRequestParameterMap();
 
      String response = (String) parameters.get(id);
      if (response == null || response.equals("")) return; 
 
      String dataTableId = (String) component.getAttributes().get("dataTableId");
      int showpages = toInt(component.getAttributes().get("showpages"));      
 
      UIData data = (UIData) component.findComponent(dataTableId);
 
      int first = data.getFirst();
      int itemcount = data.getRowCount();
      int pagesize = data.getRows();
      if (pagesize <= 0) pagesize = itemcount;
 
      if (response.equals("<")) first -= pagesize;
      else if (response.equals(">")) first += pagesize;
      else if (response.equals("<<")) first -= pagesize * showpages;
      else if (response.equals(">>")) first += pagesize * showpages;
      else {
         int page = Integer.parseInt(response);
         first = (page - 1) * pagesize;
      }
      if (first + pagesize > itemcount) first = itemcount - pagesize;
      if (first < 0) first = 0;
      data.setFirst(first);
   }
 
   private static int toInt(Object value) {
      if (value == null) return 0;
      if (value instanceof Number) return ((Number) value).intValue();
      if (value instanceof String) return Integer.parseInt((String) value);
      throw new IllegalArgumentException("Cannot convert " + value);
   }
}

配置方面还需要:

web.xml   
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">
   <servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>/faces/*</url-pattern>
   </servlet-mapping>
   <welcome-file-list>
      <welcome-file>faces/index.xhtml</welcome-file>
   </welcome-file-list>
   <context-param>
      <param-name>javax.faces.PROJECT_STAGE</param-name>
      <param-value>Development</param-value>
   </context-param>
   <context-param>
      <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
      <param-value>/WEB-INF/corejsf.taglib.xml</param-value>
   </context-param>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib version="2.0"
   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-facelettaglibary_2_0.xsd">
   <namespace>http://corejsf.com</namespace>
   <tag>
      <tag-name>pager</tag-name>
      <component>
         <component-type>javax.faces.Command</component-type>
         <renderer-type>com.corejsf.Pager</renderer-type>
      </component>
   </tag>
</facelet-taglib>

具体实现如图,代码在tomcat 6.0.29 x64测试通过。

  • Share/Bookmark
This entry was posted in 网络开发 [Web-based Development] and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>