当前位置: 首页 > news >正文

ElasticSearch - SpringBoot整合ES实现文档的增删改操作

文章目录

      • 1. ElasticSearch和kibana的安装和配置
      • 2. SpringBoot 项目环境搭建
      • 3. 创建索引
      • 4. 索引文档
      • 5. 更新文档
      • 6. 删除文档

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-your-data.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_retrieving_a_document.html

1. ElasticSearch和kibana的安装和配置

① 下载地址:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-4-2

② 修改elasticsearch.yml文件:

 cluster.name: my-applicationpath.data: D:/install/elasticsearch-7.4.2-windows-x86_64/elasticsearch-7.4.2/datapath.logs: D:/install/elasticsearch-7.4.2-windows-x86_64/elasticsearch-7.4.2/logs

③ 配置环境变量:D:\install\elasticsearch-7.4.2-windows-x86_64\elasticsearch-7.4.2\bin

④ 下载ik分词器:https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v7.4.2

⑤ 解压ik分词器,必须解压到D:\install\elasticsearch-7.4.2-windows-x86_64\elasticsearch-7.4.2\plugins\ik目录下

⑥ 点击elasticsearch.bat启动elasticsearch服务,并访问:localhsot:9200

⑦ kibana下载地址:https://www.elastic.co/cn/downloads/past-releases/kibana-7-4-2

⑧ 修改kibana.yml文件(不必须):

 server.port: 5601server.host: "localhost"elasticsearch.hosts: ["http://localhost:9200"]i18n.locale: "zh-CN"

⑨ 点击kibana.bat启动kibana服务(一定要先启动es):

⑦ kibana下载地址:https://www.elastic.co/cn/downloads/past-releases/kibana-7-4-2

⑧ 修改kibana.yml文件(不必须):

 server.port: 5601server.host: "localhost"elasticsearch.hosts: ["http://localhost:9200"]i18n.locale: "zh-CN"

⑨ 点击kibana.bat启动kibana服务(一定要先启动es)

⑩ 访问localhost:5601

2. SpringBoot 项目环境搭建

1、创建项目:ElasticSearch和SpringBoot的版本一定要对应,否则会报各种错误

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><!-- 这里我的springboot的版本使用是2.3.2 --><version>2.3.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xiao</groupId><artifactId>estest</artifactId><version>0.0.1-SNAPSHOT</version><name>estest</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><!-- 这里必须要填写,因为springboot2.3.2默认的elasticsearch版本为7.6.2,我们使用的是7.4.2,不更改会产生版本不兼容等问题 --><elasticsearch.version>7.4.2</elasticsearch.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 这里我使用的是elasticsearch的high-level-client 版本要和你的elasticsearch版本对应--><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.4.2</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.6.5</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version><scope>provided</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2、创建一个配置类,用于配置Elasticsearch的集群信息:

@Configuration
public class ElasticSearchConfig {@Beanpublic RestHighLevelClient restHighLevelClient(){RestClientBuilder builder = RestClient.builder(new HttpHost("localhost",9200,"http"));RestHighLevelClient client = new RestHighLevelClient(builder);return client;}
}

3. 创建索引

1、在项目的resource/elasticsearch目录下创建一个文件mapping.json文件定义索引的映射:

{"properties": {"categoryId": {"type": "keyword"},"content": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_smart"},"name": {"analyzer": "ik_max_word","search_analyzer": "ik_smart","type": "text"},"creator": {"type": "keyword"},"editor": {"type": "keyword"},"from": {"type": "keyword"},"id": {"type": "keyword"},"tags": {"type": "keyword"},"updateTime": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||epoch_millis"},"createTime": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||epoch_millis"}}
}

2、项目启动的时候判断knowledge索引是否存在并根据定义的映射创建该索引:

@Slf4j
@Service
public class ElasticSearchImpl {private static final String KNOWLEDGE_INDEX = "knowledge";@Autowiredprivate RestHighLevelClient restHighLevelClient;@PostConstructpublic void init(){try {// 查询索引GetIndexRequest request = new GetIndexRequest(KNOWLEDGE_INDEX);boolean exist = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);if (!exist) {CreateIndexRequest createIndexRequest = new CreateIndexRequest("knowledge");ClassPathResource mappingResource = new ClassPathResource("elasticsearch/mapping.json");byte[] bytes = FileCopyUtils.copyToByteArray(mappingResource.getInputStream());String json = new String(bytes, StandardCharsets.UTF_8);createIndexRequest.mapping(json, XContentType.JSON);restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);}} catch (IOException e) {log.error("failed to create index mapping:", e);throw new CommonException("elasticsearch.create.index.failed");}}
}

3、启动项目,在kibana客户端查看索引是否创建成功:

GET /knowledge/_search 
{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 0,"relation" : "eq"},"max_score" : null,"hits" : [ ]}
}

