mybatis解析sql xml腳本記錄

須要給activiti的query接口新增查詢條件,可是activiti內部具體基本都是基於實現類,沒法擴展。只好使用nativequery接口寫sql。而後就想到直接copy複用activiti內部的sql語句。node

include標籤只能本身用方法字符串去拼接,動態邏輯標籤仍是能夠用mybatis內部實現去解析。另外查詢類get的時候會調用到activiti的查詢操做,因此在外層還須要加上activiti的殼(使用命令模式,中間加入攔截鏈,執行操做必須通過攔截鏈如:日誌,事務,上下文,緩存批處理): procEngineCfg.getCommandExecutor().execute(command)sql

主要的代碼整理出來看成備忘:緩存

String XML_PREFIX="<mapper namespace=\"\"><select id=\"temp\">";
String XML_SUFFIX="</select></mapper>";

//得到mybatis的Configuration
Configuration myCfg=procEngineCfg.getMybatisConfiguraton();
//繼承HashMap,把xxx:activiti的查詢類實例用BeanWrapper包裝
ContextMap param=new ContextMap(xxx);
//另外查詢條件
param.put("yyy","zzz"); 

//得到sql腳本
String sqlScript=getSelectTaskByQueryCriteria();

//加載sql的xml,解析${},生成XNode(一個Dom API中的Node接口的擴展類)
XPathParser parser=new XPathParser(new ByteArrayInputStream((XML_PREFIX+sqlScript+XML_SUFFIX).getBytes()), false);
XNode xnode=parser.evalNode("/mapper/select");

//從XNode解析xml中的每一個標籤(如trim,if標籤),把XNode轉成sqlNode,生成SqlSource
XMLScriptBuilder builder = new XMLScriptBuilder(myCfg, xnode, Map.class);
SqlSource taskByQueryCriteriaSS=builder.parseScriptNode();

//sqlSource裏的sqlNode解析邏輯標籤後生成BoundSql 帶#{}的sql 和 參數
//BoundSql封裝mybatis最終產生sql的類,包括sql語句,參數,參數源數據等參數
BoundSql boundSql=taskByQueryCriteriaSS.getBoundSql(param);

//獲取參數值
Map<String,Object> params=new LinkedHashMap<String, Object>();
Object parameterObject=boundSql.getParameterObject(); 
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

if (parameterMappings == null)
	return params;

//循環設參數
for (int i = 0; i < parameterMappings.size(); i++) 
{
	ParameterMapping parameterMapping = parameterMappings.get(i);
    if (parameterMapping.getMode() == ParameterMode.OUT)
    	continue;

    //若是不是OUT,才設進去
    Object value;
    String propertyName = parameterMapping.getProperty();
    if (boundSql.hasAdditionalParameter(propertyName)) //如有額外的參數, 設爲額外的參數 issue #448 ask first for additional params
        value = boundSql.getAdditionalParameter(propertyName);
    else if (parameterObject == null) //若參數爲null,直接設null
        value = null;
    else if (myCfg.getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass())) //若參數有相應的TypeHandler,直接設object
        value = parameterObject;
    else 
    {
        //除此之外,MetaObject.getValue反射取得值設進去
        MetaObject metaObject = myCfg.newMetaObject(parameterObject);
        value = metaObject.getValue(propertyName);
    }
    params.put(String.valueOf(i), value);
}

class ContextMap extends HashMap<String, Object> 
{
	private static final long serialVersionUID = 1L;

    private BeanWrapper beanWrapper;
    public ContextMap(Object obj) {
    	beanWrapper= PropertyAccessorFactory.forBeanPropertyAccess(obj);
    }

    @Override
    public Object get(Object key) 
    {
    	String strKey = (String) key;
    	if (super.containsKey(strKey)) 
    		return super.get(strKey);

    	if (beanWrapper != null)
    		return beanWrapper.getPropertyValue(strKey);

    	return null;
    }
}
相關文章
相關標籤/搜索