JSON驱动的动态SQL查询:实现灵活条件筛选的查询

news2024/11/23 6:59:40

当我们构建动态 SQL 查询功能时,需要考虑到安全性和灵活性的平衡。本文将讨论如何通过 JSON 数据和 FreeMarker 模板构造动态 SQL 查询,以及如何减少 SQL 注入的风险。

JSON 数据与动态 SQL

JSON 是一种常用的数据交换格式,它的灵活性和易读性使得它在前后端数据传输中得到广泛应用。我们可以利用 JSON 数据来构建动态 SQL 查询,根据用户的输入条件动态生成 SQL 语句,实现灵活的查询功能。

FreeMarker 模板引擎

FreeMarker 是一个强大的模板引擎,它可以将数据模型和模板文件结合起来生成文本输出。我们可以利用 FreeMarker 的语法和功能,将 JSON 数据和 SQL 查询模板结合起来,动态生成最终的 SQL 语句。

动态 SQL 查询示例

让我们以一个示例来说明如何通过 JSON 数据和 FreeMarker 构造动态 SQL 查询功能。假设我们有一个需求:根据用户输入的查询条件动态生成 SQL 查询语句,并执行查询操作。

首先,我们可以定义一个 JSON 数据格式,包含用户的查询条件,如下所示

{
    "model": "pageForPurchaseOrder",
    "page": 1,
    "size": 10,
    "filters": {
        "acceptance": "0",
        "account": "",
        "beginDate": "2024-01-03",
        "endDate": "2024-05-09",
        "warehouseCodeList": "000,SD002"
    }
}

接下来,我们可以编写一个 FreeMarker 模板文件,定义 SQL 查询语句的模板,例如:

SELECT * FROM users
WHERE 1=1
</#if>
<#if age??>
AND age = ${age}
</#if>
<#if city??>
AND city = '${city}'
</#if>

在这个模板中,我们使用了 FreeMarker 的条件判断语句 <#if>${} 表达式,根据传入的查询条件动态生成 SQL 查询语句。

后台配置具体内容

结合后台的 FreeMarker 模板引擎和前台传递的 JSON 数据是一种常见的做法。下面将通过引入代码示例来说明如何整合后台的 FreeMarker 和前台的 JSON 数据生成 SQL 查询语句,并进一步探讨其实现原理和优势。

首先,让我们来看一下代码示例:

