將查詢結果映射成map的注解,其中第一個字段為key,第二個字段為value.


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 將查詢結果映射成map的注解,其中第一個字段為key,第二個字段為value.
* <p>
* 注:返回類型必須為{@link java.util.Map Map<K, V>}。K/V的類型通過MyBatis的TypeHander進行類型轉換,如有必要可自定義TypeHander。
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface MapF2F {
/**
* 是否允許key重復。如果不允許,而實際結果出現了重復,會拋出org.springframework.dao.DuplicateKeyException。
* @return
*/
boolean isAllowKey() default true;
}
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.vimtech.common.util.ReflectUtil;
import com.vimtech.system.configuration.annotation.MapF2F;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;


import javafx.util.Pair;

/**
* MapF2F的攔截器
*/
@Intercepts(@Signature(method = "handleResultSets", type = ResultSetHandler.class, args = { Statement.class }))
public class MapF2FInterceptor implements Interceptor {
private Logger logger = LoggerFactory.getLogger(MapF2FInterceptor.class);

@Override
public Object intercept(Invocation invocation) throws Throwable {
MetaObject metaStatementHandler = ReflectUtil.getRealTarget(invocation);
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("mappedStatement");

String className = StringUtils.substringBeforeLast(mappedStatement.getId(), ".");// 當前類
String currentMethodName = StringUtils.substringAfterLast(mappedStatement.getId(), ".");// 當前方法
Method currentMethod = findMethod(className, currentMethodName);// 獲取當前Method

if (currentMethod == null || currentMethod.getAnnotation(MapF2F.class) == null) {// 如果當前Method沒有注解MapF2F
return invocation.proceed();
}

// 如果有MapF2F注解,則這里對結果進行攔截並轉換
MapF2F mapF2FAnnotation = currentMethod.getAnnotation(MapF2F.class);
Statement statement = (Statement) invocation.getArgs()[0];
Pair<Class<?>, Class<?>> kvTypePair = getKVTypeOfReturnMap(currentMethod);// 獲取返回Map里key-value的類型
TypeHandlerRegistry typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();// 獲取各種TypeHander的注冊器
return result2Map(statement, typeHandlerRegistry, kvTypePair, mapF2FAnnotation);

}

@Override
public Object plugin(Object obj) {
return Plugin.wrap(obj, this);
}

@Override
public void setProperties(Properties properties) {

}

/**
* 找到與指定函數名匹配的Method。
*
* @param className
* @param targetMethodName
* @return
* @throws Throwable
*/
private Method findMethod(String className, String targetMethodName) throws Throwable {
Method[] methods = Class.forName(className).getDeclaredMethods();// 該類所有聲明的方法
if (methods == null) {
return null;
}

for (Method method : methods) {
if (StringUtils.equals(method.getName(), targetMethodName)) {
return method;
}
}

return null;
}

/**
* 獲取函數返回Map中key-value的類型
*
* @param mapF2FMethod
* @return left為key的類型,right為value的類型
*/
private Pair<Class<?>, Class<?>> getKVTypeOfReturnMap(Method mapF2FMethod) {
Type returnType = mapF2FMethod.getGenericReturnType();

if (returnType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) returnType;
if (!Map.class.equals(parameterizedType.getRawType())) {
throw new RuntimeException(
"[ERROR-MapF2F-return-map-type]使用MapF2F,返回類型必須是java.util.Map類型!!!method=" + mapF2FMethod);
}

return new Pair<>((Class<?>) parameterizedType.getActualTypeArguments()[0],
(Class<?>) parameterizedType.getActualTypeArguments()[1]);
}

return new Pair<>(null, null);
}

/**
* 將查詢結果映射成Map,其中第一個字段作為key,第二個字段作為value.
*
* @param statement
* @param typeHandlerRegistry MyBatis里typeHandler的注冊器,方便轉換成用戶指定的結果類型
* @param kvTypePair 函數指定返回Map key-value的類型
* @param mapF2FAnnotation
* @return
* @throws Throwable
*/
private Object result2Map(Statement statement, TypeHandlerRegistry typeHandlerRegistry,
Pair<Class<?>, Class<?>> kvTypePair, MapF2F mapF2FAnnotation) throws Throwable {
ResultSet resultSet = statement.getResultSet();
List<Object> res = new ArrayList();
Map<Object, Object> map = new HashMap();

while (resultSet.next()) {
Object key = this.getObject(resultSet, 1, typeHandlerRegistry, kvTypePair.getKey());
Object value = this.getObject(resultSet, 2, typeHandlerRegistry, kvTypePair.getValue());

if (map.containsKey(key)) {// 該key已存在
if (!mapF2FAnnotation.isAllowKey()) {// 判斷是否允許key重復
throw new DuplicateKeyException("MapF2F duplicated key!key=" + key);
}
}
map.put(key, value);// 第一列作為key,第二列作為value。
}
res.add(map);
return res;
}

/**
* 結果類型轉換。
* <p>
* 這里借用注冊在MyBatis的typeHander(包括自定義的),方便進行類型轉換。
*
* @param resultSet
* @param columnIndex 字段下標,從1開始
* @param typeHandlerRegistry MyBatis里typeHandler的注冊器,方便轉換成用戶指定的結果類型
* @param javaType 要轉換的Java類型
* @return
* @throws SQLException
*/
private Object getObject(ResultSet resultSet, int columnIndex, TypeHandlerRegistry typeHandlerRegistry,
Class<?> javaType) throws SQLException {
final TypeHandler<?> typeHandler = typeHandlerRegistry.hasTypeHandler(javaType)
? typeHandlerRegistry.getTypeHandler(javaType) : typeHandlerRegistry.getUnknownTypeHandler();

return typeHandler.getResult(resultSet, columnIndex);

}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM