Springboot + easyui + mybatis 高级搜索功能实现

最近接了个项目,客户要求项目支持高级搜索,他可以自选字段,然后自选运算符,然后输入值,字段可随意组合,类似于下图。

1 前端处理 

 

遇到问题首先抽象:

 字段类型一般有4种,第一种普通输入框,第二种日期,第三种数字,第四种下拉。

 如果是下拉的话,只支持精确匹配  =, 其他的支持所有的运算符。

 按照我的性格,这个高级搜索功能肯定是要配置出来的,而不是傻乎乎的写html代码。

 首先确定配置JSON 文件格式,然后做通用页面,解析配置,配置比较简单,就不多解释了

var advanceConfig = [{name:'name',title:'人员姓名',type:'input'},
{name:'sex',title:'性别',type:'book',code:'sex'},
{name:'birthday',title:'出生年月',type:'date',formart:'yyyy-MM'},
{name:'primaryClassification',title:'一级分类',type:'book',code:'primary_classification'},
];

 然后写公共代码。

 

<script type="text/javascript" src="${fhs_static_url}js/baidutemplate.js"></script>
<script type="text/javascript"
        src="${fhs_static_url}js/My97DatePicker/WdatePicker.js"></script>
<script>


    //记录每个index是类型是什么
    var indexType = {};

    var advnaceIsInit= false;

    var filter_index = 0;


    function openAdvance(){
        advanceConfig = advanceConfig.filter(function(val){
            return !(!val || val === "");
        });
        for(i=0;i<advanceConfig.length;i++){
            if(advanceConfig[i]){
                advanceConfig[i].index = (i+1);
            }
        }
        if(!advnaceIsInit){
            addFilter();
            advnaceIsInit = true;
        }
        $('#advanceDialog').dialog('open').dialog('setTitle', '高级搜索');
    }


    //添加一个过滤条件
    function addFilter(){
        var _html = baidu.template('rowTemplate',{filterIndex:filter_index});
        $('#advanceFormDiv').append(_html);
        $.parser.parse('#filter' + filter_index);
        filter_index = filter_index + 1;
    }


    //修改右侧内容
    function filterFieldChange(_tempIndex,_record){
        var _tempHtml = '';
        indexType[_tempIndex] = _record;
        var _needSetFilterTypeReadonly = false;
        if(_record.type=='input' || _record.type=='number'){
            _tempHtml = '<input type="text" id="advanceFilterVal'  + _tempIndex +  '"/>';
        }
        else if(_record.type=='date'){
            if(!_record.formart){
                _record.formart = 'yyyy-MM-dd';
            }
            console.log(_record.formart);
            _tempHtml = '<input type="text" id="advanceFilterVal'  + _tempIndex +  '" readonly onclick="WdatePicker({dateFmt:\'' + _record.formart + '\'})"/>';
        }
        else if(_record.type=='book'){
            _tempHtml = '<input type="text" id="advanceFilterVal'  + _tempIndex +  '"  class="easyui-combobox"' +
                ' url="${fhs_basics_url}/webApi/wordbook/getData?wordbookGroupCode=' + _record.code + '&jsonpCallback=?" valueField="wordbookCode"  textField="wordbookDesc"/>';
            _needSetFilterTypeReadonly = true;
        }
        else if(_record.type=='select'){
            _tempHtml = '<input type="text" id="advanceFilterVal'  + _tempIndex +  '"  class="easyui-combobox"' +
                ' url="' + _record.url + '" valueField="'+_record.valueField+'"  textField="'+_record.textField+'"/>';
            _needSetFilterTypeReadonly = true;
        }
        if(_record.name=='searchKey'){
            _needSetFilterTypeReadonly = true;
        }
        if(_needSetFilterTypeReadonly){
            $('#advanceFilterType' + _tempIndex).combobox('setValue','0');
            $('#advanceFilterType' + _tempIndex).combobox('readonly',true);
        }else{
            $('#advanceFilterType' + _tempIndex).combobox('readonly',false);
        }
        if(_record.searchKeyType =='str'){
            $('#advanceFilterType' + _tempIndex).combobox('setValue','1');
        }
        $('#advanceFilterValLable' + _tempIndex).html(_tempHtml);
        $.parser.parse('#advanceFilterValLable' + _tempIndex);
    }


    var extAdvanceFilterParam = [];
    function  execAdvanceSearch(){
        extAdvanceFilterParam = [];
        for(i=0;i<filter_index;i++){
            if($('#advanceFilterField' + i).length>0 && $('#advanceFilterField' + i).combobox('getValue')){
                var _val = '';
                if(indexType[i].type!=='book' && indexType[i].type!=='select'){
                    _val = $('#advanceFilterVal' + i).val();
                }else{
                    _val = $('#advanceFilterVal' + i).combobox('getValue');
                }
                if(_val){
                    extAdvanceFilterParam.push({name:indexType[i].name,val:_val,
                        filterType:$('#advanceFilterType' + i).combobox('getValue'),
                        searchKeyType:indexType[i].searchKeyType,
                        fieldName:indexType[i].fieldName});
                }
            }
        }
        $('#listGrid').datagrid('load', {
            extAdvanceFilterParam:JSON.stringify({filterType:$('#advanceFilterType').combobox('getValue'),extAdvanceFilterParamArray:extAdvanceFilterParam})
        });
       //reload();
        console.log(extAdvanceFilterParam);
    }



