1. 程式人生 > >Mybatis攔截器分頁

Mybatis攔截器分頁

使用攔截器

Web開發中我們經常會碰到分頁操作,一個專案中或許有多處使用到分頁,這時如果Java後臺使用MyBatis作為持久層,我們就可以使用MyBatis的攔截器功能來完成整個專案中多處的分頁操作,減少程式碼的冗餘。

攔截器程式碼:

//攔截StatementHandler中引數型別為Connection的prepare方法
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PageInterceptor implements Interceptor {

    private String test; // 獲取xml中配置的屬性

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        //通過MetaObject優雅訪問物件的屬性,這裡是訪問statementHandler的屬性
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
        //先攔截到RoutingStatementHandler,裡面有個StatementHandler型別的delegate變數,其實現類是BaseStatementHandler,然後就到BaseStatementHandler的成員變數mappedStatement
        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        // 配置檔案中SQL語句的ID
        String id = mappedStatement.getId();
        if(id.matches(".+ByPage$")) { //需要攔截的ID(正則匹配)
            BoundSql boundSql = statementHandler.getBoundSql();
            // 原始的SQL語句
            String sql = boundSql.getSql();
            // 查詢總條數的SQL語句
            String countSql = "select count(*) from (" + sql + ")a";
            //執行總條數SQL語句的查詢
            Connection connection = (Connection)invocation.getArgs()[0];
            PreparedStatement countStatement = connection.prepareStatement(countSql);
            ////獲取引數資訊即where語句的條件資訊,注意上面拿到的sql中引數還是用?代替的
            ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(countStatement);
            ResultSet rs = countStatement.executeQuery();

            Map<?,?> parameter = (Map<?,?>)boundSql.getParameterObject();
            Page page = (Page)parameter.get("page");
            if(rs.next()) {
                page.setTotalNumber(rs.getInt(1));
            }
            // 改造後帶分頁查詢的SQL語句
            String pageSql = sql + " limit " + page.getDbIndex() + "," + page.getDbNumber();
            metaObject.setValue("delegate.boundSql.sql", pageSql);
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        System.out.println(this.test);
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        this.test = properties.getProperty("test");
        // TODO Auto-generated method stub
    }

}

MetaObject是Mybatis提供的一個用於方便、優雅訪問物件屬性的物件,通過它可以簡化程式碼、不需要try/catch各種reflect異常,同時它支援對JavaBean、Collection、Map三種類型物件的操作。獲取MetaObject物件需要使用靜態方法MetaObject.forObject,並且需要指定ObjectFactory , ObjectWrapperFactory , ReflectorFactory(3.3.0之前不需要)。

配置攔截器:

<plugins>
    <plugin interceptor="com.chm.inteceptor.PageInterceptor">
        <property name="test" value="abc"/>
    </plugin>
</plugins>

這裡配置test的值為abc,那麼上面攔截器中test的就會被賦值為abc。

查詢SQL:

<select id="queryMessageListByPage" parameterType="java.util.Map" resultMap="MessageResult">
 select <include refid="columns"/> from MESSAGE
  <where>
    <if test="message.command != null and !&quot;&quot;.equals(message.command.trim())">
    and COMMAND=#{message.command}
   </if>
   <if test="message.description != null and !&quot;&quot;.equals(message.description.trim())">
    and DESCRIPTION like '%' #{message.description} '%'
   </if>
  </where>
  order by ID
</select>

<sql id="columns">ID,COMMAND,DESCRIPTION,CONTENT</sql>

呼叫示例:

/**
 * 根據查詢條件分頁查詢訊息列表
 */
public List<Message> queryMessageListByPage(String command,String description,Page page) {
    Map<String,Object> parameter = new HashMap<String, Object>();
    // 組織訊息物件
    Message message = new Message();
    message.setCommand(command);
    message.setDescription(description);
    parameter.put("message", message);
    parameter.put("page", page);
    MessageDao messageDao = new MessageDao();
    // 分頁查詢並返回結果
    return messageDao.queryMessageListByPage(parameter);
}