iBatis分页(基于Struts2和Freemarker)
创始人
2024-07-27 14:11:35
0

之前介绍过基于Hibernate分页的原理和设计,这里我们所用的分页都是物理分页技术,不是JS实现的页面分页技术,是在SQL语句上执行的分页,可以获取结果集数量固定的列表,执行效率很高。下面来看看iBatis中如何设计分页,本文基于Struts2,Spring3来整合,因为暂时Spring不支持MyBatis3(可以选用MyBatis官方的MyBatis-Spring插件来实现,配有中文文档,很好理解),我们这里仍然以iBatis2作为载体来介绍。

首先就是搭建开发环境,这里可以说也是对Struts2,Spring3和iBatis2进行了简单的整合,大家也可以来参考。项目的结构如下,使用Maven创建的web项目:

 

 

添加必要的依赖,因为整合了Struts2和Spring,依赖就比较多了,如下:

 

 

首先来配置一下Struts2,这个就比较简单了,相信大家都不陌生。在web.xml中:

Xml代码

  1.     
  2.     
  3.     struts2filter-name>    
  4. org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilterfilter-class>    
  5. filter>    
  6.     
  7.     struts2filter-name>    
  8.     *.actionurl-pattern>    
  9. filter-mapping>    

 

 

然后是struts.xml,配置Struts相关的内容,这里我们配置freemarker为默认的结果类型,然后配置一个测试的Action,因为和Spring进行了集成,所以Action具体的配置放到Spring中来进行,如下即可:

Xml代码

  1.     
  2.     "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"     
  3.     "http://struts.apache.org/dtds/struts-2.1.7.dtd">    
  4.     
  5.             namespace="/">    
  6.             
  7.                     class="org.apache.struts2.views.freemarker.FreemarkerResult"    
  8.                 default="true" />    
  9.         result-types>    
  10.             
  11.             user_list.ftlresult>    
  12.         action>    
  13.     package>    
  14. struts>   

 

 

 

 

对Freemarker做一个简单的设置,卸载freeemarer.properties文件中即可,这里我们主要是引用了一个宏文件,就是分页宏的配置,如下:

Properties代码

  1. template_update_delay=5    
  2. default_encoding=UTF-8    
  3. url_escaping_charset=UTF-8    
  4. number_format=0.#     
  5. date_format=yyyy-MM-dd     
  6. time_format=HH:mm:ss     
  7. datetime_format=yyyy-MM-dd HH:mm:ss     
  8. boolean_format=true,false     
  9. whitespace_stripping=true     
  10. tag_syntax=auto_detect     
  11. auto_import=/Freemarker/page_macro.ftl as p    

 

Log4J的配置这里不再贴出代码,大家可以去下载源码,一看就明白了,之后我们配置Spring,在resources文件夹下创建spring子目录,里面放置Spring的配置文件,在web.xml中如下设置即可加载Spring的配置文件:

Xml代码

  1.     
  2.     contextConfigLocationparam-name>    
  3.     classpath:spring/*.xmlparam-value>    
  4. context-param>    
  5.     
  6.         org.springframework.web.context.ContextLoaderListenerlistener-class>    
  7. listener>    

 

 

Spring中主要配置数据源,iBatis的SqlMapClient和SqlMapClientTemplate,事务处理还有Action和Service的管理,其实内容大家也都很熟悉了,比较简单:

Xml代码

  1.         destroy-method="close">    
  2.             
  3.             
  4.             
  5.             
  6.             
  7.             
  8.             
  9.             
  10.     bean>    
  11.         
  12.         
  13.             
  14.             
  15.     bean>    
  16.         
  17.         
  18.             
  19.                 
  20.         constructor-arg>    
  21.     bean>    
  22.         
  23.             class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    
  24.             
  25.     bean>    
  26.         
  27.         
  28.             
  29.                 
  30.                 
  31.                 
  32.                 
  33.                 
  34.         tx:attributes>    
  35.     tx:advice>    
  36.         
  37.                     expression="execution(* org.ourpioneer.service.*Service.*(..))" />    
  38.             
  39.     aop:config>  

 

之后对Service和Action进行配置:

Xml代码

  1.     
  2.         
  3. bean>    
  4.     
  5.         
  6. bean>  

 

 

 

 

 

下面来看一下iBatis的配置,在配置SqlMapClient的时候,加入了iBatis的配置文件,我们来看看sqlMapConfig.xml如何来设置:

Xml代码

  1.       
  2.     PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"      
  3.     "http://www.ibatis.com/dtd/sql-map-config-2.dtd">    
  4.     
  5.             lazyLoadingEnabled="true" errorTracingEnabled="true" maxRequests="32"    
  6.         maxSessions="10" maxTransactions="5" />    
  7.         
  8. sqlMapConfig>    

 

 

其实内容也很简单,就是设置一下必要的信息,其中的含义可以参考之前写过的对iBatis的介绍的相关文章,最后不要忘了加入sqlMaps配置文件即可,这里我们就一个user.xml文件,为了测试,也就是一条查询,针对这个查询进行分页操作:

Xml代码

  1.     
  2. >    
  3.     
  4.         
  5.         
  6.         select * from user     
  7.     select>    
  8. sqlMap>  

 

 

ParameterMap在之前的介绍中也多次出现,这里我们也再来看下:

Java代码

  1. package org.ourpioneer.bean;     
  2. import java.util.HashMap;     
  3. public class ParameterMap extends HashMap {     
  4.     public ParameterMap(Object... parameters) {     
  5.         for (int i = 0; i < parameters.length - 1; i += 2) {     
  6.             super.put(parameters[i], parameters[i + 1]);     
  7.         }     
  8.     }     
  9. }  

 

其实就是扩展了一下HashMap类,来进行参数的放置,注意参数类型是可变参数的形式,也就是名-值对的形式出现的,不过本例中没有使用它。下面就是分页类的设计了:

#p#

Java代码

  1. package org.ourpioneer.bean;     
  2. import java.util.List;     
  3. import org.springframework.orm.ibatis.SqlMapClientTemplate;     
  4. /**    
  5.  * iBatis分页类    
  6.  *     
  7.  * @author Nanlei    
  8.  *     
  9.  */    
  10. public class PagingList {     
  11.     private int rowCount = 0; // 记录总数     
  12.     private int pageCount = 1; // 分页总数     
  13.     private int pageSize = 10; // 每页记录数     
  14.     private int pageNum = 1; // 当前页数     
  15.     private int startIndex = 1; // 起始记录数     
  16.     private int endIndex = 1; // 结束记录数     
  17.     private List list;// 记录列表     
  18.     /**    
  19.      * 构造方法,进行分页    
  20.      *     
  21.      * @param statementName    
  22.      *            iBatis中语句的ID    
  23.      * @param parameterObject    
  24.      *            SQL语句参数    
  25.      * @param pageNum    
  26.      *            起始页数    
  27.      * @param pageSize    
  28.      *            每页大小    
  29.      * @param sqlMapClientTemplate    
  30.      *            iBatis的sqlMapClientTemplate对象    
  31.      */    
  32.     public PagingList(String statementName, Object parameterObject,     
  33.             int pageNum, int pageSize, SqlMapClientTemplate sqlMapClientTemplate) {     
  34.         preProcessParams(pageNum, pageSize);     
  35.         execute(statementName, parameterObject, pageNum, pageSize,     
  36.                 sqlMapClientTemplate);     
  37.     }     
  38.     /**    
  39.      * 构造方法,进行分页    
  40.      *     
  41.      * @param statementName    
  42.      *            iBatis中语句的ID    
  43.      * @param pageNum    
  44.      *            起始页数    
  45.      * @param pageSize    
  46.      *            每页大小    
  47.      * @param sqlMapClientTemplate    
  48.      *            iBatis的sqlMapClientTemplate对象    
  49.      */    
  50.     public PagingList(String statementName, int pageNum, int pageSize,     
  51.             SqlMapClientTemplate sqlMapClientTemplate) {     
  52.         preProcessParams(pageNum, pageSize);     
  53.         execute(statementName, pageNum, pageSize, sqlMapClientTemplate);     
  54.     }     
  55.     /**    
  56.      * 执行方法    
  57.      *     
  58.      * @param statementName    
  59.      * @param parameterObject    
  60.      * @param pageNum    
  61.      * @param pageSize    
  62.      * @param sqlMapClientTemplate    
  63.      */    
  64.     public void execute(String statementName, Object parameterObject,     
  65.             int pageNum, int pageSize, SqlMapClientTemplate sqlMapClientTemplate) {     
  66.         // 计算记录总数     
  67.         this.rowCount = sqlMapClientTemplate.queryForList(statementName,     
  68.                 parameterObject).size();     
  69.         // 计算分页数及起止记录     
  70.         countPage();     
  71.         // 获取分页列表     
  72.         this.list = sqlMapClientTemplate.queryForList(statementName,     
  73.                 parameterObject, (pageNum - 1) * pageSize, pageSize);     
  74.     }     
  75.     /**    
  76.      * 执行方法    
  77.      *     
  78.      * @param statementName    
  79.      * @param pageNum    
  80.      * @param pageSize    
  81.      * @param sqlMapClientTemplate    
  82.      */    
  83.     public void execute(String statementName, int pageNum, int pageSize,     
  84.             SqlMapClientTemplate sqlMapClientTemplate) {     
  85.         // 计算记录总数     
  86.         this.rowCount = sqlMapClientTemplate.queryForList(statementName).size();     
  87.         // 计算分页数及起止记录     
  88.         countPage();     
  89.         // 获取分页列表     
  90.         this.list = sqlMapClientTemplate.queryForList(statementName,     
  91.                 (pageNum - 1) * pageSize, pageSize);     
  92.     }     
  93.     /**    
  94.      * 预处理SQL语句和页面参数    
  95.      */    
  96.     private void preProcessParams(int pageNum, int pageSize) {     
  97.         if (pageNum > 0) {     
  98.             this.pageNum = pageNum;     
  99.         }     
  100.         if (pageSize > 0) {     
  101.             this.pageSize = pageSize;     
  102.         }     
  103.         if (pageSize > 1000) {     
  104.             this.pageSize = 1000;     
  105.         }     
  106.     }     
  107.     /**    
  108.      * 计算分页数及起止记录    
  109.      */    
  110.     private void countPage() {     
  111.         // 计算分页总数     
  112.         if ((rowCount % pageSize) == 0) {     
  113.             pageCount = rowCount / pageSize;     
  114.         } else {     
  115.             pageCount = rowCount / pageSize + 1;     
  116.         }     
  117.         if (pageCount == 0) {     
  118.             pageCount = 1;     
  119.         }     
  120.         // 判断pageNum是否过界     
  121.         if (pageNum > pageCount && rowCount != 0) {     
  122.             pageNum = pageCount;     
  123.         }     
  124.         // 计算起止记录     
  125.         startIndex = (pageNum - 1) * pageSize + 1;     
  126.         endIndex = (pageNum) * pageSize;     
  127.     }     
  128.     /**    
  129.      * 获得对象列表    
  130.      */    
  131.     public List getList() {     
  132.         return list;     
  133.     }     
  134.     /* 获得起始记录数 */    
  135.     public int getStartIndex() {     
  136.         return startIndex;     
  137.     }     
  138.     public Integer getStartIndexInteger() {     
  139.         return new Integer(startIndex);     
  140.     }     
  141.     /* 获得结束记录数 */    
  142.     public int getEndIndex() {     
  143.         return endIndex;     
  144.     }     
  145.     public Integer getEndIndexInteger() {     
  146.         return new Integer(endIndex);     
  147.     }     
  148.     /* 获得分页其它信息 */    
  149.     public int getPageCount() {     
  150.         return pageCount;     
  151.     }     
  152.     public int getPageNum() {     
  153.         return pageNum;     
  154.     }     
  155.     public int getPageSize() {     
  156.         return pageSize;     
  157.     }     
  158.     public int getRowCount() {     
  159.         return rowCount;     
  160.     }     
  161. }    

 