</script>

<script id="rowTemplate" type="text/html">
    <div class="fitem" id="filter<@=filterIndex@>">
        <div class='bigLabelDiv'><label>选择字段:</label></div>
        <div class='bigContent'>
            <select class="easyui-combobox" id="advanceFilterField<@=filterIndex@>" data-options="
                    onSelect:function(_record){
                            var _tempIndex = <@=filterIndex@>;
                            filterFieldChange(_tempIndex,_record);
                    },
                    data:advanceConfig,
                    valueField:'index',
                    textField:'title',
            ">
            </select>
            <select class="easyui-combobox" id="advanceFilterType<@=filterIndex@>">
                <option value="0" checked="checked">等于</option>
                <option value="1">包含</option>
                <option value="2">不等于</option>
                <option value="3">大于等于</option>
                <option value="4">小于等于</option>
                <option value="5">大于</option>
                <option value="6">小于</option>
                <option value="7">以什么开始</option>
                <option value="8">以什么结尾</option>
            </select>
            <lable id="advanceFilterValLable<@=filterIndex@>">

            </lable>
            <a href="javascript:void(0)" class="easyui-linkbutton" onclick="$('#filter<@=filterIndex@>').remove()">删除</a>
        </div>
    </div>
</script>
<div class="easyui-dialog" id = "advanceDialog"   style="width: 80%; height: 40%; padding: 10px" closed="true">
    <div id="advanceFormDiv">
        <div class="fitem">
            <div class='bigLabelDiv'><label>过滤条件匹配:</label></div>
            <div class='bigContent'>
                <select class="easyui-combobox" id="advanceFilterType">
                    <option value="and" checked="checked">AND(满足所有)</option>
                    <option value="or">OR(满足一个)</option>
                </select>
                <a href="javascript:void(0)" class="easyui-linkbutton"  onclick="addFilter()">添加</a>
            </div>
        </div>
    </div>
    <div class="fitem">
        <center>  <a href="javascript:void(0)" class="easyui-linkbutton"  onclick="execAdvanceSearch()">搜索</a>
            <a href="javascript:void(0)" class="easyui-linkbutton"  onclick="closeAdvanceSearch()">关闭</a></center>
    </div>
</div>


<script>

    function closeAdvanceSearch(){
        $('#advanceDialog').dialog('close');
    }


</script>

 经过上面的代码,前段基本处理完成,下面讲解后端代码如何处理。

 

