HttpUtils工具类(二)Apache HttpClient 5 使用详细教程
目录
一、Apache HttpClient 5介绍
(1)核心特性
(2)Apache HttpClient 5 的新特性
(3)在 Java 项目的主要使用场景及缺点
使用场景:
缺点:
二、在实际项目中的应用
(1)引入maven配置
(2)自定义HttpUtils工具类---实现连接管理、重试策略等
功能概述
(3)代码中的具体实现
1、Get请求
2、POST请求-常规
3、POST请求-上传文件
(4)高级用法
1、处理重定向
2、SSL/TLS 支持
3、处理异步请求
4、处理 Cookie
5、HTTPDNS支持
一、Apache HttpClient 5介绍
Apache HttpClient 5 是一个功能齐全且高度可定制的 HTTP 客户端库, 其专门用于发送 HTTP 请求、处理 HTTP 响应并支持各种 HTTP 协议特性。特别适合处理复杂的 HTTP 请求需求,如多协议支持、认证、连接池、代理等。它适合中大型项目或需要高级 HTTP 特性的应用开发。
(1)核心特性
-
功能强大:
- 同步与异步支持:支持同步和异步的 HTTP 请求处理,异步请求在处理大量并发请求时能够显著提高效率。
- 连接池管理:内置的连接池机制能提高并发处理性能,减少资源消耗。
- 多种认证机制:支持多种认证方式,包括 Basic、Digest、NTLM、Kerberos 等,能够处理多种安全场景。
- 支持Cookie管理:内置 Cookie 管理功能,能够自动处理服务端返回的 Cookie 并在后续请求中使用,模拟浏览器行为。
-
协议支持广泛:
- HTTP/1.1 和 HTTP/2 支持:支持现代 HTTP 协议,包括 HTTP/2 的多路复用和流优先级等特性,提升了网络请求效率;特别是 HTTP/2 多路复用的优势。
- SSL/TLS 支持:支持 HTTPS,提供自定义 SSL/TLS 配置,确保通信的安全性。HttpClient 5 可以方便地处理 HTTPS 请求,支持定制化的 SSL/TLS 配置。
-
灵活性和可扩展性:
- 易于扩展和定制:允许开发者根据需要进行灵活的定制,HttpClient 5 的设计高度模块化,用户可以根据需要对连接管理、重定向策略、请求重试策略、代理设置等进行灵活定制。
- 代理支持:可以轻松配置 HTTP 或 SOCKS 代理,用于跨网络访问和隐私保护。
-
健壮的错误处理机制:
- 自动重试和重定向处理:内置的重试机制和自动重定向处理,可以减少由于网络问题导致的失败请求。开发者可以定制是否启用自动重定向。
(2)Apache HttpClient 5 的新特性
与之前的 4.x 版本相比,HttpClient 5 进行了大量的改进和优化,特别是在性能和安全性方面:
- HTTP/2 支持:提供了完整的 HTTP/2 支持,包括多路复用、流优先级等特性。
- 更好的异步支持:在处理并发请求时,通过异步模型极大提升了响应速度和吞吐量。
- 灵活的响应处理:通过改进的响应处理 API,可以更方便地处理大型响应体,避免内存溢出问题。
(3)在 Java 项目的主要使用场景及缺点
使用场景:
- RESTful API 客户端:与第三方 API 交互,发送各种 HTTP 请求。
- Web 爬虫:抓取网页内容,处理重定向、Cookie 等。
- 分布式系统通信:用于微服务间的 HTTP 通信。
- 测试与自动化:模拟 HTTP 请求,进行集成和自动化测试。
- 代理与网关:处理请求代理和认证机制。
- 文件上传下载:实现大文件的传输。
- 认证交互:处理 OAuth2、JWT 等认证协议。
- 安全通信:处理 HTTPS 请求,确保数据安全。
缺点:
- 学习曲线陡峭:高级特性(如自定义连接池、SSL 配置、异步请求等)较为复杂,新手需要时间学习和掌握。
- 体积较大:相比轻量级客户端,如 OkHttp,HttpClient 依赖库较多,可能不适合小型项目。
- 性能消耗高:默认配置下的内存和 CPU 占用较高,需调整才能达到最佳性能。
- 配置繁琐:高级定制(如连接管理、认证、代理)需要较多配置,增加开发复杂度。
- 异步编程复杂:异步请求的回调、错误处理等逻辑复杂,增加代码难度。
二、在实际项目中的应用
(1)引入maven配置
首先,你需要将 HttpClient 5 的依赖加入到项目中。pom.xml
文件如下:
<dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId><version>5.1</version>
</dependency>
(2)自定义HttpUtils工具类---实现连接管理、重试策略等
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.util.Timeout;
import org.springframework.stereotype.Component;import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Map;/*** @author 响叮当* @since 2024/8/15 14:10**/
@Slf4j
@Component
public class ApacheHttpClientUtil {private CloseableHttpClient httpClient;public void init() {SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(Timeout.ofMilliseconds(1000)).build();PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create().setDefaultSocketConfig(socketConfig).setMaxConnTotal(1000).setMaxConnPerRoute(50).build();RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofMilliseconds(8000)).setResponseTimeout(Timeout.ofMilliseconds(8000)).setConnectTimeout(Timeout.ofMilliseconds(8000)).build();httpClient = HttpClients.custom().disableContentCompression().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).build();}public CloseableHttpResponse getOrHead(String url, String method, Map<String, String> headers) throws IOException {HttpUriRequestBase request = new HttpUriRequestBase(method, URI.create(url));BasicHeader[] head = mapToHeaders(headers);request.setHeaders(head);return httpClient.execute(request);}public CloseableHttpResponse post(String url, Map<String, String> headers, HttpEntity httpEntity) throws IOException {HttpPost request = new HttpPost(url);BasicHeader[] head = mapToHeaders(headers);request.setHeaders(head);request.setEntity(httpEntity);return httpClient.execute(request);}public static BasicHeader[] mapToHeaders(Map<String, String> map) {BasicHeader[] headers = new BasicHeader[map.size()];int i = 0;for (Map.Entry<String, String> entry : map.entrySet()) {headers[i++] = new BasicHeader(entry.getKey(), entry.getValue());}return headers;}public static void closeQuietly(Closeable is) {if (is != null) {try {is.close();} catch (Exception ex) {log.error("Resources encounter an exception when closing,ex:{}", ex.getMessage());}}}}
功能概述
- 初始化 HTTP 客户端:
init()
方法初始化CloseableHttpClient
,配置连接池、请求超时和套接字超时。- 连接池配置:通过
PoolingHttpClientConnectionManagerBuilder
设置最大连接数(1000)和每路由的最大连接数(50),用于高并发场景。 - 请求配置:包括连接超时、请求超时和响应超时,确保在合理的时间内处理请求。
- 连接池配置:通过
- HTTP 请求处理:
- GET/HEAD 请求:
getOrHead()
方法可发送 GET 或 HEAD 请求,并接受自定义请求头。 - POST 请求:
post()
方法可发送 POST 请求,支持自定义请求头和实体。
- GET/HEAD 请求:
- 资源管理:
closeQuietly()
方法用于关闭资源,避免抛出异常。
(3)代码中的具体实现
1、Get请求
@GetMapping("/get")public void testGet() {String url = "http://xxx.com.cn";try {// 1、构建入参、添加 headersMap<String, String> headers = new HashMap<>();// 2、发起http请求CloseableHttpResponse httpResponse = apacheHttpClientUtil.getOrHead(url, "GET", headers);// 3、返回结果,异常处理if (httpResponse.getCode() == 200) {String resStr = EntityUtils.toString(httpResponse.getEntity());log.info("request_success, response:{}, httpResponse_Code:{}, reasonPhrase:{}", resStr, httpResponse.getCode(), httpResponse.getReasonPhrase());} else {log.error("request_fail, httpResponse_Code:{}, reasonPhrase:{}", httpResponse.getCode(), httpResponse.getReasonPhrase());}} catch (Exception e) {log.error("request_udmp_fail, ex:{}", e);}}
2、POST请求-常规
@PostMapping("/post")public void testPost(@RequestBody PostReq req) {String url = "http://xxx.com.cn";try {// 1、构建入参、添加 headersStringEntity stringEntity = new StringEntity(JSONUtil.toJsonStr(req), ContentType.APPLICATION_JSON);Map<String, String> headers = new HashMap<>();// 2、发起http请求CloseableHttpResponse httpResponse = apacheHttpClientUtil.post(url, headers, stringEntity);// 3、返回结果,异常处理if (httpResponse.getCode() == 200) {String resStr = EntityUtils.toString(httpResponse.getEntity());log.info("request_success, response:{}, httpResponse_Code:{}, reasonPhrase:{}", resStr, httpResponse.getCode(), httpResponse.getReasonPhrase());} else {log.error("request_fail, httpResponse_Code:{}, reasonPhrase:{}", httpResponse.getCode(), httpResponse.getReasonPhrase());}} catch (Exception e) {log.error("request_udmp_fail, ex:{}", e);}}
3、POST请求-上传文件
/*** 上传文件* @param multipartFile* @param token* @param key* @return*/@PostMapping("/uploadFile")public UploadRes testPostFile(@RequestParam("file") MultipartFile multipartFile,@RequestParam("token") String token,@RequestParam("key") String key) {UploadRes res = null;String url = "http://xxx.com.cn";try {// 1、构建File参数File file = new File(multipartFile.getOriginalFilename());try (FileOutputStream fos = new FileOutputStream(file)) {fos.write(multipartFile.getBytes());}MultipartEntityBuilder builder = MultipartEntityBuilder.create();builder.addBinaryBody("file", file, ContentType.MULTIPART_FORM_DATA, "ex.xlsx");// 2、构建其他参数builder.addTextBody("token", token, ContentType.TEXT_PLAIN);builder.addTextBody("key", key, ContentType.TEXT_PLAIN);HttpEntity multipartEntity = builder.build();// 3、需要加 header,在这里加Map<String, String> headers = new HashMap<>();// 4、发起http请求CloseableHttpResponse httpResponse = apacheHttpClientUtil.post(url, headers, multipartEntity);// 5、返回结果,异常处理if (httpResponse.getCode() == 200) {String resStr = EntityUtils.toString(httpResponse.getEntity());res = JSONUtil.toBean(resStr, UploadRes.class);log.info("request_success, response:{}, httpResponse_Code:{}, reasonPhrase:{}", resStr, httpResponse.getCode(), httpResponse.getReasonPhrase());} else {log.error("request_fail, httpResponse_Code:{}, reasonPhrase:{}", httpResponse.getCode(), httpResponse.getReasonPhrase());}} catch (Exception e) {log.error("request_udmp_fail, ex:{}", e);}return res;}
(4)高级用法
1、处理重定向
HttpClient 5 默认会处理 3XX 重定向,但你也可以自定义行为。
CloseableHttpClient httpClient = HttpClients.custom().disableRedirectHandling() // 禁用自动重定向.build();
2、SSL/TLS 支持
使用 HttpClient 5 可以轻松处理 HTTPS 请求,下面展示如何自定义 SSL 配置。
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import javax.net.ssl.SSLContext;SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true) // 信任所有证书.build();CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
3、处理异步请求
如果你需要发送异步 HTTP 请求,可以使用 HttpAsyncClient
。
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.client5.http.classic.methods.HttpGet;CloseableHttpAsyncClient asyncClient = HttpAsyncClients.createDefault();asyncClient.start();HttpGet request = new HttpGet("https://jsonplaceholder.typicode.com/posts/1");asyncClient.execute(request, new FutureCallback<>() {@Overridepublic void completed(CloseableHttpResponse response) {System.out.println("Response received: " + response.getCode());}@Overridepublic void failed(Exception ex) {System.out.println("Request failed: " + ex.getMessage());}@Overridepublic void cancelled() {System.out.println("Request cancelled");}
});
4、处理 Cookie
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.cookie.CookieStore;CookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
5、HTTPDNS支持
// 当域名为www.baidu.com结尾时候,转到local的机器上String Target_IP= "127.0.0.1";String[] domains = new String[]{"www.baidu.com"};DnsResolver dnsResolver = new DnsResolver() {@Overridepublic InetAddress[] resolve(String host) throws UnknownHostException {if (host.endsWith(domains[0]))) {return new InetAddress[]{InetAddress.getByName(Target_IP)};}return new InetAddress[0];}@Overridepublic String resolveCanonicalHostname(String s) {return null;}};// @PostConstructpublic void init() {SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(Timeout.ofMilliseconds(1000)).build();PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create().setDnsResolver(dnsResolver) // 这里是HttpDns配置.setDefaultSocketConfig(socketConfig).setMaxConnTotal(1000).setMaxConnPerRoute(50).build();
相关文章:
HttpUtils工具类(二)Apache HttpClient 5 使用详细教程
目录 一、Apache HttpClient 5介绍 (1)核心特性 (2)Apache HttpClient 5 的新特性 (3)在 Java 项目的主要使用场景及缺点 使用场景: 缺点: 二、在实际项目中的应用 …...

Vue3.0生命周期钩子(包含:Vue 2.0 和 Vue 3.0)
1、Vue 2.0 生命周期钩子 每个应用程序实例在创建时都有一系列的初始化步骤。例如,创建数据绑定、编译模板、将实例挂载到 DOM 并在数据变化时触发 DOM 更新、销毁实例等。在这个过程中会运行一些叫做生命周期钩子的函数,通过这些钩子函数可以定义业务逻…...

遥感之常用各种指数总结大全
目前在遥感领域基本各种研究领域都会用到各种各样的指数,如水体指数,植被指数,农业长势指数,盐分指数,云指数,阴影指数,建筑物指数,水质指数,干旱指数等等众多。 本文对上…...

【C++】C++11新增特性
目录 C11简介: 1、统一的列表初始化: std::initializer_list 2、自动类型推导: auto: decltype: 3、final 和 override final: override: 4、默认成员函数控制: 显示缺省…...

【LeetCode每日一题】——662.二叉树最大宽度
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 广度优先搜索 二【题目难度】 中等 三【题目编号】 662.二叉树最大宽度 四【题目描述】 给…...

第二十三节、血量更新逻辑的实现
一、创建代码 引入命名空间 using UnityEngine.UI; 调用UI必须有这个代码 二、ScriptObject类 1、是一个持久化存储文件的类型 接收所有的事件方法 先继承SO类,然后创建项目菜单 2、进行订阅 放入事件类,关联代码,即可进行广播 传递给这…...
Spring Authorization Server 认证服务器搭建
Spring Authorization Server实现了oauth2和oidc,最近有了解相关技术的需求,所以就尝试着进行了基本的环境搭建和技术测试,目前只测试了授权码模式,做一个记录,后续需要用时方便查找和参考。 1. 版本要求 Spring Authorization Server 版本:1.3.1 JDK 版本:17 Spring B…...

秋招突击——8/15——知识补充——垃圾回收机制
文章目录 引言正文指针引用可达性分析算法垃圾回收算法标记清除算法标记整理算法复制分代收集 垃圾收集器Serial收集器ParNew并行收集器Parallel Scavenge吞吐量优先收集器Serial Old老年代收集器Parallel old收集器CMS收集器G1收集器(Garbage First垃圾优先&#x…...

【iOS】UITableViewCell的重用问题解决方法
我自己在实验中对cell的重用总结如下: 非自定义Cell和非自定义cell的复用情况一样: 第一次加载创建tableView的时候,是屏幕上最多也显示几行cell就先创建几个cell,此时复用池里什么都没有开始下滑tableView,刚开始滑…...
开发一个微信小程序商城需要哪些技术栈
开发一个小程序商城需要掌握以下技术栈: 前端技术:包括HTML、CSS和JavaScript,用于定义商城的页面结构、样式设计和交互功能。 微信小程序专用技术:如WXML、WXSS、JavaScript和JSON,用于描述小程…...

望繁信科技荣膺上海市浦东新区博士后创新实践基地称号
近日,上海望繁信科技有限公司(简称“望繁信科技”)凭借在大数据流程智能领域的卓越表现,成功入选上海市浦东新区博士后创新实践基地。这一荣誉不仅是对望繁信科技创新能力和技术实力的高度认可,也标志着公司在推动产学…...

Nginx--代理与负载均衡(扩展nginx配置7层协议及4层协议方法、会话保持)
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、代理原理 1、反向代理产生的背景 单个服务器的处理客户端(用户)请求能力有一个极限,当接入请求过多时&#…...

Ubuntu20.4 系统安装后无wifi图标
0. 问题排查 1.检查 BIOS 设置: 有时候,无线网卡可能在 BIOS 中被禁用。重启电脑,进入 BIOS 设置,确保无线网卡选项是启用的。 2.检查硬件开关: 检查您的笔记本电脑是否有物理开关或键盘快捷键来启用或禁用无线网卡。 3.在软件更新中切换…...

牛客网SQL进阶135 :每个6/7级用户活跃情况
每个67级用户活跃情况_牛客题霸_牛客网 0 问题描述 基于用户信息表user_info、、试卷作答记录表exam_record、题目练习记录表practice_record,统计 每个6/7级用户总活跃月份数、2021年活跃天数、2021年试卷作答活跃天数、2021年答题活跃天数,结果 按照总…...
SQLite3使用接口写入二进制文件
使用接口的方式写入二进制文件 ,有二种方案。 一、全部文件 一次性写下到数据中 使用sqlite3_bind_blob接口 FILE* fpfopen("user.bmp","rb"); iLenfread(buffer,1,65535,fp); fclose(fp);sqlite3_prepare(pDB,"insert into user values …...
在复杂的数据库架构中,如何优化 SQL 查询以提高性能和减少资源消耗?
在优化 SQL 查询以提高性能和减少资源消耗时,可以考虑以下几个方面: 使用索引:为经常被查询的列创建索引,可以大大加快查询速度。同时,避免过多的索引,因为过多的索引会增加写入操作的开销。 编写高效的查…...

【HarmonyOS】端云一体化初始化项目
简介 端云一体化开发是HarmonyOS对云端开发的支持、实现端云联动。云开发服务提供了云函数、云数据库、云存储等服务,可以使开发者专注于应用的业务逻辑开发,无需关注基础设施,例如:服务器、操作系统等问题。 因此,…...
LLM之KG:利用大语言模型(LLM)对文本语料提取概念和概念之间的语义关系进而实现自动构建知识图谱
LLM之KG:利用大语言模型(LLM)对文本语料提取概念和概念之间的语义关系进而实现自动构建知识图谱 目录 ML之KG:基于MovieLens电影评分数据集利用基于知识图谱的推荐算法(networkx+基于路径相似度的方法)实现对用户进行Top电影推荐案例 LLMs之AutoKG:《大型语言模型在知识图…...
Spring Security 6如何使用?
Spring Security 6 是一个功能强大且高度可定制的身份验证和访问控制框架,它专注于为基于Java的应用程序提供全面的安全解决方案。以下是对Spring Security 6的详细解析: 一、核心功能 身份验证(Authentication): 验…...

PyTorch深度学习快速入门教程--学习笔记
目录 P4 PyCharm和Jupyter的对比 P5 PyTorch加载数据 P6 Dataset类代码实现 P7 Tensorboard 写日志 读取日志文件 Tensorboard 读图片 P10 Transforms使用 Transforms用途 常见的Transforms工具 P14 torchvision数据集使用 P15 Dataloader使用 P16 nn.Module模块使…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...

【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
qt 双缓冲案例对比
双缓冲 1.双缓冲原理 单缓冲:在paintEvent中直接绘制到屏幕,绘制过程被用户看到 双缓冲:先在redrawBuffer绘制到缓冲区,然后一次性显示完整结果 代码结构 单缓冲:所有绘制逻辑在paintEvent中 双缓冲:绘制…...

前端异步编程全场景解读
前端异步编程是现代Web开发的核心,它解决了浏览器单线程执行带来的UI阻塞问题。以下从多个维度进行深度解析: 一、异步编程的核心概念 JavaScript的执行环境是单线程的,这意味着在同一时间只能执行一个任务。为了不阻塞主线程,J…...