public ResponseObject<SqlObject> getSqlObject(HttpServletRequest request) {
    ResponseObject<SqlObject> result = new ResponseObject<>();
    try {
        SqlObject obj = new SqlObject();
        JSONObject search = JSON.parseObject(request.getInputStream());
        obj.setPage(search.getLongValue("page", 1));
        obj.setSize(search.getLongValue("size", 10));
        String modelKey = search.getString("model");
        QueryTemplateRequest req = new QueryTemplateRequest();
        req.setId(modelKey);
        ResponseObject<QueryTemplateResponse> model = queryTemplateApi.view(req);
        if (model.getCode() != 200) {
            result.setCode(501);
            result.setMsg("model不存在");
            return result;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("phone", UserUtils.user().getPhone());
        if (search.containsKey("filters")){
            JSONObject filters = search.getJSONObject("filters");

            QueryTemplateExt ext = model.getData().getExtData();
            if (ext != null && ext.getFilters() != null) {
                for (QueryFilter filter : ext.getFilters()) {
                    if (filter.getJavaName() != null) {
                        if (filters.containsKey(filter.getJavaName())){
                            try {
                                Object temp = FieldTypeMatch.matchType(filter.getJavaName(), filter.getFieldType(), filters);
                                if (temp!=null){
                                    param.put(filter.getJavaName(), temp);
                                }
                            }catch (Exception e){
                                e.printStackTrace();
                            }

                        }
                    }
                }
            }
        }

        obj.setSql(process(model.getData().getContent(), param));
        result.setData(obj);
        return result;
    } catch (Exception e) {
        e.printStackTrace();
        result.setCode(501);
        result.setMsg("解析json出错");
        return result;
    }
}

在这段代码中,我们接收了一个 HTTP 请求,通过 HttpServletRequest 获取了前台传递的 JSON 数据。然后,利用 FreeMarker 模板引擎和后台的业务逻辑,动态生成了 SQL 查询语句。下面我们来逐步解析这段代码的关键步骤:

  1. 解析 JSON 数据: 首先通过 JSON.parseObject(request.getInputStream()) 解析前台传递的 JSON 数据,获取了查询所需的各种参数,例如页码、每页大小、模型关键字和筛选条件等。

  2. 查询模型信息: 根据获取的模型关键字,调用 queryTemplateApi 获取模型信息。如果模型不存在或获取失败,则返回相应的错误信息。

  3. 构建参数: 根据前台传递的筛选条件,利用后台的业务逻辑构建查询所需的参数。这里通过 FieldTypeMatch 类中的 matchType 方法,根据字段类型匹配,减少 SQL 注入的风险,并构建最终的查询参数。

  4. 生成 SQL 语句: 最后通过 process 方法,结合模型内容和参数,生成最终的 SQL 查询语句,并将其设置到 SqlObject 对象中,作为返回结果。

通过这段代码示例,我们展示了如何整合后台的 FreeMarker 模板引擎和前台传递的 JSON 数据,实现动态生成 SQL 查询语句的功能。这种方法使得系统可以根据用户的不同需求动态生成不同的 SQL 查询,具有很高的灵活性和可扩展性。

这种整合方式的优势在于:

  • 灵活性: 可以根据前端传递的 JSON 数据动态生成不同的 SQL 查询,适应不同的业务需求。
  • 安全性: 通过后台的业务逻辑和参数处理,可以有效减少 SQL 注入的风险。
  • 可维护性: 使用 FreeMarker 模板可以将 SQL 查询逻辑与 Java 代码分离,提高代码的可读性和可维护性。

在动态生成 SQL 查询语句的过程中,FieldTypeMatch 类发挥了重要作用。这个类中的 matchType 方法根据字段类型和前台传递的 JSON 数据,将不同类型的值转换为适合 SQL 查询的格式。让我们来看一下这个方法的具体实现:

 public static Object matchType(String key, Integer fieldType, JSONObject filter) {
        Object value;
        if (fieldType == 1) {
            value = filter.getString(key);
        } else if (fieldType == 2) {
            value = filter.getInteger(key);
        } else if (fieldType == 3) {
            value = filter.getLong(key);
        } else if (fieldType == 4) {
            value = filter.getDouble(key);
        } else if (fieldType == 5) {
            value = filter.getBigDecimal(key);
        } else if (fieldType == 6) {
            Object value = filter.getDate(key);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            value = format.format(value);
        } else if (fieldType == 7) {
            value = filter.getBoolean(key);
        } else {
            String[] stars;
            String temp;
            if (fieldType == 10) {
                temp = filter.getString(key);
                if (temp == null) {
                    return null;
                }

                stars = temp.split(",");
                value = Arrays.stream(stars).map(String::trim).filter(StringUtils::hasText).map((s) -> {
                    return "'" + s + "'";
                }).collect(Collectors.joining(","));
                value = "(" + value + ")";
            } else if (fieldType == 11) {
                temp = filter.getString(key);
                if (temp == null) {
                    return null;
                }

                stars = temp.split(",");
                value = Arrays.stream(stars).map(String::trim).filter(StringUtils::hasText).map(Long::valueOf).map(String::valueOf).collect(Collectors.joining(","));
                value = "(" + value + ")";
            } else if (fieldType == 12) {
                temp = filter.getString(key);
                if (temp == null) {
                    return null;
                }

                stars = temp.split(",");
                value = Arrays.stream(stars).map(String::trim).filter(StringUtils::hasText).map(Double::valueOf).map(String::valueOf).collect(Collectors.joining(","));
                value = "(" + value + ")";
            } else {
                value = null;
            }
        }

        return value;
    }

在这个方法中,根据传入的 fieldType 参数,对应处理了不同类型的值转换:

  • 对于基本类型(如字符串、整数、长整数、双精度浮点数、布尔值等),直接通过 filter 对象的对应方法获取值。
  • 对于日期类型(fieldType 为 6),采用 SimpleDateFormat 进行日期格式化处理。
  • 对于其他复杂类型(例如逗号分隔的字符串列表,整数列表,双精度浮点数列表等),进行了特殊处理,将其转换为适合 SQL 查询的格式。

这样的设计使得在动态生成 SQL 查询语句时,可以根据字段类型准确地处理对应的值,避免了因数据类型不匹配而导致的错误或异常,同时也增强了代码的健壮性和可维护性。

总结

通过结合 JSON 数据和 FreeMarker 模板引擎,我们可以实现动态生成 SQL 查询语句的功能。这种方法使得查询条件可以灵活地根据用户需求动态生成,提高了系统的灵活性和可维护性。在实际应用中,可以根据具体的业务需求和数据模型,结合 FreeMarker 的强大功能,实现更加智能和高效的动态 SQL 查询功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1607948.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

正则表达式(Regular Expression)

正则表达式很重要&#xff0c;是一个合格攻城狮的必备利器&#xff0c;必须要学会&#xff01;&#xff01;&#xff01; &#xff08;参考视频&#xff09;10分钟快速掌握正则表达式&#xff08;奇乐编程学院&#xff09;https://www.bilibili.com/video/BV1da4y1p7iZ在线测试…

07.QT信号和槽-2

一、自定义信号和槽 在Qt中&#xff0c;允许⾃定义信号的发送⽅以及接收⽅&#xff0c;即可以⾃定义信号函数和槽函数。但是对于⾃定义的信号函数和槽函数有⼀定的书写规范。 1.基本语法 1.1 自定义信号 &#xff08;1&#xff09;⾃定义信号函数必须写到"signals"…

GCC/G++详解

文章目录 GCC/G编译gcc是如何完成的预处理编译汇编链接 编译流程 GCC/G 编译 C语言源文件可以使用gcc和g编译&#xff08;优先选择gcc&#xff09; gcc test.c -o mybin / gcc -o mybin test.c 基于test.c文件生成可执行程序mybing tes.c -o mybin / g -o mybin test.c 基于te…

【C语言】多字节字符、宽字符(涉及字符集和编码)

字符集、编码&#xff1a; 字符集&#xff1a;一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称&#xff0c;包括各国家文字、标点符号、图形符号、数字等。例如&#xff1a;ASCII、Unicode、GB2312、GBK、GB18030、BIG5(繁体中文) ... 编码方式&#xff1a;符号…

在H5开发App应用程序过程中的一些常见问题

哈喽&#xff0c;大家好呀&#xff0c;淼淼又来和大家见面啦&#xff0c;H5开发是一种可以跨平台、跨设备、且可以在各种设备上运行&#xff0c;无需安装额外的应用程序。最近有许多小伙伴跟我聊到在h5开发App应用程序的过程中遇到了一些问题&#xff0c;今天我们就这些问题来做…

【数学建模】最优旅游城市的选择问题:层次分析模型(含MATLAB代码)

层次分析法&#xff08;The analytic hierarachy process&#xff0c;简称AHP&#xff09;是一种常用的决策分析方法&#xff0c;其基本思路是将复杂问题分解为多个组成部分&#xff0c;然后对这些部分进行逐一评估和比较&#xff0c;最后得出最优解决方案。&#xff08;例如&a…

【Linux】创建IDEA桌面快捷方式

Linux系统安装IDEA保姆级教程_linux安装idea-CSDN博客 在Ubuntu上安装Intellij IDEA并创建桌面快捷方式 - 极客子羽 - 博客园 (cnblogs.com) 下载安装包解压到指定目录 /opt/softWare 进入bin目录&#xff0c;ll查看 桌面打开终端&#xff0c;创建文件 touch idea.desktop s…

[大模型]Qwen-7B-hat Transformers 部署调用

Qwen-7B-hat Transformers 部署调用 环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下…

C++初阶学习第一弹——C++入门(上)

前言&#xff1a; 很高兴&#xff0c;从今天开始&#xff0c;我们就要步入C的学习了&#xff0c;在这之前我们已经对C语言有了不错的了解&#xff0c;对数据结构也有了一些自己的认识&#xff0c;今天开始&#xff0c;我们就进入这个新的主题的学习——C 目录 一、C的发展即其特…

Redis教程——数据类型(有序集合、位图)

上篇文章我们学习了Redis教程——数据类型&#xff08;哈希、集合&#xff09;&#xff0c;这篇文章学习Redis教程——数据类型&#xff08;有序集合、位图&#xff09; 有序集合ZSet 有序集合和集合都是string类型的无序集合&#xff0c;其数据是唯一&#xff0c;都是通过哈…

华为路由器基于接口限速

一、背景 ISP与企业内网通过华为路由器接入Internet时,当大量流量进入路由器时,可能会因为带宽不足产生拥塞,导致丢包,严重影响用户上网体验。对于此需要对网络流量进行限制,其方式通常有防火墙带宽策略、路由器基于接口限速等。 二、华为路由器基于接口限速方式 在路由…

代码随想录算法训练营第四十四天| LeetCode70. 爬楼梯 (进阶)、322. 零钱兑换、279.完全平方数

一、LeetCode 70. 爬楼梯 &#xff08;进阶&#xff09; 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/0070.%E7%88%AC%E6%A5%BC%E6%A2%AF%E5%AE%8C%E5%85%A8%E8%83%8C%E5%8C%85%E7%89%88%E6%9C%AC.html 状态&#xff1a;已解决 1.思路 这道题跟70.爬楼…

如何在深度学习中调用CAME

1、介绍 CAME&#xff1a;一种以置信度为导向的策略&#xff0c;以减少现有内存高效优化器的不稳定性。基于此策略&#xff0c;我们提出CAME同时实现两个目标:传统自适应方法的快速收敛和内存高效方法的低内存使用。大量的实验证明了CAME在各种NLP任务(如BERT和GPT-2训练)中的…

【python】直接在python3下安装 jupyter notebook,以及处理安装报错,启动不了问题

目录 问题&#xff1a; 1 先做准备&#xff0c;查看环境 1.1 先看python3 和pip &#xff0c;以及查看是否有 juypter 1.2 开始安装 1.3 安装完成后得到警告和报错 2 处理安装的报错问题 2.1 网上有说是因为 pip 自身需要更新&#xff0c;更新之 2.1.1 更新pip 2.1.…

vue快速入门(三十二)局部与全局注册组件的步骤

注释很详细&#xff0c;直接上代码 上一篇 新增内容 局部注册组件全局注册组件 文件结构 源码 MyHeader.vue <!-- 用于测试全局注册组件 --> <template><div><h1>又可以愉快的学习啦</h1></div> </template><script>export d…

开启Three.js之旅(会持续完善)

文章目录 Three.js必备构建项目场景Scene相机CameraPerspectiveCamera 渲染器WebGLRendererCSS3DRenderer 灯光LightAmbientLightDirectionalLight 平行光PointLight 加载器CacheFileLoaderLoaderGLTFLoaderRGBELoaderTextureLoader 材质MetarialMeshBasicMaterialMeshLambertM…

武汉星起航:上海股权中心成功挂牌,创始人张振邦领航跨境新纪元

在金秋十月的尾声&#xff0c;上海股权托管交易中心迎来了一场备受瞩目的盛事。2023年10月30日&#xff0c;武汉星起航电子商务有限公司成功挂牌展示&#xff0c;正式登录资本市场&#xff0c;开启了一段崭新的发展篇章。这一里程碑式的跨越&#xff0c;不仅标志着武汉星起航在…

MySQL基础-----约束详解

目录 一. 概述: 二.约束演示&#xff1a; 三.外键约束&#xff1a; 3.1介绍&#xff1a; 3.2外键约束语法&#xff1a; 3.3删除&#xff0c;更新行为&#xff1a; 一. 概述: &#x1f9d0;&#x1f9d0;概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制…

【机器学习】数据变换---小波变换特征提取及应用案列介绍

引言 在机器学习领域&#xff0c;数据变换是一种常见且重要的预处理步骤。通过对原始数据进行变换&#xff0c;我们可以提取出更有意义的特征&#xff0c;提高模型的性能。在众多数据变换方法中&#xff0c;小波变换是一种非常有效的方法&#xff0c;尤其适用于处理非平稳信号和…

会话seesion的使用,结合ddddocr识别简单验证码的登录实现。

古诗文网登录代码&#xff1a; # 古诗文网登录实战 # 验证码链接:https://so.gushiwen.cn/RandCode.ashx # 变动参数链接:__VIEWSTATE所在的地址:https://so.gushiwen.cn/user/login.aspx?fromhttp://so.gushiwen.cn/user/collect.aspx # 登录接口链接:https://so.gushiwen.c…