封装一个高级查询组件

news2024/12/27 11:43:18

封装一个高级查询组件

  • 背景
    • 一,前端相关代码
    • 二,后端相关代码
    • 三,呈现效果
    • 总结

背景

业务有个按照自定义选择组合查询条件,保存下来每次查询的时候使用的需求。查了一下项目里的代码没有现成的组件可以用,于是封装了一个

一,前端相关代码

总体的设计的设想上,需要一个弹出式的对话框,可以点击增加条件,并且整体能比较容易的嵌入到界面的查询中。根据需求的查询条件需要支持常见的如输入框,下拉,时间等控件。因为使用场景不多,目前的需求范围暂时只支持三层括号。为了通用性应该做成每个界面按需配置的,譬如一个页面可以有多少个可供选择的查询条件,因此需要有个简单的协议通过配置渲染查询条件。安全起见,查询条件在后端拼成sql传给数据库中。
另外,对于有些本身在界面的增删改查的条件本身是组合的条件或者涉及到sql语句的一些逻辑的,这里使用的方法是通过反射给本来的查询vo里设值,而这些"VO_FIELD"的选项不参与界面的与或以及括号的组合,这涉及到一些特殊的修改
配置的demo如下

[
	{
		"field": "对应后端表字段1",
		"name": "输入框查询条件",
		"fieldType": "STRING",
		"conditions": [
			{
				"value": "=",
				"label": "等于=",
				"element": {
					"type": "input",
					"placeholder": "请输入查询条件1"
				}
			}
		]
	},
	{
		"field": "对应后端表字段2",
		"name": "下拉查询条件",
		"fieldType": "STRING",
		"conditions": [
			{
				"value": "in",
				"label": "在范围内in",
				"element": {
					"type": "select",
					"placeholder": "请选择下拉查询条件",
					"options": [
						{
							"value": 1,
							"label": "下拉查询条件1"
						},
						{
							"value": 2,
							"label": "下拉查询条件2"
						}
					]
				}
			}
		]
	},
	{
		"field": "对应后端表字段3",
		"name": "日期查询条件",
		"fieldType": "DATE",
		"conditions": [
			{
				"value": "between",
				"label": "介于between",
				"element": {
					"type": "datePickerRange"
				}
			},
			{
				"value": "=",
				"label": "等于=",
				"element": {
					"type": "datePicker"
				}
			}
		]
	}
]

这是组件的前端代码,删除一些业务相关的信息,以及查询接口的信息

