Red de conocimiento informático - Aprendizaje de programación - La diferencia entre # y $ en Mybatis y su implementación

La diferencia entre # y $ en Mybatis y su implementación

En pocas palabras, la diferencia entre # {} y $ {} es que $ se inserta mediante concatenación de cadenas y # es un marcador de posición para el procesamiento. Por ejemplo, si el método de escritura es de tipo cadena, $ debe agregarse con "#" y no es necesario agregarlo. La diferencia en el registro es que se imprimirá $ en el registro, mientras que se mostrará #.

La mayoría de nosotros usamos # {} porque puede evitar la inyección de SQL, pero a veces $ {} aún es necesario, como pasar nombre de tabla o nombre de campo como Ordenar por id||hora, esto necesitas $ {} para pasar #{}

TypeHandler no puede funcionar en ${}

Solo comprendiendo cómo funcionan las herramientas podrás usarlas mejor.

Primero introduzca una clase que analice # {} y $ {}, donde $ {} se reemplaza por un par de valores correspondientes y # {} se reemplaza por? Y aquí se analizan los campos de este atributo, incluido el tipo de juicio, etc.

Clase pública GenericTokenParser {

Cadena final privada openToken//Esto es como # {o $ {

Cadena final privada closeToken//Esto es básicamente Sí}

Manejador TokenHandler final privado; //Obtiene el valor de la clave según #{key} o ${key}

public GenericTokenParser (String open token, String closeToken, Programa de procesamiento TokenHandler). ) {

este. token abierto = token abierto;

this.closeToken = closeToken

this.handler = manejador

}

/**

*Esto es para reemplazar ${key}, luego obtener el valor a través de hanlder y unirlo.

**/

Análisis de cadenas públicas (texto de cadena) {

Constructor StringBuilder = new StringBuilder();

If (texto != nulo & amp& amptext . length()& gt; 0) {

char[]src = tochararray();

int offset = 0;

char[]src = text . tochararray();

int offset = 0;

p>

int start = text índice de (token abierto, offset);

while(start>-1) {

if(start>0& amp& ampsrc[start - 1] == '\\') {

//Variables están escapados. Elimine las barras invertidas.

builder.append(fuente, desplazamiento, inicio - 1).

append(token de apertura);

desplazamiento = inicio+token de apertura();

}else {

int end = text.indexOf(closeToken, inicio);

if (end == -1) {

builder.append(src, offset, src . length-offset); src.length

} En caso contrario {

builder.append(src, offset, start-offset);

offset = inicio+token abierto(). ;

Contenido de cadena = nueva cadena (src, offset, end-offset); //Obtener la clave en #{key}||${key}

builder . handler .handle token(content)); //Obtiene el "valor" correspondiente según la clave.

desplazamiento = fin+closetoken . longitud();

}

}

inicio = text.indexOf(openToken, desplazamiento) ;

}

if(desplazamiento & lt; longitud){

builder.append(src, desplazamiento, src . longitud-desplazamiento);

}

}

Devuelve builder.tostring();

}

}

De hecho, la mayor diferencia es la clase de implementación de análisis de las siguientes dos clases de implementación diferentes

1. ${}

Determina el tipo de parámetro, luego fija el valor, sin agregar nada más, el Ognl universal.

La clase estática privada BindingTokenParser implementa TokenHandler {

Contexto privado DynamicContext

BindingTokenParser público (contexto de contexto dinámico) {

this.context; = contexto

}

Cadena pública handleToken(contenido de cadena){

parámetro de objeto = contexto obtener enlaces(). get(" _ parámetro ");

if (parámetro == null) {

context.getBindings(). put("valor ",null);

} else if(registro de tipo simple. issimpletype(parámetro. getclass())){

context.getBindings().

put("valor", parámetro);

}

valor del objeto = ognlcache . getvalue(contenido, contexto. obtener enlaces()); valor == nulo? " ":cadena valor de(valor)); // El número 274 devuelve "" en lugar de " nulo "

}

}

2.# {} clase de implementación de análisis

Esto es más complicado, a juzgar por javaType, typeHandler y precisión digital. A través de Handler, podemos procesar algunos datos de columnas complejos.

