Mybatis工具類--在執行(批量)sql前 先判斷參數是否爲空

若有這樣的dao方法:java

List<User> getUsersByIds(List<Long> idList) ;
void deleteUsersByIds(List<Long> idList) ;
void batchAddUsers(List<User> userList);

若參數爲空的話,執行相關sql時,會報錯,因是不完整的sql,以下所示:spring

select * from user where id in 
delete from user where id in 
insert into user(name,idcard,...) values

若想避免此一狀況,能夠在調用dao方法前進行判斷。sql

if(idList!=null && !idList.isEmpty()){
    //call dao here
}

可否省去這種判斷呢?若參數爲空,不去執行sql不就好了嗎。apache

剛開始想到用spring aop, 可是發覺不易實現,想攔截dao方法,但報錯:數組

Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy27]: Common causes of this problem include using a final class or a non-visible class;

因dao均是接口,而其實現類自己是一個由mybatis實現的動態代理類,如今spring又要對該代理類進行代理,但mybatis生成的代理類又不能再被代理(理由見上面的錯誤提示)。session

而對servcie層進行代理處理起來也不方便,因參數不如dao方法直觀,可能List參數是封裝在一個業務對象中,如BussinessDTO.而且使用Spring Aop 還不通用(即每一個項目都要有本身的一套)。mybatis

最後想到了用Mybatis的攔截器,攔截其最後的執行sql類(org.apache.ibatis.executor.Executor的某個具體實現子類),判斷輸入參數是否爲空,若爲空,直接返回,不往下執行了。app

@Intercepts({
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class }),
@Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, Object.class }) })
public class MyBatisCheckEmptyBeforeExecuteInterceptor implements Interceptor {
    //...
}

註解定義須要攔截的方法。mybatis最終的執行方法只有兩個,查詢調用query方法,增、刪、改均調用update方法。ide

具體攔截方法:this

Object parameter = invocation.getArgs()[1];
if (parameter == null) { // 參數值爲null
    MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
    Class parameterType = ms.getParameterMap().getType();
    if (parameterType != null)// 實際存在輸入參數 即並非無參方法 如getAll()
        return getDefaultReturnValue(invocation); //直接返回一個默認值(根據調用方法的返回類型) 如new ArrayList()
}
//若dao 方法的輸入參數爲List的話,mybatis會自動將其封轉到一個map中 key爲list(數組參數同樣 但key爲array)
if (parameter instanceof Map) {
    Map map = (Map) parameter;
    //list參數是否爲空或數組是否爲空 
    if ((map.containsKey("list") && CollectionUtils.isEmpty((List) map.get("list")))
        || (map.containsKey("array") && ArrayUtils.isEmpty((Object[]) map.get("array"))))
        return getDefaultReturnValue(invocation);
}
//參數非空 繼續往下執行
return invocation.proceed();

完整代碼:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * 執行sql前統一判空 如getByIds(List<Long> idList) 若輸入參數爲空 直接返回 再也不執行sql
 * 
 * @author zhuguowei
 *
 */
@Intercepts({
		@Signature(type = Executor.class, method = "query", args = {
				MappedStatement.class, Object.class, RowBounds.class,
				ResultHandler.class }),
		@Signature(type = Executor.class, method = "update", args = {
				MappedStatement.class, Object.class }) })
public class MyBatisCheckEmptyBeforeExecuteInterceptor implements Interceptor {

	@SuppressWarnings("rawtypes")
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object parameter = invocation.getArgs()[1];

		if (parameter == null) { // 參數值爲空
			MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
			Class parameterType = ms.getParameterMap().getType();
			if (parameterType != null)// 存在輸入參數
				return getDefaultReturnValue(invocation);
		}
		if (parameter instanceof Map) {
			Map map = (Map) parameter;
			if ((map.containsKey("list") && CollectionUtils.isEmpty((List) map
					.get("list")))
					|| (map.containsKey("array") && ArrayUtils
							.isEmpty((Object[]) map.get("array"))))
				return getDefaultReturnValue(invocation);
		}
		return invocation.proceed();
	}

	/**
	 * 獲得默認返回值
	 * 
	 * @param invocation
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private Object getDefaultReturnValue(Invocation invocation) {
		Class returnType = invocation.getMethod().getReturnType();
		if (returnType.equals(List.class))
			return new ArrayList();
		else if (returnType.equals(Integer.TYPE))
			return 0;
		return null;
	}

	/**
	 * 只攔截Executor
	 */
	@Override
	public Object plugin(Object target) {
		if (target instanceof Executor) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}
	}

	@Override
	public void setProperties(Properties properties) {

	}

}
相關文章
相關標籤/搜索