欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在mybatis執(zhí)行SQL語句之前進(jìn)行攔擊處理實例

 更新時間:2017年04月24日 10:56:50   作者:黃飛Gary  
本篇文章主要介紹了在mybatis執(zhí)行SQL語句之前進(jìn)行攔擊處理實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。

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

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

相關(guān)文章

  • Java實現(xiàn)大文件的切割與合并操作示例

    Java實現(xiàn)大文件的切割與合并操作示例

    這篇文章主要介紹了Java實現(xiàn)大文件的切割與合并操作,結(jié)合實例形式分析了java基于io及util操作大文件按指定個數(shù)分割與合并相關(guān)操作技巧,需要的朋友可以參考下
    2018-07-07
  • springboot實現(xiàn)分段上傳功能的示例代碼

    springboot實現(xiàn)分段上傳功能的示例代碼

    這篇文章主要介紹了springboot實現(xiàn)分段上傳,包括文件上傳下載,斷點續(xù)傳,增量上傳功能,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • springBoot2.X配置全局捕獲異常的操作

    springBoot2.X配置全局捕獲異常的操作

    這篇文章主要介紹了springBoot2.X配置全局捕獲異常的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot學(xué)習(xí)之全局異常處理設(shè)置(返回JSON)

    SpringBoot學(xué)習(xí)之全局異常處理設(shè)置(返回JSON)

    本篇文章主要介紹了SpringBoot學(xué)習(xí)之全局異常處理設(shè)置(返回JSON),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Java中l(wèi)ombok的@Builder注解的解析與簡單使用詳解

    Java中l(wèi)ombok的@Builder注解的解析與簡單使用詳解

    這篇文章主要介紹了Java中l(wèi)ombok的@Builder注解的解析與簡單使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • java如何調(diào)用Groovy腳本

    java如何調(diào)用Groovy腳本

    這篇文章主要介紹了java如何調(diào)用Groovy腳本問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 如何在java 8 map中使用stream

    如何在java 8 map中使用stream

    這篇文章主要介紹了如何在java 8 map中使用stream,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • SpringBoot中的健康檢查詳解

    SpringBoot中的健康檢查詳解

    這篇文章主要介紹了SpringBoot中的健康檢查詳解,健康檢查是一種用來確保應(yīng)用程序和其所依賴的服務(wù)的狀態(tài)正常的機制,在本文中,我們將探討SpringBoot中的健康檢查是什么以及如何使用它來監(jiān)視應(yīng)用程序的狀態(tài),需要的朋友可以參考下
    2023-07-07
  • springboot注入servlet的方法

    springboot注入servlet的方法

    本篇文章主要介紹了springboot注入servlet的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Spring Boot日志收集及鏈路追蹤實現(xiàn)示例

    Spring Boot日志收集及鏈路追蹤實現(xiàn)示例

    這篇文章主要為大家介紹了Spring Boot日志收集及鏈路追蹤實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評論