最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Mybatis全面分頁(yè)插件

 更新時(shí)間:2016年08月22日 16:53:48   作者:junehappylove  
這篇文章主要為大家詳細(xì)介紹了Mybatis全面分頁(yè)插件的使用方法,比較適用于在分頁(yè)時(shí)候進(jìn)行攔截,感興趣的小伙伴們可以參考一下

根據(jù)下面分頁(yè)的思想,很容易實(shí)現(xiàn)Mybitas的多租戶設(shè)計(jì)。 

使用Mybatis提供的攔截器。對(duì)分頁(yè)的SQL語(yǔ)句通過(guò)封裝處理,處理成不同的分頁(yè)sql。 

本例已經(jīng)實(shí)現(xiàn)了對(duì)Mysql和Oracle的分頁(yè)功能。注意下面的引用包,不要引用錯(cuò)了。 

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;

import com.yidao.utils.Page;
import com.yidao.utils.ReflectHelper;

/** 
 * 
 * 分頁(yè)攔截器,用于攔截需要進(jìn)行分頁(yè)查詢的操作,然后對(duì)其進(jìn)行分頁(yè)處理。 
 * 利用攔截器實(shí)現(xiàn)Mybatis分頁(yè)的原理: 
 * 要利用JDBC對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作就必須要有一個(gè)對(duì)應(yīng)的Statement對(duì)象,Mybatis在執(zhí)行Sql語(yǔ)句前就會(huì)產(chǎn)生一個(gè)包含Sql語(yǔ)句的Statement對(duì)象,而且對(duì)應(yīng)的Sql語(yǔ)句 
 * 是在Statement之前產(chǎn)生的,所以我們就可以在它生成Statement之前對(duì)用來(lái)生成Statement的Sql語(yǔ)句下手。在Mybatis中Statement語(yǔ)句是通過(guò)RoutingStatementHandler對(duì)象的 
 * prepare方法生成的。所以利用攔截器實(shí)現(xiàn)Mybatis分頁(yè)的一個(gè)思路就是攔截StatementHandler接口的prepare方法,然后在攔截器方法中把Sql語(yǔ)句改成對(duì)應(yīng)的分頁(yè)查詢Sql語(yǔ)句,之后再調(diào)用 
 * StatementHandler對(duì)象的prepare方法,即調(diào)用invocation.proceed()。 
 * 對(duì)于分頁(yè)而言,在攔截器里面我們還需要做的一個(gè)操作就是統(tǒng)計(jì)滿足當(dāng)前條件的記錄一共有多少,這是通過(guò)獲取到了原始的Sql語(yǔ)句后,把它改為對(duì)應(yīng)的統(tǒng)計(jì)語(yǔ)句再利用Mybatis封裝好的參數(shù)和設(shè) 
 * 置參數(shù)的功能把Sql語(yǔ)句中的參數(shù)進(jìn)行替換,之后再執(zhí)行查詢記錄數(shù)的Sql語(yǔ)句進(jìn)行總記錄數(shù)的統(tǒng)計(jì)。 
 * 
 */ 
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PageInterceptor implements Interceptor {
 private String dialect = ""; //數(shù)據(jù)庫(kù)方言 
 private String pageSqlId = ""; //mapper.xml中需要攔截的ID(正則匹配) 
  
 public Object intercept(Invocation invocation) throws Throwable {
  //對(duì)于StatementHandler其實(shí)只有兩個(gè)實(shí)現(xiàn)類(lèi),一個(gè)是RoutingStatementHandler,另一個(gè)是抽象類(lèi)BaseStatementHandler, 
  //BaseStatementHandler有三個(gè)子類(lèi),分別是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler, 
  //SimpleStatementHandler是用于處理Statement的,PreparedStatementHandler是處理PreparedStatement的,而CallableStatementHandler是 
  //處理CallableStatement的。Mybatis在進(jìn)行Sql語(yǔ)句處理的時(shí)候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面擁有一個(gè) 
  //StatementHandler類(lèi)型的delegate屬性,RoutingStatementHandler會(huì)依據(jù)Statement的不同建立對(duì)應(yīng)的BaseStatementHandler,即SimpleStatementHandler、 
  //PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的實(shí)現(xiàn)都是調(diào)用的delegate對(duì)應(yīng)的方法。 
  //我們?cè)赑ageInterceptor類(lèi)上已經(jīng)用@Signature標(biāo)記了該Interceptor只攔截StatementHandler接口的prepare方法,又因?yàn)镸ybatis只有在建立RoutingStatementHandler的時(shí)候 
  //是通過(guò)Interceptor的plugin方法進(jìn)行包裹的,所以我們這里攔截到的目標(biāo)對(duì)象肯定是RoutingStatementHandler對(duì)象。
  if(invocation.getTarget() instanceof RoutingStatementHandler){ 
   RoutingStatementHandler statementHandler = (RoutingStatementHandler)invocation.getTarget(); 
   StatementHandler delegate = (StatementHandler) ReflectHelper.getFieldValue(statementHandler, "delegate"); 
   BoundSql boundSql = delegate.getBoundSql();
   Object obj = boundSql.getParameterObject();
   if (obj instanceof Page<?>) { 
    Page<?> page = (Page<?>) obj; 
    //通過(guò)反射獲取delegate父類(lèi)BaseStatementHandler的mappedStatement屬性 
    MappedStatement mappedStatement = (MappedStatement)ReflectHelper.getFieldValue(delegate, "mappedStatement"); 
    //攔截到的prepare方法參數(shù)是一個(gè)Connection對(duì)象 
    Connection connection = (Connection)invocation.getArgs()[0]; 
    //獲取當(dāng)前要執(zhí)行的Sql語(yǔ)句,也就是我們直接在Mapper映射語(yǔ)句中寫(xiě)的Sql語(yǔ)句 
    String sql = boundSql.getSql(); 
    //給當(dāng)前的page參數(shù)對(duì)象設(shè)置總記錄數(shù) 
    this.setTotalRecord(page, 
      mappedStatement, connection); 
    //獲取分頁(yè)Sql語(yǔ)句 
    String pageSql = this.getPageSql(page, sql); 
    //利用反射設(shè)置當(dāng)前BoundSql對(duì)應(yīng)的sql屬性為我們建立好的分頁(yè)Sql語(yǔ)句 
    ReflectHelper.setFieldValue(boundSql, "sql", pageSql); 
   } 
  } 
  return invocation.proceed(); 
 }
 
 /** 
  * 給當(dāng)前的參數(shù)對(duì)象page設(shè)置總記錄數(shù) 
  * 
  * @param page Mapper映射語(yǔ)句對(duì)應(yīng)的參數(shù)對(duì)象 
  * @param mappedStatement Mapper映射語(yǔ)句 
  * @param connection 當(dāng)前的數(shù)據(jù)庫(kù)連接 
  */ 
 private void setTotalRecord(Page<?> page, 
   MappedStatement mappedStatement, Connection connection) { 
  //獲取對(duì)應(yīng)的BoundSql,這個(gè)BoundSql其實(shí)跟我們利用StatementHandler獲取到的BoundSql是同一個(gè)對(duì)象。 
  //delegate里面的boundSql也是通過(guò)mappedStatement.getBoundSql(paramObj)方法獲取到的。 
  BoundSql boundSql = mappedStatement.getBoundSql(page); 
  //獲取到我們自己寫(xiě)在Mapper映射語(yǔ)句中對(duì)應(yīng)的Sql語(yǔ)句 
  String sql = boundSql.getSql(); 
  //通過(guò)查詢Sql語(yǔ)句獲取到對(duì)應(yīng)的計(jì)算總記錄數(shù)的sql語(yǔ)句 
  String countSql = this.getCountSql(sql); 
  //通過(guò)BoundSql獲取對(duì)應(yīng)的參數(shù)映射 
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); 
  //利用Configuration、查詢記錄數(shù)的Sql語(yǔ)句countSql、參數(shù)映射關(guān)系parameterMappings和參數(shù)對(duì)象page建立查詢記錄數(shù)對(duì)應(yīng)的BoundSql對(duì)象。 
  BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, page); 
  //通過(guò)mappedStatement、參數(shù)對(duì)象page和BoundSql對(duì)象countBoundSql建立一個(gè)用于設(shè)定參數(shù)的ParameterHandler對(duì)象 
  ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, page, countBoundSql); 
  //通過(guò)connection建立一個(gè)countSql對(duì)應(yīng)的PreparedStatement對(duì)象。 
  PreparedStatement pstmt = null; 
  ResultSet rs = null; 
  try { 
   pstmt = connection.prepareStatement(countSql); 
   //通過(guò)parameterHandler給PreparedStatement對(duì)象設(shè)置參數(shù) 
   parameterHandler.setParameters(pstmt); 
   //之后就是執(zhí)行獲取總記錄數(shù)的Sql語(yǔ)句和獲取結(jié)果了。 
   rs = pstmt.executeQuery(); 
   if (rs.next()) { 
    int totalRecord = rs.getInt(1); 
    //給當(dāng)前的參數(shù)page對(duì)象設(shè)置總記錄數(shù) 
    page.setTotalRecord(totalRecord); 
   } 
  } catch (SQLException e) { 
   e.printStackTrace(); 
  } finally { 
   try { 
    if (rs != null) 
     rs.close(); 
    if (pstmt != null) 
     pstmt.close(); 
   } catch (SQLException e) { 
    e.printStackTrace(); 
   } 
  } 
 } 
 
 /** 
  * 根據(jù)原Sql語(yǔ)句獲取對(duì)應(yīng)的查詢總記錄數(shù)的Sql語(yǔ)句 
  * @param sql 
  * @return 
  */ 
 private String getCountSql(String sql) { 
  int index = sql.indexOf("from"); 
  return "select count(*) " + sql.substring(index); 
 } 
 
 /** 
  * 根據(jù)page對(duì)象獲取對(duì)應(yīng)的分頁(yè)查詢Sql語(yǔ)句,這里只做了兩種數(shù)據(jù)庫(kù)類(lèi)型,Mysql和Oracle 
  * 其它的數(shù)據(jù)庫(kù)都 沒(méi)有進(jìn)行分頁(yè) 
  * 
  * @param page 分頁(yè)對(duì)象 
  * @param sql 原sql語(yǔ)句 
  * @return 
  */ 
 private String getPageSql(Page<?> page, String sql) { 
  StringBuffer sqlBuffer = new StringBuffer(sql); 
  if ("mysql".equalsIgnoreCase(dialect)) { 
   return getMysqlPageSql(page, sqlBuffer); 
  } else if ("oracle".equalsIgnoreCase(dialect)) { 
   return getOraclePageSql(page, sqlBuffer); 
  } 
  return sqlBuffer.toString(); 
 } 
 
 /** 
 * 獲取Mysql數(shù)據(jù)庫(kù)的分頁(yè)查詢語(yǔ)句 
 * @param page 分頁(yè)對(duì)象 
 * @param sqlBuffer 包含原sql語(yǔ)句的StringBuffer對(duì)象 
 * @return Mysql數(shù)據(jù)庫(kù)分頁(yè)語(yǔ)句 
 */ 
 private String getMysqlPageSql(Page<?> page, StringBuffer sqlBuffer) { 
  //計(jì)算第一條記錄的位置,Mysql中記錄的位置是從0開(kāi)始的。 
// System.out.println("page:"+page.getPage()+"-------"+page.getRows());
  int offset = (page.getPage() - 1) * page.getRows(); 
  sqlBuffer.append(" limit ").append(offset).append(",").append(page.getRows()); 
  return sqlBuffer.toString(); 
 } 
 
 /** 
 * 獲取Oracle數(shù)據(jù)庫(kù)的分頁(yè)查詢語(yǔ)句 
 * @param page 分頁(yè)對(duì)象 
 * @param sqlBuffer 包含原sql語(yǔ)句的StringBuffer對(duì)象 
 * @return Oracle數(shù)據(jù)庫(kù)的分頁(yè)查詢語(yǔ)句 
 */ 
 private String getOraclePageSql(Page<?> page, StringBuffer sqlBuffer) { 
  //計(jì)算第一條記錄的位置,Oracle分頁(yè)是通過(guò)rownum進(jìn)行的,而rownum是從1開(kāi)始的 
  int offset = (page.getPage() - 1) * page.getRows() + 1; 
  sqlBuffer.insert(0, "select u.*, rownum r from (").append(") u where rownum < ").append(offset + page.getRows()); 
  sqlBuffer.insert(0, "select * from (").append(") where r >= ").append(offset); 
  //上面的Sql語(yǔ)句拼接之后大概是這個(gè)樣子: 
  //select * from (select u.*, rownum r from (select * from t_user) u where rownum < 31) where r >= 16 
  return sqlBuffer.toString(); 
 } 
 
  
 /** 
  * 攔截器對(duì)應(yīng)的封裝原始對(duì)象的方法 
  */  
 public Object plugin(Object arg0) { 
  // TODO Auto-generated method stub 
  if (arg0 instanceof StatementHandler) { 
   return Plugin.wrap(arg0, this); 
  } else { 
   return arg0; 
  } 
 } 
 
 /** 
  * 設(shè)置注冊(cè)攔截器時(shí)設(shè)定的屬性 
  */ 
 public void setProperties(Properties p) {
  
 }

 public String getDialect() {
 return dialect;
 }

 public void setDialect(String dialect) {
 this.dialect = dialect;
 }

 public String getPageSqlId() {
 return pageSqlId;
 }

 public void setPageSqlId(String pageSqlId) {
 this.pageSqlId = pageSqlId;
 }
 
} 

