news 2026/4/3 4:49:19

Spring Boot 集成 Kafka 实战:生产者确认 + 消费者重试 + 死信队列实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 集成 Kafka 实战:生产者确认 + 消费者重试 + 死信队列实现

在分布式系统中,消息队列是实现异步通信、解耦服务、削峰填谷的核心组件,而 Kafka 凭借其高吞吐、高可用、高容错的特性,成为企业级应用的首选。Spring Boot 作为主流的微服务开发框架,提供了对 Kafka 的便捷集成能力。

本文将聚焦 Kafka 集成中的三个核心痛点:生产者消息可靠性(避免消息丢失)、消费者异常处理(避免消息消费失败直接丢弃)、死信队列机制(隔离处理无法修复的异常消息),通过实战代码演示完整实现方案,帮助开发者构建健壮的 Kafka 消息链路。

一、环境准备

1.1 基础环境

  • JDK 1.8+(Spring Boot 2.x 推荐)

  • Spring Boot 2.7.x(稳定版本,兼容性好)

  • Kafka 2.8.x(单机/集群均可,本文以单机为例)

  • Maven 3.6+

1.2 Kafka 环境搭建(单机)

  1. 下载 Kafka 安装包:从 Kafka 官网 下载对应版本,解压至本地目录。

  2. 启动 Zookeeper(Kafka 依赖 Zookeeper 管理元数据):

# 进入 Kafka 根目录cdkafka_2.13-2.8.2# 启动 Zookeeper(后台运行)nohupbin/zookeeper-server-start.sh config/zookeeper.properties
  1. 启动 Kafka 服务:
# 启动 Kafka 服务(后台运行)nohupbin/kafka-server-start.sh config/server.properties
  1. 验证 Kafka 启动成功:通过jps命令查看是否存在KafkaQuorumPeerMain(Zookeeper 进程)。

1.3 项目依赖配置

在 Spring Boot 项目的pom.xml中引入 Kafka Starter 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Kafka 集成依赖 --><dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId></dependency><!-- 工具类依赖(可选,用于 JSON 序列化) --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

二、核心概念梳理

在动手编码前,先明确三个核心功能的设计目标,避免理解偏差:

  1. 生产者确认(Producer ACK):Kafka 生产者发送消息后,通过配置 ACK 级别,确保消息被 Broker 接收并持久化后再返回成功,避免因网络波动、Broker 宕机导致消息丢失。

  2. 消费者重试(Consumer Retry):消费者处理消息时若出现临时异常(如数据库连接超时、接口临时不可用),不直接丢弃消息,而是通过重试机制重新消费,提高消息处理成功率。

  3. 死信队列(Dead-Letter Queue, DLQ):当消息重试达到最大次数仍处理失败(如消息格式错误、业务逻辑无法兼容),将消息转发至专门的死信队列,避免阻塞正常消息消费,同时便于后续人工排查。

三、完整实现方案

3.1 全局配置(application.yml)

集中配置 Kafka 连接信息、生产者确认机制、消费者重试策略及死信队列规则,核心配置已添加注释说明:

