Mybatis插件开发
MyBatis采用责任链模式,通过动态代理组织多个插件(拦截器) ,允许用户自定义拦截器类,从而实现插件开发功能。
默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler(getParameterObject, setParameters)
- ResultSetHandler(handleResultSets, handleOutputParameters)
- StatementHandler(prepare, parameterize, batch, update, query)
1. 拦截器接口介绍
Mybatis插件可以通过实现接口org.apache.ibatis.plugin.Interceptor
Interceptor接口源码:
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
Object plugin(Object target);
void setProperties(Properties properties);
}
- Object intercept(Invocation invocation):是mybatis要执行的拦截方法。
- Object plugin(Object target):在创建被拦截的接口实现类时调用。
- void setProperties(Properties properties):用来传递插件参数,可以通过参数修改插件的行为。
2. 拦截器签名介绍
Mybatis插件实现需要给接口实现类配置拦截器签名。需要在实现类上配置注解。
@Intercepts
和@Signature
注解。注解类源码如下:
public @interface Intercepts {
Signature[] value();
}
public @interface Signature {
Class<?> type();
String method();
Class<?>[] args();
}
@Intercepts
注解中的属性为@Signature
数组,可以在同一个拦截器中同时拦截不同的接口和方法。
@Signature
注解包含3个属性。
type:设置拦截的接口。参数值为Executor、ParameterHandler、ResultSetHandler、StatementHandler
4个接口
method:设置拦截接口中的方法名。参数为上面4个接口中的方法名。
args:设置拦截方法的参数类型数组。通过方法名和参数类型确定唯一的一个方法。
Executor接口源码
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement ms, Object parameter) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean required) throws SQLException;
void rollback(boolean required) throws SQLException;
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
boolean isCached(MappedStatement ms, CacheKey key);
void clearLocalCache();
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
Transaction getTransaction();
void close(boolean forceRollback);
boolean isClosed();
void setExecutorWrapper(Executor executor);
}
ParameterHandler接口源码:
public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps)
throws SQLException;
}
ResultSetHandler接口源码:
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
StatementHandler接口源码:
public interface StatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
void parameterize(Statement statement)
throws SQLException;
void batch(Statement statement)
throws SQLException;
int update(Statement statement)
throws SQLException;
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler();
}
3. Mybatis PageHelper插件使用
3.1 通过Maven引入Jar包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
注意pagehelper版本和mybatis版本。版本差异可能导致如下错误。
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor
3.2 mybatis-config.xml中添加plugin
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 方言 -->
<property name="dialect" value="mysql"/>
<!-- 该参数默认为false -->
<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
<property name="rowBoundsWithCount" value="true"/>
</plugin>
</plugins>
3.3 CountryMapper.xml
<select id="getCountry" resultType="com.zm.entity.Country">
select id,countryname,countrycode from country
</select>
3.4 测试类
@Test
public void test8() {
SqlSession session = sqlSessionFactory.openSession();
CountryMapper mapper = session.getMapper(CountryMapper.class);
// pageNum 第几页 pageSize 每页的条数
PageHelper.startPage(1,3);
List<Country> list = mapper.getCountry();
PageInfo<Country> info = new PageInfo<>(list);
list.forEach(country -> System.out.println(country));
System.out.println("------------");
System.out.println("查询结果条数:"+info.getTotal());
System.out.println("数据总页数:"+info.getPages());
System.out.println("每页的size:"+info.getPageSize());
System.out.println("最后页数:"+info.getEndRow());
}
3.5 结果
DEBUG [main] - ==> Preparing: SELECT count(0) FROM country
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 1
DEBUG [main] - ==> Preparing: select id,countryname,countrycode from country limit ?,?
DEBUG [main] - ==> Parameters: 0(Integer), 3(Integer)
DEBUG [main] - <== Total: 3
Country{id=1, countryname='中国', countrycode='CN'}
Country{id=2, countryname='美国', countrycode='US'}
Country{id=3, countryname='俄罗斯', countrycode='RU'}
------------
查询结果条数:7
数据总页数:3
每页的size:3
最后页数:3
3.6 PageInfo 类的方法
private void calcNavigatepageNums()
private void calcPage()
private void judgePageBoudary()
public int getPageNum()
public void setPageNum(int pageNum)
public int getPageSize()
public void setPageSize(int pageSize)
public int getSize()
public void setSize(int size)
public String getOrderBy()
public void setOrderBy(String orderBy)
public int getStartRow()
public void setStartRow(int startRow)
public int getEndRow()
public void setEndRow(int endRow)
public long getTotal()
public void setTotal(long total)
public int getPages()
public void setPages(int pages)
public List<T> getList()
public void setList(List<T> list)
public int getFirstPage()
public void setFirstPage(int firstPage)
public int getPrePage()
public void setPrePage(int prePage)
public int getNextPage()
public void setNextPage(int nextPage)
public int getLastPage()
public void setLastPage(int lastPage)
public boolean isIsFirstPage()
public void setIsFirstPage(boolean isFirstPage)
public boolean isIsLastPage()
public void setIsLastPage(boolean isLastPage)
public boolean isHasPreviousPage()
public void setHasPreviousPage(boolean hasPreviousPage)
public boolean isHasNextPage()
public void setHasNextPage(boolean hasNextPage)
public int getNavigatePages()
public void setNavigatePages(int navigatePages)
public int[] getNavigatepageNums()
public void setNavigatepageNums(int[] navigatepageNums)
public int getNavigateFirstPage()
public int getNavigateLastPage()
public void setNavigateFirstPage(int navigateFirstPage)
public void setNavigateLastPage(int navigateLastPage)
public String toString()