自定義MyBatis返回Map物件
阿新 • • 發佈:2019-01-24
最近一個專案要進行重構,需要把之前的ibatis轉為mybatis,其中有幾個方法是需要返回一個Map物件,我就到網上找方法,但找了半天,發現網上的好多都是同時指定Map的Key和Value,但現在專案需求是指指定Key值,而Value為實體類,於是我就把網上的方法進行了改善,程式碼如下:
1、MapParam.java
需要mybatis返回Map時需要指定引數型別為MapParam,可以通過建構函式單獨指定Key,也可以同時指定Key和Value屬性。
2、MapInterceptor.javapublic 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); } }
攔截mybatis的結果集處理方法,進行自定義操作
3、Reflect.java@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) { } } }
通過反射方法,獲取攔截物件中的某些引數
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>