2 后端处理 

     首先在VO中创建接收前段搜索条件的字段。

    

 /**
     * 高级搜索过滤条件
     */
    @Transient
    private String extAdvanceFilterParam;

  然后写格式化sql的代码。

  

 private static final Map<String, String> SIMPLE_OPERATOR = new HashMap();

    static {
        SIMPLE_OPERATOR.put(POJOConstant.EQ, " = ");
        SIMPLE_OPERATOR.put(POJOConstant.LIKE, " LIKE ");
        SIMPLE_OPERATOR.put(POJOConstant.NEQ, " != ");
        SIMPLE_OPERATOR.put(POJOConstant.BIGGER_EQ, " >= ");
        SIMPLE_OPERATOR.put(POJOConstant.LESS_EQ, " <= ");
        SIMPLE_OPERATOR.put(POJOConstant.LESS, " < ");
        SIMPLE_OPERATOR.put(POJOConstant.START_WITH, " LIKE ");
        SIMPLE_OPERATOR.put(POJOConstant.END_WITH, " LIKE ");
        SIMPLE_OPERATOR.put(POJOConstant.BIGGER, " > ");
    }

    /**
     * 获取高级搜索的where条件
     *
     * @return
     */
    public String getAdvanceSearchSql() {
        if (extAdvanceFilterParam == null) {
            return null;
        }
        JSONObject extAdvanceFilterParamJson = JSON.parseObject(extAdvanceFilterParam);
        String filterType = " OR ";
        boolean isOr = true;
        if (extAdvanceFilterParamJson.getString("filterType").equals("and")) {
            filterType = " AND ";
            isOr = false;
        }
        JSONArray extAdvanceFilterParamArray = extAdvanceFilterParamJson.getJSONArray("extAdvanceFilterParamArray");
        JSONObject tempAFilter = null;
        Field field = null;
        String sqlField = null;
        String tempVal = null;
        StringBuilder whereSql = new StringBuilder(isOr ? " AND (" : " AND ");
        boolean isHashWhere = false;
        for (int i = 0; i < extAdvanceFilterParamArray.size(); i++) {
            tempAFilter = extAdvanceFilterParamArray.getJSONObject(i);
            field = ReflectUtils.getDeclaredField(this.getClass(), tempAFilter.getString("name"));
            if (field == null) {
                log.error("字段不存在:" + field);
                continue;
            }
            sqlField = getSqlField(field);
            tempVal = formartVal(field, tempAFilter.get("val"), tempAFilter.getString("filterType"), tempAFilter.getString("searchKeyType")
                    , tempAFilter.getString("fieldName"));
            if (sqlField == null || tempVal == null || !SIMPLE_OPERATOR.containsKey(tempAFilter.getString("filterType"))) {
                log.error("条件不满足,无法拼接此字段,详情请打断点:" + field);
                continue;
            }
            if (whereSql.length() > 6) {
                whereSql.append(filterType);
            }
            whereSql.append(sqlField + ("searchKey".equals(field.getName()) ? " LIKE " : SIMPLE_OPERATOR.get(tempAFilter.getString("filterType"))) + tempVal + " ");
            isHashWhere = true;
        }
        if(!isHashWhere){
            return "";
        }
        whereSql.append(isOr ? ")" : "");
        return whereSql.toString();
    }

    /**
     * 格式化值
     *
     * @param field      lambdaSett
     * @param val        值
     * @param filterType
     * @return 值的sql格式
     */
    protected String formartVal(Field field, Object val, String filterType, String searchKeyType, String fieldName) {
        if (val == null || "null".equals(val)) {
            return "null";
        }
        Class<?> type = field.getType();
        String result = null;
        // 字符串直接是字段名
        if (!CheckUtils.isNullOrEmpty(searchKeyType)) {
            if ("str".equals(searchKeyType)) {
                return " CONCAT('%','\"" + fieldName + "\"','%','" + val + "','%') ";
            } if ("streq".equals(searchKeyType)) {
                return " CONCAT('%','\"" + fieldName + "\":\"" + val + "\"','%') ";
            } else if ("date".equals(searchKeyType)) {
                return " CONCAT('%','\"" + fieldName + "\":\"" + val + "','%') ";
            } else if ("int".equals(searchKeyType)) {
                return " CONCAT('%','\"" + fieldName + "\":\"" + val + "\"','%') ";
            }
        }
        //只有字符串才有like 需要特殊处理
        if (type == String.class) {
            if (POJOConstant.LIKE.equals(filterType)) {
                result = " CONCAT('%','" + val + "','%') ";
            } else if (POJOConstant.START_WITH.equals(filterType)) {
                result = " CONCAT('" + val + "','%') ";
            } else if (POJOConstant.END_WITH.equals(filterType)) {
                result = " CONCAT('%','" + val + "') ";
            } else {
                result = "'" + val + "'";
            }
        } else if (type == Number.class || Number.class.isAssignableFrom(type)) {
            result = ConverterUtils.toString(val);
        } else if (type == Date.class || Date.class.isAssignableFrom(type)) {
            Date dateVal = DateUtils.parseStr(ConverterUtils.toString(val));
            return "FROM_UNIXTIME(" + (dateVal.getTime() / 1000) + ")";
        } else {
            log.warn("格式不支持:" + field + val);
            return null;
        }
        return result;
    }


    public String getSqlField(Field field) {
        if (field.isAnnotationPresent(TableField.class)) {
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField.exist()) {
                return tableField.value();
            } else {

                return null;
            }
        } else if (field.isAnnotationPresent(Column.class)) {
            Column column = field.getAnnotation(Column.class);
            return column.name();
        }
        return null;
    }

通过上面代码,基本上已经把sql拼接出来了,如果觉得不安全可以加个sql的过滤,如果有人故意黑,可以抛异常。

有了sql 之后拼到查询语句中就可以了。

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值