Mybatis的ResultSetHandler接口是用来处理查询结果Statement的,默认实现是DefaultResultSetHandelr类
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
在执行select语句时,会创建DefaultresultSetHandler对象处理Statement,并且添加拦截器
// 代码位置 org.apache.ibatis.session.Configuration#newResultSetHandler
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
所有可以自定义拦截器,拦截其中的handleResultSets方法,实现自定义的结果集处理
import com.sun.rowset.CachedRowSetImpl;
import org.apache.ibatis.executor.result.DefaultResultContext;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Properties;
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class CachedRowSetIntercept implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Class<? extends Object> targetClass = invocation.getTarget().getClass();
Field resultHandlerField = targetClass.getDeclaredField("resultHandler");
resultHandlerField.setAccessible(true);
Object resultHandler = resultHandlerField.get(invocation.getTarget());
// 如果是需要返回特定的结果,做特定的处理
if (resultHandler != null && resultHandler instanceof CachedRowSetHandler) {
Statement arg = (Statement) invocation.getArgs()[0];
CachedRowSetImpl cachedRowSet = new CachedRowSetImpl();
cachedRowSet.populate(arg.getResultSet());
DefaultResultContext resultContext = new DefaultResultContext();
resultContext.nextResultObject(cachedRowSet);
// 保存结果为CachedRowSetImpl对象
((CachedRowSetHandler) resultHandler).handleResult(resultContext);
return Arrays.asList(cachedRowSet);
}
// 走原有逻辑
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
因为需要返回CachedRowSetImpl对象,所以不能走mybatis的自动映射成Bean的代码逻辑。
这时需要用到Mybatis的ResultHandler这个接口
package org.apache.ibatis.session;
/**
* @author Clinton Begin
*/
public interface ResultHandler<T> {
void handleResult(ResultContext<? extends T> resultContext);
}
并且需要用到SqlSessionTemplate来执行mapper中sql,传入ResultHandler接口的一个对象,用于保存自定义的结果集
@Autowired
SqlSessionTemplate sqlSessionTemplate;
@GetMapping("/get")
public Object find(@RequestParam(value = "cityName", required = true) String cityName) {
CachedRowSetHandler cachedRowSetHandler = new CachedRowSetHandler();
Map<String, Object> param = new HashMap<>();
param.put("cityName", cityName);
sqlSessionTemplate.select("org.spring.springboot.dao.CityDao.findByName",param, cachedRowSetHandler);
try {
CachedRowSetImpl result = cachedRowSetHandler.getResult();
if(result.size()>0 && !result.isAfterLast() &&result.next()){
return result.getString(1)+result.getString(2)+result.getString(3);
}
} catch (SQLException e) {
e.printStackTrace();
return e;
}
return cachedRowSetHandler.getResult().toString();
}
public class CachedRowSetHandler implements ResultHandler {
private CachedRowSetImpl cachedRowSet;
@Override
public void handleResult(ResultContext resultContext) {
cachedRowSet = (CachedRowSetImpl) resultContext.getResultObject();
}
public CachedRowSetImpl getResult() {
return this.cachedRowSet;
}
}
最后,还需要将自定义的拦截器配置到mybatis中去,在mybatis-config.xml中添加配置(这里是叫plugin)
<plugins>
<plugin interceptor="org.spring.springboot.resultset.CachedRowSetIntercept"></plugin>
</plugins>
mapper文件如下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.spring.springboot.dao.CityDao">
<resultMap id="BaseResultMap" type="org.spring.springboot.domain.City">
<result column="id" property="id" />
<result column="province_id" property="provinceId" />
<result column="city_name" property="cityName" />
<result column="description" property="description" />
</resultMap>
<parameterMap id="City" type="org.spring.springboot.domain.City"/>
<sql id="Base_Column_List">
id, province_id, city_name, description
</sql>
<select id="findByName" resultMap="BaseResultMap" >
select
<include refid="Base_Column_List" />
from city
where city_name = #{cityName}
</select>
</mapper>