简单SQL报表解析器

功能:
把SQL从代码中解脱出来,修改XML文件中的SQL即时生效不需要重启服务,支持查询参数传递自动判空,参数支持SPEL表达式,功能简单,适用于简单报表场景。
特点:
1、每个查询条件用一对花括号{}括起来,语句内的参数使用SPEL表达式
2、每次查询要解析一次xml的SQL,修改SQL后不需要重启服务
3、配置一份XML报表文件即可同时支持浏览器端数据EXCEL导出,所见即所得
4、gitee完整代码地址:https://gitee.com/hhf002/rpt.git

SQL解析器部分可执行代码

package org.hhf.rpt;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.CompositeStringExpression;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author haohaifeng
 * @date 2021/1/13 17:40
 */
@Slf4j
public class SQLUtils {

    private static String SQL_FILE = "/rpt/RPT_I18N.xml";

    /**
     *
     * @param obj  参数接收对象
     * @return 返回解析后的sql
     */
    public static String getSQL(Object obj) {
        SAXReader saxReader = new SAXReader();
        Document doc = null;
        try {
            doc = saxReader.read(SQLUtils.class.getResourceAsStream(SQL_FILE));
            Element root = doc.getRootElement();
            String sql = root.elementText("sql");
            return parseSql(sql, obj);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(), e);
        }
        return null;
    }

    private static String parseSql(String sqlTemplate, Object obj) throws IllegalAccessException {
        //创建表达式解析器
        ExpressionParser paser = new SpelExpressionParser();
        //通过evaluationContext.setVariable可以在上下文中设定变量。
        EvaluationContext context = new StandardEvaluationContext();
        if (obj instanceof Map) {
            Map<String, Object> map = (Map) obj;
            String[] sqlRow = sqlTemplate.split("\n");
            List<String> sqlRowList = Arrays.stream(sqlRow).filter(n -> n.trim().startsWith("{") && n.trim().endsWith("}")).collect(Collectors.toList());
            for (String row : sqlRowList) {
                row = row.trim();
                Expression expression = paser.parseExpression(row, new TemplateParserContext());
                SpelExpression spelExpression = (SpelExpression) ((CompositeStringExpression) expression).getExpressions()[1];
                String key = spelExpression.getExpressionString().replace("#", "");
                Object value = map.get(key);
                if (value != null && StringUtils.isNotBlank(value.toString())) {
                    sqlTemplate = sqlTemplate.replace(row, row.substring(1, row.length() - 1));
                    context.setVariable(key, "'" + value.toString() + "'");
                } else {
                    sqlTemplate = sqlTemplate.replace(row, "");
                }
            }
        } else {
            log.error("参数类型传递异常");
        }
        //解析表达式,如果表达式是一个模板表达式,需要为解析传入模板解析器上下文。
        Expression expression = paser.parseExpression(sqlTemplate, new TemplateParserContext());
        //使用Expression.getValue()获取表达式的值,这里传入了Evalution上下文,第二个参数是类型参数,表示返回值的类型。
        String result = expression.getValue(context, String.class);
        return result;
    }

    public static void main(String[] args) {
        Map params = new HashMap(1);
        params.put("msg", "异常");
        String sql = getSQL(params);
        log.info(sql);
    }
}

xml模板

<?xml version="1.0" encoding="UTF-8"?>
<RPT_I18N show="true">
  <rptName>自定义问卷列表</rptName>
  <colNames>ID,资源包,语言,键,值,排序,是否有效</colNames>
  <sql>
    <![CDATA[
      SELECT
        id,
        bundle,
        locale,
        `code`,
        msg,
        sort,
        state
      FROM t_i18n
      where 1=1
      { and msg like concat('%',#{#msg},'%')}
    ]]>
  </sql>
</RPT_I18N>

依赖参考

        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.4.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.11</version>
        </dependency>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值