xml配置: 

<!-- MyBatis 接口編程配置 -->
 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <!-- basePackage指定要掃描的包,在此包之下的映射器都會(huì)被搜索到,可指定多個(gè)包,包與包之間用逗號(hào)或分號(hào)分隔-->
  <property name="basePackage" value="com.yidao.mybatis.dao" />
  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
 </bean>
 
 <!-- MyBatis 分頁(yè)攔截器-->
 <bean id="paginationInterceptor" class="com.mybatis.interceptor.PageInterceptor">
  <property name="dialect" value="mysql"/> 
  <!-- 攔截Mapper.xml文件中,id包含query字符的語(yǔ)句 --> 
  <property name="pageSqlId" value=".*query$"/>
 </bean> 

Page類(lèi)

 package com.yidao.utils;


/**自己看看,需要什么字段加什么字段吧*/
public class Page {
 
 private Integer rows;
 
 private Integer page = 1;
 
 private Integer totalRecord;

 public Integer getRows() {
 return rows;
 }

 public void setRows(Integer rows) {
 this.rows = rows;
 }

 public Integer getPage() {
 return page;
 }

 public void setPage(Integer page) {
 this.page = page;
 }

 public Integer getTotalRecord() {
 return totalRecord;
 }

 public void setTotalRecord(Integer totalRecord) {
 this.totalRecord = totalRecord;
 }
 
}