El parámetro de clase estática privada MappingTokenHandler extiende BaseBuilder para implementar TokenHandler {

Lista de distribución personal & ltparameter mapeo& gtparameter mapeos = new ArrayList & lt;parameter mapeo>();

Clase privada<? & gtparameterType

Metaparámetro de metaobjeto privado;

parámetro público MappingTokenHandler (configuración de configuración, clase & lt?& gt tipo de parámetro, mapeo & lt cadena, objeto & gt parámetros adicionales ) {

Super(configuración);

este . tipo de parámetro = tipo de parámetro;

este . meta parámetros = configuración nuevo meta (parámetros adicionales)

}

Lista pública & mapeo de parámetros& gtgetParameterMappings() {

Devolver mapeos de parámetros

}

Público; string handleToken(string content){

asignaciones de parámetros add(buildParameterMapping(content));

Return "?";

}

p. >

//Esto es para analizar el contenido #{key} en una clase con una serie de atributos y luego establecer el valor mediante una serie de controladores de tipos.

Asignación de parámetros privados crear asignación de parámetros (contenido de cadena){

Map<String, String>properties map = parseParameterMapping(content);

propiedad de cadena = mapa de propiedades get(. " propiedad ");

Clase & lt? & gtpropertyType

if(meta parámetros. has getter(property)){//número 448 Obtener tipo de parámetros adicionales

tipo de propiedad = meta parámetros getgetter type(property);

} else if(typehandlerregistry . hastypehandler(tipo de parámetro)){

propertyType = tipo de parámetro

} else if (JdbcType.CURSOR.name().

es igual a (mapa de propiedades. get(" tipo JDBC ")){

tipo de propiedad = Java SQL . clase de resultados

} else if (propiedad! = nulo) {

Metaclase MetaClass = MetaClass . para clase(tipo de parámetro);

if(metaclase. tiene getter(propiedad)){

tipo de propiedad = metaclase. tipo(propiedad);

}else{

tipo de propiedad = Objeto.clase

}

}else{

propertyType = Object.class

}

Mapeo de parámetros. generador generador = nuevo mapa de parámetros. Constructor(configuración, propiedad, tipo de propiedad);

Clase & lt? & gtjavaType = propertyType

String typeHandlerAlias ​​​​= null

For (Fig. Entrada & ltString, String & gtentry:properties map . conjunto de entrada()){

nombre de cadena = entrada . getkey();

valor de cadena = entrada valor();

if ("tipojava". Igual a (nombre)){

javaType = resolver clase(valor);

constructor . Tipo Java(tipo Java);

} else if ("jdbcType ". Igual a (nombre)){

constructor . JDBC tipo(resolveJdbcType(valor));

} else if ("modo ". es igual a (nombre)){

constructor . resolveParameterMode(valor) );

} else if ("numericScale ". igual a (nombre)){

constructor escala numérica (entero . valor de(valor));

} else if ("resultMap"). igual a (nombre)){

builder.resultMapId(valor);

} else if ("typeHandler ". igual a (nombre)){

typeHandlerAlias ​​​​= valor

} else if ("jdbcTypeName ". Igual a (nombre)){

builder.jdbcTypeName(valor);

} else if ("Propiedad". igual a (nombre) {

//no hacer nada

} else if("expresión". igual a (nombre)){

throw new BuilderException("Los parámetros basados ​​en expresiones aún no son compatibles");

}else{

throw new BuilderException("Se encontró un valor no válido en el mapeo #{" + contenido + "} Atributo ' "+ nombre +").

Las propiedades válidas son "+propiedades de parámetros);

}

}

if (typeHandlerAlias!= null) {

builder . type handler(resolveTypeHandler(tipo Java, typeHandlerAlias));

}

Devolver builder.build();

}

Mapa privado & ltString, String & gtparseParameterMapping(string content) {

Intenta {

Devolver nueva ParameterExpression(content);

} catch (BuilderException ex) {

Throw ex;

} catch (Exception ex) {

throw new BuilderException("Error de análisis encontrado en el mapeo #{" + contenido + "} . Verifique la sintaxis #{propiedad|(expresión), var1=valor1, var2=valor2,...}", ej);

}

}

}