在java代码中对于PageHelper的配置
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTypeAliasesPackage(MODEL_PACKAGE);
// 配置分页插件,详情请查阅官方文档
CustomPageHelper customPageHelper = new CustomPageHelper();
Properties properties = new Properties();
properties.setProperty("pageSizeZero", "true");//分页尺寸为0时查询所有纪录不再执行分页
properties.setProperty("reasonable", "true");//页码<=0 查询第一页,页码>=总页数查询最后一页
properties.setProperty("supportMethodsArguments", "true");//支持通过 Mapper 接口参数来传递分页参数
customPageHelper.setProperties(properties);
// 添加插件
factory.setPlugins(new Interceptor[]{customPageHelper});
// 添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return factory.getObject();
}
在xml中配置 Interceptor ==> PageHelper
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
配置SqlSessionFactory,主要是配置mapper映射与pageHelper
1
2
3
4
5
6
7
8
9
xml配置参考自在流云的博客
正题部分
实际上,这些配置都是在进行Mybatis插件(plugins)的配置。
Mybatis允许你在已映射语句执行过程中的某一点进行拦截调用,默认情况下,MyBatis允许使用插件来拦截的方法包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 的发行包中的源代码。 假设你想做的不仅仅是监控方法的调用,那么你应该很好的了解正在重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定了想要拦截的方法签名即可。
第一个方法,顾名思义,配置拦截器,拦截器的参数 Invocation 中带有以下属性:
- Object target
- Method method
- Object[] args
在PageHelper中,使用了sqlUtil.intercept进行了一次转发,将 Invocation 赋值给了SqlUtil的intercept方法
在这个方法中,调用了真正的拦截器方法。
第二个方法,plugin,返回了自身
第三个方法,用于配置中定义属性
@SuppressWarnings("rawtypes")
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class CustomPageHelper extends PageHelper{
private final CustomSqlUtil sqlUtil = new CustomSqlUtil();
@Override
public Object intercept(Invocation invocation) throws Throwable {
return sqlUtil.intercept(invocation);
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
sqlUtil.setProperties(properties);
}
}
这个时候反过来看,
// 配置分页插件,详情请查阅官方文档
CustomPageHelper customPageHelper = new CustomPageHelper();
Properties properties = new Properties();
properties.setProperty("pageSizeZero", "true");//分页尺寸为0时查询所有纪录不再执行分页
properties.setProperty("reasonable", "true");//页码<=0 查询第一页,页码>=总页数查询最后一页
properties.setProperty("supportMethodsArguments", "true");//支持通过 Mapper 接口参数来传递分页参数
customPageHelper.setProperties(properties);
这些属性,在PageHelper中,都是需要通过SqlUtil去处理的。
public void setProperties(Properties properties) {
super.setProperties(properties);
//多数据源时,获取jdbcurl后是否关闭数据源
String closeConn = properties.getProperty("closeConn");
//解决#97
if(StringUtil.isNotEmpty(closeConn)){
this.closeConn = Boolean.parseBoolean(closeConn);
}
//数据库方言
String dialect = properties.getProperty("dialect");
String runtimeDialect = properties.getProperty("autoRuntimeDialect");
if (StringUtil.isNotEmpty(runtimeDialect) && runtimeDialect.equalsIgnoreCase("TRUE")) {
this.autoRuntimeDialect = true;
this.autoDialect = false;
this.properties = properties;
} else if (StringUtil.isEmpty(dialect)) {
autoDialect = true;
this.properties = properties;
} else {
autoDialect = false;
this.dialect = initDialect(dialect, properties);
}
try {
//反射获取 BoundSql 中的 additionalParameters 属性
additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
additionalParametersField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
另外的,同样重要的是拦截器上的注解
@Intercepts(
@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
@Intercepts表明当前对象是一个Interceptor
@Signature则表明要拦截的接口、方法以及对应的参数类型
上面的注解表明,在查询时,type = Executor.class(暂时没弄明白),字面意思应该是在查询执行的时候,拦截了MappedStatement,Object,RowBounds,ResultHandler。
MappedStatement:对应mapper配置文件中一个节点,主要描述的是一条SQL语句。
其中有许多属性,包括使用了哪个mapper,使用了dao的哪个方法之类的。
Object:主要指的是参数
例如使用了condition进行查询,object将带有Criteria对象,entityClass,orderBy之类的属性。
RowBounds:主要指的偏移量,可以用它来进行分页(pageHelper好像并不使用它)
ResultHandler:暂时不知道是干什么的,百度说:
有些sql查询会返回一些复杂类型,这些复杂类型没有办法简单的通过xml或者注解配置来实现,这种时候我们需要实现mybatis 的ResultHandler接口,来做自定义的对象属性映射。