使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题

  • 1. 问题描述
  • 2. SSE介绍
    • 2.1 SSE 的工作原理
    • 2.2 SSE 的事件格式规范
    • 2.3 SSE与其他技术对比
    • 2.4 SSE 的优缺点
  • 3. 实战代码

1. 问题描述

目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中需要轮询文件上传的状态的接口,还有要调用整个任务状态的接口,因为我们的Mysql是单例的,有多个大文件上传的时候会出现任务状态不一致的问题,经过调研有WebSocket与SSE两种方式,但是我只需要把信息推给前端,所以使用个更轻量的SSE。

2. SSE介绍

SSE(Server-Sent Events) 是 HTML5 标准中的一项技术,它允许服务器通过单向连接持续地将数据推送给客户端(通常是浏览器)。

  • 与传统的 HTTP 请求响应不同,SSE 是一种服务器主动推送数据的机制。
  • 与 WebSocket 不同,它是单向通信:服务器 -> 客户端。

SSE 使用标准的 HTTP 协议 和 文本/event-stream 格式,通常用于实时消息推送,如股票行情、社交动态通知、在线状态更新等。

2.1 SSE 的工作原理

  1. 客户端通过普通的 HTTP 请求发起连接:
GET /events HTTP/1.1
Accept: text/event-stream
  1. 服务器响应:
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
  1. 事件流
event: message
id: 123
data: 这是要推送的数据
  1. 客户端自动处理每一条数据,并在连接断开时自动重连。

2.2 SSE 的事件格式规范

每条消息由一组字段组成,字段以冒号: 分隔,每条消息之间由两个换行符 \n\n 分隔:
在这里插入图片描述

示例:

id: 1001
event: update
data: {"progress": 50}

2.3 SSE与其他技术对比

在这里插入图片描述

2.4 SSE 的优缺点

✅ 优点:

  • 使用标准 HTTP 协议,兼容性好;
  • 实现简单,开发成本低;
  • 支持自动重连机制;
  • 支持事件类型、多行数据等;
  • 适用于需要实时更新、但无需客户端发送大量消息的场景。

❌ 缺点:

  • 只支持单向通信;
  • 不支持二进制数据;
  • 不支持所有浏览器(如 IE);
  • 有并发连接数限制(部分浏览器每个域名默认最大连接数限制);
  • 需配置好心跳机制、防止代理服务器中断连接。

3. 实战代码

