工具类-列表请求工具 useList
useList
用于列表请求的基于 vue 3 的 hooks,接收请求函数、请求参数等数据,自动生成请求请求函数,分页信息等
本文有涉及到 http 请求工具和接口返回格式的内容:
- http 工具:一个基于 axios 封装的请求工具
- ResponseData 接口:定义接口返回数据结构的 interface
interface ResponseData<T = any> {code: number;data: T;message: string;
}
详情可参考文章:工具类-基于 axios 的 http 请求工具 Request
实现一个简单的列表请求
import { ref, Ref } from 'vue';
import { get, cloneDeep } from 'lodash-es';
import { ResponseData } from '@/http/type';interface UseListConfig<P = any, T = any> {request: {/*** 请求列表方法*/api: (params: P) => Promise<ResponseData<T[]>>;/*** 请求参数*/params?: P;};response?: {/*** 列表数据 默认 data* 例: 响应数据为 { data: { list: [] } } 则传递 data.list;*/listDataKey?: string;};
}export function useList<P extends object = any, T = any>(config: UseListConfig<P, T>) {const cacheConfig = cloneDeep(config);const { api } = cacheConfig.request;const { listDataKey = 'data' } = cacheConfig.response || {};const params = ref(cloneDeep(cacheConfig.request.params || {}) as P) as Ref<P>;const list = ref([]) as Ref<T[]>;const handleSearch = async () => {const res = await api(params.value as P);// 更具 listDataKey 获取列表数据list.value = get(res, listDataKey);return res;};return {params,list,handleSearch,};
}
useList 定义了两个泛型,其中 P 代表请求的参数类型,T 代表列表数据每一项的类型,接收请求方法和请求参数等数据, 最后返回了请求参数变量 params,列表数据 list,还有发起列表请求的 handlerSearch 方法
在 vue 3 中使用
script
import { useList } from '@/hooks/-useList';
import { ResponseData } from '@/http/type';// 定义请求参数类型
interface GetListParams {name: string;
}
// 定义请求项类型
interface ListItem {id: number;name: string;
}// 模拟列表数据和 http 请求
const MOCK_LIST: ListItem[] = Array(100).fill(0).map((_, index) => ({id: index + 1,name: `list-item-${index + 1}`,}));
const getList = async (params: GetListParams): Promise<ResponseData<ListItem[]>> => {await new Promise(resolve => setTimeout(resolve, 3 * 1e3));const list: ListItem[] = [];if (params.name) list.push(...MOCK_LIST.filter(item => item.name.includes(params.name)));else list.push(...MOCK_LIST);return {code: 200,data: list,message: 'success',};
};const { params, list, handleSearch } = useList<GetListParams, ListItem>({request: {api: getList,params: {name: '',},},response: {listDataKey: 'data',},
});
template
<template><div><div><a-input v-model="params.name" placeholder="请输入名称" /><a-button type="primary" @click="handleSearch()">查询</a-button></div><div><p v-for="item of list" :key="item.id">{{ item.name }}</p></div></div>
</template>
使用泛型定义好请求的参数和返回的内容的类型,向 useList 传入请求函数和参数,获得 params,list,以及 handlerSearch,将 params 的字段绑定到搜索的表单元素,点击搜索调用 handlerSearch 即可完成列表的请求
增加 loading
每次列表请求时需要给 列表增加一个加载中的文案或图表,每次手动去声明一个 loading,在 调用 handleSearch 前赋值为 true,调用结束后赋值为 false,可以实现控制列表的加载状态。
但是每个列表都要实现一遍过于麻烦和冗余,可以在 useList 中增加一个 loading 的变量并返回,在请求前后改变 loading 的值,实现加载状态的控制。
loading 的实现使用了 useLoading,可以查阅 工具类-useLoading
export function useList<P extends object = any, T = any>(config: UseListConfig<P, T>) {...const { loading, executor } = useLoading();const handleSearch = async () => {const res = await executor(async () => api(params.value as P));list.value = get(res, listDataKey);return res;};return {...loading,...}
}
使用示例
script
...
const { params, loading, list, handleSearch } = useList<GetListParams, ListItem>({request: {api: getList,params: {name: '',},},
});
template
<template><div><div><a-input v-model="params.name" placeholder="请输入名称" /><a-button type="primary" @click="handleSearch()">查询</a-button></div><!-- v-loading 是使元素显示加载状态的指令 --><div v-loading="loading"><p v-for="item of list" :key="item.id">{{ item.name }}</p></div></div>
</template>
处理分页信息
首先增加 UseListConfig 的分页信息类型定义
interface UseListConfig<P = any, T = any> {request: {.../*** 分页信息-当前页数参数在 params 中的 key* 默认: page*/pageNumKey?: string;/*** 分页信息-每页条数参数在 params 中的 key* 默认: pageSize*/pageSizeKey?: string;};response?: {.../*** 总条数字段的 key* 例: 响应数据为 { data: { list: [], total: 0 } } 则传递 data.total;* 默认 pageInfo.items*/listDataKey?: string;};
}
在 handleSearch 中增加分页控制,增加 handleCurrentChange 和 handleSizeChange 方法
export function useList<P extends object = any T = any>(config: UseListConfig<P, T>) {...const total = ref(0);const handleSearch = async (pageNum = 1) => {if (pageNumKey in (params.value as object)) {(params.value as any)[pageNumKey] = pageNum;}const res = await executor(async () => api(params.value as P));list.value = get(res, listDataKey);total.value = get(res, totalKey);return res;};/*** 切换当前页码 刷新列表*/const handleCurrentChange = async (pageNum: number) => {await handleSearch(pageNum);};/*** 切换分页大小 刷新列表*/const handleSizeChange = async (pageSize: number) => {if (pageSizeKey in (params.value as object)) {(params.value as any)[pageSizeKey] = pageSize;}// 切换分页大小后,默认回到第一页await handleSearch(1);};return {...handleSearch,handleCurrentChange,handleSizeChange,}
}
使用示例
script
import { useList } from '@/hooks/-useList';
import { ResponseData } from '@/http/type';
import Pagination from '@/components/pagination/index.vue'; // 分页的组件interface GetListParams {name: string;page: number;pageSize: number;
}interface ListItem {id: number;name: string;
}// 模拟列表数据和 http 请求
const MOCK_LIST: ListItem[] = Array(100).fill(0).map((_, index) => ({id: index + 1,name: `list-item-${index + 1}`,}));
const getList = async (params: GetListParams): Promise<ResponseData<ListItem[]>> => {await new Promise(resolve => setTimeout(resolve, 3 * 1e3));let list: ListItem[] = [];if (params.name) list = MOCK_LIST.filter(item => item.name.includes(params.name));else list = MOCK_LIST;list = list.slice(params.page * params.pageSize - params.pageSize, params.page * params.pageSize);return {code: 200,data: list,message: 'success',pageInfo: {items: MOCK_LIST.length,},};
};const { params, total, loading, list, handleSearch, handleCurrentChange, handleSizeChange } =useList<GetListParams, ListItem>({request: {api: getList,params: {name: '',page: 1,pageSize: 10,},pageNumKey: 'page',pageSizeKey: 'pageSize',},response: {listDataKey: 'data',totalKey: 'pageInfo.items',},});
template
<template><div><div><a-input v-model="params.name" placeholder="请输入名称" /><a-button type="primary" @click="handleSearch()">查询</a-button><pagination:total="total":page-size="params.pageSize":current="params.page":show-total="true"@change="handleCurrentChange"@page-size-change="handleSizeChange"/></div><!-- v-loading 是使元素显示加载状态的指令 --><div v-loading="loading"><p v-for="item of list" :key="item.id">{{ item.name }}</p></div></div>
</template>
增加 reset 方法
在列表请求页中,经常有需要清空或重置搜索条件的需求,可以在 useList 中记录传入的初始 params,增加 handleReset 函数,将 params 变量的值赋值为 初始的 params 值
export type DeepReadonly<T> = {readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};export function useList<P extends object = any, T = any>(config: UseListConfig<P, T>) {...// 使用 readonly 约束 defaultParams,避免被更改const defaultParams: DeepReadonly<P> = cloneDeep(cacheConfig.request.params || ({} as P));const handleReset = () => {params.value = cloneDeep(defaultParams as P);handleSearch(); // 重置完立即发起搜索};return {...handleReset,}
}
有可能 rest 函数不一定是将 params 变量重置为使用 useList 时传入的值,为了应付这种特殊情况,我们可以增加一个 handleCustomeReset 的参数,将重置的权限暴露出去
interface UseListConfig<P = any, T = any> {request: {.../*** 自定义重置方法*/handleCustomReset?: (params: P, defaultParams: DeepReadonly<P>) => P;;};
}export function useList<P extends object = any, T = any>(config: UseListConfig<P, T>) {...const defaultParams = cloneDeep(cacheConfig.request.params || ({} as P));const { handleCustomReset } = cacheConfig.request;const handleReset = () => {if (handleCustomReset) params.value = handleCustomReset(params.value, defaultParams);else params.value = cloneDeep(defaultParams as P);handleSearch(); // 重置完立即发起搜索};return {...handleReset,}
}
增加 handleCustomReset 的可选项, 将当前 params 的值和 defaultParmas 传给 handleCustomReset,如果有传入 handleCustomReset,则重置时使用 handleCustomReset 的返回值赋值给 params 变量,若没有 handleCustomReset,则使用默认的重置方式
增加一些回调钩子
请求前的钩子
- handleValidate: 请求前校验,校验参数是否合理等
- handleParams:请求前处理参数
- resetApi: 重置列表请求方法
请求完成后的钩子
- handleResponseData:处理返回的列表数据
interface UseListConfig<P = any, T = any> {request: {.../*** 自定义重置方法*/handleCustomReset?: (params: P, defaultParams: DeepReadonly<P>) => P;/*** 校验函数,校验参数是否合理等* 返回 false 则不发起请求*/handleValidate?: (params: DeepReadonly<P>) => boolean;/*** 处理请求参数*/handleParams?: (params: DeepReadonly<P>) => P;/*** 重置请求方法*/resetApi?: (params: DeepReadonly<P>) => (params: P) => Promise<ResponseData<T[]>>;};response?: {.../*** 处理响应数据*/handleResponseData?: (list: T[]) => T[];};
}export function useList<P extends object = any, T = any>(config: UseListConfig<P, T>) {...const {handleValidate,handleParams,resetApi,} = cacheConfig.request || {};const {handleResponseData,} = cacheConfig.response || {};const handleSearch = async (pageNum = 1) => {if (pageNumKey in params.value) {(params.value as any)[pageNumKey] = pageNum;}let _params = cloneDeep(params.value);if (handleValidate && !handleValidate(_params)) return;if (handleParams) _params = handleParams(_params);if (resetApi) api = resetApi(_params);const res = await executor(async () => api(params.value as P));const _list = get(res, listDataKey);if (handleResponseData) list.value = handleResponseData(_list);else list.value = _list;total.value = get(res, totalKey);return res;};
}
使用示例
const getList = async (params: GetListParams): Promise<ResponseData<ListItem[]>> => {console.log('getList');await new Promise(resolve => setTimeout(resolve, 3 * 1e3));...
};
const getListLongTime = async (params: GetListParams): Promise<ResponseData<ListItem[]>> => {console.log('getListLongTime');await new Promise(resolve => setTimeout(resolve, 10 * 1e3));...
};const { params, total, loading, list, handleSearch, handleCurrentChange, handleSizeChange } =useList<GetListParams, ListItem>({request: {...handleValidate(params) {if (params.page <= 0) {console.error('page 必须大于 0');return false;}return true;},handleParams(params) {return {...params,pageSize: Math.min(params.pageSize, 10), // 当 pageSize 小于 10 时,默认设置为 10};},resetApi(params) {// 根据 params.name 判断调用哪个接口if (params.name.toLocaleLowerCase() === 'longtime') return getListLongTime;return getList;},},response: {...handleResponseData(list) {// 将 list 中的 name 转为大写return list.map(item => ({...item,name: item.name.toUpperCase(),}));},},});
增加防抖
在 UseListConfig 中增加 lazy 字段,接收一个以毫秒为单位的时间值作为搜索时函数的防抖时间
interface UseListConfig<P = any, T = any> {request: {.../*** 搜索函数防抖延迟时间* 默认不开启防抖*/lazy?: number;...};response?: {...};
}
先实现一个用于防抖的函数,类似 lodash 的 debounce 函数
注:为什么不直接用 ladash 的 debounce,因为 debounce 的返回值类型不太符合需求
type AnyFunction = (...args: any[]) => any;const debounce = <T extends AnyFunction>(fn: T, lazy = 300): ((...args: Parameters<T>) => Promise<ReturnType<T>>) => {let timer: number | null = null;return (...args) =>new Promise(resolve => {if (timer) clearTimeout(timer);timer = window.setTimeout(() => {resolve(fn(...args));}, lazy);});
};
export function useList<P extends object = any, T = any>(config: UseListConfig<P, T>) {...const {...lazy,} = cacheConfig.request;...const _handleSearch = async (pageNum = 1) => {const res = await api(params.value); // 去掉了 Loading 的 executor 函数执行...};const handleSearch = async (pageNum = 1) => {const func = lazy ? debounce(_handleSearch, lazy) : _handleSearch;// 在这里执行 Loading 的 executor 函数,因为在防抖时间内也需要显示 Loading 状态return executor(func, pageNum);};...
}
相关文章:
工具类-列表请求工具 useList
useList 用于列表请求的基于 vue 3 的 hooks,接收请求函数、请求参数等数据,自动生成请求请求函数,分页信息等 本文有涉及到 http 请求工具和接口返回格式的内容: http 工具:一个基于 axios 封装的请求工具Response…...
5G终端自动拔号脚本
5G终端自动拔号脚本 5G终端自动拔号脚本 5G终端自动拔号脚本, 先进入飞行模式,再切出飞行模式, 最后 查询UE IP地址 5G终端自动拔号脚本 input$1 if [ "$input"x "1"x ]; then cmdatcfun1echo "start dialing &…...
3-1 C指针与数组
前言: 基于本人回顾与思考,仅供学习参考 1.0 数组名称的用途 注:可以用于求数组占用的内存空间:sizeof(arrName);此时数组名称代表整个数组 int32 t buffer[5] {1,2,3,4,5};int32 t size sizeof(buffer);printf("sizeof(buffer) %d.\…...
swift 屏幕录制
步骤 1:导入 ReplayKit import ReplayKit步骤 2:开始录屏 let screenRecorder RPScreenRecorder.shared() // 麦克风或系统音频 screenRecorder.isMicrophoneEnabled truefunc startRecording() {guard screenRecorder.isAvailable else {print(&quo…...
Graphviz 的详细介绍
Graphviz 的详细介绍 Graphviz 是一个开源的图形可视化软件,专门用于生成结构化图形。它特别适合用于表示关系图、流程图、依赖关系图和树状结构等类型的图表。Graphviz 使用一种名为 DOT 的脚本语言描述图形,通过解析 DOT 文件生成图像。 Graphviz 的特…...
前端工程化
文章目录 前端工程化模块化与组件化代码规范与风格统一自动化构建与部署性能优化版本控制与团队协作自动化测试 前端工程化 前端工程化是一种将软件工程的方法应用于前端开发的过程,旨在提高开发效率、降低维护成本、优化代码质量,并支持团队协作。以下…...
【LC】41. 缺失的第一个正数
题目描述: 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 示例 1: 输入:nums [1,2,0] 输出:3 解释:范围…...
高频面试题(含笔试高频算法整理)基本总结回顾29
干货分享,感谢您的阅读! (暂存篇---后续会删除,完整版和持续更新见高频面试题基本总结回顾(含笔试高频算法整理)) 备注:引用请标注出处,同时存在的问题请在相关博客留言…...
Hive 的 Hook 机制 完全解析
Hive 的 Hook 是一种扩展机制,允许用户在执行查询时自定义行为,例如日志记录、审计或其他操作。Hook 通常在 Hive 的生命周期中某些关键节点被触发,开发者可以插入自定义代码执行特定任务。 一、Hook 的用途和核心概念 1. 用途 审计&#x…...
远程debug
这里写自定义目录标题 一、首先配置idea二、配置jvm1、将刚才idea生成的jvm指令复制下来,就是如下内容(注意要从你的idea中复制)2、在粘贴之前,要拼接上java-jar命令,还有servery,suspendy命令,最后拼接项目…...
一些常见网络安全术语
1、黑帽 为非法目的进行黑客攻击的人,通常是为了经济利益。他们进入安全网络以销毁,赎回,修改或窃取数据,或使网络无法用于授权用户。这个名字来源于这样一个事实:老式的黑白西部电影中的恶棍很容易被电影观众识别&…...
golang学习,小结
切片 切片,底层就是数组,len(切片的长度)和cap(容量,切片的空间) 从一个数组来得到切片,修改切片会修改原来的数组,数据会收到影响 我们可以通过内置的 append 函数对一…...
【C++ map和set】数据的吟游诗:Map与Set的双城记
公主请阅 set1.序列式容器和关联式容器2.set的介绍3.set的构造和迭代器部分set可以进行去重操作的,在去重的同时可以对插入进来的数字进行排序的操作4.set的增删查inserterasefindupper_bound和 lower_bound 5.multiset和set的差异6相关题目349.两个数组的交集142.环…...
leetcode 之 二分查找(java)(3)
文章目录 5. 81. 搜索旋转排序数组 II6. 378、有序矩阵中第k个小的元素 5. 81. 搜索旋转排序数组 II 题目描述: 已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。 在传递给函数之前,nums 在预先未知的某个下标 k&#…...
后端返回前端的数据量过大解决方案
后端返回前端的数据量过大解决方案 性能面板(Performance) chrome调试指南 原因 遇到一个页面有好几个表格,部分表格采用虚拟滚动条 数据量有点大 接近快60s了,看一下是哪里导致的慢 后台请求方法执行并不慢 2024-12-04 15:21:52.889 INFO 69948 …...
STL算法之其它算法_下
random_shuffle 这个算法将[first,last)的元素次序随机排列。也就说,在N!中可能的元素排列中随机选出一种,此处N为last-first。 N个元素的序列,其排列方式为N!中,random_shuffle会产生一个均匀分布,因此任何一个排列被…...
MySQL如何区分幻读和不可重复读
在MySQL中,幻读和不可重复读都是并发事务中可能出现的问题,但它们的表现和原因略有不同。 不可重复读 (Non-Repeatable Read) 不可重复读是指在同一个事务内,多次读取同一行数据时,可能会得到不同的结果。这种情况发生在一个事务…...
html ul li 首页渲染多条数据 但只展示八条,其余的数据全部隐藏,通过icon图标 进行展示
<div style"float: left;" id"showMore"> 展开 </div> <div style"float: left;“id"hideLess"> 收起 </div> var data document.querySelectorAll(.allbox .item h3 a); const list document.querySelectorAl…...
Vue3安装 运行教程
本文是综合了所有vue安装教程而成 更细化 更简略 希望对各位读者有所帮助! Vue安装 1. Vue-cli脚手架安装 安装vue的方式有很多 我们这里选择npm方式安装vue npm方式 npm方式安装vue,详细介绍见下文。 1.node.js安装和配置 安装npm 需要安装note.js&…...
Spring事务的一道面试题
每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。 原理 Spring事务的原理是:通过AOP切面的方式实现的,也就是通过代理模式去实现事务增强。 具体过程是&a…...
PHP SM4 加密
PHP SM4 加密 sm4基类 class Sm4 {private $ck [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,0xc0c7ced5, 0xdce3ea…...
群控系统服务端开发模式-应用开发-短信工厂腾讯云短信开发
一、腾讯云短信工厂开发 1、添加框架对应的SDK composer require tencentcloud/tencentcloud-sdk-php 2、添加腾讯云工厂 在根目录下extend文件夹下Sms文件夹下channel文件夹下,创建腾讯云短信发送工厂并命名为TencentSmsSender。记住,一定要在腾讯云短…...
vue key属性强制刷新组件
在 Vue 中,key 属性通常用来帮助 Vue 跟踪每个组件或元素的身份,尤其是在使用 v-for 渲染列表时。当 key 值发生变化时,Vue 会销毁并重新渲染组件,这也可以用于强制刷新组件。 如果你想强制刷新一个组件,可以通过动态…...
浪潮X86服务器NF5280、8480、5468、5270使用inter VROC Raid key给NVME磁盘做阵列
浪潮服务器inter VROC Raid key给NVME磁盘做阵列方法 Inter VROC技术简介Raid Key 授权,即VROC SKU兼容性处理器兼容性列表平台和芯片组兼容性列表各Raid级别最大磁盘数量硬盘型号操作系统 服务器上的操作安装Raid Key确认服务器能识别硬盘识别磁盘所在的通道及服务…...
最长最短单词
最长最短单词 C语言实现C实现Java实现Python实现 💐The Begin💐点点关注,收藏不迷路💐 输入1行句子(不多于200个单词,每个单词长度不超过100),只包含字母、空格和逗号。单词由至少一…...
Muduo网络库剖析 --- 架构设计
文章目录 前言概述篇一、Muduo网络库简介Reactor事件处理模式 二、基于muduo实现简易聊天服务器实现测试运行 三、muduo的架构设计Reacor模式muduo框架架构解析主从Reactor工作流程主线程(main Reactor)工作线程(sub Reactor) 线程分配与负载均衡 四、总结线程分配与负载均衡 四…...
lwip raw、netcoon、socket三种接口编程的区别
目录 一、前言 二、LWIP 简介 三、LWIP RAW 编程 1.概念与原理 2.编程模型与流程 3.示例代码 4.优点与缺点 四、LWIP NETCONN 编程 1.概念与原理 2.编程模型与流程 3.示例代码 4.优点与缺点 五、LWIP SOCKET 编程 1.概念与原理 2.编程模型与流程 3.示例代码 …...
在办公室环境中用HMD替代传统显示器的优势
VR头戴式显示器(HMD)是进入虚拟现实环境的一把钥匙,拥有HMD的您将能够在虚拟现实世界中尽情探索未知领域,正如如今的互联网一样,虚拟现实环境能够为您提供现实中无法实现的或不可能实现的事。随着技术的不断进步&#…...
P3916 图的遍历(Tarjan缩点和反向建边)
P3916 图的遍历 - 洛谷 | 计算机科学教育新生态 写法一:Tarjan 思路:先运用Tarjan算法得到每个连通块中最大的编号,然后对每个连通块进行缩点重新建图,进行dfs,得到缩点后的连通块能够达到的最大编号。 Code: conste…...
Element UI 的 el-tree 组件e中默认展开前两层,设置 default-expanded-keys 属性来实现
在使用 Element UI 的 el-tree 组件时,如果你希望默认展开树的前两层节点,可以通过设置 default-expanded-keys 属性来实现。这个属性接受一个数组,数组中的值是需要默认展开的节点的 key。 首先,你需要确保你的每个树节点都有唯…...
Vue 项目中未登录状态如何统一处理
在 Vue 项目中,处理未登录状态(比如用户访问需要登录的页面时)是一项常见的需求。为了实现这一需求,我们通常使用 Vue Router 配合 Vuex 或者 Vue 的全局状态管理来统一处理未登录的状态,确保用户只能访问允许的页面。…...
Java 集合:强大的数据管理工具
在 Java 编程中,集合是一种非常重要的工具,它提供了一种方便的方式来存储和操作一组对象。本文将深入探讨 Java 集合框架,包括其主要类型、特点、用法以及一些最佳实践。 一、引言 在软件开发过程中,我们经常需要处理一组数据。…...
Creating Server TCP listening socket *:6379: bind: No error
启动redis报错:Creating Server TCP listening socket *:6379: bind: No error 解决方案: 1、直接在命令行中输入 redis-cli.exe 2、输入shutdown,关闭 3、输exit,退出 4、重新输入 redis-server.exe redis.windows.conf&…...
iOS免费共享企业证书、苹果最新企业证书免费获取
前言 大家可能都注意到了,苹果手机和安卓手机在安装软件上有点不一样。如果你在苹果手机上想装那些没在官方商店(App Store)里的软件,那就得给它们“签个名”,就像是给它们盖个章,这样手机才能认识它们&am…...
如果用Python写爬虫,具体怎么实现随机请求间隔呢?
在Python中实现随机请求间隔,通常使用time.sleep()函数结合random模块来生成随机的等待时间。以下是一个具体的实现方法: 导入必要的模块 首先,你需要导入time和random模块: import time import random 设置随机间隔 然后&am…...
aws(学习笔记第十五课) 如何从灾难中恢复(recover)
aws(学习笔记第十五课) 如何从灾难中恢复 学习内容: 使用CloudWatch对服务器进行监视与恢复区域(region),可用区(available zone)和子网(subnet)使用自动扩展(AutoScalingGroup) 1. 使用CloudWatch对服务器进行监视与恢复 整体架构 这里模拟Jenkins Se…...
nginx4层限速
Nginx的功能概述 Nginx是一个高性能的HTTP和反向代理服务器,也可以作为邮件代理服务器等。它主要工作在7层(应用层),但在某些场景下也可以实现部分4层(传输层)的功能。 关于4层限速 Nginx自身的限制&#x…...
Spring Cloud Alibaba 之 “Feign多参数构造”
在上一篇文章整合好了Feign,现在来总结以下Feign调用多参数方法的使用。 GET方式: Spring Cloud为Feign支持了Spring Mvc注解的。如果请求的是localhost:8083/test?id1&namecoco,那么如果我们这样写(User实体类有这二个属性)…...
C#高级教程
目录 C# 特性(Attribute)C# 反射(Reflection)C# 属性(Property)C# 索引器(Indexer)C# 委托(Delegate)C# 事件(Event)C# 集合…...
c++ 位图和布隆过滤器
位图(bitmap) 定义 位图是一种使用位数组存储数据的结构。每一位表示一个状态,通常用于快速判断某个值是否存在,或者用来表示布尔类型的集合。 特点 节省空间:一个字节可以表示8个状态。高效操作:位操作…...
基于Springboot开发的云野旅游平台
一、功能介绍 云野旅游平台包含管理员、用户两个角色以及前后台系统。 前台系统功能 用户登录成功后,可以进行查看旅游路线、最新线路、旅游资讯、个人中心、后台管理、购物车、客服等功能模块。进行相对应操作。 后台系统功能 管理员或用户登录成功后…...
微服务即时通讯系统(5)用户管理子服务,网关子服务
用户管理子服务(user文件) 用户管理子服务也是这个项目中的一个业务最多的子服务,接口多,但是主要涉及的数据表只有user表,Redis的键值对和ES的一个搜索引擎,主要功能是对用户的个人信息进行修改管理&#…...
docker.io连接超时的处理,用代理网站
docker pull的时候会超时: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) 这时可以找一些代理网站,比如…...
【测试工具JMeter篇】JMeter性能测试入门级教程(四):JMeter中BeanShell内置方法使用
一、什么是BeanShell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;BeanShell是一种松散类型的脚本语言(这点和JS类似);BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简…...
JavaScript 键盘控制移动
如果你想通过 JavaScript 实现键盘控制对象(比如一个方块)的移动,下面是一个简单的示例,展示如何监听键盘事件并根据按下的键来移动一个元素。 HTML 和 CSS: <!DOCTYPE html> <html lang"en">…...
如何预防服务器后台爆破攻击
服务器后台爆破(Brute Force Attack)是一种通过反复尝试用户名和密码组合,以非法获取系统访问权限的攻击方式。这种攻击不仅会消耗服务器资源,还可能导致合法用户被锁定或敏感数据泄露。为了有效预防服务器后台爆破攻击࿰…...
AI 写作(一):开启创作新纪元(1/10)
一、AI 写作:重塑创作格局 在当今数字化高速发展的时代,AI 写作正以惊人的速度重塑着创作格局。AI 写作在现代社会中占据着举足轻重的地位,发挥着不可替代的作用。 随着信息的爆炸式增长,人们对于内容的需求日益旺盛。AI 写作能够…...
【HarmonyOS】鸿蒙应用使用lottie动画
【HarmonyOS】鸿蒙应用使用lottie动画 一、lottie动画是什么? https://airbnb.design/lottie Lottie是由Airbnb团队开发的一个适用于iOS、Android、React Native、Web和Windows的开源动画库,用于解析使用Bodymovin导出为JSON的Adobe After Effects动…...
SQL面试题——腾讯SQL面试题 合并连续支付订单
合并连续支付订单 现有一张用户支付表:user_pay包含字段订单ID,用户ID,商户ID,支付时间,支付金额。如果同一用户在同一商户存在多笔订单,且中间该用户没有其他商户的支付记录,则认为是连续订单,请把连续订单进行合并,时间取最早支付时间,金额求和。 +----------+------…...
【docker】10. 容器操作案例
容器操作案例 容器基本操作 • 通过 nginx 镜像文件创建容器 • 容器的列举(包含正在运行的容器) # 发现此时 e7c33d9f5c61 这个容器运行的状态为 Up,即运行状态 rootLAPTOP-H2EI4I6A:~# docker container ls CONTAINER ID IMAGE COMMAND CREATED …...