package cn.edu.neu.core.common;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
/**
*
* 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。
* 利用拦截器实现Mybatis分页的原理:
* 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句
* 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的
* prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用
* StatementHandler对象的prepare方法,即调用invocation.proceed()。
* 对于分页而言,在拦截器里面我们还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设
* 置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。
*
*/
@Intercepts( {
@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class}) })
public class PageInterceptor implements Interceptor {
private String databaseType;//数据库类型,不同的数据库有不同的分页方法
/**
* 拦截后要执行的方法
*/
public Object intercept(Invocation invocation) throws Throwable {
//对于StatementHandler其实只有两个实现类,一个是RoutingStatementHandler,另一个是抽象类BaseStatementHandler,
//BaseStatementHandler有三个子类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,
//SimpleStatementHandler是用于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是
//处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个
//StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、
//PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。
//我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候
//是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
//通过反射获取到当前RoutingStatementHandler对象的delegate属性
StatementHandler delegate = (StatementHandler)ReflectUtil.getFieldValue(handler, "delegate");
//获取到当前StatementHandler的 boundSql,这里不管是调用handler.getBoundSql()还是直接调用delegate.getBoundSql()结果是一样的,因为之前已经说过了
//RoutingStatementHandler实现的所有StatementHandler接口方法里面都是调用的delegate对应的方法。
BoundSql boundSql = delegate.getBoundSql();
//拿到当前绑定Sql的参数对象,就是我们在调用对应的Mapper映射语句时所传入的参数对象
Object obj = boundSql.getParameterObject();
//这里我们简单的通过传入的是Page对象就认定它是需要进行分页操作的。
if (obj instanceof Page<?>) {
Page<?> page = (Page<?>) obj;
//通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement");
//拦截到的prepare方法参数是一个Connection对象
Connection connection = (Connection)invocation.getArgs()[0];
//获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句
String sql = boundSql.getSql();
//给当前的page参数对象设置总记录数
this.setTotalRecord(page,
mappedStatement, connection);
//获取分页Sql语句
String pageSql = this.getPageSql(page, sql);
//利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
}
return invocation.proceed();
}
/**
* 拦截器对应的封装原始对象的方法
*/
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/**
* 设置注册拦截器时设定的属性
*/
public void setProperties(Properties properties) {
this.databaseType = properties.getProperty("databaseType");
}
/**
* 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle
* 其它的数据库都 没有进行分页
*
* @param page 分页对象
* @param sql 原sql语句
* @return
*/
private String getPageSql(Page<?> page, String sql) {
StringBuffer sqlBuffer = new StringBuffer(sql);
if ("mysql".equalsIgnoreCase(databaseType)) {
return getMysqlPageSql(page, sqlBuffer);
} else if ("oracle".equalsIgnoreCase(databaseType)) {
return getOraclePageSql(page, sqlBuffer);
}
return sqlBuffer.toString();
}
/**
* 获取Mysql数据库的分页查询语句
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Mysql数据库分页语句
*/
private String getMysqlPageSql(Page<?> page, StringBuffer sqlBuffer) {
//计算第一条记录的位置,Mysql中记录的位置是从0开始的。
int offset = (page.getPageNo() - 1) * page.getPageSize();
sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageSize());
return sqlBuffer.toString();
}
/**
* 获取Oracle数据库的分页查询语句
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Oracle数据库的分页查询语句
*/
private String getOraclePageSql(Page<?> page, StringBuffer sqlBuffer) {
//计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的
int offset = (page.getPageNo() - 1) * page.getPageSize() + 1;
sqlBuffer.insert(0, "select u.*, rownum r from (").append(") u
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
购物网站这个项目是我在学校的java实践项目,项目使用ssm框架,对以后的面试问题很有帮助,源码中关键部分做了注释,仅供参考.首先大体介绍下这个项目实现的内容: ●用户的注册,登录,修改密码界面. ●总商品浏览界面 ●某个商品具体信息界面 ●用户购物车及付款界面 ●数据库(数据库存放着大量的商品,用户信息) 基本上就是仿照淘宝的购物界面,导入数据库再导入源码就可以运行
资源推荐
资源详情
资源评论
收起资源包目录
购物网站源码+数据库 (248个子文件)
OrderAction.class 8KB
PageInterceptor.class 7KB
Goods.class 7KB
UserAction.class 6KB
AddressAction.class 5KB
CommonBaseAction.class 5KB
OrderServiceImpl.class 5KB
Order.class 4KB
GoodsAction.class 4KB
Page.class 4KB
GoodsServiceImpl.class 4KB
LoginInterceptor.class 3KB
UserServiceImpl.class 3KB
OrderDetail.class 3KB
Address.class 3KB
LoginFilter.class 3KB
User.class 2KB
QueryHelper.class 2KB
Constants.class 2KB
MapUtil.class 2KB
QueryUtil.class 2KB
PageInterceptor$ReflectUtil.class 2KB
Color.class 2KB
Size.class 2KB
XmlUtil.class 2KB
AddressServiceImpl.class 2KB
UserTest.class 2KB
Category.class 2KB
CateAction.class 2KB
Pic.class 2KB
IndexAction.class 2KB
ExceptionInterceptor.class 1KB
ServiceManager.class 1KB
StringUtil.class 1KB
BaseAction.class 1KB
ExecuteResult.class 1KB
CateServiceImpl.class 1016B
SpringTest.class 937B
OrderService.class 674B
OrderMapper.class 663B
UserMapper.class 632B
GoodsMapper.class 629B
GoodsService.class 628B
UserService.class 573B
AddressMapper.class 506B
AddressService.class 473B
CommonAnonymousAction.class 397B
CateMapper.class 315B
CateService.class 235B
Anonymous.class 122B
.classpath 849B
org.eclipse.wst.common.component 478B
org.eclipse.wst.jsdt.ui.superType.container 49B
bootstrap.css 144KB
bootstrap.min.css 120KB
bootstrap-theme.css 26KB
bootstrap-theme.min.css 23KB
adminnav.css 5KB
carousel.css 3KB
dashboard.css 2KB
default.css 673B
style.css 304B
glyphicons-halflings-regular.eot 20KB
adminlogo.ico 134KB
spring-context-4.2.1.RELEASE.jar 1.03MB
spring-core-4.2.1.RELEASE.jar 1.02MB
jackson-databind-2.1.5.jar 906KB
spring-webmvc-4.2.1.RELEASE.jar 847KB
spring-web-4.2.1.RELEASE.jar 751KB
spring-beans-4.2.1.RELEASE.jar 713KB
mysql-connector-java-5.1.7-bin.jar 693KB
mybatis-3.2.0.jar 684KB
joda-time-2.1.jar 557KB
spring-test-4.2.1.RELEASE.jar 548KB
log4j-1.2.16.jar 470KB
spring-jdbc-4.2.1.RELEASE.jar 413KB
standard-1.1.2.jar 384KB
spring-aop-4.2.1.RELEASE.jar 358KB
spring-tx-4.2.1.RELEASE.jar 259KB
spring-expression-4.2.1.RELEASE.jar 256KB
jsqlparser-0.9.1.jar 246KB
jackson-core-2.1.5.jar 202KB
spring-context-support-4.2.1.RELEASE.jar 175KB
commons-io-2.0.jar 156KB
commons-logging-1.1.1.jar 59KB
spring-aspects-4.2.1.RELEASE.jar 57KB
commons-fileupload-1.2.1.jar 56KB
mybatis-spring-1.2.1.jar 48KB
jackson-annotations-2.1.5.jar 34KB
jstl.jar 17KB
aopalliance.jar 4KB
PageInterceptor.java 14KB
OrderAction.java 8KB
UserAction.java 5KB
Goods.java 5KB
CommonBaseAction.java 4KB
AddressAction.java 4KB
Order.java 3KB
Page.java 3KB
Constants.java 3KB
共 248 条
- 1
- 2
- 3
资源评论
- Next码云2017-11-18代码导进来一直404 调试了半天也没好
- 冯程程啊2018-03-20不知道怎么样下载来看看
qinglangdeyitian
- 粉丝: 3
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功