源码分析 iBatis简单动态SQL处理($$)

  在iBatis中对于$param$的处理方法是怎么样的呢?下面将通过源码解读具体的处理逻辑

 

public class SimpleDynamicSql implements Sql {

  private static final Probe PROBE = ProbeFactory.getProbe();

  // 分词字符
  private static final String ELEMENT_TOKEN = "$";

  private String sqlStatement;

  private SqlMapExecutorDelegate delegate;

  public SimpleDynamicSql(SqlMapExecutorDelegate delegate, String sqlStatement) {
    this.delegate = delegate;
    this.sqlStatement = sqlStatement;
  }
// 获取sql
  public String getSql(StatementScope statementScope, Object parameterObject) {
    return processDynamicElements(sqlStatement, parameterObject);
  }

  public ParameterMap getParameterMap(StatementScope statementScope, Object parameterObject) {
    return statementScope.getParameterMap();
  }

  public ResultMap getResultMap(StatementScope statementScope, Object parameterObject) {
    return statementScope.getResultMap();
  }

  public void cleanup(StatementScope statementScope) {
  }
// 如果sql不为null且存在$则认为是简单动态sql
  public static boolean isSimpleDynamicSql(String sql) {
    return sql != null && sql.indexOf(ELEMENT_TOKEN) > -1;
  }

  private String processDynamicElements(String sql, Object parameterObject) {
  // 新建一个分词工具
    StringTokenizer parser = new StringTokenizer(sql, ELEMENT_TOKEN, true);
    StringBuffer newSql = new StringBuffer();

    String token = null;
    String lastToken = null;
	//如果sql中含有$
    while (parser.hasMoreTokens()) {
	// 获取第一个分词对象
      token = parser.nextToken();
		//如果最后一个分词对象等于$
      if (ELEMENT_TOKEN.equals(lastToken)) {
        if (ELEMENT_TOKEN.equals(token)) {
          newSql.append(ELEMENT_TOKEN);
          token = null;
        } else {
// 如果lastToken=$且token不等于$则将token替换为token对应的属性值,默认为空字符串
          Object value = null;
          if (parameterObject != null) {
            if (delegate.getTypeHandlerFactory().hasTypeHandler(parameterObject.getClass())) {
              value = parameterObject;
            } else {
              value = PROBE.getObject(parameterObject, token);
            }
          }
          if (value != null) {
            newSql.append(String.valueOf(value));
          }
          //获取下一个分词,如果下一个分词不是$则抛出异常
          token = parser.nextToken();
          if (!ELEMENT_TOKEN.equals(token)) {
            throw new SqlMapException("Unterminated dynamic element in sql (" + sql + ").");
          }
          token = null;
        }
		// 如果最后一个分词对象不等于$
      } else {
	     //如果当前分词不是$在将当前分词追加在newSql中
        if (!ELEMENT_TOKEN.equals(token)) {
          newSql.append(token);
        }
		// 如果当前分词等于$则不做任何处理
      }
		//将当前分词赋值给最后一次分词
      lastToken = token;
    }

    return newSql.toString();
  }


}

 

 例如:select * from $a$,param={a,tax_refund_info}的分词结果是:


select * from

$

a

$

第一次循环:
  lastToken=null,
  token=select*from
 
  lastToken!=$

  newSql=select* from
 
 lastToken=select*from
 
第二次循环
  lastToken=select * from
  token=$
 //doNothing
 lastToken=$
第三次循环
  lastToken=$
  token=a;
 
  newSql=select * from tax_refund_info
 
 第三次循环
   lastToken=a;
   token=$
   //doNothing
   newSql=select * from  tax_refund_info
  
 我们可以发现这样的查询完全无法防止SQL注入攻击。

 

你可能感兴趣的:(ibatis)