Mybatis攔截器分頁
阿新 • • 發佈:2018-11-11
使用攔截器
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 !"".equals(message.command.trim())"> and COMMAND=#{message.command} </if> <if test="message.description != null and !"".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);
}