数据权限的设计与实现系列11——前端筛选器组件Everright-filter集成功能完善2

news2024/9/30 10:18:11

筛选条件数据类型完善

文本类

筛选器组件给了一个文本类操作的范例,如下:

            Text: [
                {
                  label: '等于',
                  en_label: 'Equal',
                  style: 'noop'
                },
                {
                  label: '等于其中之一',
                  en_label: 'Equal to one of',
                  value: 'one_of',
                  style: 'tags'
                },
                {
                  label: '不等于',
                  en_label: 'Not equal',
                  value: 'not_equal',
                  style: 'noop'
                },
                {
                  label: '包含',
                  en_label: 'Contains',
                  value: 'contains',
                  style: 'noop'
                },
                {
                  label: '不包含',
                  en_label: 'Not contain',
                  value: 'not_contain',
                  style: 'noop'
                },
                {
                  label: '为空',
                  en_label: 'Empty',
                  value: 'empty',
                  style: 'none'
                },
                {
                  label: '不为空',
                  en_label: 'Not empty',
                  value: 'not_empty',
                  style: 'none'
                }
              ]

即以下几种情况:

  • 等于
  • 等于其中之一
  • 不等于
  • 包含
  • 不包含
  • 为空
  • 不为空

平台认为不是太合理,做了以下调整:

  1. 等于其中之一很少用,并且可以等价转换一个条件组,内含多个等于关系的条件,组内逻辑关系为或,因此去除
  2. 对于字符串,常用的主要是模糊匹配、以……开始、以……结束,因此将包含调整为模糊匹配、去除不包含,增加以……开始、以……结束两种,其他保留不变,同时对操作符的编码也做了相应调整。

调整完成后如下:

              Text: [
                {
                  label: '等于',
                  value: 'EQ',
                  style: 'noop'
                },
                {
                  label: '模糊匹配',
                  value: 'LK',
                  style: 'noop'
                },

                {
                  label: '以…开始',
                  value: 'RL',
                  style: 'noop'
                },
                {
                  label: '以…结束',
                  value: 'LL',
                  style: 'noop'
                },
                {
                  label: '不等于',
                  value: 'NE',
                  style: 'noop'
                },
                {
                  label: '为空',
                  value: 'NL',
                  style: 'none'
                },
                {
                  label: '不为空',
                  value: 'NN',
                  style: 'none'
                }
              ]

后端将规则转换成SQL片段的功能方法也要进行相应调整,这里参考了平台原本的通用查询功能的部分处理,改造如下:

