mybatis 分页拦截器,经网上资料修改可用

来源:互联网 发布:淘宝好评返现是真的吗 编辑:程序博客网 时间:2024/06/05 20:00
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})public class PaginationInterceptor implements Interceptor{    private static final Log                  logger                         = LogFactory                                                                                     .getLog(PaginationInterceptor.class);    private static final ObjectFactory        DEFAULT_OBJECT_FACTORY         = new DefaultObjectFactory();    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();    private static String                     defaultDialect                 = "mysql";                             // 数据库类型(默认为mysql)    private static String                     defaultPageSqlId               = ".*Page$";                           // 需要拦截的ID(正则匹配)    private static String                     dialect                        = "";                                  // 数据库类型(默认为mysql)    private static String                     pageSqlId                      = "";                                  // 需要拦截的ID(正则匹配)    @Override    public Object intercept(Invocation invocation) throws Throwable    {        StatementHandler statementHandler = (StatementHandler) invocation                .getTarget();        MetaObject metaStatementHandler = MetaObject.forObject(                statementHandler, DEFAULT_OBJECT_FACTORY,                DEFAULT_OBJECT_WRAPPER_FACTORY);        // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环可以分离出最原始的的目标类)        while (metaStatementHandler.hasGetter("h"))        {            Object object = metaStatementHandler.getValue("h");            metaStatementHandler = MetaObject.forObject(object,                    DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);        }        // 分离最后一个代理对象的目标类        while (metaStatementHandler.hasGetter("target"))        {            Object object = metaStatementHandler.getValue("target");            metaStatementHandler = MetaObject.forObject(object,                    DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);        }        Configuration configuration = (Configuration) metaStatementHandler                .getValue("delegate.configuration");        dialect = configuration.getVariables()==null?null:configuration.getVariables().getProperty("dialect");        if (null == dialect || "".equals(dialect))        {            logger.warn("Property dialect is not setted,use default 'mysql' ");            dialect = defaultDialect;        }        pageSqlId = configuration.getVariables()==null?null:configuration.getVariables().getProperty("pageSqlId");        if (null == pageSqlId || "".equals(pageSqlId))        {            logger.warn("Property pageSqlId is not setted,use default '.*Page$' ");            pageSqlId = defaultPageSqlId;        }        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler                .getValue("delegate.mappedStatement");        // 只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的MappedStatement的sql        if (mappedStatement.getId().matches(pageSqlId))        {            BoundSql boundSql = (BoundSql) metaStatementHandler                    .getValue("delegate.boundSql");            Object parameterObject = boundSql.getParameterObject();            if (parameterObject == null)            {                throw new NullPointerException("parameterObject is null!");            }            else            {                Pagination page = (Pagination) metaStatementHandler                        .getValue("delegate.boundSql.parameterObject.page");                String sql = boundSql.getSql();                // 重写sql                String pageSql = buildPageSql(sql, page);                metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);                // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数                metaStatementHandler.setValue("delegate.rowBounds.offset",                        RowBounds.NO_ROW_OFFSET);                metaStatementHandler.setValue("delegate.rowBounds.limit",                        RowBounds.NO_ROW_LIMIT);                Connection connection = (Connection) invocation.getArgs()[0];                // 重设分页参数里的总页数等                setPageParameter(sql, connection, mappedStatement, boundSql,                        page);            }        }        // 将执行权交给下一个拦截器        return invocation.proceed();    }    /**     * 从数据库里查询总的记录数并计算总页数,回写进分页参数<code>PageParameter</code>,这样调用者就可用通过 分页参数     * <code>PageParameter</code>获得相关信息。     *      * @param sql     * @param connection     * @param mappedStatement     * @param boundSql     * @param page     */    private void setPageParameter(String sql, Connection connection,            MappedStatement mappedStatement, BoundSql boundSql,            Pagination page)    {        // 记录总记录数        String countSql = "select count(0) from (" + sql + ") as total";        PreparedStatement countStmt = null;        ResultSet rs = null;        try        {            countStmt = connection.prepareStatement(countSql);            BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(),                    countSql, boundSql.getParameterMappings(),                    boundSql.getParameterObject());            setParameters(countStmt, mappedStatement, countBS,                    boundSql.getParameterObject());            rs = countStmt.executeQuery();            int totalCount = 0;            if (rs.next())            {                totalCount = rs.getInt(1);            }            page.setTotalCount((long)totalCount);            int totalPage = totalCount / page.getPageSize()                    + ((totalCount % page.getPageSize() == 0) ? 0 : 1);            page.setTotalPage(totalPage);        }        catch (SQLException e)        {            logger.error("Ignore this exception", e);        }        finally        {            try            {                rs.close();            }            catch (SQLException e)            {                logger.error("Ignore this exception", e);            }            try            {                countStmt.close();            }            catch (SQLException e)            {                logger.error("Ignore this exception", e);            }        }    }    /**     * 对SQL参数(?)设值     *      * @param ps     * @param mappedStatement     * @param boundSql     * @param parameterObject     * @throws SQLException     */    private void setParameters(PreparedStatement ps,            MappedStatement mappedStatement, BoundSql boundSql,            Object parameterObject) throws SQLException    {        ParameterHandler parameterHandler = new DefaultParameterHandler(                mappedStatement, parameterObject, boundSql);        parameterHandler.setParameters(ps);    }    /**     * 根据数据库类型,生成特定的分页sql     *      * @param sql     * @param page     * @return     */    private String buildPageSql(String sql, Pagination page)    {        if (page != null)        {            String pageSql = new String();            if ("mysql".equals(dialect))            {                pageSql =  MysqlDialect.getInstance().getLimitString(sql, page.getStartIndex(), page.getPageSize());            }            else if ("oracle".equals(dialect))            {                pageSql =  OracleDialect.getInstance().getLimitString(sql, page.getStartIndex(), page.getPageSize());            }            else            {                return sql;            }            return pageSql;        }        else        {            return sql;        }    }        @Override    public Object plugin(Object target)    {        // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数        if (target instanceof StatementHandler)        {            return Plugin.wrap(target, this);        }        else        {            return target;        }    }    @Override    public void setProperties(Properties properties)    {    }}

0 0
原创粉丝点击