ReflectHelper類(lèi)

package com.yidao.utils;

import java.lang.reflect.Field;

import org.apache.commons.lang3.reflect.FieldUtils;

public class ReflectHelper {
 
 public static Object getFieldValue(Object obj , String fieldName ){
 
 if(obj == null){
 return null ;
 }
 
 Field targetField = getTargetField(obj.getClass(), fieldName);
 
 try {
 return FieldUtils.readField(targetField, obj, true ) ;
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } 
 return null ;
 }
 
 public static Field getTargetField(Class<?> targetClass, String fieldName) {
 Field field = null;

 try {
 if (targetClass == null) {
 return field;
 }

 if (Object.class.equals(targetClass)) {
 return field;
 }

 field = FieldUtils.getDeclaredField(targetClass, fieldName, true);
 if (field == null) {
 field = getTargetField(targetClass.getSuperclass(), fieldName);
 }
 } catch (Exception e) {
 }

 return field;
 }
 
 public static void setFieldValue(Object obj , String fieldName , Object value ){
 if(null == obj){return;}
 Field targetField = getTargetField(obj.getClass(), fieldName); 
 try {
 FieldUtils.writeField(targetField, obj, value) ;
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 } 
 } 
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java合并區(qū)間的實(shí)現(xiàn)

    Java合并區(qū)間的實(shí)現(xiàn)

