高并发项目-分布式Session解决方案

分布式Session解决方案

1.保存Session,进入商品列表页面

1.保存Session
1.编写工具类
1.MD5Util.java
package com.sxs.seckill.utils;import org.apache.commons.codec.digest.DigestUtils;/*** Description: MD5加密工具类** @Author sun* @Create 2024/5/5 14:23* @Version 1.0*/
public class MD5Util {/*** 将一个字符串转换为MD5* @param src* @return*/public static String md5(String src) {return DigestUtils.md5Hex(src);}// 固定的saltpublic static final String SALT = "4tIY5VcX";// 第一次加密加盐public static String inputPassToMidPass(String inputPass) {// 加盐String str = SALT.charAt(0) + inputPass + SALT.charAt(6);return md5(str);}/*** 第二次加密加盐* @param midPass* @param salt* @return*/public static String midPassToDBPass(String midPass, String salt) {String str = salt.charAt(0) + midPass + salt.charAt(5);return md5(str);}/*** 两次加密* @param input* @param saltDB* @return*/public static String inputPassToDBPass(String input, String saltDB) {String midPass = inputPassToMidPass(input);String dbPass = midPassToDBPass(midPass, saltDB);return dbPass;}
}
2.CookieUtil.java
package com.sxs.seckill.utils;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;/*** Description: Cookie工具类** @Author sun* @Create 2024/5/6 16:04* @Version 1.0*/public class CookieUtil {/*** 得到 Cookie 的值, 不编码** @param request* @param cookieName* @return*/public static String getCookieValue(HttpServletRequest request, StringcookieName) {return getCookieValue(request, cookieName, false);}/*** 得到 Cookie 的值, *** @param request* @param cookieName* @return*/public static String getCookieValue(HttpServletRequest request, StringcookieName, boolean isDecoder) {Cookie[] cookieList = request.getCookies();if (cookieList == null || cookieName == null) {return null;}String retValue = null;try {for (int i = 0; i < cookieList.length; i++) {if (cookieList[i].getName().equals(cookieName)) {if (isDecoder) {retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");} else {retValue = cookieList[i].getValue();}break;}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return retValue;}/*** 得到 Cookie 的值, *** @param request* @param cookieName* @param encodeString* @return*/public static String getCookieValue(HttpServletRequest request, StringcookieName, String encodeString) {Cookie[] cookieList = request.getCookies();if (cookieList == null || cookieName == null) {return null;}String retValue = null;try {for (int i = 0; i < cookieList.length; i++) {if (cookieList[i].getName().equals(cookieName)) {retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);break;}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return retValue;}/*** 设置 Cookie 的值 不设置生效时间默认浏览器关闭即失效,也不编码*/public static void setCookie(HttpServletRequest request, HttpServletResponseresponse, String cookieName, String cookieValue) {setCookie(request, response, cookieName, cookieValue, -1);}/*** 设置 Cookie 的值 在指定时间内生效,但不编码*/public static void setCookie(HttpServletRequest request, HttpServletResponseresponse, String cookieName, String cookieValue, int cookieMaxage) {setCookie(request, response, cookieName, cookieValue, cookieMaxage,false);}/*** 设置 Cookie 的值 不设置生效时间,但编码*/public static void setCookie(HttpServletRequest request, HttpServletResponseresponse, String cookieName, String cookieValue, boolean isEncode) {setCookie(request, response, cookieName, cookieValue, -1, isEncode);}/*** 设置 Cookie 的值 在指定时间内生效, 编码参数*/public static void setCookie(HttpServletRequest request, HttpServletResponseresponse, String cookieName, String cookieValue, int cookieMaxage, booleanisEncode) {doSetCookie(request, response, cookieName, cookieValue, cookieMaxage,isEncode);}/*** 设置 Cookie 的值 在指定时间内生效, 编码参数(指定编码)*/public static void setCookie(HttpServletRequest request, HttpServletResponseresponse, String cookieName, String cookieValue, int cookieMaxage, StringencodeString) {doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);}/*** 删除 Cookie 带 cookie 域名*/public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) {doSetCookie(request, response, cookieName, "", -1, false);}/*** 设置 Cookie 的值,并使其在指定时间内生效** @param cookieMaxage cookie 生效的最大秒数*/private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue,int cookieMaxage, boolean isEncode) {try {if (cookieValue == null) {cookieValue = "";} else if (isEncode) {cookieValue = URLEncoder.encode(cookieValue, "utf-8");}Cookie cookie = new Cookie(cookieName, cookieValue);if (cookieMaxage > 0) {cookie.setMaxAge(cookieMaxage);}// if (null != request) {// 设置域名的 cookie// String domainName = getDomainName(request);// if (!"localhost".equals(domainName)) {// cookie.setDomain(domainName);// }// }cookie.setPath("/");response.addCookie(cookie);} catch (Exception e) {e.printStackTrace();}}/*** 设置 Cookie 的值,并使其在指定时间内生效** @param cookieMaxage cookie 生效的最大秒数*/private static final void doSetCookie(HttpServletRequest request,HttpServletResponse response, String cookieName, String cookieValue,int cookieMaxage, String encodeString) {try {if (cookieValue == null) {cookieValue = "";} else {cookieValue = URLEncoder.encode(cookieValue, encodeString);}Cookie cookie = new Cookie(cookieName, cookieValue);if (cookieMaxage > 0) {cookie.setMaxAge(cookieMaxage);}if (null != request) {// 设置域名的 cookieString domainName = getDomainName(request);System.out.println(domainName);if (!"localhost".equals(domainName)) {cookie.setDomain(domainName);}}cookie.setPath("/");response.addCookie(cookie);} catch (Exception e) {e.printStackTrace();}}/*** 得到 cookie 的域名*/private static final String getDomainName(HttpServletRequest request) {String domainName = null;// 通过 request 对象获取访问的 url 地址String serverName = request.getRequestURL().toString();if ("".equals(serverName)) {domainName = "";} else {// 将 url 地下转换为小写serverName = serverName.toLowerCase();// 如果 url 地址是以 http://开头 将 http://截取if (serverName.startsWith("http://")) {serverName = serverName.substring(7);}int end = serverName.length();// 判断 url 地址是否包含"/"if (serverName.contains("/")) {// 得到第一个"/"出现的位置end = serverName.indexOf("/");}// 截取serverName = serverName.substring(0, end);// 根据"."进行分割final String[] domains = serverName.split("\\.");int len = domains.length;if (len > 3) {// www.abc.com.cndomainName = domains[len - 3] + "." + domains[len - 2] + "." +domains[len - 1];} else if (len > 1) {// abc.com or abc.cndomainName = domains[len - 2] + "." + domains[len - 1];} else {domainName = serverName;}}if (domainName.indexOf(":") > 0) {String[] ary = domainName.split("\\:");domainName = ary[0];}return domainName;}
}
2.关于session和cookie关系的回顾
  • 当浏览器请求到服务端时cookie会携带sessionid
  • 然后在服务端getSession时会得到当前用户的session
  • cookie-sessionid 连接到session
3.修改UserServiceImpl.java的doLogin方法,增加保存信息到session的逻辑

image-20240506180654918

4.测试,用户票据成功保存到cookie中

image-20240506164400785

2.访问到商品列表页面
1.编写GoodsController.java 验证用户登录后进入商品列表页
package com.sxs.seckill.controller;import com.sxs.seckill.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpSession;/*** Description:** @Author sun* @Create 2024/5/6 18:16* @Version 1.0*/
@Controller
@Slf4j
@RequestMapping("/goods")
public class GoodsController {// 进入到商品首页@RequestMapping("/toList")public String toList(HttpSession session, Model model, @CookieValue("userTicket") String ticket) {// 首先判断是否有票据if (null == ticket) {return "login";}// 根据票据来获取用户信息User user = (User) session.getAttribute(ticket);if (null == user) {return "login";}// 将用户信息存入model中,返回到前端model.addAttribute("user", user);return "goodsList";}
}
2.商品列表页goodsList.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>商品列表</title>
</head>
<body>
<h1>商品列表</h1>
<p th:text="'hi: ' + ${user.nickname}"></p>
</body>
</html>
3.测试登录成功后进入商品列表页

image-20240506182533204

image-20240506182619668

2.分布式session解决方案

1.session绑定/粘滞(不常用)

image-20240507084426254

image-20240507084410603

2.session复制

image-20240507084606158

image-20240507084657719

3.前端存储

image-20240507084727017

4.后端集中存储

image-20240507084749944

3.方案一:SpringSession实现分布式Session

1.安装使用redis-desktop-manager
1.一直下一步,安装到D盘

image-20240507085744926

2.首先要确保redis集群的端口是开放的并使其支持远程访问(之前配置过)
3.使用telnet指令测试某个服务是否能够连接成功
telnet 140.143.164.206 7489

image-20240507090655656

4.连接Redis,先测试连接然后确定

image-20240507091103602

5.在redis命令行设置两个键

image-20240507091252851

6.在可视化工具查看

image-20240507091332860

2.项目整合Redis并配置分布式session
1.pom.xml引入依赖
        <!--spring data redis 依赖, 即 spring 整合 redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.4.5</version></dependency><!--pool2 对象池依赖--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.9.0</version></dependency><!--实现分布式 session, 即将 Session 保存到指定的 Redis--><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId></dependency>
2.application.yml配置Redis
spring:redis:password:  # Redis服务器密码database: 0 # 默认数据库为0号timeout: 10000ms # 连接超时时间是10000毫秒lettuce:pool:max-active: 8 # 最大活跃连接数,使用负值表示没有限制,最佳配置为核数*2max-wait: 10000ms # 最大等待时间,单位为毫秒,使用负值表示没有限制,这里设置为10秒max-idle: 200 # 最大空闲连接数min-idle: 5 # 最小空闲连接数cluster:nodes:- - 

image-20240507094324857

3.启动测试
1.登录

image-20240507094643899

2.Redis可视化工具发现session成功存到redis

image-20240507094628773

image-20240507095339215

4.方案二:统一存放用户信息到Redis

1.修改pom.xml,去掉分布式springsession的依赖

image-20240507103646670

2.将用户信息放到Redis
1.添加Redis配置类 com/sxs/seckill/config/RedisConfig.java
package com.sxs.seckill.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;/*** Description:** @Author sun* @Create 2024/4/29 21:29* @Version 1.0*/
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template =new RedisTemplate<>();System.out.println("template=>" + template);RedisSerializer<String> redisSerializer =new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);jackson2JsonRedisSerializer.setObjectMapper(om);template.setConnectionFactory(factory);// key 序列化方式template.setKeySerializer(redisSerializer);// value 序列化template.setValueSerializer(jackson2JsonRedisSerializer);// value hashmap 序列化template.setHashValueSerializer(jackson2JsonRedisSerializer);return template;}@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer =new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = newJackson2JsonRedisSerializer(Object.class);// 解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);jackson2JsonRedisSerializer.setObjectMapper(om);// 配置序列化(解决乱码的问题),过期时间 600 秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).disableCachingNullValues();RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();return cacheManager;}
}
2.修改 com/sxs/seckill/service/impl/UserServiceImpl.java
1.注入RedisTemplate

image-20240507104718538

2.修改doLogin方法,将用户信息放到Redis中

image-20240507104748489

3.启动测试
1.登录

image-20240507105110074

2.可视化工具查看用户信息

image-20240507105302615

3.实现使用Redis + Cookie实现登录,可以访问商品列表页面
1.刚才已经实现了Redis记录信息的功能,但是校验还没实现,修改GoodsController.java完成校验
1.注入RedisTemplate

image-20240507110303645

2.从Redis中获取校验信息,进行校验

image-20240507110342489

2.测试
1.登录成功后访问商品列表页面

image-20240507110534647

5.扩展:自定义参数解析器,直接获取User

1.修改 com/sxs/seckill/controller/GoodsController.java 使参数直接为User
    // 进入到商品首页@RequestMapping("/toList")public String toList(Model model, User user) {// 判断是否有用户信息if (null == user) {return "login";}// 将用户信息存入model中,返回到前端model.addAttribute("user", user);return "goodsList";}
2.service层添加方法,通过票据从Redis中获取User对象
1.UserService.java
    /*** 根据cookie获取用户* @param userTicket* @param request* @param response* @return*/public User getUserByCookie(String userTicket, HttpServletRequest request, HttpServletResponse response);
2.UserServiceImpl.java
  • 这里需要注意,每次获取完User,需要重新设置Cookie,来刷新Cookie的时间
  • 原因是,调用这个的目的是为了校验,而用户访问每个页面都要进行校验,如果每次校验之后都不刷新Cookie的时间,一旦Cookie失效了,用户就要重新登陆
    @Overridepublic User getUserByCookie(String userTicket, HttpServletRequest request, HttpServletResponse response) {// 判断是否有票据if (null == userTicket) {return null;}// 根据票据来获取用户信息,从redis中获取User user = (User) redisTemplate.opsForValue().get("user:" + userTicket);if (null == user) {return null;}// 重新设置cookie的有效时间CookieUtil.setCookie(request, response, "userTicket", userTicket);return user;}
3.编写自定义参数解析器对User类型参数进行解析 config/UserArgumentResolver.java
package com.sxs.seckill.config;import com.sxs.seckill.pojo.User;
import com.sxs.seckill.service.UserService;
import com.sxs.seckill.utils.CookieUtil;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** Description: 自定义参数解析器** @Author sun* @Create 2024/5/7 14:39* @Version 1.0*/
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {@Resourceprivate UserService userService;/** 判断是否支持要转换的参数类型,简单来说,就是在这里设置要解析的参数类型*/@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {// 如果参数类型是User,则进行解析Class<?> parameterType = methodParameter.getParameterType();if (parameterType == User.class) {return true;}return false;}/*** 编写参数解析的逻辑** @param methodParameter* @param modelAndViewContainer* @param nativeWebRequest* @param webDataBinderFactory* @return* @throws Exception*/@Overridepublic Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {// 首先获取request和responseHttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);// 从cookie中获取票据String userTicket = CookieUtil.getCookieValue(request, "userTicket");// 如果票据为空,则返回nullif (null == userTicket) {return null;}// 如果票据不为空,则根据票据获取用户信息User user = this.userService.getUserByCookie(userTicket, request, response);return user;}
}
4.编写config/WebConfig.java 将自定义参数解析器放到 resolvers 才能生效
package com.sxs.seckill.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;
import java.util.List;/*** Description:** @Author sun* @Create 2024/5/7 14:53* @Version 1.0*/
@Configuration
// @EnableWebMvc 使用这个注解会导致SpringBoot的自动配置失效,一切都要自己配置,所以建议不要使用这个注解
public class WebConfig implements WebMvcConfigurer {// 注入自定义参数解析器@Resourceprivate UserArgumentResolver userArgumentResolver;/*** 静态资源加载,静态资源放在哪里就怎么配置* @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");}/*** 添加自定义参数解析器到resolvers中,才能生效* @param resolvers*/@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {resolvers.add(userArgumentResolver);}
}
5.测试
1.在登录之后,可以正常访问商品列表页面

image-20240507151255032

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

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

相关文章

Window系统安装Docker

因为docker只适合在liunx系统上运行&#xff0c;如果在window上安装的话&#xff0c;就需要开启window的虚拟化&#xff0c;打开控制面板&#xff0c;点击程序&#xff0c;在程序和功能中可以看到启动和关闭window功能&#xff0c;点开后&#xff0c;找到Hyper-V&#xff0c;Wi…

【环信IM集成教程】分分钟带你实现视频消息的在线播放和本地播放

有种需求&#xff0c;叫下班前实现 发送视频消息是即时通讯应用中很常见的功能&#xff0c;现在的视频播放场景五花八门&#xff0c;眼瞅快下班&#xff0c;接到产品需求 如何实现这个需求&#xff0c;好准点下班回家抢显卡 &#xff0c;快速提升自己的工作效率&#xff0c;那…

yolov5-ros模型结合zed2相机部署在 Ubuntu系统

前言 本篇文章主要讲解yolov5-ros模型结合zed2相机进行实时检测&#xff0c;经改进实现了红绿灯检测&#xff0c;并输出检测类别与置信度&#xff01; 目录 一、环境配置二、zed2驱动安装三、yolov5-ros功能包配置四、运行官方权重文件四、运行自己权重文件 一、环境配置 1、…

vue2转vue3初步下载pnpm遇到的问题 pnpm : 无法加载文件 D:\nodejs\pnpm.ps1

安装pnpm npm install -g pnpm pnpm -v 提示&#xff1a; 解决&#xff1a;nvm install 18.18.0 下载最稳定版本的nodejs nvm use 18.18.0 然后注意重新下载删除pnpm npm uninstall -g pnpm npm install -g pnpmlatest 在vscode使用pnpm报错 解决&#xff1a;管理员运行Windo…

博士毕业论文/CTEX/LATEX

LATEX环境安装 CTEX 安装 &#xff08;垃圾&#xff0c;不要装&#xff09; 运行 clean.batcomp.bat 缺少字体 Couldn’t find Adobe Heiti S.cfg’ miktex-maketfm: No creation rule for font “Adobe Heiti Std”.解决方法&#xff1a;其实就是下载这四个字体之后&…

深度学习-语言模型

深度学习-语言模型 统计语言模型神经网络语言模型语言模型的应用序列模型&#xff08;Sequence Model&#xff09;语言模型&#xff08;Language Model&#xff09;序列模型和语言模型的区别 语言模型&#xff08;Language Model&#xff09;是自然语言处理&#xff08;NLP&…

16:00面试,16:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

32. 【Java教程】集合

在前面的小节中&#xff0c;我们学习了数组&#xff0c;本小节学习的集合同样用于存放一组数据&#xff0c;我们将学习什么是集合、集合的应用场景 &#xff0c;在应用场景部分我们将对比 Java 数组与集合的区别&#xff0c;还将系统介绍 Java 集合的架构&#xff0c;也将结合实…

【课程总结】Day4:信息论和决策树算法

前言 本章内容主要是学习机器学习中的一个重要模型&#xff1a;决策树&#xff0c;围绕决策树的应用&#xff0c;我们展开了解到&#xff1a;熵的定义、熵的计算、决策树的构建过程(基于快速降熵)、基尼系数等&#xff0c;从而使得我们对决策树有了直观认识。 熵的介绍 因为…

用HAL库改写江科大的stm32入门-6-3 PWM驱动LED呼吸灯

接线图&#xff1a; 2 :实验目的&#xff1a; 利用pwm实现呼吸灯。 关键PWM定时器设置&#xff1a; 代码部分&#xff1a; int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*…

10.Halcon3D点云和MESH的相互转换

1.实现效果 这个案例主要是想告诉我们,如何在点云数据(全是点)和MESH(网格数据)中转换,理论上说可以点云数据可以看作的离散的,而MESH网格数据可以看作是连续的。 上图展示了三个(其实是四个)空间中的3d对象,左边第一个是一个立方体,经过降采样之后的点云,中间的是…

匿名函数(lambda)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 匿名函数是指没有名字的函数&#xff0c;应用在需要一个函数&#xff0c;但是又不想费神去命名这个函数的场合。通常情况下&#xff0c;这样的函数只…

LabVIEW中进行步进电机的位置控制

在LabVIEW中进行步进电机的位置控制&#xff0c;通常涉及以下几个关键步骤&#xff1a;设置硬件、配置通信、编写控制算法和实施反馈控制。以下是一个详细的介绍。 硬件设置 步进电机&#xff1a;选择合适的步进电机&#xff0c;根据负载和应用需求选择适当的步数和转矩。 驱…

TensorFlow Playground神经网络演示工具使用方法详解

在现代机器学习领域,神经网络无疑是一个重要的研究方向。然而,对于许多初学者来说,神经网络的概念和实际操作可能显得相当复杂。幸运的是,TensorFlow Playground 提供了一个交互式的在线工具,使得我们可以直观地理解和实验神经网络的基本原理。在这篇博客中,我们将详细介…

IMU状态预积分代码实现 —— IMU状态预积分类

IMU状态预积分代码实现 —— IMU状态预积分类 实现IMU状态预积分类 实现IMU状态预积分类 首先&#xff0c;实现预积分自身的结构。一个预积分类应该存储一下数据&#xff1a; 预积分的观测量 △ R ~ i j , △ v ~ i j , △ p ~ i j \bigtriangleup \tilde{R} _{ij},\bigtrian…

Superset二次开发之更新 SECRET_KEY

SECRET_KEY 的作用 加密和签名:SECRET_KEY用于对敏感数据(如会话、cookie、CSRF令牌)进行加密和签名,防止数据被篡改。安全性:确保应用的安全性,防止跨站请求伪造(CSRF)攻击和会话劫持等安全问题。如何生成 SECRET_KEY openssl rand -base64 42 配置 SECRET_KEY 在sup…

git使用流程与规范

原文网址&#xff1a;git代码提交流程与规范-CSDN博客 简介 本文git提交流程与规范是宝贵靠谱的经验&#xff0c;它能解决如下问题&#xff1a; 分支差距过大&#xff0c;导致合代码无数的冲突合完代码后发现代码丢失分支不清晰&#xff0c;无法追溯问题合代码耗时很长&…

使用Spring Boot自定义注解 + AOP实现基于IP的接口限流和黑白名单

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

数据在内存中的存储<C语言>

导言 在计算机中不同类型的数据在计算机内部存储形式各不相同&#xff0c;弄懂各种数据在计算机内部存储形式是有必要的&#xff0c;C语言的学习不能浮于表面&#xff0c;更要锻炼我们的“内功”&#xff0c;将来在写程序的时候遇见各种稀奇古怪的bug时&#xff0c;也便能迎刃而…

应用案例|精密制造中使用复合机器人得到显著提升

精密制造行业对设备的精度、稳定性和效率要求极高&#xff0c;而复合机器人凭借其多功能性、高度灵活性和精准控制能力&#xff0c;正逐渐成为该领域的新宠。以下是一个富唯智能复合机器人在精密制造中的应用案例。 案例背景 某知名汽车零部件制造企业&#xff0c;专注于生产…