美文网首页
MyBatis 解析 XML 配置文件

MyBatis 解析 XML 配置文件

作者: Tinyspot | 来源:发表于2024-04-13 23:07 被阅读0次

    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;
    }
    

    相关文章

      网友评论

          本文标题:MyBatis 解析 XML 配置文件

          本文链接:https://www.haomeiwen.com/subject/njblxjtx.html