8. MyBatis - 深度學習 - 插件原理與定製

前言

本文整理並製作一個簡單的分頁插件

什麼時候應用了插件?

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;
  }
}

img

定製插件

@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

實現目標分解:

  1. 修改SQL 並添加 limit 語句

  2. 判斷方法參數中是否有Page對象

  3. 取出Page對象,加入limit

  4. 上述操作必須在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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章