- 浏览: 1758028 次
- 性别:
- 来自: 大连
博客专栏
-
Spring数据库访问系列...
浏览量:173791
-
Android学习笔记
浏览量:368251
-
iBatis开发详解
浏览量:189381
-
Objective-C学习...
浏览量:99956
最新评论
-
iLidy:
引用[/c
Hibernate持久化对象的生命周期详解 -
fengzigogo:
您好,有这个项目架构的源码下载地址吗?
一种Java Web应用开发框架的构建(基于Struts2+Spring+FreeMarker)之一 -
spring_springmvc:
可以参考最新的文档:如何在eclipse jee中检出项目并转 ...
用Maven构建Java Web开发环境(Jetty容器)之二 -
springdata_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
Spring 3之MVC & Security简单整合开发(二) -
赵庆辉:
看帖回复是美德,楼主讲的很清晰明了,看了豁然开朗.
Java String对象的经典问题(new String())
之前介绍过基于Hibernate分页的原理和设计,这里我们所用的分页都是物理分页技术,不是JS实现的页面分页技术,是在SQL语句上执行的分页,可以获取结果集数量固定的列表,执行效率很高。下面来看看iBatis中如何设计分页,本文基于Struts2,Spring3来整合,因为暂时Spring不支持MyBatis3(可以选用MyBatis官方的MyBatis-Spring插件来实现,配有中文文档,很好理解),我们这里仍然以iBatis2作为载体来介绍。
首先就是搭建开发环境,这里可以说也是对Struts2,Spring3和iBatis2进行了简单的整合,大家也可以来参考。项目的结构如下,使用Maven创建的web项目:
添加必要的依赖,因为整合了Struts2和Spring,依赖就比较多了,如下:
首先来配置一下Struts2,这个就比较简单了,相信大家都不陌生。在web.xml中:
然后是struts.xml,配置Struts相关的内容,这里我们配置freemarker为默认的结果类型,然后配置一个测试的Action,因为和Spring进行了集成,所以Action具体的配置放到Spring中来进行,如下即可:
对Freemarker做一个简单的设置,卸载freeemarer.properties文件中即可,这里我们主要是引用了一个宏文件,就是分页宏的配置,如下:
Log4J的配置这里不再贴出代码,大家可以去下载源码,一看就明白了,之后我们配置Spring,在resources文件夹下创建spring子目录,里面放置Spring的配置文件,在web.xml中如下设置即可加载Spring的配置文件:
Spring中主要配置数据源,iBatis的SqlMapClient和SqlMapClientTemplate,事务处理还有Action和Service的管理,其实内容大家也都很熟悉了,比较简单:
之后对Service和Action进行配置:
下面来看一下iBatis的配置,在配置SqlMapClient的时候,加入了iBatis的配置文件,我们来看看sqlMapConfig.xml如何来设置:
其实内容也很简单,就是设置一下必要的信息,其中的含义可以参考之前写过的对iBatis的介绍的相关文章,最后不要忘了加入sqlMaps配置文件即可,这里我们就一个user.xml文件,为了测试,也就是一条查询,针对这个查询进行分页操作:
ParameterMap在之前的介绍中也多次出现,这里我们也再来看下:
其实就是扩展了一下HashMap类,来进行参数的放置,注意参数类型是可变参数的形式,也就是名-值对的形式出现的,不过本例中没有使用它。下面就是分页类的设计了:
写好分页类,还要和框架进行集成,那么我们可以抽象出Service的基类,在业务逻辑层中调用它来获取分页信息:
两个构造方法我们都使用了,也就是一个带参数,一个不带参数。下面来看抽象出的Action基类,主要是处理页面传入的分页参数的处理:
这里为了演示,我们将分页的信息都直接定义死了,大家可以根据需要来修改,其中处理信息的QueryUtil大家可以直接参考源代码,这里不做说明了,下面是UserAction处理代码的编写:
根据前面的配置,我们也不难写出代码,下面就是视图处理了,我们使用了Freemarker进行解析,也编写了FreeMarker的分页宏:
之后,我们来运行项目:
可以通过点击全部显示和页面来查看分页效果。
本文系作者本人的实践探索,方案可能不是最佳实践,希望和大家交流沟通,源码随附件可以下载。另外关于本文涉及到的技术可以参看本博客中以往对iBatis的介绍:
框架系列:框架技术,
最后,希望它对使用者和学习有用。根据大家的反馈意见全新修改。
使用数据库物理分页就行了
还真不知道,我都是查两遍的,一遍总数,一遍结果集,
总数或许可以缓存,我没试过。
呵呵,这个只是为了说明iBatis的分页思路,当然分页的实现会有很多了。
这样做是个解决办法,那么就在编写SQL的时候一次要写两条了,而且要传两个查询id进来了。
因为涉及到count总量,那么可以使用ibatis的API获得原SQL,然后加一层count,这样势必不能继续使用ibatis来执行了,要引入另外一种数据库访问API,那么可以是jdbcTemplate。这个问题我也考虑到了,因为没有什么更好的办法,所以如果大家有的话可以分享一下。
代码中的log4j设置了sql的日志,在那里面就能看到向数据库发送的sql了,也就可以看到是底层物理分页还是游标分页了。
这是从值栈中获取分页参数啊
首先就是搭建开发环境,这里可以说也是对Struts2,Spring3和iBatis2进行了简单的整合,大家也可以来参考。项目的结构如下,使用Maven创建的web项目:
添加必要的依赖,因为整合了Struts2和Spring,依赖就比较多了,如下:
首先来配置一下Struts2,这个就比较简单了,相信大家都不陌生。在web.xml中:
<!-- Struts2的过滤器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping>
然后是struts.xml,配置Struts相关的内容,这里我们配置freemarker为默认的结果类型,然后配置一个测试的Action,因为和Spring进行了集成,所以Action具体的配置放到Spring中来进行,如下即可:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <package name="ibatis-paging" extends="struts-default" namespace="/"> <result-types> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult" default="true" /> </result-types> <action name="user_*" class="userAction" method="{1}"> <result name="list">user_list.ftl</result> </action> </package> </struts>
对Freemarker做一个简单的设置,卸载freeemarer.properties文件中即可,这里我们主要是引用了一个宏文件,就是分页宏的配置,如下:
template_update_delay=5 default_encoding=UTF-8 url_escaping_charset=UTF-8 number_format=0.# date_format=yyyy-MM-dd time_format=HH:mm:ss datetime_format=yyyy-MM-dd HH:mm:ss boolean_format=true,false whitespace_stripping=true tag_syntax=auto_detect auto_import=/Freemarker/page_macro.ftl as p
Log4J的配置这里不再贴出代码,大家可以去下载源码,一看就明白了,之后我们配置Spring,在resources文件夹下创建spring子目录,里面放置Spring的配置文件,在web.xml中如下设置即可加载Spring的配置文件:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/*.xml</param-value> </context-param> <!-- Spring加载配置文件来初始化IoC容器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
Spring中主要配置数据源,iBatis的SqlMapClient和SqlMapClientTemplate,事务处理还有Action和Service的管理,其实内容大家也都很熟悉了,比较简单:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="123" /> <property name="maxActive" value="100" /> <property name="maxIdle" value="50" /> <property name="maxWait" value="100" /> <property name="defaultAutoCommit" value="true" /> </bean> <!-- 创建JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 创建sqlMapClient --> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation" value="classpath:sqlMapConfig.xml" /> <property name="dataSource" ref="dataSource" /> </bean> <!-- 创建sqlMapClientTemplate --> <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate"> <constructor-arg> <ref bean="sqlMapClient" /> </constructor-arg> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务处理通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="add*" rollback-for="Exception" /> <tx:method name="addOrUpdate*" rollback-for="Exception" /> <tx:method name="del*" rollback-for="Exception" /> <tx:method name="update*" rollback-for="Exception" /> </tx:attributes> </tx:advice> <aop:config proxy-target-class="true"> <aop:pointcut id="serviceMethod" expression="execution(* org.ourpioneer.service.*Service.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" /> </aop:config>
之后对Service和Action进行配置:
<bean id="baseService" class="org.ourpioneer.service.BaseService"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="userService" class="org.ourpioneer.service.UserService" parent="baseService"> <property name="sqlMapClientTemplate" ref="sqlMapClientTemplate" /> </bean> <bean id="userAction" class="org.ourpioneer.action.UserAction"> <property name="userService" ref="userService" /> </bean>
下面来看一下iBatis的配置,在配置SqlMapClient的时候,加入了iBatis的配置文件,我们来看看sqlMapConfig.xml如何来设置:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" errorTracingEnabled="true" maxRequests="32" maxSessions="10" maxTransactions="5" /> <sqlMap resource="sqlMaps/user.xml" /> </sqlMapConfig>
其实内容也很简单,就是设置一下必要的信息,其中的含义可以参考之前写过的对iBatis的介绍的相关文章,最后不要忘了加入sqlMaps配置文件即可,这里我们就一个user.xml文件,为了测试,也就是一条查询,针对这个查询进行分页操作:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap> <typeAlias alias="parameterMap" type="org.pioneer.bean.ParameterMap" /> <select id="selectAllUsers" resultClass="java.util.HashMap"> select * from user </select> </sqlMap>
ParameterMap在之前的介绍中也多次出现,这里我们也再来看下:
package org.ourpioneer.bean; import java.util.HashMap; public class ParameterMap extends HashMap { public ParameterMap(Object... parameters) { for (int i = 0; i < parameters.length - 1; i += 2) { super.put(parameters[i], parameters[i + 1]); } } }
其实就是扩展了一下HashMap类,来进行参数的放置,注意参数类型是可变参数的形式,也就是名-值对的形式出现的,不过本例中没有使用它。下面就是分页类的设计了:
package org.ourpioneer.bean; import java.util.HashMap; import java.util.List; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.orm.ibatis.SqlMapClientTemplate; import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; import com.ibatis.sqlmap.engine.mapping.sql.Sql; import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement; import com.ibatis.sqlmap.engine.scope.SessionScope; import com.ibatis.sqlmap.engine.scope.StatementScope; /** * iBatis分页类 * * @author Nanlei * */ public class PagingList { private int rowCount = 0; // 记录总数 private int pageCount = 1; // 分页总数 private int pageSize = 10; // 每页记录数 private int pageNum = 1; // 当前页数 private int startIndex = 1; // 起始记录数 private int endIndex = 1; // 结束记录数 private List list;// 记录列表 /** * 构造方法,进行分页 * * @param statementName * iBatis中语句的ID * @param parameterObject * SQL语句参数 * @param pageNum * 起始页数 * @param pageSize * 每页大小 * @param sqlMapClientTemplate * iBatis的sqlMapClientTemplate对象 */ public PagingList(String statementName, Object parameterObject, int pageNum, int pageSize, SqlMapClientTemplate sqlMapClientTemplate, JdbcTemplate jdbcTemplate) { preProcessParams(pageNum, pageSize); execute(statementName, parameterObject, pageNum, pageSize, sqlMapClientTemplate, jdbcTemplate); } /** * 构造方法,进行分页 * * @param statementName * iBatis中语句的ID * @param pageNum * 起始页数 * @param pageSize * 每页大小 * @param sqlMapClientTemplate * iBatis的sqlMapClientTemplate对象 */ public PagingList(String statementName, int pageNum, int pageSize, SqlMapClientTemplate sqlMapClientTemplate, JdbcTemplate jdbcTemplate) { preProcessParams(pageNum, pageSize); execute(statementName, pageNum, pageSize, sqlMapClientTemplate, jdbcTemplate); } /** * 执行方法 * * @param statementName * @param parameterObject * @param pageNum * @param pageSize * @param sqlMapClientTemplate */ public void execute(String statementName, Object parameterObject, int pageNum, int pageSize, SqlMapClientTemplate sqlMapClientTemplate, JdbcTemplate jdbcTemplate) { // 计算记录总数 this.rowCount = jdbcTemplate.queryForInt( getCountSql(getSrcSql(statementName, parameterObject, sqlMapClientTemplate)), ((HashMap) parameterObject) .values().toArray()); System.out.println(rowCount); // 计算分页数及起止记录 countPage(); // 获取分页列表 this.list = sqlMapClientTemplate.queryForList(statementName, parameterObject, (pageNum - 1) * pageSize, pageSize); } /** * 执行方法 * * @param statementName * @param pageNum * @param pageSize * @param sqlMapClientTemplate */ public void execute(String statementName, int pageNum, int pageSize, SqlMapClientTemplate sqlMapClientTemplate, JdbcTemplate jdbcTemplate) { // 计算记录总数 this.rowCount = jdbcTemplate.queryForInt(getCountSql(getSrcSql( statementName, null, sqlMapClientTemplate))); System.out.println(rowCount); // 计算分页数及起止记录 countPage(); // 获取分页列表 this.list = sqlMapClientTemplate.queryForList(statementName, (pageNum - 1) * pageSize, pageSize); } /** * 预处理SQL语句和页面参数 */ private void preProcessParams(int pageNum, int pageSize) { if (pageNum > 0) { this.pageNum = pageNum; } if (pageSize > 0) { this.pageSize = pageSize; } if (pageSize > 1000) { this.pageSize = 1000; } } /** * 计算分页数及起止记录 */ private void countPage() { // 计算分页总数 if ((rowCount % pageSize) == 0) { pageCount = rowCount / pageSize; } else { pageCount = rowCount / pageSize + 1; } if (pageCount == 0) { pageCount = 1; } // 判断pageNum是否过界 if (pageNum > pageCount && rowCount != 0) { pageNum = pageCount; } // 计算起止记录 startIndex = (pageNum - 1) * pageSize + 1; endIndex = (pageNum) * pageSize; } /** * 获得对象列表 */ public List getList() { return list; } /* 获得起始记录数 */ public int getStartIndex() { return startIndex; } public Integer getStartIndexInteger() { return new Integer(startIndex); } /* 获得结束记录数 */ public int getEndIndex() { return endIndex; } public Integer getEndIndexInteger() { return new Integer(endIndex); } /* 获得分页其它信息 */ public int getPageCount() { return pageCount; } public int getPageNum() { return pageNum; } public int getPageSize() { return pageSize; } public int getRowCount() { return rowCount; } private String getSrcSql(String statementName, Object parameterObject, SqlMapClientTemplate sqlMapClientTemplate) { SqlMapClientImpl sqlMapClientImpl = (SqlMapClientImpl) sqlMapClientTemplate .getSqlMapClient(); MappedStatement mappedStatement = sqlMapClientImpl .getMappedStatement(statementName); Sql sql = mappedStatement.getSql(); StatementScope statementScope = new StatementScope(new SessionScope()); String srcSql = sql.getSql(statementScope, parameterObject); return srcSql; } private String getCountSql(String srcSql) { return "SELECT COUNT(*) FROM ( " + srcSql + " ) CTBL_"; } }
写好分页类,还要和框架进行集成,那么我们可以抽象出Service的基类,在业务逻辑层中调用它来获取分页信息:
package org.ourpioneer.service; import org.ourpioneer.bean.PagingList; import org.springframework.orm.ibatis.SqlMapClientTemplate; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.util.ValueStack; public class BaseService { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * 获取ValueStack * * @return ValueStack对象 */ public ValueStack getValueStack() { return ActionContext.getContext().getValueStack(); } /** * 获取分页的List * * @param statementName * @param sqlMapClientTemplate * @return */ public PagingList getPagingList(String statementName, SqlMapClientTemplate sqlMapClientTemplate) { int pageNum = ((Integer) getValueStack().findValue("pageNum")) .intValue(); int pageSize = ((Integer) getValueStack().findValue("pageSize")) .intValue(); return new PagingList(statementName, pageNum, pageSize, sqlMapClientTemplate, jdbcTemplate); } /** * 获取分页的List * * @param statementName * @param parameterObject * @param sqlMapClientTemplate * @return */ public PagingList getPagingList(String statementName, Object parameterObject, SqlMapClientTemplate sqlMapClientTemplate) { int pageNum = ((Integer) getValueStack().findValue("pageNum")) .intValue(); int pageSize = ((Integer) getValueStack().findValue("pageSize")) .intValue(); return new PagingList(statementName, parameterObject, pageNum, pageSize, sqlMapClientTemplate, jdbcTemplate); } }
两个构造方法我们都使用了,也就是一个带参数,一个不带参数。下面来看抽象出的Action基类,主要是处理页面传入的分页参数的处理:
package org.ourpioneer.action; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import org.ourpioneer.util.QueryUtil; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class BaseAction extends ActionSupport { @Override public String execute() throws Exception { return SUCCESS; } public Map<String, Object> getParameters() { return ActionContext.getContext().getParameters(); } public HttpServletRequest getRequest() { return ServletActionContext.getRequest(); } /* 分页信息 */ protected int pageNum = 1; protected int pageSize = 10; public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getMaxPageSize() { return 1000; } public int getDefaultPageSize() { return 10; } // 页面解析分页信息使用的方法 public String getQueryStringWithoutPageNum() { Map<String, Object> m = getParameters(); m.remove("pageNum"); return QueryUtil.getQueryString(m); } public String getFullUrlWithoutPageNum() { return getRequest().getServletPath() + "?" + getQueryStringWithoutPageNum(); } public String getQueryStringWithoutPageInfo() { Map<String, Object> m = getParameters(); m.remove("pageNum"); m.remove("pageSize"); return QueryUtil.getQueryString(m); } public String getFullUrlWithoutPageInfo() { return getRequest().getServletPath() + "?" + getQueryStringWithoutPageInfo(); } }
这里为了演示,我们将分页的信息都直接定义死了,大家可以根据需要来修改,其中处理信息的QueryUtil大家可以直接参考源代码,这里不做说明了,下面是UserAction处理代码的编写:
package org.ourpioneer.action; import org.ourpioneer.bean.PagingList; import org.ourpioneer.service.UserService; public class UserAction extends BaseAction { private UserService userService; public PagingList userList; public void setUserService(UserService userService) { this.userService = userService; } public PagingList getUserList() { return userList; } public String list() { userList = userService.getAllUsers(); return "list"; } }
根据前面的配置,我们也不难写出代码,下面就是视图处理了,我们使用了Freemarker进行解析,也编写了FreeMarker的分页宏:
<#-- 处理分页参数 --> <#function getPageUrl pageNum> <#local pageUrl=base+fullUrlWithoutPageInfo> <#if pageUrl?ends_with("?")> <#return pageUrl + "pageSize=" + pageSize + "&pageNum=" + pageNum> <#else> <#return pageUrl + "&pageSize=" + pageSize + "&pageNum=" + pageNum> </#if> </#function> <#-- 全部或分页显示 --> <#function getPageUrlResize size> <#local pageUrl=base+fullUrlWithoutPageInfo> <#if pageUrl?ends_with("?")> <#return pageUrl + "pageNum=1&pageSize=" + size> <#else> <#return pageUrl + "&pageNum=1&pageSize=" + size> </#if> </#function> <#-- 分页信息 --> <#macro paging pagingList> <#local pageCount=pagingList.pageCount> <#local rowCount=pagingList.rowCount> <#local pageNum=pagingList.pageNum> <#local pageSize=pagingList.pageSize> <#if rowCount == 0> <#if useFlag?exists> <div style="border:1px solid #666;padding:2 5 2 5;background:#efefef;color:#333">没有相关记录</div> <#else> <#assign useFlag = 1> </#if> <#else> <table> <tr> <td style="line-height:150%">共 ${rowCount} 条记录 ${pageCount} 页 <#if pageCount gt 1 && pageSize!=maxPageSize> <span class="selectedPage" style="padding:2px 3px 0 3px"><a class="page" href="${getPageUrlResize(maxPageSize)}">全部显示</a></span> <#elseif pageSize==maxPageSize> <span class="selectedPage" style="padding:2px 3px 0 3px"><a class="page" href="${getPageUrlResize(defaultPageSize)}">分页显示</a></span> </#if> <#if (pageCount <= 11)> <#local startPage = 1> <#local endPage = pageCount> <#elseif (pageNum + 5 > pageCount)> <#local startPage = pageCount - 10> <#local endPage = pageCount> <#elseif (pageNum - 5 < 1)> <#local startPage = 1> <#local endPage = 11> <#else> <#local startPage = pageNum - 5> <#local endPage = pageNum + 5> </#if> <#if (pageCount > 1)> <#if (pageNum != 1)> <#if (pageCount > 11)> <a class="page" href="${getPageUrl(1)}" style="font-family:Webdings" title="首页">9</a> </#if> <a class="page" href="${getPageUrl(pageNum-1)}" style="font-family:Webdings" title="上页">3</a> <#else> <#if (pageCount > 11)> <span style="font-family:Webdings;color:#999">9</span> </#if> <span style="font-family:Webdings;color:#999">3</span> </#if> <#list startPage..endPage as x> <#if x=pageNum> <span class="selectedPage">${x}</span> <#else> <span class="noSelectedPage"><a class="page" href="${getPageUrl(x)}">${x}</a></span> </#if> </#list> <#if (pageCount != pageNum)> <a class="page" href="${getPageUrl(pageNum+1)}" style="font-family:Webdings" title="下页">4</a> <#if (pageCount > 11)> <a class="page" href="${getPageUrl(pageCount)}" style="font-family:Webdings" title="尾页">:</a> </#if> <#else> <span style="font-family:Webdings;color:#999">4</span> <#if (pageCount > 11)> <span style="font-family:Webdings;color:#999">:</span> </#if> </#if> </#if> </td> </tr> </table> </#if> </#macro>
之后,我们来运行项目:
可以通过点击全部显示和页面来查看分页效果。
本文系作者本人的实践探索,方案可能不是最佳实践,希望和大家交流沟通,源码随附件可以下载。另外关于本文涉及到的技术可以参看本博客中以往对iBatis的介绍:
框架系列:框架技术,
最后,希望它对使用者和学习有用。根据大家的反馈意见全新修改。
评论
16 楼
宋建勇
2012-05-31
Very beautiful,效果非常棒,不过初学freemarker,请问${base}是在哪里定义的
15 楼
sarin
2012-04-03
anduo1989 写道
首先,楼主的分页很好,但是采用的是ibatis本身的游标分页,这样不能运用到大数据量的系统中。
使用数据库物理分页就行了
14 楼
anduo1989
2012-04-03
首先,楼主的分页很好,但是采用的是ibatis本身的游标分页,这样不能运用到大数据量的系统中。
13 楼
xieye
2011-05-06
richard_2010 写道
分页查询要两次操作数据库感觉不怎么好,有无一次操作数据库就ok的方案?
还真不知道,我都是查两遍的,一遍总数,一遍结果集,
总数或许可以缓存,我没试过。
12 楼
sarin
2011-05-04
yin_bp 写道
这个分页过于复杂,请看bbossgroups 中mvc demo中所带的分页功能,非常简单,
demo下载地址:
[url]http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download [/url]
demo部署方法(带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026245
mvc eclipse开发工程下载和搭建方法(不带url重写功能):
[url]http://yin-bp.iteye.com/admin/blogs/1026261 [/url]
demo下载地址:
[url]http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download [/url]
demo部署方法(带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026245
mvc eclipse开发工程下载和搭建方法(不带url重写功能):
[url]http://yin-bp.iteye.com/admin/blogs/1026261 [/url]
呵呵,这个只是为了说明iBatis的分页思路,当然分页的实现会有很多了。
11 楼
yin_bp
2011-05-04
这个分页过于复杂,请看bbossgroups 中mvc demo中所带的分页功能,非常简单,
demo下载地址:
[url]http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download [/url]
demo部署方法(带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026245
mvc eclipse开发工程下载和搭建方法(不带url重写功能):
[url]http://yin-bp.iteye.com/admin/blogs/1026261 [/url]
demo下载地址:
[url]http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download [/url]
demo部署方法(带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026245
mvc eclipse开发工程下载和搭建方法(不带url重写功能):
[url]http://yin-bp.iteye.com/admin/blogs/1026261 [/url]
10 楼
yin_bp
2011-05-04
这个分页过于复杂,请看bbossgroups 中mvc demo中所带的分页功能,非常简单,
demo下载地址:
[url]http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download [/url]
demo部署方法(带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026245
mvc eclipse开发工程下载和搭建方法(不带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026261
demo下载地址:
[url]http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download [/url]
demo部署方法(带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026245
mvc eclipse开发工程下载和搭建方法(不带url重写功能):
http://yin-bp.iteye.com/admin/blogs/1026261
9 楼
sarin
2011-05-04
根据大家的经验分享,全新修改实现。
8 楼
sarin
2011-05-04
mavlarn 写道
在execute()里面:
this.rowCount = sqlMapClientTemplate.queryForList(statementName,
parameterObject).size();
查找记录总数也是用相同的sql完全查一遍,只是不加pagenum,pagesize,然后看返回的list的大小,这样会有问题。
首先,如果list很大的话,对数据库资源的消耗,网络传输,已经返回的数据转换成java的对象,所有这些都白白消耗了很多资源。
其次,一般查询个数和查询详细记录的sql是不太一样的,查询个数的时候可以做一些优化。例如,对于不需要的字段,如果是在其他表里面,就不需要进行表的连接。
所以,对于查询总数的sql,应该单独写。
this.rowCount = sqlMapClientTemplate.queryForList(statementName,
parameterObject).size();
查找记录总数也是用相同的sql完全查一遍,只是不加pagenum,pagesize,然后看返回的list的大小,这样会有问题。
首先,如果list很大的话,对数据库资源的消耗,网络传输,已经返回的数据转换成java的对象,所有这些都白白消耗了很多资源。
其次,一般查询个数和查询详细记录的sql是不太一样的,查询个数的时候可以做一些优化。例如,对于不需要的字段,如果是在其他表里面,就不需要进行表的连接。
所以,对于查询总数的sql,应该单独写。
这样做是个解决办法,那么就在编写SQL的时候一次要写两条了,而且要传两个查询id进来了。
7 楼
mavlarn
2011-05-04
在execute()里面:
this.rowCount = sqlMapClientTemplate.queryForList(statementName,
parameterObject).size();
查找记录总数也是用相同的sql完全查一遍,只是不加pagenum,pagesize,然后看返回的list的大小,这样会有问题。
首先,如果list很大的话,对数据库资源的消耗,网络传输,已经返回的数据转换成java的对象,所有这些都白白消耗了很多资源。
其次,一般查询个数和查询详细记录的sql是不太一样的,查询个数的时候可以做一些优化。例如,对于不需要的字段,如果是在其他表里面,就不需要进行表的连接。
所以,对于查询总数的sql,应该单独写。
this.rowCount = sqlMapClientTemplate.queryForList(statementName,
parameterObject).size();
查找记录总数也是用相同的sql完全查一遍,只是不加pagenum,pagesize,然后看返回的list的大小,这样会有问题。
首先,如果list很大的话,对数据库资源的消耗,网络传输,已经返回的数据转换成java的对象,所有这些都白白消耗了很多资源。
其次,一般查询个数和查询详细记录的sql是不太一样的,查询个数的时候可以做一些优化。例如,对于不需要的字段,如果是在其他表里面,就不需要进行表的连接。
所以,对于查询总数的sql,应该单独写。
6 楼
sarin
2011-05-04
richard_2010 写道
分页查询要两次操作数据库感觉不怎么好,有无一次操作数据库就ok的方案?
因为涉及到count总量,那么可以使用ibatis的API获得原SQL,然后加一层count,这样势必不能继续使用ibatis来执行了,要引入另外一种数据库访问API,那么可以是jdbcTemplate。这个问题我也考虑到了,因为没有什么更好的办法,所以如果大家有的话可以分享一下。
5 楼
richard_2010
2011-05-03
分页查询要两次操作数据库感觉不怎么好,有无一次操作数据库就ok的方案?
4 楼
sarin
2011-05-03
xianshi_cn 写道
想问一句:
this.list = sqlMapClientTemplate.queryForList(statementName,
parameterObject, (pageNum - 1) * pageSize, pageSize);
分页是调用数据库底层的物理分页,还是用游标在内存中分页?
this.list = sqlMapClientTemplate.queryForList(statementName,
parameterObject, (pageNum - 1) * pageSize, pageSize);
分页是调用数据库底层的物理分页,还是用游标在内存中分页?
代码中的log4j设置了sql的日志,在那里面就能看到向数据库发送的sql了,也就可以看到是底层物理分页还是游标分页了。
3 楼
xianshi_cn
2011-05-03
想问一句:
this.list = sqlMapClientTemplate.queryForList(statementName,
parameterObject, (pageNum - 1) * pageSize, pageSize);
分页是调用数据库底层的物理分页,还是用游标在内存中分页?
this.list = sqlMapClientTemplate.queryForList(statementName,
parameterObject, (pageNum - 1) * pageSize, pageSize);
分页是调用数据库底层的物理分页,还是用游标在内存中分页?
2 楼
sarin
2011-05-03
fatesymphony 写道
嗯,楼主的分页效果没错。
但是不知道为什么在BaseService会出现如下代码ActionContext.getContext().getValueStack();
但是不知道为什么在BaseService会出现如下代码ActionContext.getContext().getValueStack();
这是从值栈中获取分页参数啊
1 楼
fatesymphony
2011-05-03
嗯,楼主的分页效果没错。
但是不知道为什么在BaseService会出现如下代码ActionContext.getContext().getValueStack();
但是不知道为什么在BaseService会出现如下代码ActionContext.getContext().getValueStack();
发表评论
-
iBatis操作DDL和映射继承
2012-09-09 21:46 9280本文系iBatis开发详解系列文章之iBatis操作D ... -
iBatis查询复杂集合
2012-09-04 20:23 15774本文系iBatis开发详解系列文章之在iBatis查询 ... -
iBatis中使用XML
2012-08-29 19:57 7705本文系iBatis开发详解系列文章之在iBatis中使 ... -
iBatis执行非查询语句(CRUD,函数和过程)
2012-08-26 21:40 9325CRUD操作中除了查询操作,其他都统一称为更新操作,因 ... -
Spring数据库访问之iBatis(二)
2012-06-10 13:56 5807接上文,我们继续来研究Spring和iBatis的整合 ... -
Spring数据库访问之iBatis(一)
2012-01-02 18:45 16000为了丰富博客专栏【Spring数据库访问系列】的内容, ... -
我的视频教程《中小企业OA系统》
2011-07-29 22:27 7752经过5个月的制作,和华章合作的《中小企业OA系统》Ja ... -
Spring数据库访问之ORM(三)
2011-03-02 20:35 17624本文接上一篇继续研究。 之前我们使用的是Hib ... -
Spring数据库访问之ORM(二)
2011-02-16 13:19 23400本文接上一篇继续来研究Spring的ORM模块。 ... -
Spring数据库访问之ORM(一)
2011-01-27 10:54 30831Spring数据库访问中另外一大模块就是ORM,ORM ... -
Spring数据库访问之异常处理
2011-01-19 10:29 27517使用JDBC API时,很 ... -
Spring数据库访问(HSQL)(四)
2011-01-16 21:49 14594本文接上一篇继续研究Spring的JDBC模板。 ... -
Spring数据库访问(HSQL)(三)
2011-01-13 10:07 13446本文接上一篇继续研究JDBC模板。 之前说的都 ... -
Spring数据库访问(HSQL)(二)
2011-01-11 11:27 10731上一篇我们介绍了 ... -
Spring数据库访问(HSQL)(一)
2011-01-09 23:34 13841本部分主要介绍Spring的JDBC模板,JDBC模板 ... -
Spring 3之MVC & Security简单整合开发(三)
2010-12-03 19:04 22083本文接上一篇继续深入研究Security框架。 ... -
Spring 3之MVC & Security简单整合开发(二)
2010-12-01 20:29 60103本文接上一篇继续 ... -
Spring 3之MVC & Security简单整合开发(一)
2010-11-30 22:00 42658Spring的MVC模块是一种简洁的Web应用框架,实 ... -
iBatis查询select详解
2010-08-07 12:19 40532<select>是iBatis已经映射的语 ... -
iBatis查询API
2010-07-31 13:04 17699先说点基础的内容 ...
相关推荐
Struts2、Spring和iBatis是Java Web开发中常用的三个框架,它们组合起来可以构建出高效、可维护的企业级应用程序。Struts2是一个MVC(Model-View-Controller)框架,Spring则是一个全面的后端解决方案,包括依赖注入...
6. **整合Struts2和Spring**:在Struts2的Action类中,通过Spring的`@Autowired`注解注入Service或DAO。同时,需要在`struts.xml`中配置Action类,使用Spring插件的`spring-plugin`拦截器: ```xml ...
本教程将讲解如何在iBatis中实现分页查询,特别是结合Struts2和Freemarker进行集成。 1. **iBatis分页基础** iBatis 提供了对分页查询的支持,可以通过设置SQL语句中的LIMIT和OFFSET子句来实现。LIMIT用于指定每页...
在这个架构中,Spring作为“粘合剂”将Struts2和Ibatis整合在一起。例如,Spring可以管理Struts2的Action实例,提供事务控制,并通过AOP进行异常处理。Ibatis则作为数据访问层,负责与数据库交互,Spring可以通过DAO...
Struts2、Spring和iBATIS(通常写作MyBatis)是Java开发中常见的三大框架,它们各自在不同的层面上提供了强大的功能,并且能够很好地整合在一起,形成一个高效的MVC(Model-View-Controller)架构。这个例子是基于...
本文档旨在通过一个简单的示例项目,帮助初学者快速理解并掌握ibatis(现称MyBatis)的基本使用方法及其与Struts2和Spring框架集成的方式。ibatis是一个支持普通SQL查询、存储过程以及高级映射的优秀数据库持久层...
主流技术struts2+spring2.5+ibaits+freemarker+restfull整合开发增删改查例子,带分页功能哦,分页和qq新闻分页一样的效果,项目结构清晰,拓展强。程序在myeclipse6.5下开发完成,jar包里面都有,直接导入就可以...
Struts 是一个基于 Model-View-Controller (MVC) 设计模式的开源Java Web框架,由Apache软件基金会维护。在本项目"struts电商网站"中,它被用来构建一个简单的小型电子商务平台,旨在为新手提供学习和实践的基础。让...
Struts2通过Action和Result来实现请求和响应的管理,Spring通过IOC(Inversion of Control)和AOP(Aspect-Oriented Programming)来管理对象和处理横切关注点,Ibatis通过XML或注解配置来定义SQL语句,实现了对...
在Web OA项目中,开发者使用Struts+Hibernate+Spring构建多层架构,利用ThreadLocal实现分页,运用JBPM和Freemarker实现工作流程,而CRM项目则展示了其在营销管理、销售管理等方面的应用。 综上所述,这位Java...
本文档旨在通过一个简单的示例来介绍如何将Struts2、Spring和Ibatis(现称为MyBatis)三个框架整合在一起,构建一个基本的Web应用程序。这种整合方式常被称为SSI(Struts2 + Spring + Ibatis/MyBatis)。对于初学者...
- **iBatis**:一个基于Java的持久层框架,用于简化SQL语句的编写和执行。 - **Spring**:负责管理业务对象的生命周期以及依赖注入。 - **Struts2**:负责接收并处理HTTP请求。 这些Jar包的引入确保了项目的正常...
##### SpringMVC、struts1和struts2区别 - **SpringMVC**:轻量级框架,与Spring无缝集成。 - **Struts1**:较早的MVC框架,使用ActionForm。 - **Struts2**:基于拦截器的设计模式。 ##### Struts2中result中的...
- **复杂度**:最坏情况和平均情况的时间复杂度为O(n^2)。 ##### 二分查找法 - **算法**:每次将查找区间分成两半,根据中间元素与目标值的比较结果缩小查找范围。 - **适用条件**:适用于已排序数组。 ##### ...