@Override
    public String generateSqlPart(String id, String rule) {
        String result = "";
        // 转换数据
        DataFilterRuleVO dataFilterRule = JSON.parseObject(rule, DataFilterRuleVO.class);
        // 获取组集合
        List<DataFilterGroupVO> dataFilterGroupList = dataFilterRule.getFilters();
        // 存放各组对应的条件sql片段
        List<String> groupSqlPartList = new ArrayList<>(dataFilterGroupList.size());
        // 遍历组集合
        for (DataFilterGroupVO dataFilterGroup : dataFilterGroupList) {
            // 获取条件集合
            List<DataFilterConditionVO> conditionList = dataFilterGroup.getConditions();
            if (CollectionUtils.isNotEmpty(conditionList)) {
                // 存放各条件对应的条件sql片段
                List<String> conditionSqlPartList = new ArrayList<>(conditionList.size());
                // 遍历条件集合
                for (DataFilterConditionVO condition : conditionList) {
                    // 获取字段名,命名风格驼峰转换成下划线
                    String fieldName = CommonUtil.camelToUnderline(condition.getProperty());
                    Object value = condition.getValue();
                    // 获取操作
                    String operator = condition.getOperator();
                    QueryRuleEnum queryRule = EnumUtils.getEnum(QueryRuleEnum.class, operator, QueryRuleEnum.EQ);
                    QueryWrapper<?> queryWrapper = new QueryWrapper<>();
                    addEasyQuery(queryWrapper, fieldName, queryRule, value);

                    log.info(queryWrapper.getSqlSegment());
                    log.info(queryWrapper.getParamNameValuePairs().toString());
                    // 放入结果列表缓存                 
                    conditionSqlPartList.add(queryWrapper.getTargetSql());
                }
                // 完成各条件的处理后,进行组内拼接
                if (conditionList.size() > 1) {
                    String logicalOperator = dataFilterGroup.getLogicalOperator();
                    StringBuffer sb = new StringBuffer();
                    sb.append("(");
                    conditionSqlPartList.stream().forEach(sqlPart -> {
                        sb.append(sqlPart);
                        sb.append(" " + logicalOperator + " ");
                    });
                    sb.delete(sb.length() - logicalOperator.length() - 1, sb.length());
                    sb.append(")");
                    groupSqlPartList.add(sb.toString());

                } else {
                    groupSqlPartList.add("(" + conditionSqlPartList.get(0) + ")");

                }
            }

        }

这里调用了一个方法,addEasyQuery,借助了MybatisPlus组件的条件构造器功能,如下:

/**
     * 根据规则走不同的查询
     *
     * @param queryWrapper QueryWrapper
     * @param name         字段名字
     * @param rule         查询规则
     * @param value        查询条件值
     */
    private void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {

        if (value == null || rule == null || ObjectUtils.isEmpty(value)) {
            return;
        }
        name = CommonUtil.camelToUnderline(name);
        switch (rule) {
            case GT:
                queryWrapper.gt(name, value);
                break;
            case GE:
                queryWrapper.ge(name, value);
                break;
            case LT:
                queryWrapper.lt(name, value);
                break;
            case LE:
                queryWrapper.le(name, value);
                break;
            case EQ:
                queryWrapper.eq(name, value);
                break;
            case NE:
                queryWrapper.ne(name, value);
                break;
            case IN:
                if (value instanceof String) {
                    queryWrapper.in(name, (Object[]) value.toString().split(COMMA));
                } else if (value instanceof String[]) {
                    queryWrapper.in(name, (Object[]) value);
                } else {
                    queryWrapper.in(name, value);
                }
                break;
            case LK:
                queryWrapper.like(name, value);
                break;
            case LL:
                queryWrapper.likeLeft(name, value);
                break;
            case RL:
                queryWrapper.likeRight(name, value);
                break;
            default:
                log.info("--查询规则未匹配到---");
                break;
        }
    }

如何获取完整SQL片段

此处遇到了一个棘手的问题。
我们需要获取到完整的SQL片段,类似这种:((param_value = ‘10’ and param_name like ‘%用户%’ ) or (param_key like ‘%password%’) )。
但是MybatisPlus组件的条件构造器QueryWrapper拿不到这种完整的sql片段,而是将sql语句参数和值分开保存的,通过getSqlSegment可以获取到参数化的sql语句,通过getParamNameValuePairs可以获取到参数值,如下:

查了半天资料,也没找到现成的方法可用,将这二者处理成我们期望的完整SQL片段。
于是有两种方案可选,一种是放弃借助QueryWrapper,自己来拼接SQL语句;一种是仍然使用QueryWrapper,自己来实现转换功能。
综合考虑了下,后一种的扩展性更好一些,只是写个单条件的字符串替换处理,复杂度不高,需要注意区分数值类和非数值类类型,相应的处理时要不要加单引号。

转换方法行不复杂,如下:

 /**
     * 将参数化的SQL填充值处理为完整的SQL片段
     *
     * @param sqlSegment          参数化的SQL片段
     * @param paramNameValuePairs 参数值对
     * @param numberFlag          是否为数值类型
     * @return 完整的SQL片段
     */
    private String handleSqlPart(String sqlSegment, Map<String, Object> paramNameValuePairs, boolean numberFlag) {

        for (int i = 0; i < paramNameValuePairs.size(); i++) {

            String value = paramNameValuePairs.get("MPGENVAL" + (i + 1)).toString();
            // 若为非数值类,则加上单引号
            if (!numberFlag) {
                value = "'" + value + "'";
            }
            sqlSegment = StringUtils.replace(sqlSegment, "#{ew.paramNameValuePairs.MPGENVAL" + (i + 1) + "}", value);

        }
        return sqlSegment;
    }

是否为数值类型,则是通过实体模型配置,获取当前模型属性的数据类型来判断的,如下:

 @Override
    public String generateSqlPart(String id, String rule) {
        String result = "";

        List<EntityModelProperty> modelPropertyList = entityModelPropertyService.getFullPropertyByEntityModelId(id);
        String[] numberDataType = {"INTEGER", "LONG", "DOUBLE", "DECIMAL"};

        // 转换数据
        DataFilterRuleVO dataFilterRule = JSON.parseObject(rule, DataFilterRuleVO.class);
        // 获取组集合
        List<DataFilterGroupVO> dataFilterGroupList = dataFilterRule.getFilters();
        // 存放各组对应的条件sql片段
        List<String> groupSqlPartList = new ArrayList<>(dataFilterGroupList.size());
        // 遍历组集合
        for (DataFilterGroupVO dataFilterGroup : dataFilterGroupList) {
            // 获取条件集合
            List<DataFilterConditionVO> conditionList = dataFilterGroup.getConditions();
            if (CollectionUtils.isNotEmpty(conditionList)) {
                // 存放各条件对应的条件sql片段
                List<String> conditionSqlPartList = new ArrayList<>(conditionList.size());
                // 遍历条件集合
                for (DataFilterConditionVO condition : conditionList) {
                    // 获取字段名,命名风格驼峰转换成下划线
                    String fieldName = CommonUtil.camelToUnderline(condition.getProperty());
                    Object value = condition.getValue();
                    // 获取操作
                    String operator = condition.getOperator();
                    QueryRuleEnum queryRule = EnumUtils.getEnum(QueryRuleEnum.class, operator, QueryRuleEnum.EQ);
                    QueryWrapper<?> queryWrapper = new QueryWrapper<>();
                    addEasyQuery(queryWrapper, fieldName, queryRule, value);

                    log.info(queryWrapper.getSqlSegment());
                    log.info(queryWrapper.getParamNameValuePairs().toString());
                    AtomicBoolean numberFlag = new AtomicBoolean(false);
                    modelPropertyList.stream().filter(modelProperty -> modelProperty.getCode().equals(condition.getProperty())).findFirst()
                            .ifPresent(modelProperty -> {
                                String dataType = modelProperty.getDataType();
                                if (ArrayUtils.contains(numberDataType, dataType)) {
                                    numberFlag.set(true);
                                }

                            });


                    String sqlPart = handleSqlPart(queryWrapper.getSqlSegment(), queryWrapper.getParamNameValuePairs(), numberFlag.get());
                    // 放入结果列表缓存
                    conditionSqlPartList.add(sqlPart);
                }
                // 完成各条件的处理后,进行组内拼接
                if (conditionList.size() > 1) {
                    String logicalOperator = dataFilterGroup.getLogicalOperator();
                    StringBuffer sb = new StringBuffer();
                    sb.append("(");
                    conditionSqlPartList.stream().forEach(sqlPart -> {
                        sb.append(sqlPart);
                        sb.append(" " + logicalOperator + " ");
                    });
                    sb.delete(sb.length() - logicalOperator.length() - 1, sb.length());
                    sb.append(")");
                    groupSqlPartList.add(sb.toString());

                } else {
                    groupSqlPartList.add("(" + conditionSqlPartList.get(0) + ")");

                }
            }

        }

实现效果如下:

数值类未加单引号,非数值类附加了单引号,符合预期。

开源平台资料

平台名称:一二三开发平台
简介: 企业级通用开发平台
设计资料:[csdn专栏]
开源地址:[Gitee]
开源协议:MIT
如果您在阅读本文时获得了帮助或受到了启发,希望您能够喜欢并收藏这篇文章,为它点赞~
请在评论区与我分享您的想法和心得,一起交流学习,不断进步,遇见更加优秀的自己!

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

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

相关文章

2024年9月30日历史上的今天大事件早读

1626年9月30日 清太祖努尔哈赤去世 1862年9月30日 德国首任宰相俾斯麦实行“铁血政策” 1887年9月30日 黄河决口 1931年9月30日 国际联盟决议日本撤兵 1937年9月30日 平型关战役结束 1938年9月30日 慕尼黑协议签订 1938年9月30日 前中华民国国务总理唐绍仪遇刺身亡 1941…

使用three.js 实现测量

使用three.js 实现测量 在线预览https://threehub.cn/#/codeMirror?navigationThreeJS&classifyapplication&idlineMeasure 在 https://threehub.cn 中还有很多案例 <!doctype html> <html lang"en"> <head> <meta charset"U…

实验四 IEEE 802.3协议分析和以太网

实验四 IEEE 802.3协议分析和以太网 一、实验目的 1、分析802.3协议 2、熟悉以太网帧的格式 二、实验内容及结果 1、俘获并分析以太网帧 &#xff08;1&#xff09;清空浏览器缓存&#xff08;在IE窗口中&#xff0c;选择“工具/Internet选项/删除文件”命令&#xff09;。 &…

【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化

0102 Linux进程生命周期 ​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录…

spring security 超详细使用教程(接入springboot、前后端分离)

Spring Security 是一个强大且可扩展的框架&#xff0c;用于保护 Java 应用程序&#xff0c;尤其是基于 Spring 的应用。它提供了身份验证&#xff08;验证用户身份&#xff09;、授权&#xff08;管理用户权限&#xff09;和防护机制&#xff08;如 CSRF 保护和防止会话劫持&a…

变压吸附制氧机:原理、应用与优势

变压吸附制氧机(Pressure Swing Adsorption Oxygen Generator&#xff0c;简称PSA制氧机)是一种利用变压吸附技术从空气中分离出氧气的设备。 一、基本原理 变压吸附制氧机的基本原理基于不同气体在吸附剂上的吸附能力随压力变化的特性。当原料空气经过鼓风机增压后&#xff0c…

鸿蒙harmonyos next flutter通信之MethodChannel获取设备信息

本文将通过MethodChannel获取设备信息&#xff0c;以此来演练MethodChannel用法。 建立channel flutter代码&#xff1a; MethodChannel methodChannel MethodChannel("com.xmg.test"); ohos代码&#xff1a; private channel: MethodChannel | null nullthis.c…

面试题:通过队列实现栈

题目&#xff1a; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。int pop() 移除并返…

C++游戏开发详解:从入门到实践

目录 引言 使用C进行游戏开发的优势 常用的C游戏引擎和工具 C游戏引擎比较 开发工具 C游戏开发核心概念与代码示例 面向对象编程&#xff08;OOP&#xff09; 封装 继承 多态 内存管理 手动内存管理 智能指针 内存池 并发编程 多线程 同步机制 游戏开发流程 …

C#开发中如何在不破坏封装性下调用控件

在C#开发中&#xff0c;我们知道每个设计文件在完成后都会存在封装性&#xff0c;如果是方法&#xff0c;对象的调用&#xff0c;我们可以采取public方法来允许外部的访问&#xff0c;但是对于控件来说&#xff0c;封装性是与生俱来的&#xff0c;强行破环封装既复杂&#xff0…

【数据结构】图的最小生成树

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C游记》《进击的C》《Linux迷航》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、最小生成树的概念二、Kruskal算法2.1 思想2.2 实现 三、Prim算法3.1 思想3.2 实现 四、Kruskal和Prim的对比…

前缀和(7)_连续数组

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 前缀和(7)_连续数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目链接…

使用python进行自然语言处理的示例

程序功能 分词&#xff1a;将输入句子拆分为单词。 词性标注&#xff1a;为每个单词标注其词性。 命名实体识别&#xff1a;识别命名实体&#xff08;如人名、地名、组织等&#xff09;。 这段代码展示了如何用 nltk 进行基础的 NLP 任务&#xff0c;包括分词、词性标注和命名…

17、CPU缓存架构详解高性能内存队列Disruptor实战

1.CPU缓存架构详解 1.1 CPU高速缓存概念 CPU缓存即高速缓冲存储器&#xff0c;是位于CPU与主内存间的一种容量较小但速度很高的存储器。CPU高速缓存可以分为一级缓存&#xff0c;二级缓存&#xff0c;部分高端CPU还具有三级缓存&#xff0c;每一级缓存中所储存的全部数据都是…

动态规划算法专题(一):斐波那契数列模型

目录 1、动态规划简介 2、算法实战应用【leetcode】 2.1 题一&#xff1a;第N个泰波那契数 2.1.1 算法原理 2.1.2 算法代码 2.1.3 空间优化原理——滚动数组 2.1.4 算法代码——空间优化版本 2.2 题二&#xff1a;三步问题 2.2.1 算法原理 2.2.2 算法代码 2.3 题二&a…

数据集-目标检测系列-鼠检测数据集 mouse >> DataBall

数据集-目标检测系列-鼠检测数据集 mouse >> DataBall 数据集-目标检测系列-老鼠检测数据集 mouse 数据量&#xff1a;6k 想要进一步了解&#xff0c;请联系。 DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。…

高效互动随心畅谈语聊大厅语音聊天系统小程序源码

高效互动随心畅谈 —— 语聊大厅语音聊天系统全解析 &#x1f389; 初识语聊大厅&#xff1a;语音社交的新大陆 在这个快节奏的数字时代&#xff0c;文字聊天似乎已经无法满足我们对即时互动和真实情感交流的需求。而“高效互动随心畅谈语聊大厅语音聊天系统”的出现&#xff…

TiDB 在线打标签实现副本调度应用实践

作者&#xff1a; 数据源的TiDB学习之路 原文来源&#xff1a; https://tidb.net/blog/4e14596a 案例背景 某原有系统为虚拟机环境部署&#xff0c;整体性能不满足预期。为提升集群整体性能&#xff0c;计划分阶段采购物理机&#xff0c;并以扩缩容的方式逐渐把物理机添加到…

如何从 Windows 11/10/8.1/8/7 中恢复已删除的视频

不小心删除了视频或格式化了 SD 卡/硬盘&#xff1f;没有备份已删除的视频&#xff1f;不要担心&#xff0c;我们有一个解决方案 可以恢复 Windows 11、10 中已删除的视频并处理这种可怕的情况。 但是&#xff0c;在详细介绍如何恢复已删除的视频和视频恢复应用程序之前&#…

【AI论文精读1】针对知识密集型NLP任务的检索增强生成(RAG原始论文)

目录 一、简介一句话简介作者、引用数、时间论文地址开源代码地址 二、摘要三、引言四、整体架构&#xff08;用一个例子来阐明&#xff09;场景例子&#xff1a;核心点&#xff1a; 五、方法 &#xff08;架构各部分详解&#xff09;5.1 模型1. RAG-Sequence Model2. RAG-Toke…