拦截器(二)
使用Mybatis进行系统开发的时候,会有这么一种需求:希望通过Mybatis查询某一个表返回的结果是一个Map,而这个Map的Key是表的一个字段,Value是另一个字段。按照Mybatis的做法,指定查询Mapper语句的resultType为map时返回的结果是一个Map列表(表中有多条记录时),而且每个元素Map对应的是表的一行记录(Key为每个字段的名称,Value为对应的值),这跟需求是不相符合的。那有什么方法可以让Mybatis查询出来的结果是一个Key为表中某一列的值,Value为表中另一列的值的Map呢?
实现
返回结果是由ResultSetHandler的handleResultSets方法对当前的Statement处理后的返回结果,所以如果要改变返回结果的话,就需要使用Mybatis的拦截器对ResultSetHandler接口的handleResultSets方法进行拦截。
我们不可能把所有的ResultSet都拦截,然后返回对应的Map,所以需要在拦截到handleResultSets方法之后进行筛选,对于不需要拦截的调用Invocation的proceed()方法,需要拦截的则实现自己的逻辑,返回对应的结果。对于这种筛选条件一般是通过ParameterObject来进行的。这里定义一个类,叫MapParam,当某一个语句需要返回一个Map时,就指定其参数类型为MapParam
这个参数类型ParamMap一定需要有三个作用:
-
(1) 可以指定哪个字段为返回Map的Key;
-
(2) 可以指定哪个字段为返回Map的Value;
-
(3) 可以附带其他参数;
package mybatis.parameter; import java.util.HashMap; public class ParamMap extends HashMap<String,Object> { private final static String keyField="keyField"; private final static String valueField="valueField"; public ParamMap(){} public ParamMap(Object key,Object value){ put(keyField,key); put(valueField,value); } }
定义一个MapInterceptor用于拦截对应的结果集返回一个Map
package mybatis.interceptor; import mybatis.parameter.ParamMap; import mybatis.util.ReflectUtil; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.executor.resultset.DefaultResultSetHandler; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.plugin.*; 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.Properties; @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 DefaultResultSetHandler){ DefaultResultSetHandler handler=(DefaultResultSetHandler)target; ParameterHandler parameterHandler = (ParameterHandler) ReflectUtil.getFieldValue(handler, "parameterHandler"); Object parameterObject = parameterHandler.getParameterObject(); if(parameterObject instanceof ParamMap){ ParamMap paramMap=(ParamMap)parameterObject; Statement statement = (Statement) invocation.getArgs()[0]; return handleResultSet(statement.getResultSet(),paramMap); } } return invocation.proceed(); } private Object handleResultSet(ResultSet resultSet, ParamMap paramMap) { if(resultSet!=null){ HashMap<Object, Object> map = new HashMap<>(); List<Object> resultList=new ArrayList<Object>(); try { while (resultSet.next()) { Object keyFiledValue=resultSet.getObject(ParamMap.keyField); Object valueFieldValue=resultSet.getObject(ParamMap.valueField); map.put(keyFiledValue,valueFieldValue); } //handleResultSet的返回值为List resultList.add(map); }catch (SQLException e){ }finally { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } return resultList; } return null; } @Override public Object plugin(Object target) { return Plugin.wrap(target,this); } @Override public void setProperties(Properties properties) { } }
Map文件中的配置
<select id="findByParamMap" resultType="map" parameterType="paramMap">
select username,regTime from user
</select>
测试:
@Test public void testParamMap(){ SqlSession sqlSession=null; try { sqlSession=SqlSessionFactoryUtil.openSession(); UserMapper sqlSessionMapper = sqlSession.getMapper(UserMapper.class); ParamMap paramMap = new ParamMap(); paramMap.put("name","regTime"); Map map = sqlSessionMapper.findByParamMap(paramMap); System.out.println(map); }finally { sqlSession.close(); } }
参考:
http://elim.iteye.com/blog/1942464
立志如山 静心求实
浙公网安备 33010602011771号