<template>
    <div>
       <el-row :gutter="5">
         <!-- 弹窗, 高级搜索 -->
             <el-dialog
             v-dialogDrag
             title="高级搜索"
             :visible.sync="dialogFormVisible"
             @close="onClose()"
             @open="onOpen()"
             width="60%"
             >
             <el-form :model="form">
                 <!-- 操作按钮 -->
                 <el-row>
                 <el-col :span="24" class="pb15 pt5">
                     <el-button
                     @click="searchAdd()"
                     type="danger"
                     size="mini"
                     style="margin-left: 10px"
                     plain
                     >新增</el-button
                     >
                 </el-col>
                 </el-row>
                 <el-table :data="searchConditionList" style="width: 100%">

                 <el-table-column prop="relation" label="关联">
                     <template slot-scope="scope">
                     <el-select v-model="scope.row.relation" placeholder="请选择"  :disabled="scope.row.relationInputShow">
                         <el-option label="且" value="and"></el-option>
                         <el-option label="或" value="or"></el-option>
                     </el-select>
                     </template>
                 </el-table-column>

                 <el-table-column prop="leftBracket" label="括号"   width="70">
                     <template slot-scope="scope">
                     <el-select v-model="scope.row.leftBracket"  placeholder="" :disabled="scope.row.bracketShow"  clearable>
                         <el-option label="(" value="("></el-option>
                         <el-option label="((" value="(("></el-option>
                         <el-option label="(((" value="((("></el-option>
                     </el-select>
                     </template>
                 </el-table-column>

                 <el-table-column prop="field" label="栏位" width="180">
                     <template slot-scope="scope">
                     <el-select v-model="scope.row.field"
                     @change="fieldChange(scope.row,scope.row.field)"
                     placeholder="请选择">
                         <el-option
                         v-for="item in queryConditionsConfig"
                         :key="item.field"
                         :label="item.name"
                         :value="item.field"
                         >
                         </el-option>
                     </el-select>
                     </template>
                 </el-table-column>

                 
                 <el-table-column   width="25">
                     <template slot-scope="scope">
                     <span v-if="scope.row.prompt!=null&&scope.row.prompt!=''">
                        <el-tooltip placement="top">
                            <div style="white-space: pre-wrap;" slot="content">
                                {{scope.row.prompt}}
                            </div>
                            <i class="el-icon-question" />
                        </el-tooltip>
                     </span>
                     </template>
                 </el-table-column>

                 <el-table-column prop="condition" label="条件" width="180">
                     <template slot-scope="scope">
                     <el-select v-model="scope.row.condition" placeholder="请选择"
                     @change="conditionChange(scope.row.field,scope.row.condition)">
                         <el-option
                         v-for="item in fieldConditionMap.get(scope.row.field)"
                         :key="item.value"
                         :label="item.label"
                         :value="item.value"
                         >
                         </el-option>
                     </el-select>
                     </template>
                 </el-table-column>

                 <el-table-column prop="searchValue" label="搜索值" width="350">
                     <template slot-scope="scope" >
                        <!-- 输入框 -->
                     <el-input  v-if="inputChoosed(scope.row.field,scope.row.condition)"
                         v-model="scope.row.searchValue"
                         :placeholder="inputPlaceholder(scope.row.field,scope.row.condition)"
                     ></el-input>
                     <!-- 下拉多选框 -->
                     <el-select v-model="scope.row.tempSelectOptions" placeholder="请选择"
                         multiple
                     v-if="selectChoosed(scope.row.field,scope.row.condition)"
                     :placeholder="inputPlaceholder(scope.row.field,scope.row.condition)"
                     @change="combineSelectOptions(scope.row,scope.row.tempSelectOptions);(val) => this.$forceUpdate()"
                     style="width: 100%;"
                     >
                         <el-option
                         v-for="item in fieldElementOptionsMap.get(scope.row.field+scope.row.condition)"
                         :key="item.value"
                         :label="item.label"
                         :value="item.value"
                         >
                         </el-option>
                     </el-select>
                         <!-- 下拉单选框 -->
                     <el-select v-model="scope.row.searchValue" placeholder="请选择"
                     v-if="singleSelectChoosed(scope.row.field,scope.row.condition)"
                     :placeholder="inputPlaceholder(scope.row.field,scope.row.condition)"
                     clearable
                     style="width: 100%;"
                     >
                         <el-option
                         v-for="item in fieldElementOptionsMap.get(scope.row.field+scope.row.condition)"
                         :key="item.value"
                         :label="item.label"
                         :value="item.value"
                         >
                         </el-option>
                     </el-select>
                       <!-- 日期范围 -->
                     <el-date-picker v-if="datePickerRangeChoosed(scope.row.field,scope.row.condition)"
                         v-model="scope.row.tempDateRange"
                         type="daterange"
                         :default-time="['00:00:00', '23:59:59']"
                         value-format="yyyy-MM-dd"
                         range-separator="至"
                         start-placeholder="开始日期"
                         end-placeholder="结束日期"
                         size="mini" style="padding-top: 0px;padding-bottom:0px;line-height:24px;width: 100%;"
                         @change="combineDateRange(scope.row,scope.row.tempDateRange);(val) => this.$forceUpdate()"
                         >
                     </el-date-picker>
                     <!-- 日期 -->
                     <el-date-picker  v-if="datePickerChoosed(scope.row.field,scope.row.condition)"
                         v-model="scope.row.searchValue"
                         type="date"
                         value-format="yyyy-MM-dd"
                         placeholder="请输入日期"
                         size="mini" style="padding-top: 0px;padding-bottom:0px;line-height:24px;width: 100%;"
                         >
                     </el-date-picker>
                     </template>
                 </el-table-column>

                 <el-table-column prop="rightBracket" label="括号"  width="70">
                     <template slot-scope="scope" >
                     <el-select v-model="scope.row.rightBracket"  placeholder="" :disabled="scope.row.bracketShow" clearable>
                         <el-option label=")" value=")"></el-option>
                         <el-option label="))" value="))"></el-option>
                         <el-option label=")))" value=")))"></el-option>
                     </el-select>
                     </template>
                 </el-table-column>

                 <el-table-column align="center" label="操作">
                     <template slot-scope="scope">
                     <el-button
                         type="text"
                         size="small"
                         @click="deleteData(scope.row.id, scope.$index)"
                         >删除</el-button
                     >
                     </template>
                 </el-table-column>
                 </el-table>
                 <template>
                     <el-col :span="24">
                         <el-col :md="12" :lg="16" class="margin-bottom-5">
                         <div class="el-input el-input--mini el-input-group">
                             <div >收藏夹
                             <el-select v-model="currentConfigIndex" placeholder="请选择"
                             @change="changeConfig"
                             @clear="clearConfig"
                             clearable
                             >
                                 <el-option
                                 v-for="item in existQueryConfigs"
                                 :key="item.id"
                                 :label="item.configName"
                                 :value="item.id"
                                 >
                                 </el-option>
                             </el-select>
                         </div>
                         </div>
                         </el-col>
                         <el-col :span="8" class="margin-bottom-5">
                             <el-checkbox v-model="applicationShareFlag" style="display:block;">是否共享至应用层(所有人)</el-checkbox>
                             <el-checkbox v-model="roleShareFlag" style="display:block;">是否共享至角色层(当前角色)</el-checkbox>
                             <el-input  v-model="currentConfigName" placeholder="输入保存名称" style="width:300px" ></el-input>
                         </el-col>
                     </el-col>
                 </template>
             </el-form>
             <div slot="footer" class="dialog-footer">
                 <el-button plain @click="onClose()">取 消</el-button>
                 <el-button type="info" @click="saveCondition">保存到收藏夹</el-button>
                 <el-button type="info" @click="searchByConditions">搜索</el-button>
             </div>
             </el-dialog>
         </el-row>
     </div>

   </template>
   <style >
   </style>
   <script>

   import advanceQuery from './advance-query'
     import { mixin } from '@/mixin/mixin'
     import {cloneDeep} from 'lodash'

  export default {
    name: "advance-query",
    mixins: [mixin],
    components: {},
    props: {
           //查询条件整体配置
      queryConditionsConfig: {
        type: Object,
        default: {},
        required: true
      },
      queryDataFunc:  Function,
      //查主界面列表的条件
      condition:{
        type: Object,
        default: {}
      },
      //对话框显示
      dialogFormVisible: {
        type: Boolean,
        default: true
      },
       //页面名称
      bizPageName: {
        type: String,
        default: ""
      },
      dataList:{
        type: Object,
        default: {}
      },
      total:{
        type: Number,
        default: {}
      },
      //搜索条件,用于回传
      searchConditionList:{
        type: Object,
        default: {}
      },
    },
    data() {
      return {
        //当前选中的字段
        currentField:{},
        //field和条件的map
        fieldConditionMap: new Map(),
        //field和控件相关的map
        fieldElemenTypeChooseMap: new Map(),
        fieldElementPlaceholderMap: new Map(),
        fieldElementOptionsMap: new Map(),
        currentField:'',
        currentCondition:'',

        existQueryConfigs:[],
        applicationShareFlag:false,
        roleShareFlag:false,
        currentConfigName:"",
        currentConfigIndex:"",
        roleCode:""

      };
    },
    async created() {
        await this.getCurrentRoleCodes()
        this.getConfigs()
    },
    methods: {
    // 高级搜索-新增
    searchAdd() {
        let newsearchObject = {
            field: "", //栏位
            fieldType:"",//字段类型
            condition: "", //条件
            searchValue: "", //搜索值
            relation: "and", //关联
            relationInputShow:true,//控制关联不可选择
            bracketShow:false//控制括号不可选择
        };
        this.searchConditionList.push(newsearchObject);
        this.modifyRelationAndBracket()
        },
        //高级搜索-删除
        deleteData(id, index) {
            this.searchConditionList.splice(index, 1);
            this.modifyRelationAndBracket()
        },
        // 高级搜索-保存
        saveCondition() {
            let param={}
            param.applicationShareFlag=this.applicationShareFlag
            param.roleShareFlag=this.roleShareFlag
            param.configName=this.currentConfigName
            param.id=this.currentConfigIndex
            param.roleCode=this.roleCode
            param.bizPageName=this.bizPageName
            let tempConditionTable=[]
            tempConditionTable = cloneDeep(this.searchConditionList)
            //干掉两个临时变量
            tempConditionTable.forEach(item=>{
                if(item.tempDateRange!=null){
                    item.tempDateRange=null
                }
                if(item.tempSelectOptions!=null){
                    item.tempSelectOptions=null
                }
            })
            param.configJson=JSON.stringify(tempConditionTable)
            if(param.configName==''){
                this.$message.warning('配置名称不可以为空!');
                return
            }
            apAdvanceQuery.saveConfig(param).then( data => {
                if( data.data.status==0){
                    this.$message.success('保存成功')
                    this.getConfigs()
                }else{
                    this.$message.error('保存失败')
                }
            });
        },
        // 获取数据列表
        searchByConditions() {
        //   console.log("打印查询参数:",JSON.stringify(this.condition))
          let param = Object.assign({},this.condition)
          param.start= this.condition.limit * (this.condition.page - 1),
          param.length= this.condition.limit,
          param.searchConditionList=this.searchConditionList
          this.queryDataFunc(param).then( data => {
            if (data.data.status === 0) {
                this.$emit('update:dataList', data.data.data)
                this.$emit('update:total', data.data.count)
                this.$emit('update:searchConditionList', this.searchConditionList)
                this.$emit('changeAdvanceConfigName',this.currentConfigName==""&&this.searchConditionList.length>=1?"新建":this.currentConfigName)
            } else {
                this.$message.error(data.data.msg);
            }
          });
        },
        //切换栏目
        fieldChange(row,field){
            this.queryConditionsConfig.forEach(item=>{
                if(item.field===field){
                    row.fieldType=item.fieldType
                    row.prompt=item.prompt
                    this.fieldConditionMap.set(item.field,item.conditions)
                }
            })
            this.modifyRelationAndBracket()
        },
        //切换条件
        conditionChange(field,condition){
            this.currentField=field,
            this.currentCondition=condition,
            this.fieldConditionMap.get(field).forEach(item=>{
                if(item.value===condition){
                    this.fieldElementPlaceholderMap.set(field+condition,item.element.placeholder)
                    this.fieldElementOptionsMap.set(field+condition,item.element.options)
                    this.fieldElemenTypeChooseMap.set(field+condition,item.element.type)
                }
            })
        },
        inputChoosed:function(field,condition){
            return this.fieldElemenTypeChooseMap.get(field+condition)==='input';
        },
        selectChoosed:function(field,condition){
            return this.fieldElemenTypeChooseMap.get(field+condition)==='select';
        },
        singleSelectChoosed:function(field,condition){
            return this.fieldElemenTypeChooseMap.get(field+condition)==='singleSelect';
        },
        datePickerRangeChoosed:function(field,condition){
            return this.fieldElemenTypeChooseMap.get(field+condition)==='datePickerRange';
        },
        datePickerChoosed:function(field,condition){
            return this.fieldElemenTypeChooseMap.get(field+condition)==='datePicker';
        },
        //切换配置
        changeConfig(value){
            this.existQueryConfigs.forEach(config=>{
                if(config.id===value){
                    this.currentConfigName=config.configName
                    this.currentConfigIndex=config.id
                    this.applicationShareFlag=config.applicationShareFlag
                    this.roleShareFlag=config.roleShareFlag
                    this.searchConditionList=[]
                    config.searchObjects.forEach(item=>{
                        let newsearchObject={}
                        Object.assign(newsearchObject, item);
                        this.fieldChange(newsearchObject,newsearchObject.field)
                        this.conditionChange(newsearchObject.field,newsearchObject.condition)
                        this.searchConditionList.push(newsearchObject);
                        }
                    )
                }
            })
        },
        //清除选中的配置
        clearConfig(){
            this.currentConfigName=""
            this.currentConfigIndex=""
            this.applicationShareFlag=false
            this.roleShareFlag=false
            this.searchConditionList=[]
        },
        getCurrentRoleCodes(){
    		//获取当前角色信息
        },
        getConfigs(){
       //获取已经保存的查询配置
        },
        combineDateRange(row,value){
            if(value!=null&&value!=[]){
                row.searchValue=value[0]+','+value[1]
            }else{
                row.searchValue=null
            }
        },
        combineSelectOptions(row,value){
            if(value!=null){
                row.searchValue=value.reduce((prev, curr) => {
                    return prev+','+curr
                }, '')
                row.searchValue=row.searchValue.slice(1)
            }
        },
        //关联关系和括号修改
        modifyRelationAndBracket(){
            this.searchConditionList.forEach((item,index)=>{
                if(index == 0){
                    item.relation= "and"
                    item.relationInputShow = true
                    if(item.fieldType==='VO_FIELD'){
                        item.bracketShow=true
                    }else{
                        item.bracketShow=false
                    }
                }else if(item.fieldType==='VO_FIELD'){//这种类型的字段不参与与或拼接
                    item.relation= ""
                    item.relationInputShow = true
                    item.bracketShow=true
                }else{
                    item.relationInputShow = false
                    item.bracketShow=false
                }
            })
        },
        //调用父组件实现关闭事件
        onClose() {
            this.$emit('update:dialogFormVisible', false)
        },
        //打开时候先初始化一下配置的显示
        onOpen(){
            this.changeConfig(this.currentConfigIndex);
        }
    },computed:{
        inputPlaceholder(){
            return function(field,value){
               return this.fieldElementPlaceholderMap.get(field+value)
            }
        }
      },
  };
  </script>

