当前位置: 首页 > news >正文

封装一个高级查询组件

封装一个高级查询组件

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

背景

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

一,前端相关代码

总体的设计的设想上,需要一个弹出式的对话框,可以点击增加条件,并且整体能比较容易的嵌入到界面的查询中。根据需求的查询条件需要支持常见的如输入框,下拉,时间等控件。因为使用场景不多,目前的需求范围暂时只支持三层括号。为了通用性应该做成每个界面按需配置的,譬如一个页面可以有多少个可供选择的查询条件,因此需要有个简单的协议通过配置渲染查询条件。安全起见,查询条件在后端拼成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-dialogv-dialogDragtitle="高级搜索":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-optionv-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-optionv-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="请选择"multiplev-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-optionv-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)"clearablestyle="width: 100%;"><el-optionv-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-buttontype="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-optionv-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和条件的mapfieldConditionMap: new Map(),//field和控件相关的mapfieldElemenTypeChooseMap: 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.applicationShareFlagparam.roleShareFlag=this.roleShareFlagparam.configName=this.currentConfigNameparam.id=this.currentConfigIndexparam.roleCode=this.roleCodeparam.bizPageName=this.bizPageNamelet 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.searchConditionListthis.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.fieldTyperow.prompt=item.promptthis.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.configNamethis.currentConfigIndex=config.idthis.applicationShareFlag=config.applicationShareFlagthis.roleShareFlag=config.roleShareFlagthis.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=falsethis.roleShareFlag=falsethis.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 = trueif(item.fieldType==='VO_FIELD'){item.bracketShow=true}else{item.bracketShow=false}}else if(item.fieldType==='VO_FIELD'){//这种类型的字段不参与与或拼接item.relation= ""item.relationInputShow = trueitem.bracketShow=true}else{item.relationInputShow = falseitem.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类型输了多个值,也用替换成inif(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存在,还望读者不吝赐教。
作者:连

相关文章:

封装一个高级查询组件

封装一个高级查询组件 背景一&#xff0c;前端相关代码二&#xff0c;后端相关代码三&#xff0c;呈现效果总结 背景 业务有个按照自定义选择组合查询条件&#xff0c;保存下来每次查询的时候使用的需求。查了一下项目里的代码没有现成的组件可以用&#xff0c;于是封装了一个 …...

代码随想录第七章 栈与队列

1、leecode232 用栈实现队列 使用栈模拟队列的行为&#xff0c;仅使用一个栈是不行的&#xff0c;所以需要两个栈&#xff0c;一个是输入栈&#xff0c;一个是输出栈。 #include<iostream> #include<vector> #include<string> #include<stack> #incl…...

SQL Server对象类型(5)——4.5. 同义词(Synonym)

4.5. 同义词(Synonym) 4.5.1. 同义词概念 与Oracle中相同,SQL Server中的同义词是虚的、被定义的模式对象,其本身并不存储任何数据。其用途之一就是为其他类型基础对象提供一个别名;用途之二就是为应用提供一个抽象层,以方便后期应用相关的基础对象的更改和维护。用户可…...

IP风险查询:抵御DDoS攻击和CC攻击的关键一步

随着互联网的普及&#xff0c;网络攻击变得越来越普遍和复杂&#xff0c;对企业和个人的网络安全构成了重大威胁。其中&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击和CC&#xff08;网络连接&#xff09;攻击是两种常见且具有破坏性的攻击类型&#xff0c;它们…...

Tune-A-Video论文阅读

论文链接&#xff1a;Tune-A-Video: One-Shot Tuning of Image Diffusion Models for Text-to-Video Generation 文章目录 摘要引言相关工作文生图扩散模型文本到视频生成模型文本驱动的视频编辑从单个视频生成 方法前提DDPMsLDMs 网络膨胀微调和推理模型微调基于DDIM inversio…...

Dataset和DataLoader用法

Dataset和DataLoader用法 在d2l中有简洁的加载固定数据的方式&#xff0c;如下 d2l.load_data_fashion_mnist() # 源码 Signature: d2l.load_data_fashion_mnist(batch_size, resizeNone) Source: def load_data_fashion_mnist(batch_size, resizeNone):"""…...

【跟小嘉学习区块链】二、Hyperledger Fabric 架构详解

系列文章目录 【跟小嘉学习区块链】一、区块链基础知识与关键技术解析 【跟小嘉学习区块链】一、区块链基础知识与关键技术解析 文章目录 系列文章目录[TOC](文章目录) 前言一、Hyperledger 社区1.1、Hyperledger(面向企业的分布式账本)1.2、Hyperledger社区组织结构 二、Hype…...

springboot下spring方式实现Websocket并设置session时间

概述 springboot实现websocket有4种方式 servlet&#xff0c;spring&#xff0c;netty&#xff0c;stomp 使用下来spring方式是最简单的. springboot版本&#xff1a;3.1.2 jdk&#xff1a;17 当前依赖版本 <dependency><groupId>org.springframework.boot<…...

