1. 背景

对于用户来讲查询功能按易用性分三个层次:

1)最简单查询操作是一个输入框,全文检索,如百度,后台实现技术使用搜索引擎,需要设计和建立索引,技术较为复杂,适用于文档和信息数据库检索,但是结果很难精确控制。

2)其次是定义字段查询,很多企业信息系统大多用的是这种查询,针对模块特定字段的查询,有针对性、使用门坎低,适用于企业内部信息管理系统模块定制。

3)最后一种是专门针对数据模型灵活的查询编辑器,使用难度最高,但是查询结果可以灵活和精确的控制,适用于有一定IT知识并对数据相当了解的用户,同时又可以避免直接将数据库暴露给用户带来的不安全隐患。

大家不难发现一个好的系统软件的查询基本会涵盖上述三种类型的查询功能

2. jeecg实现原理

Jeecg系统中模块主要使用第二种方式的查询功能,使用hibernate的QBC来封装前端查询条件,针对字段的定制过滤条件,最后转换为sql执行数据库查询。

现有方案优点:

  • 默认无须复杂开发即可实现字段检索,支持范围、模糊、精确匹配查询
  • 内置简单表达式支持:!*,实现非、模糊、数组等

    现有方案缺点:

  • 不支持or条件
  • 不支持字段间操作field1=field2
  • 不支持非hibernate关联表联合查询
  • 单一字段条件只能出现一次
  • 不支持sql嵌套
  • 要支持上述功能需要额外开发定制工作

某些特定场景下,用户想要通过模块获得相关信息必须借助于第三方报表模块功能或求助于开发人员,无形中对报表模块开发带来一定压力。比如,用户要从模块中查询特殊的部分数据进行操作,现有查询功能无法做到,报表模块又不能操作编辑,这个时候就是高级查询器定制查询功能派上用场的时候了。

3. 类似应用举例

我们来看看Outlook邮件查询设计:

1)全文检索型

2)字段定制型

3)高级查找

微软Team Foundation Server查询编辑器:

4. Jeecg查询器设计与实现

    UI设计:首先要实现高级查询,必须要对数据表元信息metadata进行封装才可以通用化,我们利用datagrid标签中的columnList来自动生成字段下拉列表。作为高级查询,从易用的性和使用频率的角度功能所占UI比例不能太多,采用弹出窗口实现,如图:

这里的表格我使用了treegrid,因为更适合表达sql语法树,但没有实现树形结构,条件只加了大于、小于、包含等常用操作符,有待后续扩展sql嵌套。

右侧有查询历史,将每次查询的json条件保存在一个数组中实现快速重查,这个历史查询记录使用HTML5的localstorage保存在客户端缓存中,下次登录仍然有效,对于不支持localstorage的浏览器将使用cookie存储。

    前后端交互:从到向前兼容性和对框架升级改动最小的因素考虑,将查询器组装的所有内容封装到一个json字符串,作为一个参数_sqlbuidler传递到后台,由后台控制条件组装,更加安全,防止sql注入等漏洞

json格式示例:

  1. [{“id”:101,”field”:”user_name”,”condition”:”like”,”value”:”%王%”,”relation”:”and”},{“id”:101,”field”:”user_name”,”condition”:”like”,”value”:”%王%”,”relation”:”and”}]

后台封装处理java对象QueryCondition

  1. package org.jeecgframework.web.demo.entity.test;
  2. import java.util.List;
  3. public class QueryCondition {
  4. String field;
  5. String type;
  6. String condition;
  7. String value;
  8. String relation;
  9. List<QueryCondition> children;
  10. public List<QueryCondition> getChildren() {
  11. return children;
  12. }
  13. public void setChildren(List<QueryCondition> children) {
  14. this.children = children;
  15. }
  16. public String getField() {
  17. return field;
  18. }
  19. public void setField(String field) {
  20. this.field = field;
  21. }
  22. public String getType() {
  23. return type;
  24. }
  25. public void setType(String type) {
  26. this.type = type;
  27. }
  28. public String getCondition() {
  29. return condition;
  30. }
  31. public void setCondition(String condition) {
  32. this.condition = condition;
  33. }
  34. public String getValue() {
  35. return value;
  36. }
  37. public void setValue(String value) {
  38. this.value = value;
  39. }
  40. public String getRelation() {
  41. return relation;
  42. }
  43. public void setRelation(String relation) {
  44. this.relation = relation;
  45. }
  46. public String toString(){
  47. StringBuffer sb =new StringBuffer();
  48. sb.append(this.relation).append(" ");
  49. sb.append(this.field).append(" ")
  50. .append(this.condition).append(" ");
  51. if("java.util.Date".equals(this.type)){
  52. sb.append("to_date('").append(this.value).append("','yyyy-MM-dd')");
  53. }else if("java.lang.Number".equals(this.type)
  54. ||this.condition.indexOf("in")>0){//TODO 需要按类型处理
  55. sb.append(this.value);
  56. }else{
  57. sb.append("'").append(this.value).append("'");//TODO 需要处理特殊字符
  58. }
  59. return sb.toString();
  60. }
  61. }

后台解析处理代码,修改org.jeecgframework.core.extend.hqlsearch.HqlGenerateUtil:

  1. public static void installHql(CriteriaQuery cq, Object searchObj,
  2. Map<String, String[]> parameterMap) {
  3. installHqlJoinAlias(cq, searchObj, getRuleMap(), parameterMap, "");
  4. //      --增加一个特殊sql参数处理----------------------------------
  5. try{            if(StringUtil.isNotEmpty(parameterMap.get("_sqlbuilder"))){
  6. List<QueryCondition> list  = JSONHelper.toList(
  7. parameterMap.get("_sqlbuilder")[0]
  8. , QueryCondition.class);
  9. String sql=getSql(list,"");
  10. System.out.println("DEBUG sqlbuilder:"+sql);
  11. cq.add(Restrictions.sqlRestriction(sql));
  12. }
  13. }catch(Exception e){
  14. e.printStackTrace();
  15. }
  16. //      --增加一个特殊sql参数处理----------------------------------
  17. cq.add();
  18. }

5. 实现约束

  • 只支持标准命名的表名,因为是通过java驼峰命名转换带下划线的数据库表名,如果表名不是这个规则字段名会转换错误;
  • Sql前端界面在输入时并没有做太多约束和控制,因此非专业用户使用时会出现非法的语句而查询无果,建议在懂sql的人员指导下使用不要直接交给用户。

6. 标签使用

Datagrid标签中已经对高级查询器做了封装,js变量也根据每个模块的id做了命名处理防止冲突。

使用时只需在datagrid标签加一个属性queryBuilder="true",例如

  1. <t:datagrid name="jeecgDemoList" title="DEMO示例列表" autoLoadData="true" actionUrl="jeecgDemoController.do?datagrid" sortName="userName" fitColumns="true"
  2. idField="id" fit="true" queryMode="group" checkbox="true" queryBuilder="true">

模块UI效果如下,重置后面会多一个按钮:

7. TODO

UI方面:易用性还可以提升,比如选中某字段和条件=时,值自动根据数据库表中该列实际值枚举一部分候选项;字段为date类型时,值编辑框变成date控件;字段为整形时,值编辑框有校验或只能输入整数的spinbox来防呆

功能:List<QueryCondition>对象转换为sql getSql()函数中仅仅实现拼装原生sql,这块还有很大的改进空间,可以增加字段类型(int,string,date)的识别和处理、操作符(正则匹配)、内置表达式和函数(类似TFS)等扩展。

安全:模块按钮还没有跟权限绑定,只是通过标签属性来开关,应该加一个动态权限由系统配置来控制

