Commit bfb705b0 authored by 雍欢's avatar 雍欢

SelectSqlInvokeStrategy命名参数可以使用in表达式

parent 25d8efbe
package com.topsunit.query.binding;
import com.topsunit.query.annotations.Param;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author yonghuan
*/
public class DefaultParameterParser implements ParameterParser {
private final static Pattern NAMED_PARAMETER_PATTERN = Pattern.compile(":([a-zA-Z][a-zA-Z0-9]*)");
@Override
public Object[] parse(String sql, Method method, Object[] args) {
if (useNamedParameter(method, args)) {
Map<String, Object> params = new HashMap<>(args.length);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Param param = parameter.getAnnotation(Param.class);
params.put(param.value(), args[i]);
}
List<Object> parsedArgs = new ArrayList<>(args.length);
for (Matcher matcher = NAMED_PARAMETER_PATTERN.matcher(sql); matcher.find(); ) {
String paramName = matcher.group(1);
Object paramValue = params.get(paramName);
if (paramValue instanceof Collection) {
parsedArgs.addAll((Collection<?>) paramValue);
} else {
parsedArgs.add(paramValue);
}
}
return parsedArgs.toArray(new Object[parsedArgs.size()]);
} else {
return args;
}
}
private boolean useNamedParameter(Method method, Object[] args) {
long paramAnnotationCount = Arrays.stream(method.getParameters())
.map(parameter -> parameter.getAnnotation(Param.class))
.filter(Objects::nonNull)
.count();
if (paramAnnotationCount == 0) {
return false;
}
if (paramAnnotationCount != args.length) {
throw new IllegalArgumentException("Param注解数量与实参数量不一致");
}
return true;
}
}
package com.topsunit.query.binding;
import com.topsunit.query.annotations.Param;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* @author yonghuan
*/
public class DefaultSqlTranslator implements SqlTranslator {
private final Map<String, String> sqlCache = new ConcurrentHashMap<>(200);
@Override
public String translate(String sql, Method method, Object[] args) {
final String cacheKey = method.getDeclaringClass().getName() + "." + method.getName();
String cachedSql = sqlCache.get(cacheKey);
if (cachedSql != null) {
return cachedSql;
}
sql = translateInternal(sql, method, args);
sqlCache.put(cacheKey, sql);
return sql;
}
private String translateInternal(String sql, Method method, Object[] args) {
if (useNamedParameter(method, args)) {
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Param param = parameter.getAnnotation(Param.class);
String paramName = param.value();
Object paramValue = args[i];
if (paramValue instanceof Collection) {
String str = (String) ((Collection) paramValue).stream()
.map(obj -> "?")
.collect(Collectors.joining(","));
sql = sql.replaceAll(":" + paramName, str);
} else {
sql = sql.replaceAll(":" + paramName, "?");
}
}
}
return sql;
}
private boolean useNamedParameter(Method method, Object[] args) {
long paramAnnotationCount = Arrays.stream(method.getParameters())
.map(parameter -> parameter.getAnnotation(Param.class))
.filter(Objects::nonNull)
.count();
if (paramAnnotationCount == 0) {
return false;
}
if (paramAnnotationCount != args.length) {
throw new IllegalArgumentException("Param注解数量与实参数量不一致");
}
return true;
}
}
......@@ -20,7 +20,7 @@ public class MapperProxy<T> implements InvocationHandler {
public MapperProxy(Class<T> mapperInterface, String xml, SQLExecutorDao sqlExecutor) {
invokeContext = new InvokeContextImpl(mapperInterface, xml, sqlExecutor);
invokeStrategies = new ArrayList<>(4);
invokeStrategies.add(new SelectSqlInvokeStrategy());
invokeStrategies.add(new SelectSqlInvokeStrategy(new DefaultSqlTranslator(), new DefaultParameterParser()));
invokeStrategies.add(new ObtainSqlInvokeStrategy());
invokeStrategies.add(new ObtainQueryDescriptorInvokeStrategy());
invokeStrategies.add(new SqlQueryInvokeStrategy());
......
package com.topsunit.query.binding;
import java.lang.reflect.Method;
/**
* @author yonghuan
*/
public interface ParameterParser {
Object[] parse(String sql, Method method, Object[] args);
}
package com.topsunit.query.binding;
import com.huigou.cache.DictUtil;
import com.huigou.context.ThreadLocalUtil;
import com.huigou.data.query.executor.SQLExecutorDao;
import com.topsunit.query.annotations.Param;
import com.huigou.util.Constants;
import com.topsunit.query.annotations.Dictionary;
import com.topsunit.query.annotations.ResultType;
import com.topsunit.query.annotations.Select;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
......@@ -20,6 +22,14 @@ import java.util.Map;
*/
final class SelectSqlInvokeStrategy extends ObtainSqlInvokeStrategy {
private final SqlTranslator sqlTranslator;
private final ParameterParser parameterParser;
public SelectSqlInvokeStrategy(SqlTranslator sqlTranslator, ParameterParser parameterParser) {
this.sqlTranslator = sqlTranslator;
this.parameterParser = parameterParser;
}
@Override
public boolean supports(InvokeContext invokeContext, Method method, Object[] args) {
return method.getAnnotation(Select.class) != null;
......@@ -27,11 +37,28 @@ final class SelectSqlInvokeStrategy extends ObtainSqlInvokeStrategy {
@Override
public Object invoke(InvokeContext invokeContext, Method method, Object[] args) {
final String sql = (String) super.invoke(invokeContext, method, args);
String sql = (String) super.invoke(invokeContext, method, args);
// 优先解析参数
Object[] parsedArgs = parameterParser.parse(sql, method, args);
// 然后再翻译SQL
sql = sqlTranslator.translate(sql, method, args);
final Class<?> returnType = method.getReturnType();
final SQLExecutorDao sqlExecutor = invokeContext.getSqlExecutor();
final ResultType resultType = method.getAnnotation(ResultType.class);
if (ArrayUtils.isEmpty(args)) {
// 解析字典配置
Dictionary[] dictionaries = method.getAnnotationsByType(Dictionary.class);
if (dictionaries.length > 0) {
Map<String, Object> dictionaryMap = new HashMap<>(dictionaries.length);
for (Dictionary dictionary : dictionaries) {
if (StringUtils.isNotEmpty(dictionary.value()) && StringUtils.isNotEmpty(dictionary.field())) {
dictionaryMap.put(dictionary.field(), DictUtil.getDictionary(dictionary.value()));
}
}
ThreadLocalUtil.putVariable(Constants.DICTIONARY_MAP, dictionaryMap);
}
if (ArrayUtils.isEmpty(parsedArgs)) {
// 无查询参数
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, resultType.value());
......@@ -45,13 +72,13 @@ final class SelectSqlInvokeStrategy extends ObtainSqlInvokeStrategy {
}
}
}
if (args.length == 1) {
if (args[0] instanceof Map) {
if (parsedArgs.length == 1) {
if (parsedArgs[0] instanceof Map) {
// 查询参数用Map传递
return queryByMapParam(sqlExecutor, sql, returnType, resultType, (Map<String, Object>) args[0]);
return queryByMapParam(sqlExecutor, sql, returnType, resultType, (Map<String, Object>) parsedArgs[0]);
} else {
// 单个查询参数
final Object singletonParam = args[0];
final Object singletonParam = parsedArgs[0];
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, resultType.value(), singletonParam);
}
......@@ -63,27 +90,16 @@ final class SelectSqlInvokeStrategy extends ObtainSqlInvokeStrategy {
: sqlExecutor.queryOneToObject(sql, returnType, singletonParam);
}
} else {
Parameter[] parameters = method.getParameters();
if (parameters[0].getAnnotation(Param.class) == null) {
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, returnType, args);
}
if (Map.class.isAssignableFrom(returnType)) {
sqlExecutor.queryOneToMap(sql, args);
}
return resultType != null
? sqlExecutor.queryOneToObject(sql, resultType.value(), args)
: sqlExecutor.queryOneToObject(sql, returnType, args);
} else {
// 指定了查询参数的名称
final Map<String, Object> mapParam = new HashMap<>(parameters.length);
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String paramName = parameter.getAnnotation(Param.class).value();
mapParam.put(paramName, args[i]);
}
return queryByMapParam(sqlExecutor, sql, returnType, resultType, mapParam);
if (Collection.class.isAssignableFrom(returnType)) {
return sqlExecutor.queryToList(sql, resultType.value(), parsedArgs);
}
if (Map.class.isAssignableFrom(returnType)) {
sqlExecutor.queryOneToMap(sql, parsedArgs);
}
return resultType != null
? sqlExecutor.queryOneToObject(sql, resultType.value(), parsedArgs)
: sqlExecutor.queryOneToObject(sql, returnType, parsedArgs);
}
}
......
package com.topsunit.query.binding;
import java.lang.reflect.Method;
/**
* SQL解析器
*
* @author yonghuan
*/
public interface SqlTranslator {
String translate(String sql, Method method, Object[] args);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment