java_将数据存入elasticsearch进行高效搜索

使用技术简介:

(1) 使用Nginx实现反向代理,使前端可以调用多个微服务

(2) 使用nacos将多个服务管理关联起来

(3) 将数据存入elasticsearch进行高效搜索

(4) 使用消息队列rabbitmq进行消息的传递 

(5) 使用 openfeign 进行多个服务之间的api调用

参考: 56 尚上优选项目-平台管理端-整合ES+MQ实现商品上下架-功能最终测试_哔哩哔哩_bilibili

1. 使用Nginx实现反向代理

使用Nginx实现反向代理,使前端可以通过一个端口,调用多个微服务(的端口)

前端中的配置的base api端口 9901:

反向代理逻辑图:

图示 /acl /sys 为两个服务的名称中的路径字符串。

在nginx中的配置如下:

2. 使用nacos将多个服务管理关联起来

 通过nacos将多个服务关联起来,这里实现一个产品上架(存入elasticsearch仓库,简称es)下架(从es仓库删除)的功能.service-product提供商品的信息,service-search通过远程调用(FeignClient)调用service-product的接口,获取商品的具体信息,存入或者从es中删除。

service-product 和 service-search 两个服务通过消息队列进行通讯(rabbitmq消息队列, pom名称:spring-cloud-starter-bus-amqp)

nacos部分:pom依赖:

<!--服务注册 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

在各个服务中添加在naco的注册:示例 service-produce模块的application.yml中添加cloud.nacos.discovery.server-addr

 在 main主程序中添加 启用Nacos服务发现注解:@EnableDiscoveryClient

同理在service-search模块中:

启动nacos服务,同时启动自己的服务,看自己的服务是否注册成功:

下载安装合适版本的nacos(版本不对应会出兼容性问题):

到nacos目录,执行:

.\bin\startup.cmd -m standalone

启动nacos后,启动自己的服务,如自己的服务注册成功,会在log中有如下提示:

在浏览器中输入: http://192.168.136.1:8848/nacos/index.html 也可看是否启动成功,若你的目标服务在“服务列表”中,说明服务注册成功,nacos正常运行,服务可以被关联起来,可以通过restful风格进行数据的传递了。

3. 使用消息队列rabbitmq进行消息的传递 

在需要使用的服务service-search的pom.xml中添加依赖:

<!--rabbitmq消息队列-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

安装rabbitmq服务,示例在虚拟机docker中安装 rabbitmq:3.8-management:

#拉取镜像
docker pull rabbitmq:3.8-management
#创建容器启动
docker run -d --restart=always -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:3.8-management

查看安装rabbitmq的虚拟机ip地址: 

docker中安装好后,可以在本机(win11)上测试下安装是否成功:浏览器中输入:http://192.168.68.132:15672/ (注意这里是自己虚拟机的ip地址)

根据自己虚拟机的地址,在需要使用的服务service-search 和 serivice-product 中配置ip地址和端口号等信息:

 

编写代码,使用 RabbitTemplate, 进行消息的发送:

进行消息发送:指定j交换机exchange 字符串(自定义一个),路由器routing, 发送内容 Object message (这里是 Long skuId)

为了让发送的消息能构正确解析,需要定义一个@Configuration, 使用Jackson2JsonMessageConverter,进行消息的类型转换,这里是将Long skuId 转换成Json格式:

package com.atguigu.ssyx.mq.config;import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MQConfig {@Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}
}

注意rabbit端还需要对 RabbitTemplate 做一些初始化操作,参考init():