LeetCode算法二叉树—相同的树

目录 100. 相同的树 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; 运行结果&#xff1a; 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是…...

搭建Flink集群、集群HA高可用以及配置历史服务器

Flink集群搭建 Flink集群搭建集群规划下载并解压安装包修改集群配置分发安装目录启动集群访问Web UI Flink集群HA高可用概述集群规划配置flink配置master、workers配置ZK分发安装目录启动HA集群测试 Flink参数配置配置历史服务器概述配置启动、停止历史服务器提交一个Job任务查…...

vscode终端中打不开conda虚拟包管理

今天&#xff0c;想着将之前鸽的Unet网络模型给实现一下&#xff0c;结果发现&#xff0c;在vscode中运行python脚本&#xff0c;显示没有这包&#xff0c;没有那包。但是在其他的ipynb中是有的&#xff0c;感觉很奇怪。我检查了一下python版本&#xff0c;发现不是我深度学习的…...

【音视频】MP4封装格式

基本概念 使用MP4box.js查看MP4内部组成结构 整体结构 数据索引&#xff08;moov&#xff09;数据流包&#xff08;mdat&#xff09; 各个包的位置&#xff0c;大小&#xff0c;信息&#xff0c;时间戳&#xff0c;编码方式等全在数据索引 数据流包只有纯二进制码流数据 数据…...

环境-使用vagrant快速创建linux虚拟机

1.下载软件 虚拟机 Oracle VM VirtualBox 镜像 Vagrant by HashiCorp (vagrantup.com) 如果下载慢&#xff0c;可以复制下载链接&#xff0c;使用迅雷下载 2.安装 根据提示点击下一步即可&#xff0c;建议安装到空间较大的非系统盘。 打开 window cmd 窗口&#xff0c;…...

10.1网站编写(Tomcat和servlet基础)

一.Tomcat: 1.Tomcat是java写的,运行时需要依赖jre,所以要装jdk. 2.建议配置好环境变量. 3.默认端口号8080(业务端口)可能会被占用,建议改一下(本人改成了9999). 4.另一个默认端口是8005(管理端口). 二Servlet基础(编写一个hello world代码): 整体分为7个步骤,分别是创建…...

10CQRS

本系列包含以下文章&#xff1a; DDD入门DDD概念大白话战略设计代码工程结构请求处理流程聚合根与资源库实体与值对象应用服务与领域服务领域事件CQRS&#xff08;本文&#xff09; 案例项目介绍 # 既然DDD是“领域”驱动&#xff0c;那么我们便不能抛开业务而只讲技术&…...

DAZ To UMA⭐一.DAZ简单使用教程

文章目录 &#x1f7e5; DAZ快捷键&#x1f7e7; DAZ界面介绍 &#x1f7e5; DAZ快捷键 移动物体:ctrlalt鼠标左键 旋转物体:ctrlalt鼠标右键 导入模型:双击左侧模型UI &#x1f7e7; DAZ界面介绍 Files:显示全部文件 Products:显示全部产品 Figures:安装的全部人物 Wardrobe…...

面试题 —— Java集合篇(23题)

文章目录 1.Java中常见集合有哪些 &#xff1f;2. 说说你对Java集合是怎么理解的&#xff1f;3.请你说一下List&#xff0c;Set&#xff0c;Map三者的特点是 &#xff1f;4.在实际开发过程中如何更好的选择集合 &#xff1f;5. ArrayList和Vector区别 &#xff1f;6. ArrayList…...

SpringBoot2.7.14整合Swagger3.0的详细步骤及容易踩坑的地方

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Sp…...

题解:ABC321D - Set Menu

题解&#xff1a;ABC321D - Set Menu 题目 链接&#xff1a;Atcoder。 链接&#xff1a;洛谷。 难度 算法难度&#xff1a;B。 思维难度&#xff1a;C。 调码难度&#xff1a;B。 综合评价&#xff1a;见洛谷链接。 算法 枚举二分查找。 思路 先对b升序排序&#x…...

什么是Progressive Web App(PWA)?它们有哪些特点?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 渐进式Web App简介⭐ PWAs的主要特点⭐ 总结⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

【51单片机】4. 模块化编程与LCD1602Debug

1. 什么是模块化编程 传统编程会将所有函数放在main.c中&#xff0c;如果使用的模块多&#xff0c;一个文件内会有很多代码&#xff0c;不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里&#xff0c;在.h文件里提供外部可调用函数声明&#xff0c;其他.c文…...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...

Redis上篇--知识点总结

Redis上篇–解析 本文大部分知识整理自网上&#xff0c;在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库&#xff0c;Redis 的键值对中的 key 就是字符串对象&#xff0c;而 val…...