【JEECG技术文档】Jeecg高级查询器的更多相关文章

  1. 【JEECG技术文档】JEECG高级查询构造器使用说明

    功能介绍   高级查询构造器支持主子表联合查询,查询出更精确的数据. 要使用高级查询构造器需要完成以下步骤: 1. 在高级查询管理配置主子表信息. 2. 配置完后在JSP页面DataGrid标签上添加 ...

  2. 【JEECG技术文档】JEECG 接口权限开发及配置使用说明

    1.功能介绍   通过接口配置实现,对接口的访问权限控制和数据权限控制,接口时REST接口,接口权限认证机制使用Json web token (JWT) 接口权限调用流程: (1)通过接口用户的用户名 ...

  3. 【JEECG技术文档】JEECG平台对外接口JWT应用文档V3.7.2

    一. 接口方式 接口调用采用http协议,rest请求方式: 二. 接口安全 接口安全采用Json web token (JWT)机制,基于token的鉴权机制. 1. 机制说明 基于token的鉴权 ...

  4. 【JEECG技术文档】JEECG在线聊天插件功能集成文档

    原文地址:http://jeecg.iteye.com/blog/2320670 JEECG在线聊天插件功能集成文档 前提: 采用jeecg_3.6.3版本以上(Maven工程) 插件项目: 在线聊天 ...

  5. 【JEECG技术文档】JEECG online 表单填值规则使用说明

    1. 功能介绍 JEECG online规则值自动生成功能 为实现online表单数据初始化功能. 为实现图中红框字段初始化功能,需要完成下面4步操作: 1)编写规则实现类 2) 配置填值规则 3)o ...

  6. 【JEECG技术文档】Online唯一校验使用说明

    1.功能介绍 配置了唯一校验的字段,在录入和编辑页面中,动态查询用户输入值是否存在校验. 要使用online唯一校验功能必须先在online表单开发中配置唯一字段的校验方式为唯一校验. 2.配置唯一校 ...

  7. 【JEECG技术文档】表单配置-树形表单

    表单配置支持树型表单了,具体效果如下图: 配置说明: 1.是否树:选择是. 2.树形表单父Id:表的自关联外键. 3.树形表单列表:显示树形图标的列,如上图中为[组织机构名称]. 4.默认值:最外层数 ...

  8. 【JEECG技术文档】online自定义模板的使用

    一. 业务背景 客户需要快速开发一个信息采集的功能模块,并使用已规划好的页面,实现个性化页面展示,使用标准左右布局的Table或DIV风格的页面表现力不强,不能满足客户的个性化页面需要 二. 需求 1 ...

  9. 【JEECG技术文档】JEECG 组织机构导入V3.7

    1.功能介绍 组织机构导入 提供组织机构模版导入功能,使用户更快速的创建组织机构 要使用组织机构导入功能需要完成以下步骤: 1. 下载模版excel 2. 填写组织机构信息 3. 点击导入-选择文件- ...

随机推荐

  1. 纯MATLAB版本 SIFT代码

    先贴几个链接: http://blog.csdn.net/abcjennifer/article/details/7639681  Rachel-Zhang的 http://blog.csdn.net ...

  2. Bootstrap的简介及使用

    一.Bootstrap简介 Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.javascript 的,它简洁灵活,使得 Web 开发更 ...

  3. [UE4]运行模式

    Selected Viewport和Simulate都可以在游戏模式和漫游模式之间切换. Selected Viewport:默认是游戏模式. Simulate:默认是漫游模式. 按Ctrl+F1后, ...

  4. [UE4]第一人称与第三人称

    一.给Character添加一个SkeletalMesh,并设置为第三人称模型.并设置自己看不到该模型. 二.添加给骨骼的右手添加一个Socket插槽用来挂载武器 三.判断当前角色是否被本地Contr ...

  5. redis作为mysql的缓存服务器(读写分离)

    转自:https://www.iyunv.com/thread-52670-1-1.html 一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据 ...

  6. Linux查看DNS服务器及设置DNS服务器

    DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串. 一台主机的dn ...

  7. 使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .

    命令管道是进程间通讯的一种常用方式,对于命令管道的介绍可以参考别的资料和书籍,这里推荐一个<VC++下命名管道编程的原理及实现>这篇博文,写得比较清楚.但是都是介绍了阻塞模式的编程,我这里 ...

  8. 值得收藏的45个Python优质资源

    REST API:使用 Python,Flask,Flask-RESTful 和 Flask-SQLAlchemy 构建专业的 REST API https://www.udemy.com/rest- ...

  9. Java - 20 Java 继承

    Java 继承 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类.继承可以理解为一个对象从另一个对象获取属性的过程. 如果类A是类B的父类,而类B是类C的父类,我们也称C是A的子 ...

  10. JVM总结-异常处理

    众所周知,异常处理的两大组成要素是抛出异常和捕获异常.这两大要素共同实现程序控制流的非正常转移. 抛出异常可分为显式和隐式两种.显式抛异常的主体是应用程序,它指的是在程序中使用“throw”关键字,手 ...