Vue3 + Ts + Vite 封装一套企业级axiso全流程

9a69fede8b2044a79dd834e3e48f20b4.png前期回顾f8e3cc1a0f694ac2b665ca2ad14c49d7.png 

从零搭建 Vue3 + VIte + Ts 项目 —— 并集成eslint 、prettier、stylelint、husky、lint-staged、pinia、axios、loding、动态路由…_彩色之外的博客-CSDN博客

   实现功能:

  1. 取消重复请求:完全相同的接口在上一个pending状态时,自动取消下一个请求

  2. 请求失败自动重试: 接口请求后台异常时候, 自动重新发起多次请求, 直到达到所设次数

  3. 请求接口数据缓存: 接口在设定时间内不会向后台获取数据, 而是直接拿本地缓存

  4. 父页面单独取消当前请求、并发取消指定请求

  5. 父页面取消所有请求

  6. 更多功能根据你的需求自定制

目录

  🌍 第一 配置 vite.config.ts 基地址: 

  🤖 第二 配置环境变量:

 🛹 第三  配置ts类型

 🪂 第四 封装本地存储

 🎋 第五 封装axios: 

 👀 第六 页面使用:


🌍 第一 配置 vite.config.ts 基地址: 

  🤖 第二 配置环境变量:

🛹 第三  配置ts类型

src/type/axiso.d.ts

/* eslint-disable */
import * as axios from 'axios';

// 扩展 axios 数据返回类型,可自行扩展
declare module 'axios' {
	export interface AxiosResponse<T = any> {
		code: number;
		data: T;
		message: string;
		type?: string;
		/* 
		[key: string]: T; 这段代码是定义了一个索引签名,它表示可以使用任意字符串作为key,并且对应的值的类型是T。
		索引签名允许在对象中使用动态的属性,也就是说,在定义AxiosResponse接口时,除了预定义的code、data、message属性,还可以添
		加其他任意属性,且属性的值的类型是T。
	*/
		[key: string]: T;
	}
	export interface AxiosRequestConfig<T = any> {
		retry?: number;
		retryDelay?: number;
		cache?: boolean;
		cacheTimestamp?: number;
		[key: string]: T;
	}
	export interface AxiosError<T = any> {
		config: AxiosRequestConfig<T>;
		code?: string;
		request?: any;
		response?: AxiosResponse<T>;
		isAxiosError: boolean;
		retry?: number;
		retryDelay?: number;
		retryCount: number;
		cache?: boolean;
		cacheTimestamp?: number;
		[key: string]: T;
	}

	export interface CancelTokenSource<T = any> {
		token: CancelToken;
		cancel: Canceler;
		isFinished?: boolean;
		[key: string]: T;
	}
}

 🪂 第四 封装本地存储

/**
 * window.localStorage 浏览器永久缓存
 * @method set 设置永久缓存
 * @method get 获取永久缓存
 * @method remove 移除永久缓存
 * @method clear 移除全部永久缓存
 */
export const Local = {
	// 设置永久缓存
	set(key: string, val: any) {
		window.localStorage.setItem(key, JSON.stringify(val));
	},
	// 获取永久缓存
	get(key: string) {
		let json = <string>window.localStorage.getItem(key);
        // !null为true
		if (!json) return null;
		return JSON.parse(json);
	},
	// 移除永久缓存
	remove(key: string) {
		window.localStorage.removeItem(key);
	},
	// 移除全部永久缓存
	clear() {
		window.localStorage.clear();
	},
};

/**
 * window.sessionStorage 浏览器临时缓存
 * @method set 设置临时缓存
 * @method get 获取临时缓存
 * @method remove 移除临时缓存
 * @method clear 移除全部临时缓存
 */
export const Session = {
	// 设置临时缓存
	set(key: string, val: any) {
		window.sessionStorage.setItem(key, JSON.stringify(val));
	},
	// 获取临时缓存
	get(key: string) {
		let json = <string>window.sessionStorage.getItem(key);
		if (!json) return null;
		return JSON.parse(json);
	},
	// 移除临时缓存
	remove(key: string) {
		window.sessionStorage.removeItem(key);
	},
	// 移除全部临时缓存
	clear() {
		window.sessionStorage.clear();
	},
};

  🎋 第五 封装axios: 

新建 \src\api 文件夹,里面有三个ts文件,request.ts 封装axios统一请求,requestMethod.ts   封装的是请求方法,api.ts 封装的是api接口,方便统一管理不至于api接口分散项目各处造成不易维护。

src\api\request.ts

import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, CancelTokenSource } from 'axios';
/* 
	1. 取消重复请求:完全相同的接口在上一个pending状态时,自动取消下一个请求 
	2. 请求失败自动重试: 接口请求后台异常时候, 自动重新发起多次请求, 直到达到所设次数 
	3. 请求接口数据缓存: 接口在设定时间内不会向后台获取数据, 而是直接拿本地缓存
	4. 父页面单独取消当前请求
	5. 父页面取消所有请求
*/

// 导入 element-plus 中的消息和弹框组件
import { ElMessage, ElMessageBox } from 'element-plus';
// 导入 storage.ts 中的 Session 对象
import { Session } from '/@/utils/storage';
// 导入 main.ts 中的 app 对象 用于Loading组件的显示和隐藏
import app from '/@/main';

// 创建 Axios 实例
const service: AxiosInstance = axios.create({
	baseURL: import.meta.env.VITE_API_URL, // 设置基础 URL
	timeout: 5000, // 设置超时时间
	headers: { 'Content-Type': 'application/json' }, // 设置请求头
});

// handlerRequest Start --------------------------------------------------------------------------

// cacheTimestamp用于判断是否存在相同缓存的请求
let cacheTimestampFlag = 0;
// requestKey用于缓存接口函数 判断是否存在相同的请求
let requestKey = '';
// 创建一个存储请求的Map对象
const pendingRequests: Map<string, CancelTokenSource> = new Map();
// 取消重复请求的方法
const cancelDuplicateRequest = (config: AxiosRequestConfig): void => {
	// 生成请求的唯一标识
	requestKey = `${config.method}-${config.url}`;

	// 如果已经存在该请求,则取消该请求
	if (pendingRequests.has(requestKey)) {
		const cancelToken = pendingRequests.get(requestKey);
		cancelToken?.cancel('进行中的重复请求被拦截,请您等待当前请求完成后再发起请求');
	}
	// 生成一个取消请求的标识
	const cancelToken = axios.CancelToken.source();
	// 将该请求保存到 pendingRequests 中
	pendingRequests.set(requestKey, cancelToken);
	// 设置取消请求的标识
	config.cancelToken = cancelToken.token;
	// 设置缓存时间
	if (config.cacheTimestamp) {
		cacheTimestampFlag = eval(`1000 * 60 * ${config.cacheTimestamp}`);
	}
	// 如果本地有缓存数据,直接返回缓存数据,不经过请求拦截
	/* 
	当Promise被拒绝并且这个拒绝状态没有被处理(即没有调用.catch()方法)时,	会在控制台打印出一个未捕获的Promise拒绝警告。
	如果你不希望在控制台看到这个警告,你需要确保每个Promise都有一个.catch()方法来处理拒绝状态
	*/
	if (config.cache)
		requestIsCache()
			.then(() => {})
			.catch(() => {});
};
// 缓存接口函数 - 注意发起请求判断是否存在相同url需要再组件中调用此函数,不会进过这里的请求拦截器
async function requestIsCache(): Promise<any> {
	// 获取本地存储的所有键
	const keys = Object.keys(sessionStorage);
	if (requestKey) {
		// 停留时间 > 缓存时间阈值
		const isCache = Date.now() - Session.get(requestKey)?.cacheTimestamp > cacheTimestampFlag;
		// console.log('是否有key', keys.includes(requestKey));
		// console.log('停留时间', Date.now() - Session.get(requestKey)?.cacheTimestamp);
		// console.log('判断阈值', cacheTimestampFlag);

		// 如果包含 requestKey 并且 缓存未过期
		if (keys.includes(requestKey) && !isCache) {
			// 直接返回本地缓存数据
			const cacheData = Session.get(requestKey);
			return Promise.resolve(cacheData);
		} else {
			// 清除缓存
			Session.remove(requestKey);
			return Promise.reject('接口开启了catch,不存在缓存 或 缓存已过期');
		}
	}
}

// 封装提示函数 (token过期、重复登录)
const tipError = (value: string, title: string) => {
	ElMessageBox.alert(value, title, {
		confirmButtonText: title,
		type: 'warning',
	}).then(() => {
		Session.clear(); // 清除临时缓存
		// 清除cookie
		document.cookie.split(';').forEach(function (c) {
			document.cookie = c
				.replace(/^ +/, '')
				.replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
		});
		window.location.reload(); // 刷新页面
	});
};

// 请求失败自动重试的方法
const retryFailedRequest = async (error: AxiosError): Promise<any> => {
	const config = error;
	// 如果没有设置重试次数 或 已经达到最大重试次数,则直接返回错误
	if (!config || !config.retry || config.retryCount >= config.retry) {
		return Promise.reject(config);
	}
	// 设置重试次数关闭阈值
	config.retryCount = config.retryCount || 0;
	// 重试次数自增
	config.retryCount += 1;
	// 设置重试延时
	const delay = config.retryDelay || 1000;
	// 延时处理
	await new Promise<void>((resolve) => {
		setTimeout(() => resolve(), delay);
	});
	// console.log('🤺🤺  🚀 ==>:', service(config));
	return service(config);
};
// handlerRequest End --------------------------------------------------------------------------

// Axios 的请求拦截器期望返回一个配置对象,而不是响应对象。如果你试图返回一个响应对象,Axios 将会抛出一个错误。
service.interceptors.request.use(
	async (config: AxiosRequestConfig) => {
		// 在发送请求之前做些什么?
		const token = Session.get('token');
		if (token) config.headers!['token'] = token; // 在请求头中添加 token
		// 取消重复请求
		cancelDuplicateRequest(config);

		app.config.globalProperties.$smallLoading.showLoading();
		return config;
	},
	async (error) => {
		// 对请求错误做些什么?
		app.config.globalProperties.$smallLoading.hideLoading();
		// 请求失败重试
		await retryFailedRequest(error);
		return Promise.reject(error);
	}
);

// 响应拦截器
service.interceptors.response.use(
	(response) => {
		// 对响应数据做点什么? 这里只返回成功响应数据!
		const { config, data } = response;
		// 给 pendingRequests 标记一个isFinished为true 请求完成的标识
		const responseKey = `${config.method}-${config.url}`;
		const request = pendingRequests.get(responseKey);
		if (request && request.token) {
			pendingRequests.set(responseKey, { ...request, isFinished: true });
		}

		app.config.globalProperties.$smallLoading.hideLoading();

		// 判断是否有缓存
		if (config.cache) {
			const cachedResponse = Session.get(responseKey);
			if (cachedResponse) {
				return cachedResponse;
			} else {
				// 接口有 cache 参数,且缓存不存在,则缓存接口数据,并插入当前时间戳
				data.cacheTimestamp = new Date().getTime();
				Session.set(responseKey, data);
				return data;
			}
		} else {
			return data;
		}
	},
	(error) => {
		// 对响应错误数据做点什么?这里只显示错误消息!
		app.config.globalProperties.$smallLoading.hideLoading();
		/* 
			axios.isCancel(error) 是 Axios 库中的一个方法,用于判断一个错误对象是否是由于请求取消导致的。
			当使用 axios.CancelToken 取消请求时,会抛出一个带有一个 message 属性的错误对象。
			axios.isCancel(error) 的作用就是判断这个错误对象的类型,如果是由请求取消导致的错误,则返回 true,否则返回 false。
		    console.log('打印cancelToken.cancel('xxx')传入来的值', error.message);
	    */
		if (axios.isCancel(error)) {
			// 只提示请求取消有主动填写的消息 如:cancelToken.cancel('xxx')
			if (error.message !== 'canceled') ElMessage.error(requestKey + ' 🤖 ' + error.message);
		} else {
			// 响应失败重试
			retryFailedRequest(error);
			// 不是由请求取消导致的错误
			let errorMessage; // 错误提示变量
			let statusData = error.response?.data; // 错误data数据
			const describeForNameMap = [
				[
					() => error.message.indexOf('timeout') !== -1,
					() => (errorMessage = '网络超时 🤖'),
				],
				[() => error.message === 'Network Error', () => (errorMessage = '网络连接错误 🤪')],
				[
					() => statusData?.code === 100010021,
					() => {
						// 100010021 重复登录
						errorMessage = statusData.message;
						tipError(errorMessage, '重复登录');
					},
				],
				[
					() => statusData?.code === 100010011,
					() => {
						// 100010011 token过期
						errorMessage = statusData.message;
						tipError(errorMessage, '登录过期');
					},
				],
				// 否则 显示错误消息,这里要根据后台返回的数据结构来定
				[() => statusData, () => (errorMessage = statusData.message)],
			];
			// 获取符合条件的子数组
			const getDescribe = describeForNameMap.find((item) => item[0]());
			// 执行子数组中的函数
			getDescribe && getDescribe[1]();
			ElMessage.error(errorMessage); // 显示错误消息
		}
	}
);
// 取消全部请求的方法
export const cancelAllRequest = (): void => {
	// 创建一个标记 是否取消成功,初始值为false
	let hasCancelled = false;

	// 遍历所有待处理的请求
	pendingRequests.forEach((value) => {
		// 如果请求还没有完成
		if (!value.isFinished) {
			// 取消请求
			value.cancel();
			// 将标记设为true
			hasCancelled = true;
		}
	});

	// 清空待处理请求的集合
	pendingRequests.clear();

	// 至少取消了一个请求,显示提示,防止都是成功请求点击取消按钮时也提示
	if (hasCancelled) {
		ElMessage.success('成功取消全部请求');
	}
};

// 取消当前请求的方法
export const cancelCurrentRequest = (payloadCurrentKey: string = requestKey): void => {
	// 遍历所有待处理的请求
	pendingRequests.forEach((value, key) => {
		if (key === payloadCurrentKey) {
			value.cancel();
			pendingRequests.delete(key);
			ElMessage.success('成功取消当前请求');
		}
	});
};

// 导出 service将其命名为axios , requestIsCache 用于判断是否有缓存
export { service as axios, requestIsCache };

src\api\requestMethod.ts

import { axios } from './request';
// post使用data接受参数,get使用params接受参数
// 如果是post请求,但是参数是在url上的,那么就要使用params接受参数,否则使用data接受参数
// put 也相当与post请求,如果报参数错误,就是接受参数的请求体错了post/put用data,get请求用params
type method = 'GET' | 'POST' | 'PUT' | 'DELETE';
// 规定缓存时间戳的类型只能 1 - 5 分钟
type cacheTimestamp = 1 | 2 | 3 | 4 | 5;

/**
 * @name request 配置
 * @param { string } - method 请求方法
 * @param { string } - url   请求地址
 * @param { object } - data/params 请求参数
 * @param { number } - retry  重试次数
 * @param { number } - retryDelay 重试延迟
 * @param { boolean } -  cache 是否缓存
 * @param { number }  - cacheTimestamp 缓存过期 1-5分钟
 * @createDate 2023/08/09 13:12:08
 * @lastFixDate 2023/08/09 13:12:08
 */
interface requestConfig {
	method: method;
	url: string;
	data?: object;
	params?: object;
	retry?: number;
	retryDelay?: number;
	cache?: boolean;
	cacheTimestamp?: cacheTimestamp;
}

function request({
	method = 'GET',
	url,
	data = {},
	params = {},
	retry,
	retryDelay,
	cache,
	cacheTimestamp = 1,
}: requestConfig) {
	return axios({
		method,
		url,
		data,
		params,
		retry,
		retryDelay,
		cache,
		cacheTimestamp,
	});
}

export default request;

src\api/auth-manage/menu.ts

// 导入axios中的AxiosResponse的泛型接口
import { AxiosResponse } from 'axios';
// 导入封装的axios请求方法
import request from '/@/utils/requestMethod';

// 获取菜单树接口: 不包含菜单中的按钮
export const getMenuTree = (): Promise<AxiosResponse<any>> =>
	request({
		method: 'POST',
		url: '/menu/queryMenuTree',
		cache: true,
		cacheTimestamp: 1,
	});

👀 第六 页面使用:

<script setup lang="ts" name="importGeneration">
import { getMenuTree } from '/@/api/auth-manage/menu';
import { getUserInfo } from '/@/api/auth-manage/user';
import { ElMessage } from 'element-plus';

/* 
 requestIsCache - 判断请求是否开启了缓存
 cancelAllRequest - 取消所有请求
 cancelCurrentRequest - 取消当前请求
*/
import { requestIsCache, cancelAllRequest, cancelCurrentRequest } from '/@/utils/request';

// 封装请求错误提示 http状态是200 但是code不是200 返回数据是错误的需要处理
function tipError<T extends { code: number; message: string }>(res: T) {
	if (res.code !== 200) {
		ElMessage.error(res.message);
		return;
	}
}
// 发起 getMenuTree
const handleClick = async () => {
	// 缓存函数,如果在接口开启了cache: true,需要在请求前调用此函数
	await requestIsCache()
		.then((res) => {
			if (!res) return;
			tipError(res);
			ElMessage.success('✈️ 本地数据请求成功');
		})
		.catch(() => {
			// 真正接口
			getMenuTree().then((res) => {
				if (!res) return;
				tipError(res);
				ElMessage.success('🤖 接口数据' + res.message);
			});
		});
};

// 取消 getMenuTree
const handleCance = () => {
	// 在适当的时机调用取消请求(例如点击取消按钮),不传参数默认取消最后一条请求
	cancelCurrentRequest('post-/menu/queryMenuTree');
};

// 取消 getUserInf
const handleCance1 = () => {
	cancelCurrentRequest('get-/user/info');
};

// 发起 getUserInf
const handleClick1 = async () => {
	await getUserInfo().then((res) => {
		if (!res) return;
		tipError(res);
		ElMessage.success(res.message);
	});
};

// 取消所有请求
function handleCancelAll() {
	cancelAllRequest();
}
</script>

<template>
	<div>
		<!-- 发起 -->
		<el-button type="primary" @click="handleClick">发起 getMenuTree axios</el-button>
		<!-- 取消 -->
		<el-button type="danger" @click="handleCance">取消 getMenuTree</el-button>
		<!-- 发起 -->
		<el-button type="primary" @click="handleClick1">发起 getUserInf axios</el-button>
		<!-- 取消 -->
		<el-button type="danger" @click="handleCance1">取消 getUserInf</el-button>
		<el-button type="danger" @click="handleCancelAll">取消所有请求</el-button>
	</div>
</template>

全文结束,所有代码都在文中,最上面的链接中也有原项目

7730e2bd39d64179909767e1967da702.jpeg

 _______________________________  期待再见  _______________________________ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言库函数之 qsort 讲解、使用及模拟实现

引入 我们在学习排序的时候&#xff0c;第一个接触到的应该都是冒泡排序&#xff0c;我们先来复习一下冒泡排序的代码&#xff0c;来作为一个铺垫和引入。 代码如下&#xff1a; #include<stdio.h>void bubble_sort(int *arr, int sz) {int i 0;for (i 0; i < sz…

python爬虫实战(2)--爬取某博热搜数据

1. 准备工作 使用python语言可以快速实现&#xff0c;调用BeautifulSoup包里面的方法 安装BeautifulSoup pip install BeautifulSoup完成以后引入项目 2. 开发 定义url url https://s.微博.com/top/summary?caterealtimehot定义请求头&#xff0c;微博请求数据需要cookie…

推荐 4 个 yyds 的 GitHub 项目

本期推荐开源项目目录&#xff1a; 1. 开源的 Markdown 编辑器 2. MetaGPT 3. SuperAGI 4. 一个舒适的笔记平台 01 开源的 Markdown 编辑器 Cherry 是腾讯开源的 Markdown 编辑器&#xff0c;基于 Javascript具有轻量简洁、易于扩展等特点&#xff0c; 它可以运行在浏览器或服…

Java基础入门篇——数组初识

一、数组 1.假设某公司有100个员工&#xff0c;需要统计某公司员工的工资情况&#xff0c;首先需要声明100个变量来分别记每个员工的工资&#xff0c;那么如果按照之前的做法&#xff0c;可能定义的结构如下所示&#xff1a; int a1,a2,a3,......a100; 要求你输出这100个员工…

Qt中将信号封装在一个继承类中的方法

QLabel标签类对应的信号如下&#xff1a; Qt中标签是没有双击&#xff08;double Click&#xff09;这个信号的&#xff1b; 需求一&#xff1a;若想双击标签使其能够改变标签中文字的内容&#xff0c;那么就需要自定义一个“双击”信号&#xff0c;并将其封装在QLabel类的派生…

【2023新教程】树莓派4B开机启动-树莓派第一次启动-树莓派不使用显示器启动-树莓派从购买到启动一步一步完全版!

背景 闲来无事&#xff0c;在咸鱼上买了一个树莓派4B。买来配件都十分齐全&#xff0c;于是就想着启动来测试一下。下面是树莓派无显示器第一次启动的全过程&#xff0c;包含安装系统。 网上的教程大多需要额外使用显示器、鼠标、键盘之类的外设。然而&#xff0c;树莓派本身就…

“可一学院”区块链学习平台正式启动,助力BSV技术普及与传播

2023年8月8日&#xff0c;上海可一澈科技有限公司&#xff08;以下简称“可一科技”&#xff09; 正式发布区块链学习平台“可一学院”。“可一学院” 立足于BSV区块链技术本源&#xff0c;汇集了多层次的专业课程和学习资源&#xff0c;致力于打造一个适合各类人群使用的一站式…

因果推断(三)双重差分法(DID)

因果推断&#xff08;三&#xff09;双重差分法&#xff08;DID&#xff09; 双重差分法是很简单的群体效应估计方法&#xff0c;只需要将样本数据随机分成两组&#xff0c;对其中一组进行干预。在一定程度上减轻了选择偏差带来的影响。 因果效应计算&#xff1a;对照组y在干预…

谈谈语音助手

目录 1.什么是语音助手 2.语音助手的发展过程 3.现在有哪些成熟的语音助手 4.语音助手对人类发展的影响 1.什么是语音助手 语音助手是一种能够通过语音交互与用户进行沟通和执行任务的虚拟助手。它基于人工智能和自然语言处理技术&#xff0c;能够理解用户的语音指令&#x…

[数据集][目标检测]骑电动车摩托车不戴头盔数据集VOC格式1385张

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;1385 标注数量(xml文件个数)&#xff1a;1385 标注类别数&#xff1a;2 标注类别名称:["y","n&q…

最强自动化测试框架Playwright(22)-模拟器

可以使用测试生成器通过仿真生成测试&#xff0c;以便为特定窗口、设备、配色方案生成测试&#xff0c;以及模拟地理位置、语言或时区。测试生成器还可以生成测试&#xff0c;同时保留经过身份验证的状态。 模拟视口大小 Playwright 打开一个浏览器窗口&#xff0c;其视口设置…

C语言——将一串字符进行倒序

//将一串字符进行倒序 #include<stdio.h> #define N 6 int main() {int a[N]{0,1,2,3,4,5};int i,t;printf("原数组数值&#xff1a; ");for(i0;i<N;i)printf("%d",a[i]);for(i0;i<N/2;i){ta[i];a[i]a[N-1-i];a[N-1-i]t;}printf("\n排序…

掌握Python的X篇_27_Python中标准库文档查阅方法介绍

前面的博文介绍了python的基本语法、模块及其导入方法。前人将各种方法封装成模块、库、函数供我们使用&#xff0c;如何去使用前人做好的东西&#xff0c;那就需要去查阅文档。今天就介绍python中官方文档的查阅方式。对于初学者而言&#xff0c;python自带的文档就已经足够好…

小白带你部署LNMP分布式部署

目录 前言 一、概述 二、LNMP环境部署 三、配置nginx 1、yum安装 2、编译安装 四、安装 1、编译安装nginx 2、网络源 3、稍作优化 4、修改配置文件vim /usr/local/nginx/conf/nginx.conf 5、书写测试页面 五、部署应用 前言 LNMP平台指的是将Linux、Nginx、MySQL和…

Python爬虫——requests_cookie登陆古诗文网

寻找登陆需要的参数 __VIEWSTATE:aiMG0UXAfCzak10C7436ZC/RXoZbM2lDlX1iU/4wjjdUNsW8QUs6W2/3M6XIKagQZrC7ooD8Upj8uCnpQMXjDAp6fS/NM2nGhnKO0KOSXfT3jGHhJAOBouMI3QnlpJCQKPXfVDJPYwh169MGLFC6trY __VIEWSTATEGENERATOR: C93BE1AE from: http://so.gushiwen.cn/user/collect.…

Java并发编程(五)线程同步 下 [CAS/原子类/同步容器类/同步工具类]

CAS 概述 CAS全称为Compare-And-Swap。它是一条CPU的原子指令,是硬件对于并发操作共享数据的支持。其作用是CPU在某个时刻比较两个值是否相等 核心原理&#xff1a;在操作期间CAS先比较下主存中的值和线程中工作内存中的值是否相等,如果相等才会将主存中的值更新为新值&…

3.2 Tomcat基础

1. Tomcat概述 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;属于轻量级应用服务器。 Tomcat版本&#xff1a;apache-tomcat-8.5.76。 2.IDEA集成Tomcat 第一步 第二步 第三步 ​ 编辑切换为居中 添加图片注释&#xff0c;不超过 140 字&#xff0…

【JavaEE进阶】SpringBoot 配置文件

文章目录 SpringBoot配置文件1. 配置文件的作用2. 配置文件的格式3. properties 配置文件说明3.1 properties 基本语法3.2 读取配置文件3.3 properties 优缺点分析 4. yml配置文件说明4.1 yml 基本语法4.2 yml 配置读取 5. properties和yml的对比 SpringBoot配置文件 1. 配置文…

002-Spring boot 自动配置相关分析

目录 自动配置 EnableAutoConfiguration开启自动配置读取配置提前过滤自动配置配置包 AutoConfigurationPackage 自动配置 EnableAutoConfiguration 开启自动配置 在Spring 启动类上的 SpringBootApplication 中有 EnableAutoConfiguration 读取配置 Import(AutoConfigurat…

【福建事业单位-数学运算】04计算、最值和几何

【福建事业单位-数学运算】04计算、最值和几何 一、计算1.1 基础计算1.2 数列计算等差数列等比数列 总结 二、最值问题2.1 最不利构造最不利加排列组合 2.2 构造数列 三、几何问题2.1 公式计算类规则图形非规则图形 2.2结论技巧性&#xff08;三角形&#xff09;总结 一、计算 …