Mybatis返回Map的一种实现
public class MapParam extends HashMap<String, Object> {/** * */private static final long serialVersionUID = 1L;/** * 作为Key的字段对应MapParam的Key */public static final String KEY_FIELD = "mapKeyField";/** * 作为Value的字段对应MapParam的Key */public static final String VALUE_FIELD = "mapValueField";public MapParam() {}/** * 指定keyField和valueField * @param keyField Map中key对应的字段 * @param valueField Map中value对应的字段 */public MapParam(String keyField, String valueField) {this.put(KEY_FIELD, keyField);this.put(VALUE_FIELD, valueField);}}
@Intercepts(@Signature(method="handleResultSets", type=ResultSetHandler.class, args={Statement.class}))public class MapInterceptor implements Interceptor {/* (non-Javadoc) * @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation) */public Object intercept(Invocation invocation) throws Throwable {//通过invocation获取代理的目标对象Object target = invocation.getTarget();//暂时ResultSetHandler只有FastResultSetHandler这一种实现if (target instanceof FastResultSetHandler) {FastResultSetHandler resultSetHandler = (FastResultSetHandler) target;//利用反射获取到FastResultSetHandler的ParameterHandler属性,从而获取到ParameterObject;ParameterHandler parameterHandler = ReflectUtil.getFieldValue(resultSetHandler, "parameterHandler");Object parameterObj = parameterHandler.getParameterObject();//判断ParameterObj是否是我们定义的MapParam,如果是则进行自己的处理逻辑if (parameterObj instanceof MapParam) {//拦截到了MapParam mapParam = (MapParam) parameterObj;//获取到当前的StatementStatement stmt = (Statement) invocation.getArgs()[0];//通过Statement获取到当前的结果集,对其进行处理,并返回对应的处理结果return handleResultSet(stmt.getResultSet(), mapParam);}}//如果没有进行拦截处理,则执行默认逻辑return invocation.proceed();}/** * 处理结果集 * @param resultSet * @param mapParam * @return */private Object handleResultSet(ResultSet resultSet, MapParam mapParam) {// TODO Auto-generated method stubif (resultSet != null) {//拿到Key对应的字段String keyField = (String) mapParam.get(MapParam.KEY_FIELD);//拿到Value对应的字段String valueField = (String) mapParam.get(MapParam.VALUE_FIELD);//定义用于存放Key-Value的MapMap<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) {e.printStackTrace();} 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) {}}/* (non-Javadoc) * @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object) */public Object plugin(Object obj) {return Plugin.wrap(obj, this);}/* (non-Javadoc) * @see org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties) */public void setProperties(Properties props) {}}
?
public class ReflectUtil {/** * 利用反射获取指定对象的指定属性 * @param obj 目标对象 * @param fieldName 目标属性 * @return 目标属性的值 */@SuppressWarnings("unchecked")public static <T> T getFieldValue(Object obj, String fieldName) {Object result = null;Field field = ReflectUtil.getField(obj, fieldName);if (field != null) {field.setAccessible(true);try {result = field.get(obj);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.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;}/** * 利用反射设置指定对象的指定属性为指定的值 * @param obj 目标对象 * @param fieldName 目标属性 * @param fieldValue 目标值 */public static void setFieldValue(Object obj, String fieldName,String fieldValue) {Field field = ReflectUtil.getField(obj, fieldName);if (field != null) {try {field.setAccessible(true);field.set(obj, fieldValue);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
<plugins> <plugin interceptor="com.tiantian.mybatis.interceptor.MapInterceptor"/> </plugins>
?
<bean id="sqlSessionFactory" name="code"> <select id="find" resultType="map" parameterType="MapParam"> select code, name from t_city </select>
public interface CityMapper extends SuperMapper { public Map<Object, Object> find(MapParam param); }
@Test public void testMap() { MapParam param = new MapParam("code", "name"); Map<Object, Object> result = cityMapper.find(param); System.out.println(result); }
?????? 在这篇博客中,我只是介绍使用Mybatis拦截器实现Mybatis查询返回Map的这么一种方法,里面的代码考虑是比较粗糙的,想要在使用Mybatis拦截器拦截到ResultSetHandler的handleResultSets方法,对ResultSet做更加严谨的处理的话,推荐参考Mybatis ResultSetHandler接口的实现类FastResultSetHandler关于handleResultSets(Statement stmt)的实现。
1 楼 nichlas_yu 2013-09-16 挺好的,学习了。 2 楼 234390216 2013-09-16 nichlas_yu 写道挺好的,学习了。