@GetMapping("/file-upload-status")
@Operation(summary = "文件上传状态SSE")
public SseEmitter fileUploadStatus(@RequestParam("taskCode") String taskCode,@RequestHeader(value = "Last-Event-ID", required = false) String lastEventId) {
log.info("文件上传状态SSE, 请求参数: {}, Last-Event-ID: {}", taskCode, lastEventId);try {return dataConfigService.fileUploadStatus(taskCode, lastEventId);
} catch (Exception e) {log.error("文件上传状态SSE,失败,错误信息:{}", e.getMessage());throw e;}
}/*** 用于存储每个任务对应的 SseEmitter 实例。* key 为任务唯一标识 taskCode,value 为与该任务关联的 SseEmitter。* 使用 ConcurrentHashMap 是为了支持多线程环境下的并发读写,确保线程安全。* <p>* 场景:* - 客户端发起 SSE 连接时,将对应的 SseEmitter 存入此 Map。* - 后台定时任务或上传进度更新时可以通过 taskCode 拿到对应的 emitter 推送数据。* - 当连接断开(如超时、关闭、出错)时,从 Map 中移除对应的 emitter,避免内存泄漏。*/private final Map<String, SseEmitter> emitterMap = new ConcurrentHashMap<>();/*** 定时任务线程池,用于定期推送每个任务的上传状态到前端客户端(通过 SseEmitter)。* 使用 Runtime.getRuntime().availableProcessors() 获取当前机器的可用处理器核心数,* 并以此设置线程池大小,合理利用系统资源。* <p>* 特点:* - ScheduledExecutorService 支持定时或周期性任务调度,适合做周期性状态推送。* - 使用线程池而不是单线程可以支持多个任务并发状态推送。* - 可根据系统并发量和任务复杂度调整线程池大小。*/private final ScheduledExecutorService scheduledExecutorService =Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());/*** 缓存最近一次推送的状态(用于断线续传)*/private final Map<String, DataFileUploadStatusVO> lastEventDataMap = new ConcurrentHashMap<>();
@Overridepublic SseEmitter fileUploadStatus(String taskCode, String lastEventId) {// 检查任务代码是否为空if (StringUtils.isBlank(taskCode)) {throw new ServiceException(400, "请求参数不能为空");}// 创建 SseEmitter 实例,设置超时时间为 1 小时(单位:毫秒)SseEmitter emitter = new SseEmitter(60 * 60 * 1000L);// 将当前任务的 emitter 注册到全局 emitterMap 中,用于后续状态推送emitterMap.put(taskCode, emitter);// 定义清理逻辑(连接关闭时自动移除 emitter,避免内存泄漏)Runnable cleanup = () -> {emitterMap.remove(taskCode);lastEventDataMap.remove(taskCode);};// 注册回调:客户端主动关闭连接时调用emitter.onCompletion(cleanup);// 注册回调:连接超时后自动关闭并清理emitter.onTimeout(cleanup);// 注册回调:出现异常时进行日志记录并清理资源emitter.onError(e -> {log.error("文件上传状态SSE 错误,taskCode:{}, 错误信息:{}", taskCode, e.getMessage(), e);cleanup.run();});// 尝试断点续传(只在客户端提供 Last-Event-ID 的情况下)if (StringUtils.isNotBlank(lastEventId)) {DataFileUploadStatusVO lastData = lastEventDataMap.get(taskCode);if (lastData != null) {try {emitter.send(SseEmitter.event().id(lastEventId).name("upload-status").reconnectTime(5000L).data(lastData, MediaType.APPLICATION_JSON));log.info("文件上传状态SSE,断点续传成功,taskCode:{}, lastEventId:{}, 数据:{}", taskCode, lastEventId,JSON.toJSONString(lastData));} catch (IOException e) {log.error("文件上传状态SSE,断点续传失败,taskCode:{}, 错误:{}", taskCode, e.getMessage(), e);}}}// 创建一个原子容器用于持有定时任务引用,以便后续取消任务AtomicReference<ScheduledFuture<?>> futureRef = new AtomicReference<>();// 启动定时任务ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(() -> {try {// 从全局映射中获取当前连接的 emitter,若为空说明连接已关闭,停止执行SseEmitter currentEmitter = emitterMap.get(taskCode);if (currentEmitter == null) {return;}// 查询文件上传状态List<DataConfigRespVO> dataConfigList = getDataConfigList(taskCode);// 查询任务信息TaskRespVO taskRespVO = taskService.getTask(taskCode);// 将数据库实体转换为状态对象列表List<DataFileUploadStatusVO.FileStatus> fileStatusList = dataConfigList.stream().map(item -> {DataFileUploadStatusVO.FileStatus fileStatus = new DataFileUploadStatusVO.FileStatus();fileStatus.setId(item.getId());fileStatus.setCode(item.getCode());fileStatus.setImportMethod(item.getImportMethod());fileStatus.setFilename(item.getFilename());fileStatus.setFileUrl(item.getFileUrl());fileStatus.setSize(item.getSize());fileStatus.setUploadStatusCode(item.getUploadStatusCode());return fileStatus;}).collect(Collectors.toList());// 构建完整状态返回对象DataFileUploadStatusVO statusVO = new DataFileUploadStatusVO();statusVO.setTaskCode(taskCode);statusVO.setCurrentTime(TimeUtil.getCurrentTime());statusVO.setFileStatusList(fileStatusList);statusVO.setName(taskRespVO.getName());statusVO.setDataType(taskRespVO.getDataType());statusVO.setDataTypeStr(taskRespVO.getDataTypeStr());statusVO.setImportType(taskRespVO.getImportType());statusVO.setCurrentLinkCode(taskRespVO.getCurrentLinkCode());statusVO.setCurrentLink(taskRespVO.getCurrentLink());statusVO.setCurrentLinkStatusCode(taskRespVO.getCurrentLinkStatusCode());statusVO.setCurrentLinkStatus(taskRespVO.getCurrentLinkStatus());String eventId = String.valueOf(System.currentTimeMillis());// 推送状态try {// 设置状态statusVO.setFinished(fileUploadFished(statusVO));// 保存最后一次推送的数据,用于断线续传lastEventDataMap.put(taskCode, statusVO);currentEmitter.send(SseEmitter.event()// 事件 ID,供断线续传.id(eventId)// 事件名.name("upload-status")// 告诉客户端:断线后5秒再重连.reconnectTime(5000L)// 推送数据为 JSON.data(statusVO, MediaType.APPLICATION_JSON));log.info("文件上传状态SSE,当前时间:{},taskCode:{},推送数据:{}", TimeUtil.getCurrentTime(), taskCode,JSON.toJSONString(statusVO));} catch (IOException ioException) {// 客户端断开连接或传输异常,主动清理资源并中止定时任务log.error("文件上传状态SSE,错误:{},taskCode:{}", ioException.getMessage(), taskCode);currentEmitter.completeWithError(ioException);cleanup.run();futureRef.get().cancel(true);return;}// 判断任务是否完成if (fileUploadFished(statusVO)) {// 设置任务完成statusVO.setFinished(true);currentEmitter.send(SseEmitter.event().name("upload-status").data(statusVO, MediaType.APPLICATION_JSON));// 主动关闭连接currentEmitter.complete();// 清理资源并取消定时任务cleanup.run();futureRef.get().cancel(true);log.info("文件上传状态SSE,任务已完成,taskCode:{},当前时间:{},emitterMap:{},大小:{}", taskCode,TimeUtil.getCurrentTime(), JSON.toJSONString(emitterMap), emitterMap.size());}} catch (Exception e) {log.error("文件上传状态SSE, SSE推送失败,taskCode:{},错误信息:{}", taskCode, e.getMessage(), e);SseEmitter failedEmitter = emitterMap.get(taskCode);if (failedEmitter != null) {failedEmitter.completeWithError(e);}cleanup.run();futureRef.get().cancel(true);}// 每2秒执行一次}, 0, 2, TimeUnit.SECONDS);// 记录定时任务引用futureRef.set(future);// 返回 emitter 给前端,保持连接return emitter;}
event:upload-status
data:{"finished":false,"taskCode":"366d1b2c760f4afd8b709e64c188a27c","currentTime":"2025-06-06 09:53:27","fileStatusList":[{"id":3922,"code":"64d9c1ab4abc441280abb61bba72a611","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本1.txt","fileUrl":"data-config/file/64d9c1ab4abc441280abb61bba72a611_新闻文本1.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.39 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3923,"code":"33735f65a0b940a996ded37ff4066299","importMethod":{"code":1,"desc":"文件导入"},"filename":"英文文本.txt","fileUrl":"data-config/file/33735f65a0b940a996ded37ff4066299_英文文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.77 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3924,"code":"e7c06f1da1a34e4fb8ee46eeac6f9f2e","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本.txt","fileUrl":"data-config/file/e7c06f1da1a34e4fb8ee46eeac6f9f2e_新闻文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"2.84 MB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":1}],"name":"测试文件上传123","dataType":2,"dataTypeStr":"非结构化数据","importType":"file","currentLinkCode":2,"currentLink":"数据配置","currentLinkStatusCode":1,"currentLinkStatus":"执行中"}event:upload-status
data:{"finished":false,"taskCode":"366d1b2c760f4afd8b709e64c188a27c","currentTime":"2025-06-06 09:53:29","fileStatusList":[{"id":3922,"code":"64d9c1ab4abc441280abb61bba72a611","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本1.txt","fileUrl":"data-config/file/64d9c1ab4abc441280abb61bba72a611_新闻文本1.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.39 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3923,"code":"33735f65a0b940a996ded37ff4066299","importMethod":{"code":1,"desc":"文件导入"},"filename":"英文文本.txt","fileUrl":"data-config/file/33735f65a0b940a996ded37ff4066299_英文文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.77 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3924,"code":"e7c06f1da1a34e4fb8ee46eeac6f9f2e","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本.txt","fileUrl":"data-config/file/e7c06f1da1a34e4fb8ee46eeac6f9f2e_新闻文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"2.84 MB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":1}],"name":"测试文件上传123","dataType":2,"dataTypeStr":"非结构化数据","importType":"file","currentLinkCode":2,"currentLink":"数据配置","currentLinkStatusCode":1,"currentLinkStatus":"执行中"}event:upload-status
data:{"finished":false,"taskCode":"366d1b2c760f4afd8b709e64c188a27c","currentTime":"2025-06-06 09:53:31","fileStatusList":[{"id":3922,"code":"64d9c1ab4abc441280abb61bba72a611","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本1.txt","fileUrl":"data-config/file/64d9c1ab4abc441280abb61bba72a611_新闻文本1.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.39 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3923,"code":"33735f65a0b940a996ded37ff4066299","importMethod":{"code":1,"desc":"文件导入"},"filename":"英文文本.txt","fileUrl":"data-config/file/33735f65a0b940a996ded37ff4066299_英文文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.77 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3924,"code":"e7c06f1da1a34e4fb8ee46eeac6f9f2e","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本.txt","fileUrl":"data-config/file/e7c06f1da1a34e4fb8ee46eeac6f9f2e_新闻文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"2.84 MB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":1}],"name":"测试文件上传123","dataType":2,"dataTypeStr":"非结构化数据","importType":"file","currentLinkCode":2,"currentLink":"数据配置","currentLinkStatusCode":1,"currentLinkStatus":"执行中"}event:upload-status
data:{"finished":false,"taskCode":"366d1b2c760f4afd8b709e64c188a27c","currentTime":"2025-06-06 09:53:33","fileStatusList":[{"id":3922,"code":"64d9c1ab4abc441280abb61bba72a611","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本1.txt","fileUrl":"data-config/file/64d9c1ab4abc441280abb61bba72a611_新闻文本1.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.39 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3923,"code":"33735f65a0b940a996ded37ff4066299","importMethod":{"code":1,"desc":"文件导入"},"filename":"英文文本.txt","fileUrl":"data-config/file/33735f65a0b940a996ded37ff4066299_英文文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.77 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3924,"code":"e7c06f1da1a34e4fb8ee46eeac6f9f2e","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本.txt","fileUrl":"data-config/file/e7c06f1da1a34e4fb8ee46eeac6f9f2e_新闻文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"2.84 MB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":1}],"name":"测试文件上传123","dataType":2,"dataTypeStr":"非结构化数据","importType":"file","currentLinkCode":2,"currentLink":"数据配置","currentLinkStatusCode":1,"currentLinkStatus":"执行中"}event:upload-status
data:{"finished":true,"taskCode":"366d1b2c760f4afd8b709e64c188a27c","currentTime":"2025-06-06 09:53:35","fileStatusList":[{"id":3922,"code":"64d9c1ab4abc441280abb61bba72a611","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本1.txt","fileUrl":"data-config/file/64d9c1ab4abc441280abb61bba72a611_新闻文本1.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.39 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3923,"code":"33735f65a0b940a996ded37ff4066299","importMethod":{"code":1,"desc":"文件导入"},"filename":"英文文本.txt","fileUrl":"data-config/file/33735f65a0b940a996ded37ff4066299_英文文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.77 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3924,"code":"e7c06f1da1a34e4fb8ee46eeac6f9f2e","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本.txt","fileUrl":"data-config/file/e7c06f1da1a34e4fb8ee46eeac6f9f2e_新闻文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"2.84 MB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2}],"name":"测试文件上传123","dataType":2,"dataTypeStr":"非结构化数据","importType":"file","currentLinkCode":2,"currentLink":"数据配置","currentLinkStatusCode":2,"currentLinkStatus":"已完成"}event:upload-status
data:{"finished":true,"taskCode":"366d1b2c760f4afd8b709e64c188a27c","currentTime":"2025-06-06 09:53:35","fileStatusList":[{"id":3922,"code":"64d9c1ab4abc441280abb61bba72a611","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本1.txt","fileUrl":"data-config/file/64d9c1ab4abc441280abb61bba72a611_新闻文本1.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.39 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3923,"code":"33735f65a0b940a996ded37ff4066299","importMethod":{"code":1,"desc":"文件导入"},"filename":"英文文本.txt","fileUrl":"data-config/file/33735f65a0b940a996ded37ff4066299_英文文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"1.77 KB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2},{"id":3924,"code":"e7c06f1da1a34e4fb8ee46eeac6f9f2e","importMethod":{"code":1,"desc":"文件导入"},"filename":"新闻文本.txt","fileUrl":"data-config/file/e7c06f1da1a34e4fb8ee46eeac6f9f2e_新闻文本.txt","tableName":null,"fieldName":null,"createTime":null,"introduction":null,"size":"2.84 MB","includeHeader":null,"csvSeparator":null,"uploadStatusCode":2}],"name":"测试文件上传123","dataType":2,"dataTypeStr":"非结构化数据","importType":"file","currentLinkCode":2,"currentLink":"数据配置","currentLinkStatusCode":2,"currentLinkStatus":"已完成"}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为×小鹏战略合作:破局智能驾驶深水区的商业逻辑深度解析

当中国智能电动车竞争进入下半场&#xff0c;头部玩家的合纵连横正在重构产业格局。华为与小鹏汽车近日官宣的“战略合作”&#xff0c;表面看是技术互补的常规操作&#xff0c;实则暗藏改写行业游戏规则的深层商业逻辑。 一、技术破壁&#xff1a;从“单点突破”到“全栈协同”…

Tailwind CSS 实战:基于 Kooboo 构建 AI 对话框页面(六):图片上传交互功能

在 《Tailwind CSS 实战&#xff1a;基于 Kooboo 构建 AI 对话框页面&#xff08;五&#xff09;》 中&#xff0c;完成了语音交互功能的优化。本文作为该系列教程的第六篇&#xff0c;将聚焦于图片上传功能的开发。通过集成图片上传与预览能力&#xff0c;我们将进一步完善 AI…

40. 自动化异步测试开发之编写异步业务函数、测试函数和测试类(类写法)

40. 自动化异步测试开发之编写异步业务函数、测试函数和测试类&#xff08;类写法&#xff09; 一、类结构设计解析 1.1 基类设计 class Base:async_driver None # &#x1f697; 存储浏览器驱动实例async def get(self, url: str http://secure.smartbearsoftware.com/.…

面向开发者的提示词工程④——文本推断(Inferring)

文章目录 前言一、情感&#xff08;正向/负向&#xff09;二、识别情感类型三、识别愤怒四、从客户评论中提取产品和公司名称五、一次完成多项任务 前言 面向开发者的提示词工程——导读 在这节课中&#xff0c;你将从产品评论和新闻文章中推断情感和主题。 举了个商品评论的例…

java day15 (数据库)

进入数据库的学习 DB 因为数据太多了&#xff0c;方便统一管理的软件 操作就不用改代码了&#xff0c;直接改数据库则可&#xff1b; 命令就是sql语句 这些都是关系型数据库&#xff0c;sql可以控制全部&#xff0c;至于具体的环境我以前就有安装过了&#xff1b; 理解&am…

国标GB28181设备管理软件EasyGBS远程视频监控方案助力高效安全运营

一、方案背景​ 在商业快速扩张的背景下&#xff0c;连锁店门店数量激增&#xff0c;分布范围广。但传统人工巡检、电话汇报等管理方式效率低下&#xff0c;存在信息滞后、管理盲区&#xff0c;难以掌握店铺运营情况&#xff0c;影响企业效率与安全。网络远程视频监控系统可有…

Python 字典(dict)的高级用法与技巧

今天我们继续深入讲解 Python 字典的 高级用法与技巧&#xff0c;包括&#xff1a; defaultdict&#xff1a;带默认值的字典Counter&#xff1a;快速统计工具字典排序&#xff1a;按键或值排序合并字典&#xff08;传统方式和 Python 3.9 新语法&#xff09;嵌套字典的安全访问…

动静态库的使用(Linux)

1.库 通俗来说&#xff0c;库就是现有的&#xff0c;可复用的代码&#xff0c;例如&#xff1a;在C/C语言编译时&#xff0c;就需要依赖相关的C/C标准库。本质上来说库是一种可执行代码的二进制形式&#xff0c;可以被操作系统载入内存执行。通常我们可以在windows下看到一些后…

R²ec: 构建具有推理能力的大型推荐模型,显著提示推荐系统性能!!

摘要&#xff1a;大型推荐模型通过编码或项目生成将大型语言模型&#xff08;LLMs&#xff09;扩展为强大的推荐工具&#xff0c;而近期在LLM推理方面的突破也同步激发了在推荐领域探索推理的动机。目前的研究通常将LLMs定位为外部推理模块&#xff0c;以提供辅助性思考来增强传…

【Java后端基础 005】ThreadLocal-线程数据共享和安全

&#x1f4da;博客主页&#xff1a;代码探秘者 ✨专栏&#xff1a;文章正在持续更新ing… ✅C语言/C&#xff1a;C&#xff08;详细版&#xff09; 数据结构&#xff09; 十大排序算法 ✅Java基础&#xff1a;JavaSE基础 面向对象大合集 JavaSE进阶 Java版数据结构JDK新特性…

Tesseract配置参数详解及适用场景(PyTesseract进行OCR)

在使用 PyTesseract 进行 OCR 时&#xff0c;合理配置参数是提高识别准确率的关键。以下是 Tesseract 常用参数的详细解释和适用场景。 一、关键参数 &#xff08;1&#xff09;页面分割模式&#xff08;Page Segmentation Mode, --psm&#xff09; 控制 Tesseract 如何分析…

【Zephyr 系列 12】BLE + NVS + 低功耗融合实战:打造可配置蓝牙信标系统

🧠关键词:Zephyr、BLE 广播、信标、NVS 参数、低功耗、状态机、周期唤醒 📌适合人群:希望实现 BLE 信标类产品(定位标签、资产管理)的开发者 📊预计篇幅:约 5200+ 字 🎯 项目目标 构建一个可广泛应用于资产标签、定位信标、设备标识等场景的蓝牙广播模块,具备:…

图解浏览器多进程渲染:从DNS到GPU合成的完整旅程

目录 浏览器进程架构的演化 进程和线程关系图示 进程&#xff08;Process&#xff09; 线程&#xff08;Thread&#xff09; 协程&#xff08;Coroutine&#xff09; 进程&线程&协程核心对比 单进程和多进程浏览器 单进程浏览器​编辑 单进程浏览器存在的问题…

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…

C# 类和继承(抽象成员)

抽象成员 抽象成员是指设计为被覆写的函数成员。抽象成员有以下特征。 必须是一个函数成员。也就是说&#xff0c;字段和常量不能为抽象成员。必须用abstract修饰符标记。不能有实现代码块。抽象成员的代码用分号表示。 例如&#xff0c;下面取自一个类定义的代码声明了两个抽…

基于JWT+SpringSecurity整合一个单点认证授权机制

基于 JWT Spring Security 的授权认证机制&#xff0c;在整体架构设计上体现了高度的安全性与灵活性。其在整合框架中的应用&#xff0c;充分展示了模块化、可扩展性和高效鉴权的设计理念&#xff0c;为开发者提供了一种值得借鉴的安全架构模式。 1.SpringSecurity概念理解 …

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…

Git 切换到旧提交,同时保证当前修改不丢失

在 Git 中&#xff0c;可以通过以下几种方式切换到之前的提交&#xff0c;同时保留当前的修改 1. 使用 git checkout 创建临时分离头指针&#xff08;推荐用于查看代码&#xff09; git checkout <commit-hash>这会让你进入"分离头指针"状态&#xff0c;你可…

东芝Toshiba DP-4528AG打印机信息

东芝 Toshiba DP 4528AG 是一款黑白激光数码复合机&#xff1a; 类型&#xff1a;激光数码复合机&#xff0c;涵盖复印、打印、扫描、传真功能&#xff0c;能满足办公室多样化的文档处理需求。速度类型&#xff1a;中速&#xff0c;黑白复印和打印速度可达 45 页 / 分钟&#…

Qt生成日志与以及捕获崩溃文件(mingw64位,winDbg)————附带详细解说

文章目录 Qt生成日志与以及报错文件(mingw64位&#xff0c;winDbg)0 背景与结果0.1 背景0.2 结果1 WinDbg1.1 安装1.2 使用 2 编写代码2.1 ccrashstack类2.2 编写输出捕获异常的dmp文件2.2 编写输出日志文件2.3 调用生成日志和dmp文件 参考 Qt生成日志与以及报错文件(mingw64位…