Mybatis之#{}和${}的区别及其实现方式

来源:互联网 发布:存货毕业设计数据分析 编辑:程序博客网 时间:2024/04/28 08:01
简单的说#{}和${}的区别:$是String 拼接插入的#则是占位符来做处理的,写法比如字符串类型,$需要自己添加''#就不需要添加,对于日志的差别就是$会打印在日志里面,#则显示?
        大多数我们都是用#{} 因为可以防止sql注入,但是有时候${}还是很必要的,比如传入tableName,或者fieldName比如Order By id||time 就需要${}传入 #{}就无法搞定
typeHandler就无法对${}起作用
---只有明白工具是如何玩耍的,我们才能更好的使用工具
        先介绍一个解析#{}和${}的类,这里${}就替换成对对应的值了,而#{}替换成?,并且在这里解析了这个属性的字段,包括判断了类型等等

public class GenericTokenParser {
 
  private final String openToken;//这个比如#{ 或者${
  private final String closeToken;//这里基本上就是}
  private final TokenHandler handler;//根据#{key}或者${key}得到key的值
 
  public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
    this.openToken = openToken;
    this.closeToken = closeToken;
    this.handler = handler;
  }
 /**
*这个就是替换的了${key} 然后通过hanlder获取value 拼接进去
**/
  public String parse(String text) {
    StringBuilder builder = new StringBuilder();
    if (text != null && text.length() > 0) {
      char[] src = text.toCharArray();
      int offset = 0;
      int start = text.indexOf(openToken, offset);
      while (start > -1) {
        if (start > 0 && src[start - 1] == '\\') {
          // the variable is escaped. remove the backslash.
          builder.append(src, offset, start - 1).append(openToken);
          offset = start + openToken.length();
        else {
          int end = text.indexOf(closeToken, start);
          if (end == -1) {
            builder.append(src, offset, src.length - offset);
            offset = src.length;
          else {
            builder.append(src, offset, start - offset);
            offset = start + openToken.length();
            String content = new String(src, offset, end - offset);//拿到#{key}||${key}中的key
            builder.append(handler.handleToken(content));//根据key获取对应的"value"
            offset = end + closeToken.length();
          }
        }
        start = text.indexOf(openToken, offset);
      }
      if (offset < src.length) {
        builder.append(src, offset, src.length - offset);
      }
    }
    return builder.toString();
  }
 
}

其实最大的区别也就是下面的两个不同的实现类
1.${} 的解析实现类
判断一下参数的类型,然后就把value给搞定了,没有添加其他的东西,万能的Ognl
private static class BindingTokenParser implements TokenHandler {
 
    private DynamicContext context;
 
    public BindingTokenParser(DynamicContext context) {
      this.context = context;
    }
 
    public String handleToken(String content) {
      Object parameter = context.getBindings().get("_parameter");
      if (parameter == null) {
        context.getBindings().put("value"null);
      else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
        context.getBindings().put("value", parameter);
      }
      Object value = OgnlCache.getValue(content, context.getBindings());
      return (value == null "" : String.valueOf(value)); // issue #274 return "" instead of "null"
    }
  }

2.#{} 的解析实现类
这里就比较复杂了,判断了javaType,typeHandler,数字精度,通过hanlder,我们就可以处理一些列复杂的数据
private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
 
    private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
    private Class<?> parameterType;
    private MetaObject metaParameters;
 
    public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {
      super(configuration);
      this.parameterType = parameterType;
      this.metaParameters = configuration.newMetaObject(additionalParameters);
    }
 
    public List<ParameterMapping> getParameterMappings() {
      return parameterMappings;
    }
 
    public String handleToken(String content) {
      parameterMappings.add(buildParameterMapping(content));
      return "?";
    }
 
//这里就是把#{key}内容进行解析成一个带有一些列属性的类然后再由一些列typehanlder来setValue
    private ParameterMapping buildParameterMapping(String content) {
      Map<String, String> propertiesMap = parseParameterMapping(content);
      String property = propertiesMap.get("property");
      Class<?> propertyType;
      if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
        propertyType = metaParameters.getGetterType(property);
      else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
        propertyType = parameterType;
      else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
        propertyType = java.sql.ResultSet.class;
      else if (property != null) {
        MetaClass metaClass = MetaClass.forClass(parameterType);
        if (metaClass.hasGetter(property)) {
          propertyType = metaClass.getGetterType(property);
        else {
          propertyType = Object.class;
        }
      else {
        propertyType = Object.class;
      }
      ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
      Class<?> javaType = propertyType;
      String typeHandlerAlias = null;
      for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
        String name = entry.getKey();
        String value = entry.getValue();
        if ("javaType".equals(name)) {
          javaType = resolveClass(value);
          builder.javaType(javaType);
        else if ("jdbcType".equals(name)) {
          builder.jdbcType(resolveJdbcType(value));
        else if ("mode".equals(name)) {
          builder.mode(resolveParameterMode(value));
        else if ("numericScale".equals(name)) {
          builder.numericScale(Integer.valueOf(value));
        else if ("resultMap".equals(name)) {
          builder.resultMapId(value);
        else if ("typeHandler".equals(name)) {
          typeHandlerAlias = value;
        else if ("jdbcTypeName".equals(name)) {
          builder.jdbcTypeName(value);
        else if ("property".equals(name)) {
          // Do Nothing
        else if ("expression".equals(name)) {
          throw new BuilderException("Expression based parameters are not supported yet");
        else {
          throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}.  Valid properties are " + parameterProperties);
        }
      }
      if (typeHandlerAlias != null) {
        builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
      }
      return builder.build();
    }
 
    private Map<String, String> parseParameterMapping(String content) {
      try {
        return new ParameterExpression(content);
      catch (BuilderException ex) {
        throw ex;
      catch (Exception ex) {
        throw new BuilderException("Parsing error was found in mapping #{" + content + "}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex);
      }
    }
  }
1 0
原创粉丝点击