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

简单的说#{}和${}的区别:$是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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值