写好分页类,还要和框架进行集成,那么我们可以抽象出Service的基类,在业务逻辑层中调用它来获取分页信息:

Java代码

  1. package org.ourpioneer.service;     
  2. import org.ourpioneer.bean.PagingList;     
  3. import org.springframework.orm.ibatis.SqlMapClientTemplate;     
  4. import com.opensymphony.xwork2.ActionContext;     
  5. import com.opensymphony.xwork2.util.ValueStack;     
  6. public class BaseService {     
  7.     /**    
  8.      * 获取ValueStack    
  9.      *     
  10.      * @return ValueStack对象    
  11.      */    
  12.     public ValueStack getValueStack() {     
  13.         return ActionContext.getContext().getValueStack();     
  14.     }     
  15.     /**    
  16.      * 获取分页的List    
  17.      *     
  18.      * @param statementName    
  19.      * @param sqlMapClientTemplate    
  20.      * @return    
  21.      */    
  22.     public PagingList getPagingList(String statementName,     
  23.             SqlMapClientTemplate sqlMapClientTemplate) {     
  24.         int pageNum = ((Integer) getValueStack().findValue("pageNum"))     
  25.                 .intValue();     
  26.         int pageSize = ((Integer) getValueStack().findValue("pageSize"))     
  27.                 .intValue();     
  28.         return new PagingList(statementName, pageNum, pageSize,     
  29.                 sqlMapClientTemplate);     
  30.     }     
  31.     /**    
  32.      * 获取分页的List    
  33.      *     
  34.      * @param statementName    
  35.      * @param parameterObject    
  36.      * @param sqlMapClientTemplate    
  37.      * @return    
  38.      */    
  39.     public PagingList getPagingList(String statementName,     
  40.             Object parameterObject, SqlMapClientTemplate sqlMapClientTemplate) {     
  41.         int pageNum = ((Integer) getValueStack().findValue("pageNum"))     
  42.                 .intValue();     
  43.         int pageSize = ((Integer) getValueStack().findValue("pageSize"))     
  44.                 .intValue();     
  45.         return new PagingList(statementName, parameterObject, pageNum,     
  46.                 pageSize, sqlMapClientTemplate);     
  47.     }     
  48. }    

 