    本文主要介紹了Java合并區(qū)間的實(shí)現(xiàn),通過(guò)合理使用集合類(lèi)和排序算法,可以有效地解決合并區(qū)間問(wèn)題,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • Spring?Security短信驗(yàn)證碼實(shí)現(xiàn)詳解

    Spring?Security短信驗(yàn)證碼實(shí)現(xiàn)詳解

    本文主要介紹了Spring?Security短信驗(yàn)證碼的實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • Java詳解如何將excel數(shù)據(jù)轉(zhuǎn)為樹(shù)形

    Java詳解如何將excel數(shù)據(jù)轉(zhuǎn)為樹(shù)形

    在平常的辦公工作中,excel數(shù)據(jù)的操作是最常見(jiàn)的需求,今天就來(lái)看一下通過(guò)Java如何來(lái)實(shí)現(xiàn)將excel數(shù)據(jù)轉(zhuǎn)為樹(shù)形,感興趣的朋友可以了解下
    2022-08-08
  • Java源碼解析ArrayList及ConcurrentModificationException

    Java源碼解析ArrayList及ConcurrentModificationException

    今天小編就為大家分享一篇關(guān)于Java源碼解析ArrayList及ConcurrentModificationException,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • java實(shí)現(xiàn)查找PDF關(guān)鍵字所在頁(yè)碼及其坐標(biāo)