说明索引添加成功。

4. 索引文档

1、定义一个映射对象:

@Data
public class Doc {private String id;private String name;private String content;private String creator;private String editor;private Date createTime;private Date updateTime;
}

2、索引文档:

@Slf4j
@Service
public class ElasticSearchImpl {private static final String KNOWLEDGE_INDEX = "knowledge";@Autowiredprivate RestHighLevelClient restHighLevelClient;public void saveDoc(Doc doc) throws JsonProcessingException {IndexRequest indexRequest = new IndexRequest("knowledge");indexRequest.id(doc.getId());// ES使用 json 文档代表了一个对象String jsonString = new JsonMapper().writeValueAsString(doc);indexRequest.source(jsonString, XContentType.JSON);// ElasticSearch是近实时搜索,刚索引的文档并不是立即对搜索可见,需要手动刷新indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);try {restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);} catch (IOException e) {log.error("failed to add document to elasticsearch,the doc is:{},the exception is {}", doc, e);throw new CommonException("elasticsearch.create.index.failed");}}
}

3、测试索引文档:

@SpringBootTest
@RunWith(SpringRunner.class)
public class BeanLoadServiceTest {@Autowiredprivate ElasticSearchImpl elasticSearchImpl;@Testpublic void testSaveDoc(){// Elasticsearch 是面向文档的,意味着它存储整个对象或文档Doc doc = new Doc();doc.setId("1");doc.setName("茶花女");doc.setContent("这是一本非常好看的小说,有时间的小伙伴可以看一下");doc.setCreator("小仲马");doc.setEditor("小仲马");doc.setCreateTime(new Date());doc.setUpdateTime(new Date());elasticSearchImpl.saveDoc(doc);}
}

4、在kibana客户端查询索引中的文档:

GET /knowledge/_doc/1
{"_index" : "knowledge","_type" : "_doc","_id" : "1","_version" : 1,"_seq_no" : 0,"_primary_term" : 1,"found" : true,"_source" : {"id" : "1","name" : "茶花女","content" : "这是一本非常好看的小说,有时间的小伙伴可以看一下","creator" : "小仲马","editor" : "小仲马","createTime" : 1677229499680,"updateTime" : 1677229499680}
}

5. 更新文档

1、更新文档:

@Slf4j
@Service
public class ElasticSearchImpl {private static final String KNOWLEDGE_INDEX = "knowledge";@Autowiredprivate RestHighLevelClient restHighLevelClient;public void updateDoc(Doc doc) throws JsonProcessingException {UpdateRequest updateRequest = new UpdateRequest(KNOWLEDGE_INDEX, doc.getId());String jsonString = new JsonMapper().writeValueAsString(doc);updateRequest.doc(jsonString, XContentType.JSON);updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);try {restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);} catch (IOException e) {log.error("failed to update document to elasticsearch,the doc is:{},the exception is {}", doc, e);throw new CommonException("elasticsearch.create.index.failed");}}
}

2、测试更新文档:

@SpringBootTest
@RunWith(SpringRunner.class)
public class BeanLoadServiceTest {@Autowiredprivate ElasticSearchImpl elasticSearchImpl;@Testpublic void testUpdateDoc() throws JsonProcessingException {// Elasticsearch 是面向文档的,意味着它存储整个对象或文档Doc doc = new Doc();doc.setId("1");doc.setName("茶花女");doc.setContent("这是一本非常好看的小说,有时间的小伙伴可以看一下");doc.setCreator("大仲马");doc.setEditor("大仲马");doc.setCreateTime(new Date());doc.setUpdateTime(new Date());elasticSearchImpl.saveDoc(doc);}
}

3、在kibana客户端查看索引中的文档:

{"_index" : "knowledge","_type" : "_doc","_id" : "1","_version" : 2,"_seq_no" : 1,"_primary_term" : 1,"found" : true,"_source" : {"id" : "1","name" : "茶花女","content" : "这是一本非常好看的小说,有时间的小伙伴可以看一下","creator" : "大仲马","editor" : "大仲马","createTime" : 1677229755142,"updateTime" : 1677229755142}
}

6. 删除文档

1、删除文档:

@Slf4j
@Service
public class ElasticSearchImpl {private static final String KNOWLEDGE_INDEX = "knowledge";@Autowiredprivate RestHighLevelClient restHighLevelClient;public void deleteDoc(Set<String> ids) {DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(KNOWLEDGE_INDEX);deleteByQueryRequest.setQuery(new TermsQueryBuilder("id", ids));deleteByQueryRequest.setRefresh(true);try {restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);} catch (IOException e) {log.error("failed to delete the document in elasticsearch,the doc ids is:{},the exception is {}", ids, e);throw new CommonException("elasticsearch.create.index.failed");}}
}

