1. 功能背景
项目上有一个需求,需要根据用户手动编写的带xml的<if>、<choose>等标签的sql脚本,解析(转换)出可执行的sql脚本进行查询。
以下代码夹带了自定义表达式替换参数值的动能,如不需要删除代码即可。
MyBatis版本为3.5.3
2. 具体实现
2.1. 原始脚本
select
id aId,
user_name aUserName,
org_id aOrgId,
sex aSex,
img aImg
from
a_cyf_data a
<where>
<choose>
<when test='aaa=="@aaa@"'>
id=@aaa@
</when>
<otherwise>
id=@bbb@
</otherwise>
</choose>
</where>
2.2. 引入的包
import java.util.*;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.scripting.xmltags.XMLScriptBuilder;
import org.apache.ibatis.session.Configuration;
2.3. 功能代码
/**
* 根据sql和参数,替换sql内带@符号的表达式和xml标签
*
* @author: xxx
* @date: 2022-05-10 11:09:21
* @param params 参数
* @return
*/
public static SqlCondition replaceSqlPermission(SqlParameter params) {
String sql = params.getSql();
List<ReportDbParam> paramList = params.getParamList();
// 转换paramList为JSONObject
JSONObject paramsJson = new JSONObject();
if (null != paramList && !paramList.isEmpty()) {
// 循环替换@表达式为参数值
for (ReportDbParam param : paramList) {
String key = param.getParamName();
String permission = "@" + key + "@";
String value = param.getParamValue();
// 判断是否有表达式
if (sql.contains(permission)) {
// 有则替换为参数值
sql = sql.replaceAll(permission, value);
paramsJson.put(key, value);
}
}
// 替换XML标签
if (sql.contains("<if") || sql.contains("<choose")) {
// 追加select的xml标签
sql = "<select>" + sql + "</select>";
// 实例化解析XML对象
XPathParser parser = new XPathParser(sql, false, null, new XMLMapperEntityResolver());
XNode context = parser.evalNode("/select");
Configuration configuration = new Configuration();
configuration.setDatabaseId("");
XMLScriptBuilder xmlScriptBuilder = new XMLScriptBuilder(configuration, context);
SqlSource sqlSource = xmlScriptBuilder.parseScriptNode();
// 获取转换xml标签后的sql对象
BoundSql bs = sqlSource.getBoundSql(paramsJson);
// 获取查询sql
sql = bs.getSql();
}
}
// 封装并返回
SqlCondition sqlCondition = new SqlCondition();
sqlCondition.setSql(sql);
return sqlCondition;
}
2.4. 传入的参数
JSONObject params = JSONObject.parse("{\"aaa\":\"1\",\"bbb\":\"2\"}"));
2.5. 转换后的sql
select
id aId,
user_name aUserName,
org_id aOrgId,
sex aSex,
img aImg
from
a_cyf_data a
WHERE id=1
|