1、黑馬點評復盤(短信登錄-Session或Redis實現)

短信登錄分別使用session和redis實現

1、基于Session實現登錄

主要功能:

  1. 發送驗證碼
  2. 短信驗證碼登錄、注冊
  3. 校驗登錄狀態

1.1 實現發送短信驗證碼功能

1.1.1 業務邏輯

用戶在提交手機號后,會校驗手機號是否合法,如果不合法,則要求用戶重新輸入手機號

如果手機號合法,后臺此時生成對應的驗證碼,同時將驗證碼進行保存,然后再通過短信的方式將驗證碼發送給用戶

1.1.2 代碼實現

模擬發送短信驗證碼功能,把短信驗證碼控制臺打印

    @Overridepublic Result sendCode(String phone, HttpSession session) {// 1. 校驗手機號if (RegexUtils.isPhoneInvalid(phone)) {return Result.fail("手機號格式錯誤!");}// 2.生成驗證碼, 長度6位隨機數String code = RandomUtil.randomNumbers(CAPTCHA_LENGTH);// 3.保存驗證碼到sessionsession.setAttribute("code", code);// 4.發送驗證碼(模擬)log.info("發送驗證碼成功,驗證碼:{}", code);// 5.返回成功信息return Result.ok();}

代碼使用了Hutool的工具類,RegexUtils和RandomUtil,其中:

  1. RegexUtils.isPhoneInvalid() : 用于手機號格式校驗、郵箱校驗、驗證碼校驗。手機號格式,不滿足,返回true。
  2. RandomUtil.randomNumbers() : 生成隨機數

1.1.3 實現效果

1.2 實現短信驗證登錄、注冊功能

1.2.1 業務邏輯

用戶將驗證碼和手機號進行輸入,后臺從session中拿到當前驗證碼,然后和用戶輸入的驗證碼進行校驗,如果不一致,則無法通過校驗,如果一致,則后臺根據手機號查詢用戶,如果用戶不存在,則為用戶創建賬號信息,保存到數據庫,無論是否存在,都會將用戶信息保存到session中,方便后續獲得當前登錄信息

1.2.2 代碼實現

    @Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1.獲取手機號、驗證碼String phone = loginForm.getPhone();String code = loginForm.getCode();// 2.校驗驗證碼if (!code.equals(session.getAttribute(CAPTCHA))) {return Result.fail("驗證碼錯誤!");}// 3.根據手機號查詢用戶User user = this.lambdaQuery().eq(User::getPhone, phone).one();// 4.判斷用戶是否存在if (user == null) {// 4.1 不存在,創建新用戶,并保存到數據庫中user = createNewUser(phone);}// 4.2 存在,保存用戶到sessionLoginFormDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);session.setAttribute(USER_NICK_NAME, userDTO);// 5.返回成功信息return Result.ok();}/*** 創建新用戶* @param phone 手機號* @return User*/private User createNewUser(String phone) {User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(USER_NICK_NAME_APPEND_LENGTH));save(user);return user;}

代碼使用了Hutool的工具類,BeanUtil,其中:

  1. BeanUtil.copyProperties(user, UserDTO.class)? : 用于將user中的數據復制給UserDTO實體,其中字段和字段類型要保存一致。這步操作是用來,session存儲盡可能存儲少量數據,防止數據泄露。

1.2.3 實現效果

注意用Apifox實現這個操作,要先調用手機驗證碼接口,然后在調用用戶登錄接口,并且用戶登錄接口的驗證碼參數需要用到調用的手機驗證碼接口生成的驗證碼

1.2.4 tomcat的運行原理和ThreadLocal

1.2.4.1 tomcat的運行原理

當用戶發起請求時,會訪問我們像tomcat注冊的端口,任何程序想要運行,都需要有一個線程對當前端口號進行監聽,tomcat也不例外,當監聽線程知道用戶想要和tomcat連接連接時,那會由監聽線程創建socket連接,socket都是成對出現的,用戶通過socket像互相傳遞數據,當tomcat端的socket接受到數據后,此時監聽線程會從tomcat的線程池中取出一個線程執行用戶請求,在我們的服務部署到tomcat后,線程會找到用戶想要訪問的工程,然后用這個線程轉發到工程中的controller,service,dao中,并且訪問對應的DB,在用戶執行完請求后,再統一返回,再找到tomcat端的socket,再將數據寫回到用戶端的socket,完成請求和響應

通過以上講解,我們可以得知 每個用戶其實對應都是去找tomcat線程池中的一個線程來完成工作的, 使用完成后再進行回收,既然每個請求都是獨立的,所以在每個用戶去訪問我們的工程時,我們可以使用threadlocal來做到線程隔離,每個線程操作自己的一份數據

1.2.4.2 ThreadLocal

如果小伙伴們看過threadLocal的源碼,你會發現在threadLocal中,無論是他的put方法和他的get方法, 都是先從獲得當前用戶的線程,然后從線程中取出線程的成員變量map,只要線程不一樣,map就不一樣,所以可以通過這種方式來做到線程隔離

1.3 實現登錄校驗攔截器(ThreadLocal)

如果不用攔截器,每個controller都會先進行登錄校驗

1.3.1 業務邏輯

把攔截器攔截的用戶信息保存到ThreadLocal,因為ThreadLocal是線程,每一個進入tomcat的請求都是一個線程,ThreadLocal給每一個用戶開辟線程空間創建獨立線程。

1.3.2 代碼實現

/*** ThreadLocal 處理user信息*/
public class UserHolder {/*** 定義ThreadLocal常量*  這里使用UserDTO,是因為ThreadLocal存儲,只需要存儲少量數據,避免數據泄露*/private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();/*** 保存用戶** @param user*/public static void saveUser(UserDTO user) {tl.set(user);}/*** 從ThreadLocal獲取用戶** @return UserDTO*/public static UserDTO getUser() {return tl.get();}/*** 刪除用戶*/public static void removeUser() {tl.remove();}
}/*** 登錄攔截器*/
public class LoginInterceptor implements HandlerInterceptor {/*** 前置攔截* 登錄校驗* @param request 獲取session* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.從request中獲取sessionHttpSession session = request.getSession();// 2.獲取session中的用戶 userObject user = session.getAttribute(USER_NICK_NAME);// 3.判斷用戶是否存在if (user == null) {// 4.不存在,攔截 ,返回狀態碼401response.setStatus(UNAUTHORIZED);return false;}// 5.存在,保存用戶信息到ThreadLocalUserHolder.saveUser((UserDTO) user);// 6.放行return true;}/*** 渲染之后攔截* 用戶登錄完畢,銷毀登錄信息,避免用戶信息泄露* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用戶,避免數據泄露UserHolder.removeUser();}
}/*** 登錄攔截器生效*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {/*** 添加攔截器* @param registry 攔截器注冊器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加攔截器,并排除不需要攔截的路徑// ** 是通配符,表示任意registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/shop/**","/voucher/**","/shop-type/**","/upload/**","/blog/hot","/user/code","/user/login");}
}

2、Session實現登錄的弊端

session登錄會有session共享問題

每個tomcat中都有一份屬于自己的session,假設用戶第一次訪問第一臺tomcat,并且把自己的信息存放到第一臺服務器的session中,但是第二次這個用戶訪問到了第二臺tomcat,那么在第二臺服務器上,肯定沒有第一臺服務器存放的session,所以此時 整個登錄攔截功能就會出現問題,我們能如何解決這個問題呢?早期的方案是session拷貝,就是說雖然每個tomcat上都有不同的session,但是每當任意一臺服務器的session修改時,都會同步給其他的Tomcat服務器的session,這樣的話,就可以實現session的共享了

但是這種方案具有兩個大問題

1、每臺服務器中都有完整的一份session數據,服務器壓力過大。

2、session拷貝數據時,可能會出現延遲

所以咱們后來采用的方案都是基于redis來完成,我們把session換成redis,redis數據本身就是共享的,就可以避免session共享的問題了

3、基于Redis實現登錄

首先我們要思考一下利用redis來存儲數據,那么到底使用哪種結構呢?由于存入的數據比較簡單,我們可以考慮使用String,或者是使用哈希,如下圖,如果使用String,同學們注意他的value,用多占用一點空間,如果使用哈希,則他的value中只會存儲他數據本身,如果不是特別在意內存,其實使用String就可以啦。

3.1 實現發送短信驗證碼功能

3.1.1 業務邏輯

由原理存儲到session,改為存儲到redis中。

3.1.2 代碼實現

    @Overridepublic Result sendCode(String phone, HttpSession session) {// 1. 校驗手機號if (RegexUtils.isPhoneInvalid(phone)) {return Result.fail("手機號格式錯誤!");}// 2.生成驗證碼, 長度6位隨機數String code = RandomUtil.randomNumbers(CAPTCHA_LENGTH);// 3.保存驗證碼到redis,設置過期時間stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 4.發送驗證碼(模擬)log.info("發送驗證碼成功,驗證碼:{}", code);// 5.返回成功信息return Result.ok();}

3.1.3 Apifox調用接口,實現效果

小技巧:把有效期改為無效

3.2 實現短信驗證登錄、注冊功能

3.2.1 業務邏輯

當注冊完成后,用戶去登錄會去校驗用戶提交的手機號和驗證碼,是否一致,如果一致,則根據手機號查詢用戶信息,不存在則新建,最后將用戶數據保存到redis,并且生成token作為redis的key,當我們校驗用戶是否登錄時,會去攜帶著token進行訪問,從redis中取出token對應的value,判斷是否存在這個數據,如果沒有則攔截,如果存在則將其保存到threadLocal中,并且放行。

3.2.2 代碼實現

    @Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1.獲取手機號、驗證碼String phone = loginForm.getPhone();String code = loginForm.getCode();// 1. 校驗手機號if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合,返回錯誤信息return Result.fail("手機號格式錯誤!");}// 3.從redis中獲取驗證碼,校驗驗證碼String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);if (StrUtil.isBlank(cacheCode) && !code.equals(cacheCode)) {// 不一致,報錯return Result.fail("驗證碼錯誤!");}// 4.根據手機號查詢用戶User user = this.lambdaQuery().eq(User::getPhone, phone).one();// 5.判斷用戶是否存在if (user == null) {// 5.1 不存在,創建新用戶,并保存到數據庫中user = createNewUser(phone);}// 7.保存用戶信息到 redis中// 7.1.隨機生成token,作為登錄令牌String token = UUID.randomUUID().toString(true);// 7.2.將User對象轉為HashMap存儲UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((k, v) -> v.toString()));// 7.3.存儲stringRedisTemplate.opsForHash().putAll(LOGIN_USER_KEY + token, userMap);// 7.4.設置token有效期stringRedisTemplate.expire(LOGIN_USER_KEY + token, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.返回tokenreturn Result.ok(token);}/*** 創建新用戶* @param phone 手機號* @return User*/private User createNewUser(String phone) {User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(USER_NICK_NAME_APPEND_LENGTH));save(user);return user;}

代碼中使用Hutool的BeanUtil工具的beanToMap方法,把對象轉成Map

  1. ?Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((k, v) -> v.toString()));

3.2.3 實現效果

用Apifox調用接口,要先調用3.2.1,獲取驗證碼作為參數,然后在調用登錄接口

3.3 解決狀態登錄刷新問題

把token存儲到redis中,設置有效期,為了防止有效期失效,每當用戶訪問,就刷新token,讓token不失效。

3.3.1 業務邏輯(攔截器優化)

設置兩個攔截器,第一個攔截器用于刷新token,保存ThreadLocal。確保一切請求都觸發刷新token的動作。第二個攔截器,查ThreadLocal,不存在就攔截

3.3.2 代碼實現

/*** 第一個攔截器:刷新token、保存ThreadLocal* 攔截所有請求,只有要請求就攔截,然后進行刷新token有效期*/
public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.獲取請求頭中的tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}// 2.基于TOKEN獲取redis中的用戶String key  = LOGIN_USER_KEY + token;Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);// 3.判斷用戶是否存在if (userMap.isEmpty()) {return true;}// 5.將查詢到的hash數據轉為UserDTOUserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.存在,保存用戶信息到 ThreadLocalUserHolder.saveUser(userDTO);// 7.刷新token有效期stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用戶UserHolder.removeUser();}
}/*** 第二個攔截器,判斷ThreadLocal中是否有用戶信息*/
public class LoginInterceptor implements HandlerInterceptor {/*** 前置攔截* 登錄校驗* @param request 獲取session* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.判斷是否需要攔截(ThreadLocal中是否有用戶)if (UserHolder.getUser() == null) {// 沒有,需要攔截,設置狀態碼response.setStatus(UNAUTHORIZED);// 攔截return false;}// 有用戶,放行return true;}}/*** 登錄攔截器生效*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 添加攔截器* 給兩個攔截器后面加 order,用于決定誰先執行 值越小越先執行* @param registry 攔截器注冊器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 第二個攔截器,攔部分請求,登錄攔截器registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/shop/**","/voucher/**","/shop-type/**","/upload/**","/blog/hot","/user/code","/user/login").order(1);// 第一個攔截器,攔所有請求(/**),刷新token攔截器registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);}
}

上述代碼使用Hutool的BeanUtil工具的fillBeanWithMap方法,把Map轉實體。

  1. UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);

視頻學習:黑馬點評項目實戰,掌握企業實戰項目真實應用場景,一套精通redis緩存技術_嗶哩嗶哩_bilibili

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90307.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90307.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90307.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

文件管理困境如何破?ZFile+cpolar打造隨身云盤新體驗

文章目錄前言【視頻教程】1.關于ZFile2.本地部署ZFile3.使用ZFile4.ZFile的配置5.cpolar內網穿透工具安裝6.創建遠程連接公網地址7.固定ZFile公網地址前言 每天的數字生活如同在數據海洋中航行&#xff0c;工作文檔、旅行照片、學習資料…這些重要資產是否總讓你感到難以掌控&…

開源數據庫E-R圖繪制工具分享

1. 特點&#xff1a; 可直接使用&#xff0c;無需注冊賬號 無狀態的純前端工具&#xff0c;數據會存放在瀏覽器中。設計完成后可將數據保存到本地 2. 使用場景&#xff1a; 描述E-R圖&#xff0c;對數據庫表關系進行直觀分析 3. 效果&#xff1a; 4. 測試數據 用來測試的建…

安卓 Audio Thread 分析

一、PlaybackThread::threadLoop_write 1.變量 mFramesWritten 類型: int64_t 作用: 記錄從線程啟動以來已寫入音頻設備的幀數&#xff08;不包括掛起狀態下的寫入&#xff09; mSuspendedFrames 類型: int64_t 作用: 記錄線程在掛起&#xff08;suspended&#xff09;狀態下模…

JavaWeb_原始項目初識(一)

Students2025項目&#xff08;一&#xff09; 原始ServletJSP架構項目初步搭建 jsp項目已被淘汰&#xff0c;在此學習目的是了解未來學習的新技術的底層原理項目結構&#xff1a;項目結構介紹&#xff1a; 目前階段只完成了初始化的后端搭建&#xff0c;實現從本地數據庫獲取數…

前端_CSS復習

文章目錄CSS復習1. css三種引入方式1.1 行內樣式常用樣式&#xff1a;1.2頁內樣式常見選擇器&#xff1a;1. 標記選擇器2. id選擇器3. 類選擇器&#xff08;最常用&#xff09;4. 星號選擇器&#xff0c;頻率很低5. 復合選擇器6. 偽類選擇器&#xff1a;7. 子元素偽類1.3引入外…

工業互聯網時代,如何通過混合SD-WAN提升煤炭行業智能化網絡安全

1. 背景&#xff1a;煤炭行業智能化轉型的網絡挑戰隨著工業互聯網技術的普及&#xff0c;煤炭行業智能化轉型進入加速期。選煤廠作為煤炭生產的核心環節&#xff0c;需要構建一套既安全又高效的網絡系統&#xff0c;以滿足工業控制系統&#xff08;ICS&#xff09;、智能設備和…

AI浪潮下數據中心的突圍者:臺達DPH Gen3系列UPS如何重構供電架構

2025年6月13日&#xff0c;臺達-中達電通資通訊基礎設施事業部聯合中國數據中心工作組&#xff08;CDCC&#xff09;在江蘇吳江舉辦"數據中心供配電技術革新與AI算力基礎設施未來展望研討會"&#xff0c;同時開展CDCC專家組工廠參觀。盛會匯聚了數據中心行業專家、互…

DiffServ服務模型與DS碼點詳解

1. DiffServ概述 DiffServ(Differentiated Services&#xff0c;差異化服務)是IETF定義的一種QoS(Quality of Service)體系結構&#xff0c;旨在為IP網絡提供可擴展的服務區分能力。與傳統的IntServ(集成服務)模型不同&#xff0c;DiffServ采用簡單、粗粒度的流量分類機制&…

基于 PIC16 系列的多功能電子煙(溫控 + 電壓控制 + 多模式)方案

基于 PIC16 系列的多功能電子煙&#xff08;溫控 電壓控制 多模式&#xff09;方案 一、芯片與最小系統推薦型號&#xff1a;PIC16F18313/18323 8-bit 內核&#xff0c;14/20-pin 小封裝&#xff0c;成本低28 MHz 內部振蕩&#xff0c;帶 10-bit ADC&#xff08;12 通道&…

小模數齒輪的加工方法有哪些?

小模數齒輪(一般指0.3≤Mn≤1)的加工方法有哪些呢&#xff1f;小模數齒輪的加工方法主要分為減材、增材、變形加工三類&#xff1a; 去材料制造 有銑齒、滾齒、插齒、刨齒、剃齒、拉齒、沖齒、研磨、珩齒、磨齒及其拋光、線切割等。 增材制造 有注塑&#xff08;塑料、尼龍&…

若依前后端分離版學習筆記(二)——系統菜單介紹

前言&#xff1a; 這一節是將ruoyi的前端界面過一遍&#xff0c;查看所有系統菜單及頁面功能&#xff0c;為后續代碼學習做準備。&#xff08;注意&#xff1a;文中包含大量截圖&#xff0c;截圖為從本地啟動的3.9.0 vue3的前端界面。&#xff09; 一 系統管理 1 用戶管理 主要…

VRRP技術-設備備份技術

一、VRRP的概念及應用場景1.定義在 VRRP&#xff08;虛擬路由冗余協議&#xff09;中&#xff0c;將多個路由器邏輯上看作一個路由器時所使用的虛擬 IP 地址&#xff0c;需要滿足以下要求&#xff1a;這個虛擬 IP 地址必須與該 VRRP 組內所有物理路由器的接口 IP 地址處于同一網…

VUE2 學習筆記5 動態綁定class、條件渲染、列表過濾與排序

動態綁定class樣式&#xff1a;先設置css&#xff1a;<style>.styleBackgroundColor{background-color: aqua;}.styleContent{width:300px;height: 200px;}.styleBorder{border: 2px black solid;}</style>vue模版中&#xff0c;使用動態類名綁定&#xff0c;一般可…

推客系統全棧開發指南:從架構設計到高并發實戰

一、推客系統概述與市場前景推客系統&#xff08;也稱為"推客營銷系統"或"社交電商系統"&#xff09;是近年來快速崛起的社交化營銷工具&#xff0c;它通過整合社交網絡與電子商務功能&#xff0c;讓每個用戶都能成為產品的推廣者并獲得相應獎勵。市場數據…

RabbitMQ有多少種Exchange?

面試回答模板 “RabbitMQ 在 AMQP 協議中預定義了 四種常用交換機 兩種特殊類型&#xff0c;共 6 種&#xff1a; Direct&#xff1a;routing-key 全等匹配&#xff1b;Fanout &#xff1a;廣播&#xff0c;忽略 key&#xff1b;Topic&#xff1a;按 *.# 通配符匹配&#xff1…

ctfshow pwn43

1. 分析程序首先檢查程序相關保護&#xff0c;發現程序為32位且只開啟了一個NX保護checksec pwn使用IDA進行逆向分析代碼&#xff0c;查看漏洞觸發點&#xff1a;在main函數中&#xff0c;有一個ctfshow函數&#xff0c;這里我們跟進ctfshow()發現存在一個gets()函數&#xff0…

內網IM:BeeWorks私有化部署的安全通訊解決方案

在當今數字化辦公環境中&#xff0c;內網IM已成為企業保障數據安全的核心工具。BeeWorks作為一款支持私有化部署的內網IM解決方案&#xff0c;能夠幫助企業構建完全自主可控的通訊系統。無論是政府機構、金融機構&#xff0c;還是對數據安全要求極高的企業&#xff0c;BeeWorks…

SHA512算法詳解

SHA-512 是 SHA-2&#xff08;Secure Hash Algorithm 2&#xff09;系列密碼散列函數的重要成員&#xff0c;由美國國家安全局&#xff08;NSA&#xff09;設計&#xff0c;2001 年被納入 NIST&#xff08;美國國家標準與技術研究院&#xff09;的 FIPS 180 標準&#xff0c;后…

通過python管理vcenter中的虛擬機

通過python管理vcenter中的虛擬機因業務需要&#xff0c;需在夜間關閉虛擬機&#xff0c;隨通過計劃任務遠程管理開機、關機虛擬機一、通過docker配置python3.9環境 Dockerfile FROM python:3.9 RUN pip3 install pyvmomi7.0.0創建自定義鏡像 docker build -t pyvmomi7:v1 .二…

AWS S3 生命周期管理最佳實踐:IoT Core 日志的智能存儲優化

在現代物聯網應用中,設備日志數據的管理是一個重要挑戰。隨著設備數量的增長,日志數據量呈指數級增長,如何有效管理這些數據的存儲成本成為關鍵問題。本文將分享如何為 AWS IoT Core 日志實施智能生命周期管理策略。 背景與挑戰 IoT 設備產生的日志數據具有以下特點: 數據…