亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

在mybatis執行SQL語句之前進行攔擊處理實例

2019-11-26 12:30:10
字體:
來源:轉載
供稿:網友

比較適用于在分頁時候進行攔截。對分頁的SQL語句通過封裝處理,處理成不同的分頁sql。

實用性比較強。

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;  /**  *  * 分頁攔截器,用于攔截需要進行分頁查詢的操作,然后對其進行分頁處理。  * 利用攔截器實現Mybatis分頁的原理:  * 要利用JDBC對數據庫進行操作就必須要有一個對應的Statement對象,Mybatis在執行Sql語句前就會產生一個包含Sql語句的Statement對象,而且對應的Sql語句  * 是在Statement之前產生的,所以我們就可以在它生成Statement之前對用來生成Statement的Sql語句下手。在Mybatis中Statement語句是通過RoutingStatementHandler對象的  * prepare方法生成的。所以利用攔截器實現Mybatis分頁的一個思路就是攔截StatementHandler接口的prepare方法,然后在攔截器方法中把Sql語句改成對應的分頁查詢Sql語句,之后再調用  * StatementHandler對象的prepare方法,即調用invocation.proceed()。  * 對于分頁而言,在攔截器里面我們還需要做的一個操作就是統計滿足當前條件的記錄一共有多少,這是通過獲取到了原始的Sql語句后,把它改為對應的統計語句再利用Mybatis封裝好的參數和設  * 置參數的功能把Sql語句中的參數進行替換,之后再執行查詢記錄數的Sql語句進行總記錄數的統計。  *  */  @Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})}) public class PageInterceptor implements Interceptor {   private String dialect = ""; //數據庫方言    private String pageSqlId = ""; //mapper.xml中需要攔截的ID(正則匹配)        public Object intercept(Invocation invocation) throws Throwable {     //對于StatementHandler其實只有兩個實現類,一個是RoutingStatementHandler,另一個是抽象類BaseStatementHandler,      //BaseStatementHandler有三個子類,分別是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,      //SimpleStatementHandler是用于處理Statement的,PreparedStatementHandler是處理PreparedStatement的,而CallableStatementHandler是      //處理CallableStatement的。Mybatis在進行Sql語句處理的時候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面擁有一個      //StatementHandler類型的delegate屬性,RoutingStatementHandler會依據Statement的不同建立對應的BaseStatementHandler,即SimpleStatementHandler、      //PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的實現都是調用的delegate對應的方法。      //我們在PageInterceptor類上已經用@Signature標記了該Interceptor只攔截StatementHandler接口的prepare方法,又因為Mybatis只有在建立RoutingStatementHandler的時候      //是通過Interceptor的plugin方法進行包裹的,所以我們這里攔截到的目標對象肯定是RoutingStatementHandler對象。     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;          //通過反射獲取delegate父類BaseStatementHandler的mappedStatement屬性          MappedStatement mappedStatement = (MappedStatement)ReflectHelper.getFieldValue(delegate, "mappedStatement");          //攔截到的prepare方法參數是一個Connection對象          Connection connection = (Connection)invocation.getArgs()[0];          //獲取當前要執行的Sql語句,也就是我們直接在Mapper映射語句中寫的Sql語句          String sql = boundSql.getSql();          //給當前的page參數對象設置總記錄數          this.setTotalRecord(page,              mappedStatement, connection);          //獲取分頁Sql語句          String pageSql = this.getPageSql(page, sql);          //利用反射設置當前BoundSql對應的sql屬性為我們建立好的分頁Sql語句          ReflectHelper.setFieldValue(boundSql, "sql", pageSql);        }      }      return invocation.proceed();    }      /**    * 給當前的參數對象page設置總記錄數    *    * @param page Mapper映射語句對應的參數對象    * @param mappedStatement Mapper映射語句    * @param connection 當前的數據庫連接    */    private void setTotalRecord(Page<?> page,        MappedStatement mappedStatement, Connection connection) {      //獲取對應的BoundSql,這個BoundSql其實跟我們利用StatementHandler獲取到的BoundSql是同一個對象。      //delegate里面的boundSql也是通過mappedStatement.getBoundSql(paramObj)方法獲取到的。      BoundSql boundSql = mappedStatement.getBoundSql(page);      //獲取到我們自己寫在Mapper映射語句中對應的Sql語句      String sql = boundSql.getSql();      //通過查詢Sql語句獲取到對應的計算總記錄數的sql語句      String countSql = this.getCountSql(sql);      //通過BoundSql獲取對應的參數映射      List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();      //利用Configuration、查詢記錄數的Sql語句countSql、參數映射關系parameterMappings和參數對象page建立查詢記錄數對應的BoundSql對象。      BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, page);      //通過mappedStatement、參數對象page和BoundSql對象countBoundSql建立一個用于設定參數的ParameterHandler對象      ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, page, countBoundSql);      //通過connection建立一個countSql對應的PreparedStatement對象。      PreparedStatement pstmt = null;      ResultSet rs = null;      try {        pstmt = connection.prepareStatement(countSql);        //通過parameterHandler給PreparedStatement對象設置參數        parameterHandler.setParameters(pstmt);        //之后就是執行獲取總記錄數的Sql語句和獲取結果了。        rs = pstmt.executeQuery();        if (rs.next()) {         int totalRecord = rs.getInt(1);         //給當前的參數page對象設置總記錄數         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();        }      }    }       /**    * 根據原Sql語句獲取對應的查詢總記錄數的Sql語句    * @param sql    * @return    */    private String getCountSql(String sql) {      int index = sql.indexOf("from");      return "select count(*) " + sql.substring(index);    }       /**    * 根據page對象獲取對應的分頁查詢Sql語句,這里只做了兩種數據庫類型,Mysql和Oracle    * 其它的數據庫都 沒有進行分頁    *    * @param page 分頁對象    * @param sql 原sql語句    * @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數據庫的分頁查詢語句   * @param page 分頁對象   * @param sqlBuffer 包含原sql語句的StringBuffer對象   * @return Mysql數據庫分頁語句   */    private String getMysqlPageSql(Page<?> page, StringBuffer sqlBuffer) {     //計算第一條記錄的位置,Mysql中記錄的位置是從0開始的。  //   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數據庫的分頁查詢語句   * @param page 分頁對象   * @param sqlBuffer 包含原sql語句的StringBuffer對象   * @return Oracle數據庫的分頁查詢語句   */    private String getOraclePageSql(Page<?> page, StringBuffer sqlBuffer) {     //計算第一條記錄的位置,Oracle分頁是通過rownum進行的,而rownum是從1開始的     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語句拼接之后大概是這個樣子:     //select * from (select u.*, rownum r from (select * from t_user) u where rownum < 31) where r >= 16     return sqlBuffer.toString();    }           /**    * 攔截器對應的封裝原始對象的方法    */       public Object plugin(Object arg0) {      // TODO Auto-generated method stub      if (arg0 instanceof StatementHandler) {        return Plugin.wrap(arg0, this);      } else {        return arg0;      }    }      /**    * 設置注冊攔截器時設定的屬性    */    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指定要掃描的包,在此包之下的映射器都會被搜索到,可指定多個包,包與包之間用逗號或分號分隔-->     <property name="basePackage" value="com.yidao.mybatis.dao" />     <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />   </bean>      <!-- MyBatis 分頁攔截器-->   <bean id="paginationInterceptor" class="com.mybatis.interceptor.PageInterceptor">     <property name="dialect" value="mysql"/>      <!-- 攔截Mapper.xml文件中,id包含query字符的語句 -->      <property name="pageSqlId" value=".*query$"/>   </bean>  

Page類

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類

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

  以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美另类在线观看| 亚洲国产精久久久久久久| 国产精品免费久久久久久| 国产精品久久久久久久久久久新郎| 日韩最新av在线| 亚洲欧美日本精品| 国产亚洲精品va在线观看| 亚洲欧美日韩精品久久奇米色影视| 中文字幕无线精品亚洲乱码一区| 久久国产色av| 91精品免费看| 亚洲有声小说3d| 正在播放国产一区| 日本高清不卡在线| 在线观看久久av| 日韩免费观看网站| 美女少妇精品视频| 亚洲一区二区中文字幕| www国产精品com| 久久艹在线视频| 国产精品爽爽ⅴa在线观看| 国产日韩在线看| 日本成人在线视频网址| 亚洲美女喷白浆| 九九热这里只有精品6| 日本欧美爱爱爱| 在线免费观看羞羞视频一区二区| 在线观看久久久久久| 国产精品美女在线| 国产成人精品999| 国产精品影片在线观看| 在线看片第一页欧美| 欧美理论片在线观看| 亚洲精品电影在线观看| 亚洲福利小视频| 成人网中文字幕| 91精品国产精品| 国产精品久久不能| 欧美韩国理论所午夜片917电影| 精品福利在线观看| 日韩在线观看网站| 国内自拍欧美激情| 日韩精品极品在线观看播放免费视频| 亚洲欧洲美洲在线综合| 久久国产精品免费视频| 亚洲欧美成人精品| 国产+成+人+亚洲欧洲| x99av成人免费| 91成人国产在线观看| 欧美成年人视频网站欧美| 国产成+人+综合+亚洲欧美丁香花| 国产美女主播一区| 有码中文亚洲精品| 亚洲美女视频网站| 亚洲综合在线播放| 亚洲欧美一区二区激情| 精品国产91久久久久久老师| 国产精品免费久久久久久| 国产欧美精品一区二区三区介绍| 欧美精品成人91久久久久久久| 精品视频在线播放色网色视频| 最近2019年日本中文免费字幕| 国产精品亚洲自拍| 日韩激情视频在线播放| 伦伦影院午夜日韩欧美限制| 欧美激情在线视频二区| 成人h视频在线| 成人国产精品色哟哟| 亚洲精品美女免费| 最新的欧美黄色| 国产精品69av| 亚洲黄色www网站| 伊人av综合网| 一本色道久久88综合日韩精品| 91亚洲精华国产精华| 国产精品久久久久久影视| 96精品久久久久中文字幕| 日韩在线观看免费高清| 国产日韩在线看| 亚洲免费av片| 国产欧美日韩精品在线观看| 国产精品91在线观看| 最新中文字幕亚洲| 在线视频日本亚洲性| 狠狠色狠狠色综合日日小说| 精品视频www| 久久久久久国产免费| 国产精品第2页| 色中色综合影院手机版在线观看| 亚洲淫片在线视频| 岛国av在线不卡| 欧美日韩中文字幕综合视频| 粗暴蹂躏中文一区二区三区| 久久精品国产电影| 亚洲аv电影天堂网| 日韩美女主播视频| 国产成人短视频| 国产亚洲欧美一区| 亚洲2020天天堂在线观看| 中文字幕亚洲在线| 日本精品免费一区二区三区| 视频一区视频二区国产精品| 欧美性极品xxxx做受| 亚洲三级免费看| 欧美日韩国产精品专区| 最近2019中文字幕在线高清| 久久五月情影视| 亚洲香蕉成视频在线观看| 9.1国产丝袜在线观看| 国产精品久久久久影院日本| 久久久久女教师免费一区| 国产成人+综合亚洲+天堂| 国产在线播放不卡| y97精品国产97久久久久久| 亚洲黄在线观看| 高潮白浆女日韩av免费看| 国产精品男人爽免费视频1| 久久中文字幕在线| 国产69久久精品成人| 国产精品毛片a∨一区二区三区|国| 国产精品成人免费视频| 岛国av午夜精品| 国产精品一区二区三区在线播放| 久久精品视频99| 亚洲性生活视频| 欧美电影在线观看高清| 精品国产一区二区三区久久狼黑人| 国产精品69久久久久| 欧美成人精品在线| 国产精品视频网站| 秋霞av国产精品一区| 国产主播在线一区| 国产成人亚洲综合91| 性日韩欧美在线视频| 91亚洲精华国产精华| 国产在线精品成人一区二区三区| 精品久久久国产精品999| 国产精品伦子伦免费视频| 日韩av不卡电影| 亚洲国产精品久久久久秋霞不卡| 91在线直播亚洲| 久久久久免费视频| 亚洲aaaaaa| 欧美一级在线亚洲天堂| 精品av在线播放| 91干在线观看| 久久伊人精品天天| 日韩精品视频在线观看网址| 国产精品入口夜色视频大尺度| 国产精品视频专区| 亚洲图中文字幕| 久久成人18免费网站| 亚洲第一精品久久忘忧草社区| 国产一区二区欧美日韩| 欧美午夜女人视频在线| 理论片在线不卡免费观看| 久久久久久综合网天天| 日本sm极度另类视频| 国产裸体写真av一区二区| 国产精品成人aaaaa网站| 欧美中文字幕在线| 国产亚洲精品日韩| 日韩精品视频在线播放| 亚洲网站视频福利|