1. 解析XML配置
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderMapperController {
@Resource
private OrderMapper orderMapper;
private static final Configuration configuration = new Configuration();
private static String startXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<select>\n ";
private static String endXml = "</select>";
@GetMapping("/queryBySql")
public String queryBySql() {
String fileName = "third/order-template.txt";
URL url = Thread.currentThread().getContextClassLoader().getResource(fileName);
String xmlSQL = FileUtil.readUtf8String(url.getPath());
Map<String, Object> params = new HashMap<>();
params.put("dynamicColumns", "tradeId, tpCode");
params.put("groupBy", " tradeId, tpCode");
params.put("tpCode", "SF");
String template = parseSql(xmlSQL, params);
// 模板解析
OrderQuery orderQuery = new OrderQuery();
orderQuery.setSql(template);
return JSON.toJSONString(orderMapper.queryBySqlSegment(orderQuery));
}
/**
* @param xmlSql 模板
* @param params 参数
* @return
*/
public static String parseSql(String xmlSql, Map<String, Object> params) {
try {
// 拼接xml
xmlSql = startXml.concat(xmlSql).concat(endXml);
// 基于 MyBatis 配置文件构建 XPathParser 实例
XPathParser xPathParser = new XPathParser(xmlSql, false);
XNode xNode = xPathParser.evalNode("/select");
// BoundSql-预编译SQL,解析引用变量 比如 #{tpCode}
XMLScriptBuilder xmlScriptBuilder = new XMLScriptBuilder(configuration, xNode);
SqlSource sqlSource = xmlScriptBuilder.parseScriptNode();
MappedStatement statement = new MappedStatement.Builder(configuration, UUID.randomUUID().toString(), sqlSource, null).build();
BoundSql boundSql = statement.getBoundSql(params);
String resultSql = boundSql.getSql() + " ";
/*
* select ? from boot_order
* where 1 = 1
* AND tpCode = '?'
* GROUP BY ? ORDER BY count(1) DESC
*/
// 参数绑定
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
resultSql = resultSql.replaceAll("[\\t\\n]", " ")
.replaceAll(" +", " ");
if (parameterMappings == null) {
return resultSql;
}
MetaObject metaObject = null;
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value = null;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (params != null) {
if (metaObject == null) {
metaObject = configuration.newMetaObject(params);
}
value = metaObject.getValue(propertyName);
}
// 替换占位符
int index = resultSql.indexOf("?");
resultSql = resultSql.substring(0, index).concat(value.toString()).concat(resultSql.substring(index + 1));
}
}
return resultSql;
} catch (Exception e) {
log.error(e.toString());
}
return "";
}
}
1.1 核心配置 Configuration
public class Configuration {
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
}
Configuration.newMetaObject()
方法的主要作用是创建与给定 Java 对象关联的 MetaObject 实例,从而提供便捷、强大的反射功能,便于在 MyBatis 的各种场景中(如动态 SQL、插件、拦截器等)进行对象属性的访问和操作
1.2 解析器 XPathParser
public XNode evalNode(String expression) {
return evalNode(document, expression);
}
/select
是一个 XPath 表达式
/
表示从文档根节点开始查找
select
表示选择名为 select 的元素节点
综上:evalNode("/select")
表示返回 <select>
标签及其所有子节点和属性
1.3 ParameterMode
public enum ParameterMode {
IN, OUT, INOUT
}
输入参数(IN parameters)
输出参数(OUT parameters)
既能输入又能输出的参数(INOUT parameters)
2. 接口
2.1 配置文件
在 resources 目录新建 third/order-template.txt
select
<if test="dynamicColumns != null">
#{dynamicColumns}
</if>
from
boot_order
where
1 = 1
<if test="tpCode != null">
AND tpCode = '#{tpCode}'
</if>
<if test="condition != null">
AND #{condition}
</if>
<if test="groupBy != null">
GROUP BY #{groupBy} ORDER BY count(1) DESC
</if>
2.2 接口
public interface OrderMapper {
List<Order> queryBySqlSegment(OrderQuery orderQuery);
}
2.3 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="com.example.concrete.dao.mapper.OrderMapper">
<select id="queryBySqlSegment" resultType="Order" parameterType="OrderQuery">
${sql}
LIMIT #{pageStart}, #{pageSize}
</select>
</mapper>
2.4 参数模型 OrderQuery
@Data
public class OrderQuery implements Serializable {
private static final long serialVersionUID = 3930335153402169459L;
/**
* SQL语句
*/
private String sql;
private Integer pageStart = 0;
private Integer pageSize = 100;
}
网友评论