两个构造方法我们都使用了,也就是一个带参数,一个不带参数。下面来看抽象出的Action基类,主要是处理页面传入的分页参数的处理:

Java代码

  1. package org.ourpioneer.action;     
  2. import java.util.Map;     
  3. import javax.servlet.http.HttpServletRequest;     
  4. import org.apache.struts2.ServletActionContext;     
  5. import org.ourpioneer.util.QueryUtil;     
  6. import com.opensymphony.xwork2.ActionContext;     
  7. import com.opensymphony.xwork2.ActionSupport;     
  8. public class BaseAction extends ActionSupport {     
  9.     @Override    
  10.     public String execute() throws Exception {     
  11.         return SUCCESS;     
  12.     }     
  13.     public Map getParameters() {     
  14.         return ActionContext.getContext().getParameters();     
  15.     }     
  16.     public HttpServletRequest getRequest() {     
  17.         return ServletActionContext.getRequest();     
  18.     }     
  19.     /* 分页信息 */    
  20.     protected int pageNum = 1;     
  21.     protected int pageSize = 10;     
  22.     public int getPageNum() {     
  23.         return pageNum;     
  24.     }     
  25.     public void setPageNum(int pageNum) {     
  26.         this.pageNum = pageNum;     
  27.     }     
  28.     public int getPageSize() {     
  29.         return pageSize;     
  30.     }     
  31.     public void setPageSize(int pageSize) {     
  32.         this.pageSize = pageSize;     
  33.     }     
  34.     public int getMaxPageSize() {     
  35.         return 1000;     
  36.     }     
  37.     public int getDefaultPageSize() {     
  38.         return 10;     
  39.     }     
  40.     // 页面解析分页信息使用的方法     
  41.     public String getQueryStringWithoutPageNum() {     
  42.         Map m = getParameters();     
  43.         m.remove("pageNum");     
  44.         return QueryUtil.getQueryString(m);     
  45.     }     
  46.     public String getFullUrlWithoutPageNum() {     
  47.         return getRequest().getServletPath() + "?"    
  48.                 + getQueryStringWithoutPageNum();     
  49.     }     
  50.     public String getQueryStringWithoutPageInfo() {     
  51.         Map m = getParameters();     
  52.         m.remove("pageNum");     
  53.         m.remove("pageSize");     
  54.         return QueryUtil.getQueryString(m);     
  55.     }     
  56.     public String getFullUrlWithoutPageInfo() {     
  57.         return getRequest().getServletPath() + "?"    
  58.                 + getQueryStringWithoutPageInfo();     
  59.     }     
  60. }    

 

这里为了演示,我们将分页的信息都直接定义死了,大家可以根据需要来修改,其中处理信息的QueryUtil大家可以直接参考源代码,这里不做说明了,下面是UserAction处理代码的编写:

Java代码

  1. package org.ourpioneer.action;     
  2. import org.ourpioneer.bean.PagingList;     
  3. import org.ourpioneer.service.UserService;     
  4. public class UserAction extends BaseAction {     
  5.     private UserService userService;     
  6.     public PagingList userList;     
  7.     public void setUserService(UserService userService) {     
  8.         this.userService = userService;     
  9.     }     
  10.     public PagingList getUserList() {     
  11.         return userList;     
  12.     }     
  13.     public String list() {     
  14.         userList = userService.getAllUsers();     
  15.         return "list";     
  16.     }     
  17. }    

 

