前言
本文整理並製作一個簡單的分頁插件
什麼時候應用了插件?
public class Configuration {
// 1
public Executor newExecutor(
Transaction transaction, ExecutorType executorType) {
...
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
// 2
public ParameterHandler newParameterHandler(
MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang()
.createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
// 3
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
// 4
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
}
定製插件
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Page implements Serializable {
// 頁號
private int number;
// 每頁數量
private int size;
}
查詢
@Select("select * from user")
List<Student> selectByPage(String name, Page page);
使用
mapper.selectByPage("小明", new Page(1, 10))
變爲sql
select * from student limit 10,20
實現目標分解:
-
修改SQL 並添加 limit 語句
-
判斷方法參數中是否有Page對象
-
取出Page對象,加入limit
-
上述操作必須在PreparedStatement 對像生成前完成
插件類
public class PagePlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return null;
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Proxy.newProxyInstance(PagePlugin.class.getClassLoader(),
new Class[]{StatementHandler.class},
new PageHandler((StatementHandler) target));
}
return target;
}
@Override
public void setProperties(Properties properties) {
}
private class PageHandler implements InvocationHandler {
StatementHandler handler;
public PageHandler(StatementHandler handler) {
this.handler = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("prepare".equalsIgnoreCase(method.getName())) {
setParametersProxy();
}
return method.invoke(handler, args);
}
private void setParametersProxy() {
if (handler.getBoundSql().getParameterObject() instanceof Map) {
((Map) handler.getBoundSql().getParameterObject()).values().stream()
.filter(a -> a instanceof Page)
.findFirst()
.ifPresent(
page -> appendPageSql((Page) page)
);
}
}
private void appendPageSql(Page page) {
try {
BoundSql sql = handler.getBoundSql();
sql.getSql();
String limit = String.format(" limit %s,%s", page.getBegin(), page.getSzie());
setFileValue("sql", sql, sql.getSql() limit);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private Object getFileValue(String fileName, Object target) throws NoSuchFieldException, IllegalAccessException {
Field sqlField = target.getClass().getDeclaredField(fileName);
sqlField.setAccessible(true);
return sqlField.get(target);
}
private Object setFileValue(String fileName, Object target, Object value) throws NoSuchFieldException, IllegalAccessException {
Field sqlField = target.getClass().getDeclaredField(fileName);
sqlField.setAccessible(true);
sqlField.set(target, value);
return sqlField.get(target);
}
}
註冊插件 mybatis-config.xml
<configuration>
<plugins>
<plugin interceptor="com.xm.mybatis.plugin.PagePlugin"/>
</plugins>
</configuration>