2、测试删除文档:

@SpringBootTest
@RunWith(SpringRunner.class)
public class BeanLoadServiceTest {@Autowiredprivate ElasticSearchImpl elasticSearchImpl;@Testpublic void testDeleteDoc() throws JsonProcessingException {// Elasticsearch 是面向文档的,意味着它存储整个对象或文档List<String> list = Arrays.asList("1");elasticSearchImpl.deleteDoc(new HashSet<String>(list));}
}

3、在kibana客户端查看删除的文档:

GET /knowledge/_doc/1
{"_index" : "knowledge","_type" : "_doc","_id" : "1","found" : false
}

相关文章:

ElasticSearch - SpringBoot整合ES实现文档的增删改操作

文章目录1. ElasticSearch和kibana的安装和配置2. SpringBoot 项目环境搭建3. 创建索引4. 索引文档5. 更新文档6. 删除文档https://www.elastic.co/guide/en/elasticsearch/reference/current/search-your-data.htmlhttps://www.elastic.co/guide/cn/elasticsearch/guide/curre…...

嵌入式 LVGL移植到STM32F4

目录 LVGL简介 1、特点 2、LVGL的硬件要求 3、相关网站 4、LVGL源码下载 5、LVGL移植要求 5.1 移植过程-添加源码 2、更改接口文件 3、显示实现 4、添加外部中文字体的方法 5、编译下载后有几种情况 6、调用显示 6、GUI-Guider使用 6.1 安装软件 6.2 使用…...

VSCode——SSH免密登录

文章目录本地PC端&#xff08;一般为Windows&#xff09;1. 检查自己是否已经生成公钥2. 配置VScode的SSH config远程服务器端1. 服务器新建授权文件2. 赋权限3. 重启远程服务器的ssh服务最全步骤&#xff1a;【设置ssh免密不起作用&#xff1f;彻底搞懂密钥】vscode在remote S…...

python未来应用前景怎么样

Python近段时间一直涨势迅猛&#xff0c;在各大编程排行榜中崭露头角&#xff0c;得益于它多功能性和简单易上手的特性&#xff0c;让它可以在很多不同的工作中发挥重大作用。 正因如此&#xff0c;目前几乎所有大中型互联网企业都在使用 Python 完成各种各样的工作&#xff0…...

webpack基本使用和开发环境配置

目录 1 webpack 基本使用 01 webpack 简介 02 webpack 初体验 2 webpack开发环境配置 03 打包样式资源 04 打包html资源 05 打包图片资源 06 打包其他资源&#xff08;以打包icon为例&#xff09; 07 devServer 08.开发环境配置 1 webpack 基本使用 由于笔记文档没有…...

3.2 http协议

一.HTTP协议1.概述是计算机网络的核心概念,是一种网络协议网络协议种类非常多,其中IP,TCP,UDP...其中还有一个应用非常广泛的协议.HTTPHTTP协议是日常开发中用的最多的协议HTTP处在TCP/IP五层协议栈的应用层HTTP在传输层是基于TCP的,(http/1 HTTP/2是基于TCP,最新版本的HTTP/3是…...

页面访问升级出错怎么解决

相信大家在访问网站的时候时常会遇到页面访问界面升级&#xff0c;暂时不可能进行访问操作&#xff0c;可能遇到这种情况很多小伙伴们都不知道怎么版&#xff0c;其实互联网网页在正常使用过程中是不会出现这种问题的。那么如果遇到页面访问界面升级怎么办?页面访问界面升级通…...

leetcode 181. 超过经理收入的员工

SQL架构 表&#xff1a;Employee ---------------------- | Column Name | Type | ---------------------- | id | int | | name | varchar | | salary | int | | managerId | int | ---------------------- Id是该表的主键。 该表的…...

任务类风险漏洞挖掘思路

任务类风险定义&#xff1a; 大部分游戏都离不开任务&#xff0c;游戏往往也会借助任务&#xff0c;来引导玩家上手&#xff0c;了解游戏背景&#xff0c;增加游戏玩法&#xff0c;提升游戏趣味性。任务就像线索&#xff0c;将游戏的各个章节&#xff0c;各种玩法&#xff0c;…...

2023年Dubbo常见面试题

2023年Dubbo常见面试题 Dubbo 中 zookeeper 做注册中心&#xff0c;如果注册中心集群都挂掉&#xff0c;发布者和订阅者之间还能通信么&#xff1f; 可以通信的&#xff0c;启动 dubbo 时&#xff0c;消费者会从 zk 拉取注册的生产者的地址接口等数据&#xff0c;缓存在本地。…...

星光2开发板使用ECR6600U无线wifi网卡的方法

visionfive2 开发板性能还是不错的&#xff0c;有些人买的时候会带一个无线wifi网卡&#xff0c;但是官方提供的操作系统没有驱动。 所以需要自己编驱动&#xff08;他大爷的&#xff09;。 还好有人已经踩过坑了。 星光2之USB无线网卡使用教程【新增RTL8832AU WiFi6双频无线…...

【ArcGIS Pro二次开发】(11):面要素的一键拓扑

在工作中&#xff0c;经常需要对要素进行拓扑检查。 在ArcGIS Pro中正常的工作流程是在数据库中【新建要素数据集——新建拓扑——将要素加入拓扑——添加规则——验证】&#xff0c;工作流程不算短&#xff0c;操作起来比较繁琐。 下面以一个例子演示如何在ArcGIS Pro SDK二次…...

【实现点击下载按钮功能 Objective-C语言】

一、实现点击下载按钮功能, 1.接下来,我们再实现另外一个功能,是什么,点击下载按钮吧: 点击下载按钮,是不是要有效果啊, 就是给大家实现这个功能, 首先,我们要实现单击这个效果,是不是要给按钮注册单击事件吧, 请问,这个按钮在哪里啊,是在控制器里面吗,不是,…...

界面控件DevExpress WinForm——轻松构建类Visual Studio UI(三)

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…...

项目实战-瑞吉外卖day01(B站)

瑞吉外卖-Day01课程内容软件开发整体介绍瑞吉外卖项目介绍开发环境搭建后台登录功能开发后台退出功能开发1. 软件开发整体介绍作为一名软件开发工程师,我们需要了解在软件开发过程中的开发流程&#xff0c; 以及软件开发过程中涉及到的岗位角色&#xff0c;角色的分工、职责&am…...

Linux 学习整理(使用 iftop 查看网络带宽使用情况 《端口显示》)

一、命令简介 iftop 是实时流量监控工具&#xff0c;可以用来监控网卡的实时流量&#xff08;可以指定网段&#xff09;、反向解析IP、显示端口信息等。 二、命令安装 yum install -y iftop 三、命令相关参数及说明 3.1、相关参数说明 -i&#xff1a;设定监测的网卡&#…...

Vue3创建项目(四)axios封装及接口配置

项目结构: 目录 &#x1f349;&#x1f349;&#x1f349;index.ts &#x1f349;&#x1f349;&#x1f349; api.ts 看完需要预计花费10分钟。 请求拦截器与响应拦截器 阅读下面代码需先了解以下内容&#xff1a; 请求拦截器&#xff1a; 请求拦截器的作用是在请求发送前进…...

【算法笔记】递归与回溯

递归与回溯 To Iterate is Human, to Recurse, Divine. —L. Peter Deutsch 人理解迭代&#xff0c;神理解递归。 —L. Peter Deutsch 1.什么是递归呢 递归形象描述&#xff1a; 你打开面前这扇门&#xff0c;看到屋里面还有一扇门。 你走过去&#xff0c;发现手中的钥匙还可以…...

蓝桥杯备赛——Echarts学习

文章目录前言学习 ECharts 的方法快速上手基础知识option 配置选项可选配置title 标题组件tooltip 提示框组件axisPointer 坐标轴指示器legend 图例组件toolbox 工具栏坐标轴xAxis和yAxisseries &#xff08;[ ]用数组表示,数组里是一个个数据对象&#xff09;饼状图散点图交互…...

动态规划--最长公共子串

最长公共子串公共子串问题费曼算法动态规划算法思路代码实现公共子串问题 在计算机科学中&#xff0c;最长公共子串问题是寻找两个或多个已知字符串最长的子串。此问题与最长公共子序列问题的区别在于子序列不必是连续的&#xff0c;而子串却必须是。链接: 百度百科 费曼算法…...

HuTool代理请求遇阻:深入解析HTTP/1.1 407 Proxy Authentication Required的成因与实战解决方案

1. 当HuTool遇上407&#xff1a;代理认证失败的典型场景 最近在项目中使用HuTool发送HTTPS请求时&#xff0c;突然遇到一个让人头疼的错误——HTTP/1.1 407 Proxy Authentication Required。这个错误就像高速公路上的收费站&#xff0c;明明已经交了通行费&#xff08;设置了代…...

不止是收发数据:挖掘常兴串口调试助手V5.01的5个隐藏效率神器(自动回复/进制转换/批量发送)

挖掘常兴串口调试助手V5.01的5个隐藏效率神器 在嵌入式开发领域&#xff0c;串口调试工具早已超越了简单的数据收发功能。常兴串口调试助手V5.01作为一款专业级工具&#xff0c;集成了多项提升开发效率的实用功能。本文将深入解析五个常被忽视但极具价值的隐藏功能&#xff0c;…...

Charticulator:数据可视化的自由创作平台与技术革命

Charticulator&#xff1a;数据可视化的自由创作平台与技术革命 【免费下载链接】charticulator Interactive Layout-Aware Construction of Bespoke Charts 项目地址: https://gitcode.com/gh_mirrors/ch/charticulator 当数据分析师面对预设模板无法表达复杂数据关系时…...

别再混淆了!深入对比Vivado中AXI DMA IP核与PS端DMA控制器的角色与分工

深入解析Vivado中AXI DMA与PS端DMA控制器的协同设计 在Zynq/MPSoC平台的软硬件协同开发中&#xff0c;数据搬运效率往往成为系统性能的瓶颈。许多开发者虽然能够熟练使用Vivado中的AXI DMA IP核完成基本数据传输&#xff0c;却对PL端AXI DMA与PS端DMA控制器之间的分工协作机制存…...

从单体到微服务:用Ruoyi-Vue-Plus框架快速搭建多租户后台系统(含AI模块开发避坑指南)

从单体到微服务&#xff1a;Ruoyi-Vue-Plus框架的多租户实战与AI模块开发精要 当企业级应用需要同时服务多个客户群体时&#xff0c;如何确保数据隔离与系统性能的平衡成为架构设计的核心挑战。Ruoyi-Vue-Plus作为一款基于Spring Boot的快速开发框架&#xff0c;其多租户实现机…...

告别SQLite!用ObjectBox为Flutter应用打造高性能本地存储(含常见报错解决方案)

告别SQLite&#xff01;用ObjectBox为Flutter应用打造高性能本地存储&#xff08;含常见报错解决方案&#xff09; 在移动应用开发中&#xff0c;本地数据存储方案的选择直接影响着用户体验和应用性能。对于Flutter开发者来说&#xff0c;SQLite长期以来都是默认选择&#xff0…...

RWKV7-1.5B-g1a轻量对话模型应用:微信公众号自动回复+知识库问答搭建

RWKV7-1.5B-g1a轻量对话模型应用&#xff1a;微信公众号自动回复知识库问答搭建 1. 模型简介与特点 rwkv7-1.5B-g1a 是基于 RWKV-7 架构的多语言文本生成模型&#xff0c;特别适合中文轻量对话场景。相比传统大模型&#xff0c;它具有以下优势&#xff1a; 资源占用低&#…...

3分钟掌握Balena Etcher:安全可靠的跨平台镜像烧录工具

3分钟掌握Balena Etcher&#xff1a;安全可靠的跨平台镜像烧录工具 【免费下载链接】etcher Flash OS images to SD cards & USB drives, safely and easily. 项目地址: https://gitcode.com/GitHub_Trending/et/etcher Balena Etcher是一款专为简化操作系统镜像部署…...

别再手动敲代码了!用Tesseract-OCR在Linux上批量处理图片转文字(附Python脚本)

从图片到结构化数据&#xff1a;基于Tesseract-OCR的Linux批量文本提取实战 在数字化办公和自动化流程中&#xff0c;我们经常需要处理大量图片中的文字信息——可能是扫描的合同文档、会议白板照片或是PDF中的非可编辑页面。传统的手动录入不仅效率低下&#xff0c;还容易出错…...

手把手教你用STM32F405和SD卡,在阿里云物联网平台上实现OTA升级(MQTT协议详解)

STM32F405实战&#xff1a;基于SD卡与阿里云物联网平台的OTA升级全流程解析 当嵌入式设备部署在野外或工业现场时&#xff0c;固件升级往往成为工程师的噩梦。传统方式需要技术人员携带烧录器奔赴现场&#xff0c;不仅效率低下&#xff0c;在设备数量庞大或分布广泛时更是不切实…...