根据前面的配置,我们也不难写出代码,下面就是视图处理了,我们使用了Freemarker进行解析,也编写了FreeMarker的分页宏:

Html代码

  1. <#-- 处理分页参数 -->    
  2. <#function getPageUrl pageNum>    
  3. <#local pageUrl=base+fullUrlWithoutPageInfo>    
  4. <#if pageUrl?ends_with("?")>    
  5. <#return pageUrl + "pageSize=" + pageSize + "&pageNum=" + pageNum>    
  6. <#else>    
  7. <#return pageUrl + "&pageSize=" + pageSize + "&pageNum=" + pageNum>    
  8. #if>    
  9. #function>    
  10. <#-- 全部或分页显示 -->    
  11. <#function getPageUrlResize size>    
  12. <#local pageUrl=base+fullUrlWithoutPageInfo>    
  13. <#if pageUrl?ends_with("?")>    
  14. <#return pageUrl + "pageNum=1&pageSize=" + size>    
  15. <#else>    
  16. <#return pageUrl + "&pageNum=1&pageSize=" + size>    
  17. #if>    
  18. #function>    
  19.     
  20. <#-- 分页信息 -->    
  21. <#macro paging pagingList>    
  22. <#local pageCount=pagingList.pageCount>    
  23. <#local rowCount=pagingList.rowCount>    
  24. <#local pageNum=pagingList.pageNum>    
  25. <#local pageSize=pagingList.pageSize>    
  26. <#if rowCount == 0>    
  27.     <#if useFlag?exists>    
  28.         没有相关记录div>    
  29.     <#else>    
  30.         <#assign useFlag = 1>    
  31.     #if>    
  32. <#else>    
  33.     
  34.     
  35.     
  36.         共 ${rowCount} 条记录 ${pageCount} 页      
  37.         <#if pageCount gt 1 && pageSize!=maxPageSize>    
  38.             全部显示a>span>    
  39.         <#elseif pageSize==maxPageSize>    
  40.             分页显示a>span>    
  41.         #if>    
  42.         <#if (pageCount <= 11)>    
  43.             <#local startPage = 1>    
  44.             <#local endPage = pageCount>    
  45.         <#elseif (pageNum + 5 > pageCount)>    
  46.             <#local startPage = pageCount - 10>    
  47.             <#local endPage = pageCount>    
  48.         <#elseif (pageNum - 5 < 1)>    
  49.             <#local startPage = 1>    
  50.             <#local endPage = 11>    
  51.         <#else>    
  52.             <#local startPage = pageNum - 5>    
  53.             <#local endPage = pageNum + 5>    
  54.         #if>    
  55.         <#if (pageCount > 1)>    
  56.             <#if (pageNum != 1)>    
  57.                 <#if (pageCount > 11)>    
  58.                     9a>    
  59.                 #if>    
  60.                 3a>    
  61.             <#else>    
  62.                 <#if (pageCount > 11)>    
  63.                     9span>    
  64.                 #if>    
  65.                 3span>    
  66.             #if>    
  67.             <#list startPage..endPage as x>    
  68.                 <#if x=pageNum>    
  69.                     ${x}span>    
  70.                 <#else>    
  71.                     ${x}a>span>    
  72.                 #if>    
  73.             #list>    
  74.             <#if (pageCount != pageNum)>    
  75.                 4a>    
  76.                 <#if (pageCount > 11)>    
  77.                     :a>    
  78.                 #if>    
  79.             <#else>    
  80.                 4span>    
  81.                 <#if (pageCount > 11)>    
  82.                     :span>    
  83.                 #if>    
  84.             #if>    
  85.         #if>    
  86.         td>    
  87.     tr>    
  88. table>    
  89. #if>    
  90. #macro>   
  91.  

     

     

     

    之后,我们来运行项目:

     

     

    可以通过点击全部显示和页面来查看分页效果。

    【编辑推荐】

    1. Java持久层框架iBATIS 3(BETA 1)版本发布
    2. iBATIS配置类及操作类的浅析
    3. iBATIS参数理解浅析
    4. iBATIS模糊查询的实现实例浅析
    5. Hibernate与iBATIS的对比

    相关内容

    热门资讯

    如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
    如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
    施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
    20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
    德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
    为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
    《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
    2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...