spring:kafka:# Kafka 集群地址(单机填 localhost:9092)bootstrap-servers:localhost:9092# 生产者配置producer:# 消息键序列化方式key-serializer:org.apache.kafka.common.serialization.StringSerializer# 消息值序列化方式(使用 FastJSON 自定义序列化器)value-serializer:com.example.kafka.serializer.FastJsonSerializer# 生产者确认级别:acks=1 表示消息被 Leader 副本接收并持久化后确认# 可选值:0(发送即返回,可能丢失)、1(Leader 确认,默认)、all(所有 ISR 副本确认,最可靠)acks:1# 重试次数:消息发送失败时的重试次数retries:3# 批次大小:达到批次大小后发送消息(单位:字节)batch-size:16384# 缓冲区大小:生产者缓冲区大小(单位:字节)buffer-memory:33554432# 消费者配置consumer:# 消息键反序列化方式key-deserializer:org.apache.kafka.common.serialization.StringDeserializer# 消息值反序列化方式value-deserializer:com.example.kafka.serializer.FastJsonDeserializer# 消费者组 ID(同一组内消费者分摊消费,不同组重复消费)group-id:kafka-demo-group# 自动提交偏移量:false 表示手动提交,确保消息处理完成后再提交enable-auto-commit:false# 自动提交偏移量的间隔(enable-auto-commit=true 时生效)auto-commit-interval:1000# 偏移量重置策略:earliest 表示无偏移量时从头消费,latest 表示从最新消息开始auto-offset-reset:earliest# Kafka 监听器配置(消费者相关)listener:# 手动提交偏移量模式:RECORD 表示每条消息处理完成后提交ack-mode:MANUAL_IMMEDIATE# 并发消费数:根据 Topic 分区数配置(建议不超过分区数)concurrency:2# 重试配置retry:# 开启重试enabled:true# 最大重试次数(包括首次消费,共 3 次)max-attempts:3# 重试间隔(单位:毫秒)initial-interval:1000# 自定义配置:Topic 名称和死信队列 Topic 名称kafka:topic:normal:kafka-normal-topic# 正常业务 Topicdead:kafka-dead-topic# 死信队列 Topic

3.2 自定义 JSON 序列化器

Kafka 默认的序列化器不支持复杂 Java 对象,这里使用 FastJSON 实现自定义序列化/反序列化器,确保消息能正确转换:

3.2.1 序列化器(FastJsonSerializer)
packagecom.example.kafka.serializer;importcom.alibaba.fastjson.JSON;importorg.apache.kafka.common.serialization.Serializer;importjava.util.Map;/** * Kafka 消息 JSON 序列化器 */publicclassFastJsonSerializerimplementsSerializer<Object>{@Overridepublicvoidconfigure(Map<String,?>configs,booleanisKey){// 初始化配置(可选)}@Overridepublicbyte[]serialize(Stringtopic,Objectdata){if(data==null){returnnull;}// 将 Java 对象转为 JSON 字节数组returnJSON.toJSONBytes(data);}@Overridepublicvoidclose(){// 资源释放(可选)}}
3.2.2 反序列化器(FastJsonDeserializer)
packagecom.example.kafka.serializer;importcom.alibaba.fastjson.JSON;importorg.apache.kafka.common.serialization.Deserializer;importjava.util.Map;/** * Kafka 消息 JSON 反序列化器 */publicclassFastJsonDeserializerimplementsDeserializer<Object>{@Overridepublicvoidconfigure(Map<String,?>configs,booleanisKey){// 初始化配置(可选)}@OverridepublicObjectdeserialize(Stringtopic,byte[]data){if(data==null){returnnull;}// 将 JSON 字节数组转为 Object(实际使用时可指定具体类型)returnJSON.parse(data);}@Overridepublicvoidclose(){// 资源释放(可选)}}

3.3 Topic 与死信队列配置

通过 Spring 配置类自动创建 Topic 和死信队列,避免手动执行 Kafka 命令创建,提高项目可移植性:

packagecom.example.kafka.config;importorg.apache.kafka.clients.admin.NewTopic;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.kafka.config.TopicBuilder;/** * Kafka Topic 配置类 */@ConfigurationpublicclassKafkaTopicConfig{// 正常业务 Topic 名称@Value("${kafka.topic.normal}")privateStringnormalTopic;// 死信队列 Topic 名称@Value("${kafka.topic.dead}")privateStringdeadTopic;/** * 创建正常业务 Topic * 分区数:3(提高并发消费能力) * 副本数:1(单机环境,集群环境建议设为 2-3) */@BeanpublicNewTopicnormalTopic(){returnTopicBuilder.name(normalTopic).partitions(3).replicas(1).build();}/** * 创建死信队列 Topic * 分区数与正常 Topic 一致,便于排查 */@BeanpublicNewTopicdeadTopic(){returnTopicBuilder.name(deadTopic).partitions(3).replicas(1).build();}}

3.4 生产者实现(消息发送)

封装 Kafka 生产者工具类,提供同步发送和异步发送两种方式,满足不同业务场景需求:

packagecom.example.kafka.producer;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.kafka.core.KafkaTemplate;importorg.springframework.kafka.support.SendResult;importorg.springframework.stereotype.Component;importorg.springframework.util.concurrent.ListenableFuture;importorg.springframework.util.concurrent.ListenableFutureCallback;/** * Kafka 生产者工具类 */@ComponentpublicclassKafkaProducer{// 注入 Kafka 模板@AutowiredprivateKafkaTemplate<String,Object>kafkaTemplate;// 正常业务 Topic 名称@Value("${kafka.topic.normal}")privateStringnormalTopic;/** * 同步发送消息 * 特点:阻塞等待结果,适合需要立即知道发送状态的场景 */publicbooleansendSync(Stringkey,Objectmessage){try{// 同步发送,返回发送结果SendResult<String,Object>result=kafkaTemplate.send(normalTopic,key,message).get();// 打印发送成功日志System.out.printf("同步发送成功 - Topic: %s, Partition: %d, Offset: %d%n",result.getRecordMetadata().topic(),result.getRecordMetadata().partition(),result.getRecordMetadata().offset());returntrue;}catch(Exceptione){// 处理发送异常(如 Broker 不可用、网络异常等)System.err.printf("同步发送失败 - Key: %s, Message: %s, Error: %s%n",key,message,e.getMessage());returnfalse;}}/** * 异步发送消息 * 特点:非阻塞,通过回调获取结果,适合高吞吐场景 */publicvoidsendAsync(Stringkey,Objectmessage){// 异步发送,获取 Future 对象ListenableFuture<SendResult<String,Object>>future=kafkaTemplate.send(normalTopic,key,message);// 添加发送结果回调future.addCallback(newListenableFutureCallback<SendResult<String,Object>>(){@OverridepublicvoidonSuccess(SendResult<String,Object>result){// 发送成功回调System.out.printf("异步发送成功 - Topic: %s, Partition: %d, Offset: %d%n",result.getRecordMetadata().topic(),result.getRecordMetadata().partition(),result.getRecordMetadata().offset());}@OverridepublicvoidonFailure(Throwableex){// 发送失败回调System.err.printf("异步发送失败 - Key: %s, Message: %s, Error: %s%n",key,message,ex.getMessage());}});}}

3.5 消费者实现(重试 + 死信队列)

这是核心模块,通过@KafkaListener注解监听消息,结合SeekToCurrentErrorHandler实现重试机制,并将重试失败的消息转发至死信队列:

3.5.1 消费者配置类(重试与死信逻辑)
packagecom.example.kafka.config;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;importorg.springframework.kafka.core.ConsumerFactory;importorg.springframework.kafka.listener.DeadLetterPublishingRecoverer;importorg.springframework.kafka.listener.SeekToCurrentErrorHandler;importorg.springframework.kafka.support.converter.RecordMessageConverter;importorg.springframework.kafka.support.converter.StringJsonMessageConverter;/** * Kafka 消费者配置类(重试 + 死信队列) */@ConfigurationpublicclassKafkaConsumerConfig{// 死信队列 Topic 名称@Value("${kafka.topic.dead}")privateStringdeadTopic;/** * 消息转换器:将 JSON 字符串转为 Java 对象 */@BeanpublicRecordMessageConvertermessageConverter(){returnnewStringJsonMessageConverter();}/** * 配置 Kafka 监听容器工厂 * 核心:添加错误处理器,实现重试和死信转发 */@BeanpublicConcurrentKafkaListenerContainerFactory<String,Object>kafkaListenerContainerFactory(ConsumerFactory<String,Object>consumerFactory,DeadLetterPublishingRecovererdeadLetterPublishingRecoverer){ConcurrentKafkaListenerContainerFactory<String,Object>factory=newConcurrentKafkaListenerContainerFactory<>();factory.setConsumerFactory(consumerFactory);// 设置消息转换器factory.setMessageConverter(messageConverter());// 设置手动提交偏移量factory.getContainerProperties().setAckMode(org.springframework.kafka.listener.ContainerProperties.AckMode.MANUAL_IMMEDIATE);// 配置错误处理器:SeekToCurrentErrorHandler 实现重试,重试失败后转发至死信队列SeekToCurrentErrorHandlererrorHandler=newSeekToCurrentErrorHandler(deadLetterPublishingRecoverer);// 禁止重试时回溯偏移量(避免重复消费其他消息)errorHandler.setResetOffsets(false);factory.setErrorHandler(errorHandler);returnfactory;}/** * 死信发布恢复器:将重试失败的消息转发至死信队列 */@BeanpublicDeadLetterPublishingRecovererdeadLetterPublishingRecoverer(org.springframework.kafka.core.KafkaTemplate<String,Object>kafkaTemplate){// 自定义死信队列转发逻辑:将消息发送至指定的死信 Topicreturn(record,exception)->{System.err.printf("消息转发至死信队列 - Topic: %s, Key: %s, Error: %s%n",deadTopic,record.key(),exception.getMessage());// 发送消息到死信队列returnkafkaTemplate.send(deadTopic,record.key(),record.value());};}}
3.5.2 消费者监听类(消息处理逻辑)
packagecom.example.kafka.consumer;importorg.apache.kafka.clients.consumer.ConsumerRecord;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.kafka.annotation.KafkaListener;importorg.springframework.kafka.support.Acknowledgment;importorg.springframework.stereotype.Component;/** * Kafka 消费者监听类 * 包含:正常消息消费 + 死信消息消费 */@ComponentpublicclassKafkaConsumer{// 正常业务 Topic 名称@Value("${kafka.topic.normal}")privateStringnormalTopic;// 死信队列 Topic 名称@Value("${kafka.topic.dead}")privateStringdeadTopic;/** * 监听正常业务 Topic,处理消息 * topics:监听的 Topic 名称 * containerFactory:指定上文配置的容器工厂(包含重试和死信逻辑) */@KafkaListener(topics="${kafka.topic.normal}",containerFactory="kafkaListenerContainerFactory")publicvoidconsumeNormalMessage(ConsumerRecord<String,Object>record,Acknowledgmentacknowledgment){try{// 1. 获取消息内容Stringkey=record.key();Objectvalue=record.value();System.out.printf("接收到正常消息 - Topic: %s, Partition: %d, Offset: %d, Key: %s, Value: %s%n",record.topic(),record.partition(),record.offset(),key,value);// 2. 模拟业务逻辑(这里故意抛出异常,测试重试和死信)// 实际场景中替换为真实业务代码(如数据库操作、接口调用等)if("error-key".equals(key)){thrownewRuntimeException("模拟业务异常:消息处理失败");}// 3. 业务处理成功,手动提交偏移量acknowledgment.acknowledge();System.out.printf("正常消息处理成功 - Key: %s%n",key);}catch(Exceptione){// 4. 业务处理失败,抛出异常(由容器工厂的错误处理器接管,进行重试)System.err.printf("正常消息处理失败 - Key: %s, Error: %s%n",record.key(),e.getMessage());throwe;// 必须抛出异常,否则重试机制不生效}}/** * 监听死信队列 Topic,处理无法修复的异常消息 * 实际场景中可在此进行人工通知、日志记录、数据备份等操作 */@KafkaListener(topics="${kafka.topic.dead}",groupId="kafka-dead-group")publicvoidconsumeDeadLetterMessage(ConsumerRecord<String,Object>record,Acknowledgmentacknowledgment){// 1. 获取死信消息内容Stringkey=record.key();Objectvalue=record.value();System.err.printf("接收到死信消息 - Topic: %s, Partition: %d, Offset: %d, Key: %s, Value: %s%n",record.topic(),record.partition(),record.offset(),key,value);// 2. 死信消息处理逻辑(示例:记录日志、发送告警邮件等)// sendAlarmEmail(key, value); // 模拟发送告警// saveToDB(key, value); // 保存死信消息到数据库// 3. 死信消息处理完成,手动提交偏移量acknowledgment.acknowledge();System.out.printf("死信消息处理完成 - Key: %s%n",key);}}

3.6 测试接口(便于快速验证)

创建一个简单的 REST 接口,通过 HTTP 请求触发消息发送,方便测试生产者、消费者、重试及死信队列的完整链路:

packagecom.example.kafka.controller;importcom.example.kafka.producer.KafkaProducer;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;/** * 测试控制器:用于发送 Kafka 消息 */@RestControllerpublicclassKafkaTestController{@AutowiredprivateKafkaProducerkafkaProducer;/** * 同步发送消息接口 * 访问示例:http://localhost:8080/kafka/send/sync?key=test-key&message=hello-kafka */@GetMapping("/kafka/send/sync")publicStringsendSync(@RequestParamStringkey,@RequestParamStringmessage){booleansuccess=kafkaProducer.sendSync(key,message);returnsuccess?"同步发送成功":"同步发送失败";}/** * 异步发送消息接口 * 访问示例:http://localhost:8080/kafka/send/async?key=error-key&message=error-message */@GetMapping("/kafka/send/async")publicStringsendAsync(@RequestParamStringkey,@RequestParamStringmessage){kafkaProducer.sendAsync(key,message);return"异步发送请求已提交(请查看控制台日志)";}}

四、实战验证

4.1 启动项目

启动 Spring Boot 项目,观察控制台日志,确认 Kafka 连接成功,Topic 自动创建完成。

4.2 测试正常消息流程

访问同步发送接口,发送正常消息:

http://localhost:8080/kafka/send/sync?key=normal-key&message=这是一条正常消息

观察控制台日志,应输出以下内容(流程:生产者发送成功 → 消费者接收并处理 → 提交偏移量):

同步发送成功 - Topic: kafka-normal-topic, Partition: 1, Offset: 0 接收到正常消息 - Topic: kafka-normal-topic, Partition: 1, Offset: 0, Key: normal-key, Value: 这是一条正常消息 正常消息处理成功 - Key: normal-key

4.3 测试重试与死信队列流程

访问异步发送接口,发送触发异常的消息(Key 为 “error-key”,消费者会故意抛出异常):

http://localhost:8080/kafka/send/async?key=error-key&message=这是一条会触发异常的消息

观察控制台日志,应输出以下内容(流程:生产者发送成功 → 消费者接收并抛出异常 → 重试 2 次(共 3 次) → 转发至死信队列 → 死信消费者处理):

异步发送成功 - Topic: kafka-normal-topic, Partition: 2, Offset: 0 接收到正常消息 - Topic: kafka-normal-topic, Partition: 2, Offset: 0, Key: error-key, Value: 这是一条会触发异常的消息 正常消息处理失败 - Key: error-key, Error: 模拟业务异常:消息处理失败 // 第 1 次重试 接收到正常消息 - Topic: kafka-normal-topic, Partition: 2, Offset: 0, Key: error-key, Value: 这是一条会触发异常的消息 正常消息处理失败 - Key: error-key, Error: 模拟业务异常:消息处理失败 // 第 2 次重试(达到最大重试次数 3 次) 接收到正常消息 - Topic: kafka-normal-topic, Partition: 2, Offset: 0, Key: error-key, Value: 这是一条会触发异常的消息 正常消息处理失败 - Key: error-key, Error: 模拟业务异常:消息处理失败 // 转发至死信队列 消息转发至死信队列 - Topic: kafka-dead-topic, Key: error-key, Error: 模拟业务异常:消息处理失败 // 死信消费者处理 接收到死信消息 - Topic: kafka-dead-topic, Partition: 2, Offset: 0, Key: error-key, Value: 这是一条会触发异常的消息 死信消息处理完成 - Key: error-key

五、关键问题与优化建议

5.1 生产者确认级别选择

  • acks=0:适合日志收集等非核心业务,追求极致性能,允许消息丢失。

  • acks=1:适合大多数业务,平衡性能和可靠性,Leader 确认即可。

  • acks=all:适合金融、交易等核心业务,确保消息不丢失,但性能略有损耗。

5.2 消费者重试策略优化

  1. 重试间隔:避免固定间隔重试,可配置指数退避策略(如 1s → 3s → 5s),减少对下游服务的冲击。

  2. 异常过滤:仅对临时异常(如TimeoutException)重试,对永久异常(如IllegalArgumentException)直接转发至死信队列。

5.3 死信队列管理

  1. 死信消息存储:建议将死信消息持久化至数据库,便于后续排查和重新消费。

  2. 告警机制:死信消息产生时,通过邮件、短信、钉钉等方式及时通知开发人员。

  3. 定期清理:对已处理的死信消息定期清理,避免死信队列无限膨胀。

5.4 性能优化

  1. 分区数:根据业务并发量合理设置 Topic 分区数(建议为消费者并发数的 2-3 倍)。

  2. 批量发送:生产者开启批量发送(通过batch-sizelinger.ms配置),提高吞吐量。

  3. 序列化方式:推荐使用 Protobuf 替代 JSON,减少消息体积,提高序列化效率。

六、总结

本文通过 Spring Boot 与 Kafka 的实战集成,完整实现了生产者确认、消费者重试和死信队列三大核心功能,构建了一套可靠的消息处理链路。核心要点包括:

  1. 生产者通过acks配置确保消息不丢失,通过同步/异步发送适配不同场景。

  2. 消费者通过SeekToCurrentErrorHandler实现重试,结合手动提交偏移量确保消息处理可靠。

  3. 死信队列隔离异常消息,避免阻塞正常业务,同时通过告警和持久化机制便于问题排查。

在实际开发中,需根据业务场景灵活调整配置(如确认级别、重试次数、分区数等),并结合监控工具(如 Prometheus + Grafana)实时监控 Kafka 消息链路状态,确保系统稳定运行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/2 15:05:36

7、跨站脚本攻击(XSS)案例深度剖析

跨站脚本攻击(XSS)案例深度剖析 1. XSS 影响因素与修复思路 XSS 的影响取决于多种因素,如它是存储型还是反射型,cookie 是否可访问,有效负载在何处执行等。尽管 XSS 可能对网站造成潜在损害,但修复 XSS 漏洞通常很容易,软件开发人员只需在渲染用户输入之前对其进行清理…

作者头像 李华
网站建设 2026/4/1 3:40:11

Arduino_GFX 图形库终极指南:新手快速上手避坑技巧

Arduino_GFX 图形库终极指南&#xff1a;新手快速上手避坑技巧 【免费下载链接】Arduino_GFX Arduino GFX developing for various color displays and various data bus interfaces 项目地址: https://gitcode.com/gh_mirrors/ar/Arduino_GFX Arduino_GFX 图形库是一个…

作者头像 李华
网站建设 2026/3/14 10:54:45

搜维尔科技:Xsens 2026教育单位优惠方案重磅发布!

探索更多可能性让学生接触到商业大片、音乐视频和游戏&#xff08;如漫威的《黑豹》和EA的《FIFA》系列&#xff09;中使用的动作捕捉技术。与需要专用工作室的光学系统不同&#xff0c;Xsens Animate系统使用无线惯性传感器实现跟踪任务&#xff0c;支持在任何地点使用。只需要…

作者头像 李华
网站建设 2026/3/17 12:43:44

了解网络 构造网络

在 5G 全面普及、人工智能加速渗透的今天&#xff0c;网络信息技术早已不是程序员的专属技能&#xff0c;而是像 “办公软件” 一样的全民基础能力。小到个人手机流量管理、家庭网络搭建&#xff0c;大到企业数字化转型、智慧城市建设&#xff0c;都离不开网络信息技术的支撑。…

作者头像 李华
网站建设 2026/3/30 13:51:44

Python+requests+pytest接口自动化测试框架的搭建

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快框架的设计思路首先要明确进行接口自动化需要的步骤&#xff0c;如下图所示&#xff1a;然后逐步拆解需要完成的工作&#xff1a;1&#xff09;了解分析需求&#x…

作者头像 李华
网站建设 2026/3/31 10:48:14

jQuery如何实现网页大文件上传的进度显示?

大文件传输功能解决方案探索与规划 作为上海一家专注于软件和信息技术服务领域&#xff0c;且在 2019 年完成战略融资的企业&#xff0c;我们一直致力于为客户提供高质量、安全可靠的软件解决方案。近期&#xff0c;公司项目面临一个极具挑战性的需求&#xff1a;构建一个大文…

作者头像 李华