二,后端相关代码

后端相关的代码主要是参与解析条件生成配置的
配置的实体类如下

@Data
public class AdvanceSearchCondition {
    /**
     * 栏位
     */
    private String field;

    /**
     * 条件
     */
    private String  condition;

    /**
     * 搜寻值
     */
    private String searchValue;

    /**
     * 关联
     */
    private  String relation;

    /**
     * 字段类型
     */
    private  String fieldType;

    /**
     * 左括号
     */
    private String leftBracket;

    /**
     * 右括号
     */
    private String rightBracket;

}

主要的生成sql查询条件的方法如下

public class AdvancedSearchBizService {
    /**
     * 返回生成的sql查询条件,同时部分无法拼接成sql的字段修饰到查询vo里
     * @param searchConditionList
     * @param queryVo
     * @return
     */
    public static String genarateConditionSql(List<AdvanceSearchCondition> searchConditionList,Object queryVo) {
        if(CollectionUtils.isEmpty(searchConditionList)){
            return StringUtils.EMPTY;
        }
        List<AdvanceSearchCondition> validList = searchConditionList.stream().filter(AdvancedSearchBizService::validate).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(validList)){
            return StringUtils.EMPTY;
        }
        //有些字段不能用拼sql的方式处理,因此直接作用到查询vo上
        List<AdvanceSearchCondition> decorateQueryVoList = validList.stream().filter(x-> conditionFieldTypeEnum.VO_FIELD.name().equalsIgnoreCase(x.getFieldType())).collect(Collectors.toList());
        validList.removeAll(decorateQueryVoList);
        decorateQueryVo(queryVo,decorateQueryVoList);
        //select *  from table where 1=1 拼上 条件(关联符号在前)
        StringBuilder searchParamer = new StringBuilder();
        String space = " ";
        for (AdvanceSearchCondition searchCondition : validList ) {
            String field = searchCondition.getField().toLowerCase();
            String value = searchCondition.getSearchValue();
            String searchVal =AdvanceSearchUtils.convertValue(searchCondition);
            String condition = searchCondition.getCondition();
            String relation = searchCondition.getRelation();
            String leftBracket=StringUtils.isNotBlank(searchCondition.getLeftBracket())?searchCondition.getLeftBracket():space;
            String rightBracket=StringUtils.isNotBlank(searchCondition.getRightBracket())?searchCondition.getRightBracket():space;

            // = 拼接的情况
            if (condition.equals(SearchConditionEnum.EQUALS.chs())) {
                //转一下,如果是string类型输了多个值,也用替换成in
                if(searchVal.contains(",")) {
                    searchParamer.append(space).append(relation)
                            .append(space)
                            .append(leftBracket)
                            .append(space).append(field)
                            .append(space).append(SearchConditionEnum.IN.chs())
                            .append(space).append("(")
                            .append(space).append(searchVal)
                            .append(space).append(") ")
                            .append(space).append(rightBracket)
                            .append(space);
                }else {
                    searchParamer.append(space).append(relation)
                            .append(space)
                            .append(leftBracket)
                            .append(space).append(field)
                            .append(space).append(condition)
                            .append(space).append(searchVal)
                            .append(space).append(rightBracket)
                            .append(space);
                }
            }
            // <> 拼接的情况
            if (condition.equals(SearchConditionEnum.NOT_EQUALS.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append(searchVal)
                        .append(space).append(rightBracket).append(space);
            }
            //  > 拼接的情况
            if (condition.equals(SearchConditionEnum.GREATER_THAN.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append(searchVal)
                        .append(space).append(rightBracket).append(space);
            }
            // < 拼接的情况
            if (condition.equals(SearchConditionEnum.LESS_THAN.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append(searchVal)
                        .append(space).append(rightBracket).
                        append(space);
            }
            // >= 拼接的情况
            if (condition.equals(SearchConditionEnum.GREATER_EQUALS.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append(searchVal)
                        .append(space).append(rightBracket).
                        append(space);
            }
            // <= 拼接的情况
            if (condition.equals(SearchConditionEnum.LESS_EQUALS.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append(searchVal)
                        .append(space).append(rightBracket).
                        append(space);
            }
            // in 拼接的情况
            if (condition.equals(SearchConditionEnum.IN.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append("(")
                        .append(space).append(searchVal)
                        .append(space).append(") ")
                        .append(space).append(rightBracket)
                        .append(space);
            }
            // not in  拼接的情况
            if (condition.equals(SearchConditionEnum.NOT_IN.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append("(")
                        .append(space).append(searchVal)
                        .append(space).append(") ")
                        .append(space).append(rightBracket)
                        .append(space);
            }
            // like 拼接的情况
            if (condition.equals(SearchConditionEnum.LIKE.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append("'%").append(searchVal.replace("'","")).append("%'")
                        .append(space).append(rightBracket).
                        append(space);
            }
            // not like  拼接的情况
            if (condition.equals(SearchConditionEnum.NOT_LIKE.chs())) {
                searchParamer.append(space).append(relation)
                        .append(space)
                        .append(leftBracket)
                        .append(space).append(field)
                        .append(space).append(condition)
                        .append(space).append("'%").append(searchVal).append("%'")
                        .append(space).append(rightBracket).
                        append(space);
            }
            // between 拼接的情况  between... and...
            // not between  拼接的情况
            if (condition.equals(SearchConditionEnum.BETWEEN.chs())) {
                String[] contentUnits = value.split(",");
                if (contentUnits.length != 2) {
                    throw new BizException("搜索值栏位必须输入两个参数且用“,”隔开");
                }
                String leftContentUnit = contentUnits[0];
                String rightContentUnit = contentUnits[1];
                if(!AdvanceSearchUtils.isNumber(leftContentUnit)){
                    searchParamer.append(space).append(relation)
                            .append(space)
                            .append(leftBracket)
                            .append(space).append(field)
                            .append(space).append(condition).append(space)
                            .append("'").append(leftContentUnit).append("'")
                            .append(space).append("and").append(space)
                            .append("'").append(rightContentUnit).append("' ")
                            .append(space).append(rightBracket).
                            append(space);
                }else {
                    searchParamer.append(space).append(relation)
                            .append(space)
                            .append(leftBracket)
                            .append(space).append(field)
                            .append(space).append(condition)
                            .append(space).append(leftContentUnit)
                            .append(space).append("and")
                            .append(space).append(rightContentUnit)
                            .append(space).append(rightBracket).
                            append(space);
                }
            }
            if (condition.equals(SearchConditionEnum.NOT_BETWEEN.chs())) {
                String[] contentUnits = value.split(",");
                if (contentUnits.length != 2) {
                    throw new RuntimeException("搜索值栏位必须输入两个参数且用“,”隔开");
                }
                String leftContentUnit = contentUnits[0];
                String rightContentUnit = contentUnits[1];
                if(!AdvanceSearchUtils.isNumber(leftContentUnit)){
                    searchParamer.append(space).append(relation)
                            .append(space)
                            .append(leftBracket)
                            .append(space).append(field)
                            .append(space).append(condition).append(space)
                            .append("'").append(leftContentUnit).append("'")
                            .append(space).append("and").append(space)
                            .append("'").append(rightContentUnit).append("' ")
                            .append(space).append(rightBracket)
                            .append(space);
                }else {
                    searchParamer.append(space).append(relation)
                            .append(space)
                            .append(leftBracket)
                            .append(space).append(field)
                            .append(space).append(condition)
                            .append(space).append(leftContentUnit)
                            .append(space).append("and")
                            .append(space).append(rightContentUnit)
                            .append(space).append(rightBracket).
                            append(space);
                }
            }
        }
        if(!CollectionUtils.isEmpty(searchConditionList) && StringUtils.isNotBlank(searchParamer)) {
            searchParamer.insert(4, "(");
            searchParamer.append(")");
        }
        String sqlCondition=searchParamer.toString();
        checkBracketMatch(sqlCondition);
        return sqlCondition;
    }

    private static void checkBracketMatch(String sqlCondition) {
        Deque<Character> stringStack = new LinkedList<>();
        char tempChar;
        for (int i = 0; i < sqlCondition.length(); i++) {
            tempChar = sqlCondition.charAt(i);
            switch (tempChar) {
                case '(': {
                    stringStack.push(tempChar);
                    break;
                }
                case ')':
                    if(stringStack.isEmpty()){
                        throw new BizException("括号不匹配,请检查");
                    }
                    if (stringStack.pop() != '(') {
                        throw new BizException("括号不匹配,请检查");
                    }
                    break;
                default:
            }
        }
        if (!stringStack.isEmpty()) {
            throw new BizException("括号不匹配,请检查");
        }
    }

    /**
     * 把参数设置进vo里
     * @param queryVo
     * @param decorateQueryVoList
     */
    private static void decorateQueryVo(Object queryVo, List<AdvanceSearchCondition> decorateQueryVoList) {
        if(CollectionUtils.isEmpty(decorateQueryVoList)){
            return;
        }
        try {
            for (AdvanceSearchCondition one : decorateQueryVoList) {
                Field field = ReflectionUtil.getField(queryVo.getClass(), one.getField());
                Type type = field.getGenericType();
                Set<Object> supportValues = new HashSet<>();
                if (type instanceof ParameterizedType) {
                    Class<?> clazz = (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
                    for (String val : Arrays.asList(one.getSearchValue().split(","))) {
                        switch (clazz.getTypeName()) {
                            case "java.lang.String":
                                supportValues.add(val);
                                break;
                            default:
                                supportValues.add(clazz.getMethod("valueOf", String.class).invoke(null, val));
                                break;
                        }
                    }
                    ReflectionUtil.setFieldValue(queryVo, one.getField(), supportValues);
                }else{
                    ReflectionUtil.setFieldValue(queryVo, one.getField(), one.getSearchValue());
                }
            }
        }catch (Exception e){
            Log.error("高级查询设置vo参数失败"+e.getMessage(),e);
        }
    }

    private static boolean validate(AdvanceSearchCondition condition){
        if(!condition.getFieldType().equalsIgnoreCase(conditionFieldTypeEnum.VO_FIELD.name())) {
            return StringUtils.isNotBlank(condition.getField())
                    && StringUtils.isNotBlank(condition.getFieldType())
                    && StringUtils.isNotBlank(condition.getCondition())
                    && StringUtils.isNotBlank(condition.getSearchValue())
                    && StringUtils.isNotBlank(condition.getRelation())
                    ;
        }else{
            return StringUtils.isNotBlank(condition.getField())
                    && StringUtils.isNotBlank(condition.getFieldType())
                    && StringUtils.isNotBlank(condition.getCondition())
                    && StringUtils.isNotBlank(condition.getSearchValue())
                    ;
        }
    }

}

这里生成的sql片段就可以当成一个简单的查询条件追加到原来的sql上面
在这里插入图片描述

三,呈现效果

最终效果如下
在这里插入图片描述

总结

接触前端也有两年了,从一开始只想着调用别人的组件慢慢的也喜欢自己封装一些组件简化业务开发过程。不过由于对前端的一些高级的写法不太熟悉可能写出来的代码啰嗦了一些,并且时间仓促落地的场景不多可能也有比较多的隐含的bug存在,还望读者不吝赐教。
作者:连

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

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

相关文章

腾讯mini项目-【指标监控服务重构】2023-08-29

今日已办 Collector 指标聚合 由于没有找到 Prometheus 官方提供的可以聚合指定时间区间内的聚合函数&#xff0c;所以自己对接Prometheus的api来聚合指定容器的cpu_avg、cpu_99th、mem_avg 实现成功后对接小组成员测试完提供的时间序列和相关容器&#xff0c;将数据记录在表格…

相机One Shot标定

1 原理说明 原理部分网上其他文章[1][2]也已经说的比较明白了&#xff0c;这里不再赘述。 2 总体流程 参考论文作者开源的Matlab代码[3]和github上的C代码[4]进行说明&#xff08;不得不说还是Matlab代码更优雅&#xff09; 论文方法总体分两部&#xff0c;第一部是在画面中找…

李宏毅hw-9:Explainable ML

——欲速则不达&#xff0c;我已经很幸运了&#xff0c;只要珍惜这份幸运就好了&#xff0c;不必患得患失&#xff0c;慢慢来。 ----查漏补缺&#xff1a; 1.关于这个os.listdir的使用 2.从‘num_文件名.jpg’中提取出数值&#xff1a; 3.slic图像分割标记函数的作用&#xf…

【音视频流媒体】4、摄像头:分辨率、光圈|快门|感光度、焦距

文章目录 一、摄像头分辨率二、光圈、快门、感光度2.1 光圈2.1.1 外观2.1.2 光圈在相机中如何表示的2.1.3 对拍照的影响2.1.4 如何选择合适的光圈2.1.5 光圈在相机中如何设置 2.2 快门2.2.1 外观2.2.2 快门在相机中的表示2.2.3 快门对于拍照有什么影响2.2.4 选择合适的快门2.2.…

【C#】.Net基础语法一

目录 一、程序集信息 【1.1】Properties中AssemblyInfo文件 二、.Net程序的两次编译过程 三、.Net中命名空间和类 【3.1】引入命名空间 【3.2】修改默认的命名空间 【3.3】命名空间的总结 四、.Net中数据类型 【4.1】数值型 【4.2】非数值型 五、.Net中变量 【5.1】…

Selenium WebUI 自动化测试框架

框架结构 框架结构 框架基于 PO 模型进行设计&#xff0c;将页面元素与操作进行拆分&#xff0c;减少页面改动时的维护成本&#xff1b;同时使用 xsd 自定义 xml 标签&#xff0c;通过解析 xml 来驱动 selenium 进行执行&#xff0c;减少了一定的语言学习成本。 主要功能 基于…

[架构之路-221]:鸿蒙系统和安卓系统的比较:微内核VS宏内核, 分布式VS单体式

目录 一、鸿蒙系统和安卓系统的系统架构 1.1 鸿蒙系统的分层架构 1.2 安卓系统的分层架构 1.3 鸿蒙系统和安卓系统是操作系统吗&#xff1f; 二、鸿蒙系统和安卓系统的系统架构比较 2.1 它们与Linux操作系统的关系 2.2 架构比较 三、操作系统基础 3.1 微内核架构 3.2…

leetcode刷题 二维数组 八方向

题目描述 输入&#xff1a;board [[0,1,0],[0,0,1],[1,1,1],[0,0,0]] 输出&#xff1a;[[0,0,0],[1,0,1],[0,1,1],[0,1,0]] 题目分析:就是以二维数组某个元素为中心&#xff0c;寻找周围八个方向的元素&#xff0c;按照题目要求修改二维数组元素返回&#xff1b; 拷贝一份二…

FPGA板卡启动以及LED灯带调试

环境配置 软件&#xff1a; MobaXterm&#xff08;free版本即可&#xff09;下载教程参考&#xff1a; MobaXterm&#xff08;终端工具&#xff09;下载&安装&使用教程_蜗牛也不慢......的博客-CSDN博客 Win32 Disklmager 下载教程参考&#xff1a; 不分类工具&am…

Nature Communications | 张阳课题组:端到端深度学习实现高精度RNA结构预测

RNA分子是基因转录的主要执行者&#xff0c;也是细胞运作的隐形功臣。它们在基因表达调控、支架构建以及催化活性等多个生命过程中都扮演着关键角色。虽然RNA如此重要&#xff0c;但由于实验数据的缺乏&#xff0c;准确预测RNA 的三维空间结构仍然是目前计算生物学面临的重大挑…

HDMI之HDCP 2.3

Authentication and Key Exchange Without Stored Km With Stored Km HDCP2Version DDC时序 协议截图 Bit2为1,可知DUT设备支持HDCP 2.2及以上版本 RxStatus DDC时序 协议截图 <

C++ 类、方法的同一声明不同实现的方式

问题提出 头文件&#xff1a;声明CurrentTime类和PrintTime方法。 #ifndef CURRENT_TIME_H #define CURRENT_TIME_H class CurrentTime { public:void PrintTime(); }; #endifmain函数&#xff1a;创建CurrentTime对象&#xff0c;调用PrintTime。 #include "current_t…

UNet网络模型:数据集制作

UNet网络模型&#xff1a;数据集制作 一般语义分割的原始图片和标记图片在以下目录下&#xff1a; SegmentationClass&#xff1a;标记图片。 JPEGImages&#xff1a;原始图片。 数据集往往都是很多的图片等信息&#xff0c;对于数据集类来说&#xff0c;一个类里有所有数据…

腾讯mini项目-【指标监控服务重构-会议记录】2023-07-06

7/6 会议记录 Profile4个步骤 解压kafka消息初始化性能事件&#xff0c;分析事件将数据写入kafkaRun 开始执行各stage handler 上报耗时到otel-collector。。。 // ConsumerDispatchHandler consumer // // param msg *sarama.ConsumerMessage // param consumer *databus.K…

FPGA project : rom_vga_jump

只有vga_pix 模块代码与rom_vga不同&#xff0c;所以只上传了这个模块的代码与仿真代码。 // #define BLACK 0x0000 // 黑色 // #define NAVY 0x000F // 深蓝色 // #define DGREEN 0x03E0 // 深绿色 // #define DCYAN …

Linux系统下安装Mysql

1、执行命令&#xff1a;rpm -qa | grep -i mysql&#xff0c;先查看系统之前是否有安装相关的rpm包&#xff0c;如果有&#xff0c;会显示类似下面的信息&#xff1b; 2、通过命令yum -y remove mysql-*  一次性删除系统上所有相关的rpm包&#xff0c;或者通过命令yum -y …

zemax显微镜设计

光学显微镜&#xff08;Optical Microscope&#xff0c;简写OM&#xff09;是利用光学原理&#xff0c;把人眼所不能分辨的微小物体放大成像&#xff0c;以供人们提取微细结构信息的光学仪器&#xff0c;第一架复式光学显微镜是于1665年由英国物理学家虎克制作。 首先做物镜 入…

(第三百篇BLOG记录)写于象牙终章与从零开始-20230924

启 由于若干原因&#xff08;包括但不限于紧锣密鼓的完成博士毕业的一系列实验和论文撰写、学习各种百花齐放的有意思的领域、完成人生身份的重大转变&#xff09;&#xff0c;导致卡在299篇博客已经很久了&#xff0c;不过算了一下还是在一个较长时间维度上可以基本保持每周一…

数据库——理论基础

目录 1.1 什么是数据库 1.2 数据库管理系统&#xff08;DBMS&#xff09; 1.3 数据库和文件系统的区别 1.4 数据库的发展史 1.5常见的数据库 1.5.1关系型数据库 1.5.2 非关系型数据库 1.6 DBMS支持的数据模型 1.1 什么是数据库 数据&#xff1a;描述事物的符号记录 数…

云计算中的关键技术——虚拟化

在数据中心里面&#xff0c;也有一种类似的开源技术 qemu-kvm&#xff0c;能让你在一台巨大的物理机里面&#xff0c;掏出一台台小的机器。这套软件就能解决上面的问题&#xff1a;一点就能创建&#xff0c;一点就能销毁。你想要多大就有多大&#xff0c;每次创建的系统还都是新…