    java實(shí)現(xiàn)查找PDF關(guān)鍵字所在頁(yè)碼及其坐標(biāo)

    這篇文章主要介紹了java實(shí)現(xiàn)查找PDF關(guān)鍵字所在頁(yè)碼及其坐標(biāo)的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Java把Map轉(zhuǎn)為對(duì)象的實(shí)現(xiàn)代碼

    Java把Map轉(zhuǎn)為對(duì)象的實(shí)現(xiàn)代碼

    在項(xiàng)目開(kāi)發(fā)中,經(jīng)常碰到map轉(zhuǎn)實(shí)體對(duì)象或者對(duì)象轉(zhuǎn)map的場(chǎng)景,工作中,很多時(shí)候我們可能比較喜歡使用第三方j(luò)ar包的API對(duì)他們進(jìn)行轉(zhuǎn)化,但這里,我想通過(guò)反射的方式對(duì)他們做轉(zhuǎn)化,感興趣的同學(xué)跟著小編來(lái)看看吧
    2023-08-08
  • SpringBoot中的@RequestMapping注解的用法示例

    SpringBoot中的@RequestMapping注解的用法示例

    @RequestMapping注解是SpringBoot中最常用的注解之一,它可以幫助開(kāi)發(fā)者定義和處理HTTP請(qǐng)求,本篇文章我們將詳細(xì)為大家介紹如何使用SpringBoot中的@RequestMapping注解,感興趣的同學(xué)跟著小編一起來(lái)學(xué)習(xí)吧
    2023-06-06
  • Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法小結(jié)

    Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法小結(jié)

    這篇文章主要介紹了Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了java根據(jù)指定范圍生成不重復(fù)隨機(jī)數(shù)的相關(guān)操作技巧,需要的朋友可以參考下
    2017-04-04
  • java list中包含某個(gè)字符串的兩種方法實(shí)現(xiàn)

    java list中包含某個(gè)字符串的兩種方法實(shí)現(xiàn)

    在Java開(kāi)發(fā)中,經(jīng)常需要判斷一個(gè)List中是否包含特定的字符串,包括使用contains()方法和循環(huán)遍歷判斷,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java Swing JLabel標(biāo)簽的使用方法

    Java Swing JLabel標(biāo)簽的使用方法

    這篇文章主要介紹了Java Swing JLabel標(biāo)簽的使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評(píng)論

花垣县| 通州区| 北碚区| 平潭县| 潞西市| 石首市| 二手房| 江西省| 池州市| 蚌埠市| 吴桥县| 屯留县| 河西区| 襄垣县| 前郭尔| 安塞县| 达日县| 锦州市| 滦南县| 赫章县| 江口县| 大余县| 锡林浩特市| 郑州市| 鸡东县| 南木林县| 尼木县| 福鼎市| 洮南市| 清河县| 宁明县| 柳林县| 信丰县| 德钦县| 绥化市| 桂平市| 洮南市| 塔河县| 云梦县| 堆龙德庆县| 化德县|