架構設計之自定義延遲雙刪緩存注解(下)

架構設計之自定義延遲雙刪緩存注解(下)

小薛博客官方架構設計之自定義延遲雙刪緩存注解(下)地址

為了保證@Cache@ClearAndReloadCache的靈活性,特意加入EL表達式解析

1、Cache

package com.xx.cache;import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;/*** @Author: xueqimiao* @Date: 2025/3/17 14:24*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cache {/*** 過期時間,默認60s* @return*/long expire() default 60 ;TimeUnit unit() default TimeUnit.SECONDS;/*** 緩存標識name* @return*/String name() default "";/*** SpringEL表達式,解析占位符對應的匹配value值* @return*/String matchValue();}

2、CacheAspect

package com.xx.cache;import com.xx.common.Result;
import com.xx.utils.RedisService;
import com.xx.utils.ValidationUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;/*** @Author: xueqimiao* @Date: 2025/3/17 14:25*/
@Component
@Aspect
@Slf4j
public class CacheAspect {@Resourceprivate RedisService redisService;/*** aop切點* 攔截被指定注解修飾的方法*/@Pointcut("@annotation(com.xx.cache.Cache)")public void cache() {}/*** 緩存操作** @param pjp* @return*/@Around("cache()")public Object toCache(ProceedingJoinPoint joinPoint) {Object result = null;try {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(),signature.getMethod().getParameterTypes());Cache annotation = method.getAnnotation(Cache.class);String matchedValue = annotation.matchValue();String keyPrefix = annotation.name();long time = annotation.expire();TimeUnit unit = annotation.unit();// 解析EL表達式SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(matchedValue);EvaluationContext context = new StandardEvaluationContext();// 獲取參數Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++) {context.setVariable(parameterNames[i], args[i]);}String key = keyPrefix + "::" + expression.getValue(context).toString();result = redisService.get(key);if (!ValidationUtil.isEmpty(result)) {return Result.ok(result);}// 執行目標方法result = joinPoint.proceed();Object res = result;if (result instanceof Result) {res = ((Result<?>) result).getResult();}redisService.set(key, res, time, unit);} catch (Throwable e) {throw new RuntimeException(e);}return result;}}

3、ClearAndReloadCache

package com.xx.cache;import java.lang.annotation.*;/*** @Author: xueqimiao* @Date: 2025/3/17 14:26*/
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
public @interface ClearAndReloadCache {/*** 緩存標識name* @return*/String name() default "";/*** SpringEL表達式,解析占位符對應的匹配value值* @return*/String matchValue();
}

4、ClearAndReloadCacheAspect

package com.xx.cache;import com.xx.utils.RedisUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** @Author: xueqimiao* @Date: 2025/3/17 14:26*/
@Aspect
@Component
@Slf4j
public class ClearAndReloadCacheAspect {@Resourceprivate RedisUtils redisUtils;/*** 切入點* 切入點,基于注解實現的切入點  加上該注解的都是Aop切面的切入點*/@Pointcut("@annotation(com.xx.cache.ClearAndReloadCache)")public void pointCut() {}/*** 環繞通知第一個參數必須是org.aspectj.lang.ProceedingJoinPoint類型** @param proceedingJoinPoint*/@Around("pointCut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) {log.info("----------- 環繞通知 -----------");log.info("環繞通知的目標方法名:" + joinPoint.getSignature().getName());try {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(),signature.getMethod().getParameterTypes());ClearAndReloadCache annotation = method.getAnnotation(ClearAndReloadCache.class);//反射得到自定義注解的方法對象String matchedValue = annotation.matchValue();String keyPrefix = annotation.name(); //獲取自定義注解的方法對象的參數即name// 解析EL表達式SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(matchedValue);EvaluationContext context = new StandardEvaluationContext();// 獲取參數Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++) {context.setVariable(parameterNames[i], args[i]);}String key = keyPrefix + "::" + expression.getValue(context).toString();redisUtils.del(key);//模糊刪除redis的key值//執行加入雙刪注解的改動數據庫的業務 即controller中的方法業務Object proceed = null;try {proceed = joinPoint.proceed();//放行} catch (Throwable throwable) {throwable.printStackTrace();}//新開開一個線程延遲0.5秒(時間可以改成自己的業務需求),等著mysql那邊業務操作完成//在線程中延遲刪除  同時將業務代碼的結果返回 這樣不影響業務代碼的執行new Thread(() -> {try {Thread.sleep(500);redisUtils.del(key);log.info("-----------0.5秒后,在線程中延遲刪除完畢 -----------");} catch (InterruptedException e) {e.printStackTrace();}}).start();return proceed;//返回業務代碼的值} catch (Throwable e) {throw new RuntimeException(e);}}
}

5、UserController

package com.xx.controller;import com.xx.cache.Cache;
import com.xx.cache.ClearAndReloadCache;
import com.xx.common.Result;
import com.xx.entity.User;
import com.xx.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;/*** @Author: xueqimiao* @Date: 2025/3/17 14:27*/
@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@PostMapping("/updateData")@ClearAndReloadCache(name = "user", matchValue = "#user.id")public Result updateData(@RequestBody User user) {return userService.update(user);}@GetMapping("/get")@Cache(name = "user", matchValue = "#id")public Result get(@RequestParam Integer id) {return userService.get(id);}}

6、RedisService

package com.xx.utils;import jakarta.annotation.Resource;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;/*** @Author: xueqimiao* @Date: 2023/7/17 13:46*/
@Component
public class RedisService {@Resourcepublic RedisTemplate redisTemplate;/*** 默認過期時長,單位:秒 一天*/public final static long DEFAULT_EXPIRE = 60 * 60 * 24;/*** 不設置過期時長*/public final static long NOT_EXPIRE = -1;private static double size = Math.pow(2, 32);/*=======================================String - Object=======================================*//*** 緩存基本的對象,Integer、String、實體類等** @param key* @param value* @return*/public boolean set(final String key, Object value) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.set(key, value);result = true;} catch (Exception e) {e.printStackTrace();}return result;}/*** 寫入緩存設置時效時間** @param key* @param value* @return*/public boolean set(final String key, Object value, Long expireTime) {return set(key, value, expireTime, TimeUnit.SECONDS);}public boolean set(final String key, Object value, Long expireTime, TimeUnit unit) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.set(key, value);redisTemplate.expire(key, expireTime, unit);result = true;} catch (Exception e) {e.printStackTrace();}return result;}public <T> void setCacheObject(final String key, final T value) {redisTemplate.opsForValue().set(key, value);}/*** 獲得緩存的Object對象** @param key 緩存的鍵值* @return 緩存鍵值對應的數據*/public Object getCache(final String key) {return redisTemplate.opsForValue().get(key);}/*** 獲得緩存的基本對象。** @param key 緩存鍵值* @return 緩存鍵值對應的數據*/public <T> T getCacheObject(final String key) {ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 獲得緩存的基本對象。** @param key 緩存鍵值* @return 緩存鍵值對應的數據*/public <T> T get(final String key) {ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 讀取緩存** @param key* @return*/public <T> T get(final String key, Class<T> clazz) {ValueOperations<Serializable, Object> operation = redisTemplate.opsForValue();T result = (T) operation.get(key);return result;}/*** 設置有效時間** @param key     Redis鍵* @param timeout 超時時間* @return true=設置成功;false=設置失敗*/public boolean expire(final String key, final long timeout) {return expire(key, timeout, TimeUnit.SECONDS);}/*** 設置有效時間** @param key     Redis鍵* @param timeout 超時時間* @param unit    時間單位* @return true=設置成功;false=設置失敗*/public boolean expire(final String key, final long timeout, final TimeUnit unit) {return redisTemplate.expire(key, timeout, unit);}/*** 獲取有效時間** @param key Redis鍵* @return 有效時間*/public long getExpire(final String key) {return redisTemplate.getExpire(key);}/*** 判斷 key是否存在** @param key 鍵* @return true 存在 false不存在*/public Boolean hasKey(String key) {return redisTemplate.hasKey(key);}/*** 刪除單個對象** @param key*/public void delete(String key) {redisTemplate.delete(key);}/*** 刪除集合對象** @param collection*/public void delete(Collection collection) {redisTemplate.delete(collection);}/*** 判斷緩存中是否有對應的value** @param key* @return*/public boolean exists(final String key) {return redisTemplate.hasKey(key);}/*** 累加 1** @param key 緩存的鍵值* @return*/public Long increment(final String key) {return increment(key, 1L);}public Long decrement(final String key) {return decrement(key, 1L);}/*** 累加 指定值** @param key 緩存的鍵值* @param num 累加的數量* @return*/public Long increment(final String key, Long num) {return redisTemplate.opsForValue().increment(key, num);}public Long decrement(final String key, Long num) {return redisTemplate.opsForValue().decrement(key, num);}/*** 獲得緩存的基本對象key列表** @param pattern 字符串前綴* @return 對象列表*/public Collection<String> keys(final String pattern) {return redisTemplate.keys(pattern);}/*=======================================List=======================================*//*** 緩存List數據** @param key      緩存的鍵值* @param dataList 待緩存的List數據* @return 緩存的對象*/public <T> long listRightPush(final String key, final List<T> dataList) {Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}public long listRightPush(String key, String value) {Long listSize = redisTemplate.opsForList().rightPush(key, value);return null == listSize ? 0 : listSize;}public <T> long listLeftPush(final String key, final List<T> dataList) {Long count = redisTemplate.opsForList().leftPushAll(key, dataList);return count == null ? 0 : count;}public long listLeftPush(String key, String value) {Long listSize = redisTemplate.opsForList().leftPush(key, value);return null == listSize ? 0 : listSize;}public long listRemove(String key, long count, String value) {Long remove = redisTemplate.opsForList().remove(key, count, value);return null == remove ? 0 : remove;}/*** 獲得緩存的list對象** @param key 緩存的鍵值* @return 緩存鍵值對應的數據*/public <T> List<T> getCacheList(final String key) {return redisTemplate.opsForList().range(key, 0, -1);}/*** 緩存List數據** @param key      緩存的鍵值* @param dataList 待緩存的List數據* @return 緩存的對象*/public <T> long setCacheList(final String key, final List<T> dataList) {Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 列表獲取** @param k* @param start* @param end* @return*/public <T> List<T> listRange(String k, long start, long end) {ListOperations<String, T> list = redisTemplate.opsForList();return list.range(k, start, end);}public <T> List<T> listRange(String k) {return listRange(k, 0, -1);}/*=======================================Set=======================================*//*** 緩存Set** @param key     緩存鍵值* @param dataSet 緩存的數據* @return 緩存數據的對象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()) {setOperation.add(it.next());}return setOperation;}/*** 獲得緩存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key) {return redisTemplate.opsForSet().members(key);}/*** 集合添加** @param key* @param value*/public void add(String key, Object value) {SetOperations<String, Object> set = redisTemplate.opsForSet();set.add(key, value);}/*** 集合獲取** @param key* @return*/public Set<Object> setMembers(String key) {SetOperations<String, Object> set = redisTemplate.opsForSet();return set.members(key);}public <T> T pop(String key) {SetOperations<String, T> set = redisTemplate.opsForSet();return set.pop(key);}public <T> List<T> pop(String key, Long num) {SetOperations<String, T> set = redisTemplate.opsForSet();return set.pop(key, num);}/*=======================================ZSet=======================================*//*** 有序集合添加** @param key* @param value* @param scoure*/public void zAdd(String key, Object value, double scoure) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();zset.add(key, value, scoure);}/*** 有序集合獲取** @param key* @param scoure* @param scoure1* @return*/public Set<Object> rangeByScore(String key, double scoure, double scoure1) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();redisTemplate.opsForValue();return zset.rangeByScore(key, scoure, scoure1);}/*** 有序集合獲取排名** @param key   集合名稱* @param value 值*/public Long zRank(String key, Object value) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();return zset.rank(key, value);}/*** 有序集合獲取排名** @param key*/public Set<ZSetOperations.TypedTuple<Object>> zRankWithScore(String key, long start, long end) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();Set<ZSetOperations.TypedTuple<Object>> ret = zset.rangeWithScores(key, start, end);return ret;}/*** 有序集合添加** @param key* @param value*/public Double zSetScore(String key, Object value) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();return zset.score(key, value);}/*** 有序集合添加分數** @param key* @param value* @param scoure*/public void incrementScore(String key, Object value, double scoure) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();zset.incrementScore(key, value, scoure);}/*** 有序集合獲取排名** @param key*/public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithScore(String key, long start, long end) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeByScoreWithScores(key, start, end);return ret;}/*** 有序集合獲取排名** @param key*/public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithRank(String key, long start, long end) {ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeWithScores(key, start, end);return ret;}/*=======================================Hash=======================================*//*** 緩存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 獲得緩存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key) {return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入數據** @param key   Redis鍵* @param hKey  Hash鍵* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value) {redisTemplate.opsForHash().put(key, hKey, value);}/*** 獲取Hash中的數據** @param key  Redis鍵* @param hKey Hash鍵* @return Hash中的對象*/public <T> T getCacheMapValue(final String key, final String hKey) {HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 獲取多個Hash中的數據** @param key   Redis鍵* @param hKeys Hash鍵集合* @return Hash對象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 哈希 添加** @param key* @param hashKey* @param value*/public void hmSet(String key, Object hashKey, Object value) {HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();hash.put(key, hashKey, value);}/*** 哈希獲取數據** @param key* @param hashKey* @return*/public Object hmGet(String key, Object hashKey) {HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();return hash.get(key, hashKey);}/*=======================================Bit=======================================*//*** 寫入緩存** @param key* @param offset 位 8Bit=1Byte* @return*/public boolean setBit(String key, long offset, boolean isShow) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.setBit(key, offset, isShow);result = true;} catch (Exception e) {e.printStackTrace();}return result;}/*** 寫入緩存** @param key* @param offset* @return*/public boolean getBit(String key, long offset) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();result = operations.getBit(key, offset);} catch (Exception e) {e.printStackTrace();}return result;}public void saveDataToRedis(String name) {Double index = Math.abs(name.hashCode() % size);long indexLong = index.longValue();boolean availableUsers = setBit("availableUsers", indexLong, true);}public boolean getDataToRedis(String name) {Double index = Math.abs(name.hashCode() % size);long indexLong = index.longValue();return getBit("availableUsers", indexLong);}
}

博客心語

在Java編程的征程中,我們都是追夢人。每一次編寫代碼,都是在編織一個關于未來的故事。這個故事可能是一個高效的電商系統,讓購物變得更加便捷;也可能是一個智能的醫療應用,拯救無數的生命。無論你的目標是什么,Java都是你實現夢想的有力武器。所以,不要停下你前進的腳步,不斷探索Java的深度和廣度,讓你的代碼充滿生命力,因為你正在用一種偉大的語言塑造著一個充滿無限可能的未來。

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

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

相關文章

rosbag|ROS中.bag數據包轉換為matlab中.mat數據類型

代碼見代碼 msg_dict中設置自定義消息類型 test_config中設置需要記錄的具體的值 test_config中topic_name以及message_type照搬plotjuggler打開時的參數 最后生成.mat文件在matlab中進行使用

基于動態 FOF(基金中的基金)策略的基金交易推薦系統的設計與實現思路

下面為你呈現一個基于動態 FOF&#xff08;基金中的基金&#xff09;策略的基金交易推薦系統的設計與實現思路&#xff0c;同時給出一個簡單的 Python 示例代碼。 系統設計 1. 需求分析 收集各類基金的歷史數據&#xff0c;涵蓋凈值、收益率、風險指標等。依據動態 FOF 策略…

搭建主從DNS、nfs、nginx

任務需求&#xff1a; 客戶端通過訪問 www.nihao.com 后&#xff0c;能夠通過 dns 域名解析&#xff0c;訪問到 nginx 服務中由 nfs 共享的首頁文件&#xff0c;內容為&#xff1a;Very good, you have successfully set up the system. 各個主機能夠實現時間同步&#xff0c;…

JS 對象轉數組,數組轉對象

數據格式 objMap : {apiP: 8000, sder: true, host: "1.111", wPort: "1335" }要求&#xff1a;將 objMap 轉化為 數組 const equipArray Object.keys(objMap ).map(key > {return {name: key,value: objMap [key]}打印結果 數組轉為對象 let equipAr…

vue - [Vue warn]: Duplicate keys detected: ‘0‘. This may cause an update error.

問題描述&#xff1a; vue項目中&#xff0c;對表單數組賦值時&#xff0c;控制臺拋出警告&#xff1a; 問題代碼&#xff1a; 問題分析&#xff1a; 1、Vue 要求每個虛擬 DOM 節點必須有唯一的 key。該警告信息通常出現在使用v-for循環的場景中&#xff0c;多個同級節點使用…

DeepSeek V3–0324 vs DeepSeek-V3, 排名最高非推理模型

最近DeepSeek V3 升級。 本文將帶您了解該模型的核心特性、基準表現,以及如何通過Hugging Face推理終端和OpenRouter平臺親身體驗。我們還將通過創意生成與邏輯分析兩大測試案例,直觀展示其卓越性能。 DeepSeek-V3-0324 2025年3月24日,深度求索(DeepSeek)AI正式發布了V3…

docker使用uv安裝依賴

官方使用 FastAPI 官方 Dockerfile 中用了兩次&#xff1a; RUN --mounttypecache,target/root/.cache/uv \--mounttypebind,sourceuv.lock,targetuv.lock \--mounttypebind,sourcepyproject.toml,targetpyproject.toml \uv sync --frozen --no-install-project # ? 第一次…

3.0 Disruptor的使用介紹(一)

Disruptor: 其官網定義為&#xff1a;“A High Performance Inter-Thread Messaging Library”&#xff0c;即&#xff1a;線程間的高性能消息框架&#xff0c;與Labview的生產者、消費者模型很相似。 其組成部分比較多&#xff0c;先介紹幾個常用的概念&#xff1a; …

在 Windows 系統下,將 FFmpeg 編譯為 .so 文件

1. 準備環境 確保你的 Windows 系統已安裝以下工具&#xff1a; Android Studio NDK&#xff08;Native Development Kit&#xff09; MSYS2&#xff08;用于提供類 Unix 環境&#xff09; FFmpeg 源碼 Git Bash&#xff08;可選&#xff0c;推薦使用&#xff09; 安裝 …

leetcode二叉樹3

404.左葉子之和 給定二叉樹的根節點 root &#xff0c;返回所有左葉子之和。 示例 1&#xff1a; 輸入: root [3,9,20,null,null,15,7] 輸出: 24 解釋: 在這個二叉樹中&#xff0c;有兩個左葉子&#xff0c;分別是 9 和 15&#xff0c;所以返回 24示例 2: 輸入: root [1] 輸…

QT網絡通信的接口與使用

文章目錄 前言1.服務端實現流程1.1步驟 1&#xff1a;創建 QTcpServer 并監聽端口1.2步驟 2&#xff1a;處理新連接請求1.3步驟 3&#xff1a;接收客戶端數據1.4步驟 4&#xff1a;處理客戶端斷開 2.客戶端實現流程2.1步驟 1&#xff1a;創建 QTcpSocket 并連接服務器2.2步驟 2…

華為OD機試2025A卷七日集訓第1期 - 按算法分類,由易到難,循序漸進,玩轉OD(Python/JS/C/C++)

目錄 一、適合人群二、本期訓練時間三、如何參加四、7日集訓第1期五、精心挑選21道高頻100分經典題目&#xff0c;作為入門。第1天、邏輯分析第2天、邏輯分析第3天、邏輯分析第4天、邏輯分析第5天、雙指針第6天、二叉樹第7天、回溯 六、集訓總結六、國內直接使用最新GPT-4.5、滿…

Qt 重入和線程安全

重入和線程安全 在整個文檔中&#xff0c;"重入"和 "線程安全 "這兩個術語被用來標記類和函數&#xff0c;以表明它們在多線程應用程序中的使用方式&#xff1a; 線程安全函數可以同時被多個線程調用&#xff0c;即使調用使用的是共享數據&#xff0c;因…

Elasticsearch:構建 AI 驅動的搜索體驗

Elasticsearch 介紹 當你開始使用 Elastic 時&#xff0c;你將使用 Elasticsearch Relevance Engine?&#xff08;ESRE&#xff09;&#xff0c;它專為 AI 搜索應用程序提供支持。借助 ESRE&#xff0c;你可以利用一整套開發者工具&#xff0c;包括 Elastic 的文本搜索、向量…

鴻蒙生態開發

鴻蒙生態開發概述 鴻蒙生態是華為基于開源鴻蒙&#xff08;OpenHarmony&#xff09;構建的分布式操作系統生態&#xff0c;旨在通過開放共享的模式連接智能終端設備、操作系統和應用服務&#xff0c;覆蓋消費電子、工業物聯網、智能家居等多個領域。以下從定義與架構、核心技術…

JVM如何處理Java中的精度轉換: 從源碼到字節碼

你好&#xff0c;我是 shengjk1&#xff0c;多年大廠經驗&#xff0c;努力構建 通俗易懂的、好玩的編程語言教程。 歡迎關注&#xff01;你會有如下收益&#xff1a; 了解大廠經驗擁有和大廠相匹配的技術等 希望看什么&#xff0c;評論或者私信告訴我&#xff01; 文章目錄 一…

vue-next-admin修改配置指南

官方文檔地址&#xff1a;vue-next-admin 1.如何開啟側邊欄logo 在scr-layout-navbars-topBar-setings.vue中添加 getThemeConfig.value.isShowLogo true; 設置為true即可默認打開 2.修改側邊欄頂部的logo與文字 先把想要的圖標存到我的項目然后下載 然后把后面的幾個文件拉…

gin學習

gin學習筆記&#xff0c;不僅包含了基本的增刪查改外&#xff0c;還包括參數傳遞&#xff0c;上傳下載&#xff0c;模版、session與中間件等&#xff0c;方便收藏自習可用 文章目錄 獲得個請求get打印字符串get請求xmlget請求跳轉http方法路由可以通過Context的Param方法來獲取…

Flutter運行錯誤:UG! exception in phase ‘semantic analysis‘

最近在Mac Mini M4上通過Android Studio導入Flutter項目并運行&#xff0c;結果一直跑不起來&#xff0c;錯誤日志如下&#xff1a; 執行命令查看版本信息&#xff1a; flutter doctor --verbose通過輸出信息Java version OpenJDK Runtime Environment (build 21.0.41242208…