自定义MyBatis返回Map对象

最近一个项目要进行重构,需要把之前的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>




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值