当前位置: 首页 > 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开发感兴趣、刚刚踏入…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...