简单的说#{}和${}的区别:$是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);
}
}
}
时间: 2024-10-07 17:30:35