最近一個項目要進行重構,需要把之前的ibatis轉爲mybatis,其中有幾個方法是需要返回一個Map對象,我就到網上找方法,但找了半天,發現網上的好多都是同時指定Map的Key和Value,但現在項目需求是指指定Key值,而Value爲實體類,於是我就把網上的方法進行了改善,代碼如下:
1、MapParam.java
需要mybatis返回Map時需要指定參數類型爲MapParam,可以通過構造函數單獨指定Key,也可以同時指定Key和Value屬性。
public class MapParam extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
private static final String KEY_FIELD = "_mapKeyField_";
private static final String VALUE_FIELD = "_mapValueField_";
public MapParam(String keyField) {
this.put(KEY_FIELD, keyField);
}
public MapParam(String keyField, String valueField) {
this.put(KEY_FIELD, keyField);
this.put(VALUE_FIELD, valueField);
}
public String getKeyField() {
return (String)this.get(KEY_FIELD);
}
public String getValueField() {
return (String)this.get(VALUE_FIELD);
}
}
2、MapInterceptor.java
攔截mybatis的結果集處理方法,進行自定義操作
@Intercepts(@Signature(method = "handleResultSets", type = ResultSetHandler.class, args = { Statement.class }))
public class MapInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
if (target instanceof FastResultSetHandler) {
FastResultSetHandler handler = (FastResultSetHandler) target;
ParameterHandler pHandler = Reflect.getFieldValue(handler,
"parameterHandler");
Object paramObj = pHandler.getParameterObject();
if (paramObj instanceof MapParam) {
MapParam param = (MapParam) paramObj;
String keyField = param.getKeyField();
String valueField = param.getValueField();
if (valueField == null) {
return handleKeyResult(invocation.proceed(), keyField);
} else {
Statement statement = (Statement) invocation.getArgs()[0];
return handleResultSet(statement.getResultSet(), keyField,
valueField);
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
private Object handleKeyResult(Object resultObj, String keyField) {
List<?> list = (List<?>) resultObj;
Map<Object, Object> map = new HashMap<Object, Object>();
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
Object key = null;
if (obj instanceof Map<?, ?>) {
Map<?, ?> tmpMap = (Map<?, ?>) obj;
key = (Object) tmpMap.get(keyField);
} else {
key = Reflect.getFieldValue(obj, keyField);
}
map.put(key, obj);
}
List<Object> resultList = new ArrayList<Object>();
resultList.add(map);
return resultList;
}
private Object handleResultSet(ResultSet resultSet, String keyField,
String valueField) {
if (resultSet != null) {
// 定義用於存放Key-Value的Map
Map<Object, Object> map = new HashMap<Object, Object>();
// handleResultSets的結果一定是一個List,當我們的對應的Mapper接口定義的是返回一個單一的元素,並且handleResultSets返回的列表
// 的size爲1時,Mybatis會取返回的第一個元素作爲對應Mapper接口方法的返回值。
List<Object> resultList = new ArrayList<Object>();
try {
// 把每一行對應的Key和Value存放到Map中
while (resultSet.next()) {
Object key = resultSet.getObject(keyField);
Object value = resultSet.getObject(valueField);
map.put(key, value);
}
} catch (SQLException e) {
} finally {
closeResultSet(resultSet);
}
// 把封裝好的Map存放到List中並進行返回
resultList.add(map);
return resultList;
}
return null;
}
/**
* 關閉ResultSet
*
* @param resultSet
* 需要關閉的ResultSet
*/
private void closeResultSet(ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
} catch (SQLException e) {
}
}
}
3、Reflect.java
通過反射方法,獲取攔截對象中的某些參數
public class Reflect {
@SuppressWarnings("unchecked")
public static <T> T getFieldValue(Object obj, String fieldName) {
Object result = null;
Field field = getField(obj, fieldName);
if (field != null) {
field.setAccessible(true);
try {
result = field.get(obj);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return (T) result;
}
/**
* 利用反射獲取指定對象裏面的指定屬性
*
* @param obj
* 目標對象
* @param fieldName
* 目標屬性
* @return 目標字段
*/
private static Field getField(Object obj, String fieldName) {
Field field = null;
for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz
.getSuperclass()) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
// 這裏不用做處理,子類沒有該字段可能對應的父類有,都沒有就返回null。
}
}
return field;
}
}
4、註冊攔截器
在mybatis配置文件中註冊自定義攔截器,由於mybatis配置文件限制,各個標籤的位置必須按順序來,我之前不清楚,加進去之後配置文件老是報錯
<plugins>
<plugin interceptor="com.aspirecn.mcp.common.interceptor.MapInterceptor"></plugin>
</plugins>