package com.atguigu.ssyx.mq.config;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class MQProducerAckConfig implements RabbitTemplate.ReturnCallback, RabbitTemplate.ConfirmCallback {//  我们发送消息使用的是 private RabbitTemplate rabbitTemplate; 对象//  如果不做设置的话 当前的rabbitTemplate 与当前的配置类没有任何关系!@Autowiredprivate RabbitTemplate rabbitTemplate;//  设置 表示修饰一个非静态的void方法,在服务器加载Servlet的时候运行。并且只执行一次!// PostConstruct注解的函数:在 Spring 容器创建并初始化 Bean 后自动调用,一个类中只能有一个 @PostConstruct 注解的方法@PostConstructpublic void init(){rabbitTemplate.setReturnCallback(this);rabbitTemplate.setConfirmCallback(this);}/*** 表示消息是否正确发送到了交换机上** @param correlationData 消息的载体* @param ack             判断是否发送到交换机上* @param cause           原因*/@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {if (ack) {System.out.println("消息发送成功!");} else {System.out.println("消息发送失败!" + cause);}}/*** 消息如果没有正确发送到队列中,则会走这个方法!如果消息被正常处理,则这个方法不会走!** @param message* @param replyCode* @param replyText* @param exchange* @param routingKey*/@Overridepublic void returnedMessage(Message message, int replyCode, String replyText,String exchange, String routingKey) {System.out.println("消息主体: " + new String(message.getBody()));System.out.println("应答码: " + replyCode);System.out.println("描述:" + replyText);System.out.println("消息使用的交换器 exchange : " + exchange);System.out.println("消息使用的路由键 routing : " + routingKey);}
}

消息的接收端(消费者) ,通过RabbitListener 定位到到发送者发送的消息队列上:

package com.atguigu.ssyx.receiver;
import com.atguigu.ssyx.mq.constant.MqConst;
import com.rabbitmq.client.Channel;
import com.atguigu.ssyx.search.service.SkuService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.IOException;@Component
public class SkuReceiver {@Autowiredprivate SkuService skuService;/*** 商品上架* @param skuId* @param message* @param channel* @throws IOException*/@RabbitListener(bindings = @QueueBinding( //绑定接收什么消息 //消费者,接收消息value=@Queue(value = MqConst.QUEUE_GOODS_UPPER, durable = "true"), // durable 持久化exchange = @Exchange(value = MqConst.EXCHANGE_GOODS_DIRECT),key = {MqConst.ROUTING_GOODS_UPPER}))public void upperSku(Long skuId, Message message, Channel channel) throws IOException {// 发送者:   rabbitService.sendMsg(MqConst.EXCHANGE_GOODS_DIRECT,//                      MqConst.ROUTING_GOODS_UPPER,//                      skuId);//:发送者函数原型:public boolean sendMsg(String exchange, String routingKey, Object message)// 这里的Object message使用 public MessageConverter messageConverter() 方法转成了json格式,// 确保了生产者和消费者之间的消息序列化与反序列化逻辑一致,// 所以 Object message 对应这里接收者的 Long skuId 形参,实现了参数传递的目的。try{if(skuId != null) {skuService.upperSku(skuId);}/*** 第一个参数:表示收到的消息的标号* 第二个参数:如果为true表示可以签收多个消息*///DeliveryTag 交货标签channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (IOException e) {System.out.print("john:IOException occurred while processing message");throw e;  // 或者处理该异常}}/*** 商品下架* @param skuId*/@RabbitListener(bindings = @QueueBinding(value = @Queue(value = MqConst.QUEUE_GOODS_LOWER, durable = "true"),exchange = @Exchange(value = MqConst.EXCHANGE_GOODS_DIRECT), //交换器key = {MqConst.ROUTING_GOODS_LOWER} //路由器))public void lowerSku(Long skuId, Message message, Channel channel) throws IOException {try {if (skuId != null) {skuService.lowerSku(skuId);}channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);}catch (IOException e) {System.out.print("john:IOException occurred while processing message");throw e;  // 或者处理该异常}}
}

注意着的对应关系:

public boolean sendMsg(String exchange, String routingKey, Object message

sendMsg中的 Object message 被 public MessageConverter messageConverter() 正确解析成了 Long skuId

upperSku(Long skuId, Message message, Channel channel)

至此,rabbitmq完成了从service-product传递一个skuId到service-serach的动作。

若有消息发送送时,界面中会出翔对应的消息队列的名称:

4.将数据存入elasticsearch进行高效搜索

elasticsearch的配置

下载elasticsearch Past Releases of Elastic Stack Software | Elastic, elasticsearch-7.8.0-windows-x86_64.zip (注意版本不对,会有兼容性问题)

下载对应版本的分词器:elasticsearch-analysis-ik-7.8.0.zip 

下载 kibana来进行客户端操作 kibana-7.8.0-windows-x86_64.zip

解压 elasticsearch-7.8.0-windows-x86_64文件,在

path\elasticsearch-7.8.0-windows-x86_64\elasticsearch-7.8.0\plugins\ 目录下新建文件夹,命名为ik,解压elasticsearch-analysis-ik-7.8.0,将内容所有内容copy到ik目录中:

在 es目录下运行 .\bin\elasticsearch.bat 启动es:

可以看到启动成功了:

浏览器界面看下 http://localhost:9200/ ,出现下面界面,说明启动成功

配置kibana

下载,解压,修改如下3个配置 (不同版本可能不一样,有增加或者删除项):

启动kibana:

 .\bin\kibana.bat

浏览器访问看下:http://127.0.0.1:5601/ 

分词器的测试:

代码配置

首先定义一个存储仓库对应的类  SkuRepository, 继承自 ElasticsearchRepository:

package com.atguigu.ssyx.search.repository;
import com.atguigu.ssyx.model.search.SkuEs;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;public interface SkuRepository extends ElasticsearchRepository<SkuEs, Long> {
}

使用 skuRepository.save(skuEs) 方法,即可存入 es仓库中。

使用 skuRepository.deleteById(skuId); 即可从仓库中删除。 

使用 ProductFeignClient 进行跨服务访问

因为service-serach要使用service-product的信息,但时两个服务,这是需要使用 ProductFeignClient 进行restful风格的api传递参数,进行远程调用。

首先需要pom中引入依赖:

<!-- 服务调用feign -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><scope>provided </scope>
</dependency>

在对应的 service-serach的application-dev.yml中进行配置:

在主程序中药加入远程调用注释: @EnableFeignClients 

然后,定义service-product中的api,将参数传入到指定的api接口:

package com.atguigu.ssyx.product.api;import com.atguigu.ssyx.model.product.Category;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.product.service.CategoryService;
import com.atguigu.ssyx.product.service.SkuInfoService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
// 内部调用,不是前端调用
@RequestMapping("/api/product") //该类是为了内部调用,供service-search使用,所以命名为内部inner
public class ProductInnerController {@Autowiredprivate CategoryService categoryService;@Autowiredprivate SkuInfoService skuInfoService;//根据categoryId获取商品的category信息@ApiOperation(value = "根据categoryId获取商品的category信息")@GetMapping("inner/getCategory/{categoryId}")public Category getCategoryById(@PathVariable("categoryId") Long categoryId) {return categoryService.getById(categoryId);}//根据skuId获取skuInfo@ApiOperation(value = "根据skuId获取skuInfo信息")@GetMapping("inner/getSkuInfo/{skuId}")public SkuInfo getSkuInfoById(@PathVariable("skuId") Long skuId) {return skuInfoService.getById(skuId);}}

定义使用该api的函数,并使用@FeignClient 注明从哪个模块进行api的对接:

package com.atguigu.ssyx.client.product;import com.atguigu.ssyx.model.product.Category;
import com.atguigu.ssyx.model.product.SkuInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;//与service\service-product\src\main\resources\application.yml中的application。name名称一致
@FeignClient(value = "service-product")
public interface ProductFeignClient {//作为\service\service-product中的\product\api\ProductInnerController.java//中函数的接口定义文件//注意要使用完整的restful风格的路径//用于远程调用(service-search远程调用service-product)@GetMapping("/api/product/inner/getCategory/{categoryId}")public Category getCategoryById(@PathVariable("categoryId") Long categoryId);@GetMapping("/api/product/inner/getSkuInfo/{skuId}")public SkuInfo getSkuInfoById(@PathVariable("skuId") Long skuId);}

定义feign对象 productFeignClient,调用api对应的函数接口:

SkuInfo skuInfo = productFeignClient.getSkuInfoById(skuId);
// ...
Category category = productFeignClient.getCategoryById(skuInfo.getCategoryId());
package com.atguigu.ssyx.search.service.impl;import com.alibaba.fastjson.JSON;
import com.atguigu.ssyx.client.product.ProductFeignClient;
import com.atguigu.ssyx.enums.SkuType;
import com.atguigu.ssyx.model.product.Category;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.model.search.SkuEs;
import com.atguigu.ssyx.search.repository.SkuRepository;
import com.atguigu.ssyx.search.service.SkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;@Slf4j
@Service
public class SkuServiceImpl implements SkuService {//通过service-product-client中的feign远程调用service-product中的方法@Autowiredprivate ProductFeignClient productFeignClient;//写入ES,即ElasticsearchRepository的接口类@Autowiredprivate SkuRepository skuRepository;@Overridepublic void upperSku(Long skuId) {SkuEs skuEs = new SkuEs();//为skuEs一个一个属性赋值SkuInfo skuInfo = productFeignClient.getSkuInfoById(skuId);if (skuInfo == null) {return;}Category category = productFeignClient.getCategoryById(skuInfo.getCategoryId());if (category != null) {skuEs.setCategoryId(category.getId());skuEs.setCategoryName(category.getName());}skuEs.setId(skuInfo.getId());skuEs.setKeyword(skuInfo.getSkuName() + "," + skuEs.getCategoryName()); //keyword不分词查询skuEs.setWareId(skuInfo.getWareId());skuEs.setIsNewPerson(skuInfo.getIsNewPerson());skuEs.setImgUrl(skuInfo.getImgUrl());//分词查询的字段数据类型必须是 FieldType.TextskuEs.setTitle(skuInfo.getSkuName());if (skuInfo.getSkuType() == SkuType.COMMON.getCode()) //普通还是秒杀{skuEs.setSkuType(0);skuEs.setPrice(skuInfo.getPrice().doubleValue());skuEs.setStock(skuInfo.getStock()); //仓库数量skuEs.setSale(skuInfo.getSale());skuEs.setPerLimit(skuInfo.getPerLimit()); //每人限购数量} else {//TODO 待完善-秒杀商品}//使用 ElasticsearchRepository 提供的方法保存ES信息SkuEs save = skuRepository.save(skuEs);System.out.print("upperSku:" + JSON.toJSONString(save));}@Overridepublic void lowerSku(Long skuId) {//使用 ElasticsearchRepository 提供的方法删除ES信息skuRepository.deleteById(skuId);}
}

5. 效果验证

实验中的表的名称是skues:

对应

public interface SkuRepository extends ElasticsearchRepository<SkuEs, Long> {
}

对应代码中的名称: 

当服务中的  public void upperSku(Long skuId) 被调用时,即 skuRepository.save(skuEs);被调用时,对应的数据就会写入 es中,可在 kibana中进行查看:

使用下面命令进行查看:

GET /_cat/indices?v

查看更多数据,(数据结构取决于自己数据库和代码中对数据的定义):

使用如下命令,其中skues为你的index (表名)名称

POST /skues/_search
{"query":{"match_all":{}}
}

结果有了:

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

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

相关文章

Github Copilot学习笔记

&#xff08;一&#xff09;Prompt Engineering 利用AI工具生成prompt设计好的prompt结构使用MarkDown语法&#xff0c;按Role, Skills, Constrains, Background, Requirements和Demo这几个维度描述需求。然后收输入提示词&#xff1a;作为 [Role], 拥有 [Skills], 严格遵守 […

android分区和root

线刷包内容&#xff1a; 线刷包是一个完整的android镜像&#xff0c;不但包括android、linux和用户数据&#xff0c;还包括recovery等。当然此图中没有recovery,但是我们可以自己刷入一个。 主要分区 system.img 系统分区&#xff0c;包括linux下主要的二进制程序。 boot.img…

RabbitMQ基础(简单易懂)

RabbitMQ高级篇请看&#xff1a; RabbitMQ高级篇-CSDN博客 目录 什么是RabbitMQ&#xff1f; MQ 的核心概念 1. RabbitMQ 的核心组件 2. Exchange 的类型 3. 数据流向说明 如何安装RabbitQueue&#xff1f; WorkQueue&#xff08;工作队列&#xff09;&#xff1a; Fa…

大数据环境搭建进度

1.使用虚拟机的系统&#xff1a;centos7.xLinux 2.资源不足&#xff0c;使用云服务器&#xff1a; 1. 3.使用远程登录进行操作 用xshell 4.任务 1.虚拟机装好 2.设置IP地址 3.可以联网 4.设置远程登录访问 5.创建module和software目录&#xff0c;修改两…

Mysql--运维篇--主从复制和集群(主从复制I/O线程,SQL线程,二进制日志,中继日志,集群NDB)

一、主从复制 MySQL的主从复制&#xff08;Master-Slave Replication&#xff09;是一种数据冗余和高可用性的解决方案&#xff0c;它通过将一个或多个从服务器&#xff08;Slave&#xff09;与主服务器&#xff08;Master&#xff09;同步来实现。主从复制的基本原理是&#…

【EI会议征稿通知】第十一届机械工程、材料和自动化技术国际会议(MMEAT 2025)

本次大会旨在汇聚全球机械工程、材料科学及自动化技术的创新学者和行业专家&#xff0c;为他们提供一个卓越的交流与合作平台。随着全球对可持续技术和智能制造需求的不断增加&#xff0c;MMEAT 2025将重点关注这些领域的最新发展趋势和未来前景。此次大会的主要目标是推动机械…

OpenCV基础:视频的采集、读取与录制

从摄像头采集视频 相关接口 - VideoCapture VideoCapture 用于从视频文件、摄像头或其他视频流设备中读取视频帧。它可以捕捉来自多种源的视频。 主要参数&#xff1a; cv2.VideoCapture(source): source: 这是一个整数或字符串&#xff0c;表示视频的来源。 如果是整数&a…

解读Linux Bridge中的东西流向与南北流向

解读Linux Bridge中的东西流向与南北流向 在现代云计算和虚拟化环境中&#xff0c;网络流量的管理和优化变得越来越重要。Linux Bridge作为Linux内核提供的一个强大的二层交换机工具&#xff0c;在虚拟化和容器化应用中扮演着至关重要的角色。本文将深入探讨Linux Bridge中的两…

车联网安全--TLS握手过程详解

目录 1. TLS协议概述 2. 为什么要握手 2.1 Hello 2.2 协商 2.3 同意 3.总共握了几次手&#xff1f; 1. TLS协议概述 车内各ECU间基于CAN的安全通讯--SecOC&#xff0c;想必现目前多数通信工程师们都已经搞的差不多了&#xff08;不要再问FvM了&#xff09;&#xff1b;…

RuoYi Cloud项目解读【四、项目配置与启动】

四、项目配置与启动 当上面环境全部准备好之后&#xff0c;接下来就是项目配置。需要将项目相关配置修改成当前相关环境。 1 后端配置 1.1 数据库 创建数据库ry-cloud并导入数据脚本ry_2024xxxx.sql&#xff08;必须&#xff09;&#xff0c;quartz.sql&#xff08;可选&…

第432场周赛:跳过交替单元格的之字形遍历、机器人可以获得的最大金币数、图的最大边权的最小值、统计 K 次操作以内得到非递减子数组的数目

Q1、跳过交替单元格的之字形遍历 1、题目描述 给你一个 m x n 的二维数组 grid&#xff0c;数组由 正整数 组成。 你的任务是以 之字形 遍历 grid&#xff0c;同时跳过每个 交替 的单元格。 之字形遍历的定义如下&#xff1a; 从左上角的单元格 (0, 0) 开始。在当前行中向…

Harry技术添加存储(minio、aliyun oss)、短信sms(aliyun、模拟)、邮件发送等功能

Harry技术添加存储&#xff08;minio、aliyun oss&#xff09;、短信sms&#xff08;aliyun、模拟&#xff09;、邮件发送等功能 基于SpringBoot3Vue3前后端分离的Java快速开发框架 项目简介&#xff1a;基于 JDK 17、Spring Boot 3、Spring Security 6、JWT、Redis、Mybatis-P…

R数据分析:多分类问题预测模型的ROC做法及解释

有同学做了个多分类的预测模型,结局有三个类别,做的模型包括多分类逻辑回归、随机森林和决策树,多分类逻辑回归是用ROC曲线并报告AUC作为模型评估的,后面两种模型报告了混淆矩阵,审稿人就提出要统一模型评估指标。那么肯定是统一成ROC了,刚好借这个机会给大家讲讲ROC在多…

记一次学习skynet中的C/Lua接口编程解析protobuf过程

1.引言 最近在学习skynet过程中发现在网络收发数据的过程中数据都是裸奔&#xff0c;就想加入一种数据序列化方式&#xff0c;json、xml简单好用&#xff0c;但我就是不想用&#xff0c;于是就想到了protobuf&#xff0c;对于protobuf C/C的使用个人感觉有点重&#xff0c;正好…

SQLAlchemy

https://docs.sqlalchemy.org.cn/en/20/orm/quickstart.htmlhttps://docs.sqlalchemy.org.cn/en/20/orm/quickstart.html 声明模型 在这里&#xff0c;我们定义模块级构造&#xff0c;这些构造将构成我们从数据库中查询的结构。这种结构被称为 声明式映射&#xff0c;它同时定…

Trimble自动化激光监测支持历史遗产实现可持续发展【沪敖3D】

故事桥&#xff08;Story Bridge&#xff09;位于澳大利亚布里斯班&#xff0c;建造于1940年&#xff0c;全长777米&#xff0c;横跨布里斯班河&#xff0c;可载汽车、自行车和行人往返于布里斯班的北部和南部郊区。故事桥是澳大利亚最长的悬臂桥&#xff0c;是全世界两座手工建…

Playwright vs Selenium:全面对比分析

在现代软件开发中&#xff0c;自动化测试工具在保证应用质量和加快开发周期方面发挥着至关重要的作用。Selenium 作为自动化测试领域的老牌工具&#xff0c;长期以来被广泛使用。而近年来&#xff0c;Playwright 作为新兴工具迅速崛起&#xff0c;吸引了众多开发者的关注。那么…

Windows 程序设计3:宽窄字节的区别及重要性

文章目录 前言一、宽窄字节简介二、操作系统及VS编译器对宽窄字节的编码支持1. 操作系统2. 编译器 三、宽窄字符串的优缺点四、宽窄字节数据类型总结 前言 Windows 程序设计3&#xff1a;宽窄字节的区别及重要性。 一、宽窄字节简介 在C中&#xff0c;常用的字符串指针就是ch…

进阶——十六届蓝桥杯嵌入式熟练度练习(LED的全开,全闭,点亮指定灯,交替闪烁,PWM控制LED呼吸灯)

点亮灯的函数 void led_show(unsigned char upled) { HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOC,upled<<8,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RE…

力扣 最大子数组和

动态规划&#xff0c;前缀和&#xff0c;维护状态更新。 题目 从题可以看出&#xff0c;找的是最大和的连续子数组&#xff0c;即一个数组中的其中一个连续部分。从前往后遍历&#xff0c;每遍历到一个数可以尝试做叠加&#xff0c;注意是尝试&#xff0c;因为有可能会遇到一个…