通過rediss實現用戶菜單智能推薦

本人用的框架?SpringCloud+ redis+Oauth2+Security

前言: 整體使用過濾器的思想,獲取Request,然后從數據庫查到菜單名稱和路由以及計算點擊次數,最后以list的形式存在redis,設計定時任務,在一定時間后,將redis的數據存在數據庫(mysql或者oracle)中。?

設計時出現的問題(必看!!):

(一)、因為是微服務框架,所以在設計時想到的是在GateWay使用GlobalFilter對所有服務的請求進行攔截,但是有一個問題是,因為GateWay的pom文件依賴不允許有spring-web也就沒辦法使用fegin或者其他方式查詢數據庫,也就獲取不到菜單的信息,所以舍棄了這種方法

(二)、那就使用基礎模塊,讓每個服務都去依賴這個模塊,就變相的達到了,控制每一個服務的方式。那又沒辦法想GateWay那樣直接實現GlobalFilter攔截所有請求,但是又想到可以將攔截器加在security里,等每次認證結束后,經過過濾器,對請求進行處理,這樣就達到了所有的目的

(三)、如果您只是單體的springBoot項目,那就更簡單了,直接實現HandlerInterceptor,然后加到bean里讓spring管理

一、先寫攔截器內容

@Slf4j
public class UserFavoriteFunctionFilter extends OncePerRequestFilter {// 排除過濾的 uri 地址,nacos自行添加private final IgnoreWhiteProperties ignoreWhite;public UserFavoriteFunctionFilter(IgnoreWhiteProperties ignoreWhite) {this.ignoreWhite = ignoreWhite;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//  /gAcDeptController/listString urlPath = request.getRequestURI();log.info("Absolute path:{}", urlPath);// 跳過不需要統計的路徑List<String> whites = ignoreWhite.getWhites();if (CollUtil.isEmpty(whites)){filterChain.doFilter(request, response);return;}if (StringUtils.matches(urlPath, whites)) {log.info("Skip path:{}", urlPath);filterChain.doFilter(request, response);return;}RemoteSystemService remoteSystemService = SpringUtils.getBean(RemoteSystemService.class);RedisService redisService = SpringUtils.getBean(RedisService.class);String prefixKey = "userFavorite:";BigDecimal userId = SecurityUtils.getUserId();// 獲取uri的前半部分String[] split = urlPath.split("/");String ControllerPath = split[1]; // gAcDeptController//  從 G_AC_PERMISSION 查出當前菜單的 perm_noResponseData<String> data = remoteSystemService.getPermNo(ControllerPath);if (ObjectUtil.isNull(data)){filterChain.doFilter(request, response);return;}String permNo = data.getData();// 從redis查詢當前的用戶菜單點擊量String key = prefixKey+userId;List<clickCountVo> clickCountVos = redisService.getCacheList(key);if (CollUtil.isNotEmpty(clickCountVos)){Map<String, clickCountVo> clickCountMap = clickCountVos.stream().collect(Collectors.toMap(clickCountVo::getName,  // 鍵映射函數vo -> vo            // 值映射函數,直接使用對象本身));clickCountVo clickCountVo = clickCountMap.get(permNo);if (ObjectUtil.isNotNull(clickCountVo)) {// 當前的點擊量BigDecimal count = clickCountVo.getCount();AtomicLong atomicLong = new AtomicLong(count.longValue());long l = atomicLong.incrementAndGet();clickCountVo.setCount(new BigDecimal(l));clickCountVo.setTime(new Date());}else {clickCountVo clickVo = new clickCountVo();clickVo.setName(permNo);clickVo.setTime(new Date());clickVo.setCount(BigDecimal.ONE);clickCountVos.add(clickVo);}}else {clickCountVo countVo = new clickCountVo();countVo.setName(permNo);countVo.setTime(new Date());countVo.setCount(BigDecimal.ONE);clickCountVos.add(countVo);}redisService.deleteObject(key);redisService.setCacheList(key, clickCountVos);filterChain.doFilter(request, response);}}

二、創建一個Vo保存菜單信息和點擊量

@Data
public class clickCountVo {private String name;private BigDecimal count;@JsonFormat(pattern = "yyyy-MM-dd")private Date time;
}

三、有一些路徑我們不需要攔截的,可以在nacos配置一下

@RefreshScope
@ConfigurationProperties(prefix = "security.ignore")
public class IgnoreWhiteProperties {private List<String> whites = new ArrayList<>();public List<String> getWhites(){return whites;}public void setWhites(List<String> whites){this.whites = whites;}
}

四、最重要的,將我們自定義的攔截器加到Scurity里,這里還搭配了Oauth2.0

    @Bean@Order(Ordered.HIGHEST_PRECEDENCE)SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {AntPathRequestMatcher[] requestMatchers = permitAllUrl.getUrls().stream().map(AntPathRequestMatcher::new).toList().toArray(new AntPathRequestMatcher[] {});http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers).permitAll().anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.authenticationEntryPoint(resourceAuthExceptionEntryPoint).bearerTokenResolver(starBearerTokenExtractor).jwt()).addFilterAfter(new UserFavoriteFunctionFilter(whiteProperties),BearerTokenAuthenticationFilter.class).headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)).csrf(AbstractHttpConfigurer::disable);return http.build();}

.addFilterAfter(new UserFavoriteFunctionFilter(whiteProperties),BearerTokenAuthenticationFilter.class) 這個是添加我們自定義的過濾器的,熟悉Oauth2.0認證的都熟悉BearerTokenAuthenticationFilter,這個過濾器是當用戶每一次想資源服務器請求時都會經過的過濾器,這個過濾器也負責處理token以及將用戶認證信息存到SecurityContextHolder中,所以我們在這個過濾器后面加上我們自定義的過濾器UserFavoriteFunctionFilter(這個說起來都是淚,我一點一點debug后才發現addFilterAfter這個方法

然后你就找一個既又redis又有springWeb依賴的公共模塊,將代碼放進去就行了。

后面還有一個定時任務的功能,這個主要是為了防止redis數據太多,我們公司是TOB,基本沒有什么用戶量,也沒有高并發什么的,暫時就沒有寫這個功能。

附帶兩個查詢的方法,返回前端展示

@RestController
@RequestMapping("/userClickController")
@Tag(name = "獲取用戶常用菜單功能")
public class UserClickController {@Autowiredprivate RedisService redisService;@GetMapping("/getTop10Info")@Operation(summary = "獲取點擊量最多的前10個菜單信息")public List<clickCountVo> getTop10Info(){String  key = "userFavorite:";BigDecimal userId = SecurityUtils.getUserId();key = key+userId;List<clickCountVo> cacheList = redisService.getCacheList(key);// 按照點擊量排序。如果點擊量一樣就按照時間排序 都是降序return cacheList.stream().sorted(Comparator.comparing(clickCountVo::getCount).reversed().thenComparing(Comparator.comparing(clickCountVo::getTime).reversed())).limit(10).collect(Collectors.toList());}@GetMapping("/getLastWeekInfo")@Operation(summary = "獲取最近一周點擊量的菜單信息")public List<clickCountVo> getLastWeekInfo(){String  key = "userFavorite:";BigDecimal userId = SecurityUtils.getUserId();key = key+userId;List<clickCountVo> cacheList = redisService.getCacheList(key);if (CollUtil.isNotEmpty(cacheList)){// 獲取上一周的時間DateTime dateTime = DateUtil.lastWeek();// 按照點擊量排序。如果點擊量一樣就按照時間排序 都是降序return cacheList.stream().filter(da -> da.getTime().toInstant().isAfter(dateTime.toInstant())).sorted(Comparator.comparing(clickCountVo::getCount).reversed().thenComparing(Comparator.comparing(clickCountVo::getTime).reversed())).collect(Collectors.toList());}return cacheList;}}

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

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

相關文章

Search for documents with similar texts

題意&#xff1a;搜索具有相似文本的文檔 問題背景&#xff1a; I have a document with three attributes: tags, location, and text. 我有一份文檔&#xff0c;包含三個屬性&#xff1a;標簽、位置和文本。 Currently, I am indexing all of them using LangChain/pgvecto…

快速了解《大模型賦能下的AI2.0數字人平臺》白皮書

在生成式AI和大模型的賦能下&#xff0c;數字人迎來AI 2.0時代。它能否成為每個人的“數字分身”&#xff0c;轉化為新型的AI勞動力工具&#xff1f;商湯科技與上海市人工智能技術協會、零壹智庫、增強現實核心技術產業聯盟聯合發布《大模型賦能下的AI 2.0數字人平臺》。《白皮…

Kubernetes面試整理-PersistentVolumes和PersistentVolumeClaims的使用和配置

在 Kubernetes 中,PersistentVolumes (PV) 和 PersistentVolumeClaims (PVC) 提供了一種分離存儲和使用存儲的機制。PV 是集群中存儲資源的抽象表示,而 PVC 是用戶對存儲資源的請求。通過這種機制,用戶可以動態地申請和管理存儲資源。 PersistentVolumes (PV) PersistentVol…

【D3.js in Action 3 精譯】1.2.2 可縮放矢量圖形(二)

當前內容所在位置 第一部分 D3.js 基礎知識 第一章 D3.js 簡介 1.1 何為 D3.js&#xff1f;1.2 D3 生態系統——入門須知 1.2.1 HTML 與 DOM1.2.2 SVG - 可縮放矢量圖形 ?? 第一部分【第二部分】??第三部分&#xff08;精譯中 ?&#xff09; 1.2.3 Canvas 與 WebGL&#x…

自動化任務:在IPython中創建和運行腳本

在數據科學和編程中&#xff0c;自動化任務是提高效率的關鍵。IPython提供了多種方法來創建和運行腳本&#xff0c;使得重復性任務可以被輕松自動化。本文將介紹如何在IPython中創建和運行腳本&#xff0c;幫助你更高效地完成工作。 1. 創建和保存IPython腳本 使用文本編輯器…

Spring Boot 中的微服務監控與管理

微服務的概述 微服務架構的優點和挑戰 優點: 靈活性和可擴展性:微服務架構允許每個服務單獨部署和擴展,這使得系統可以更靈活地適應不同的業務需求和負載變化。 使團隊更加聚焦:每個微服務都有明確的職責,這使得開發團隊可以更加聚焦,專注于開發他們的服務。 技術和框…

讀AI新生:破解人機共存密碼筆記16對人工智能的治理

1. 愚蠢的、情緒化的人類 1.1. 與完美理性所設定的不可企及的標準相比&#xff0c;我們都是極其愚蠢的&#xff0c;我們受制于各種情緒的起伏&#xff0c;這些情緒在很大程度上支配著我們的行為 1.2. 為了充分了解人類的認知&#xff0c;我們&#xff08;或者更確切地說&…

簡易跨平臺上傳文件,前后端demo

前端文件 <!DOCTYPE html> <html> <head><title>文件上傳</title> </head> <body> <h1>文件上傳1-相對慢&#xff0c;需要等待本地選擇的文件全部上傳完成后&#xff0c;服務器再保存</h1> <form id"uploadForm…

ORA-01775: 同義詞的循環鏈問題

一、問題描述 ORA-01775: 同義詞的循環鏈問題 二、 原因分析 同義詞對應的對象&#xff08;表等&#xff09;已刪除&#xff0c;不存在了。 可能原因&#xff1a; 刪除數據庫對象&#xff0c;但是忘記刪除同義詞。刪除一個用戶&#xff0c;但忘記刪除此用戶中相關的同義詞…

@Param參數

Param參數 當方法參數大于兩個的時候必須傳遞&#xff0c;只有一個的時候可以不傳。大于兩個的時候也可以用#{arg0}和#{arg1}。。。來取值 Param&#xff08;&#xff09;括號里面的值對應sql語句中 # {} 里面的值 看AI的解釋

模版方法模式詳解:使用和實現的指南

目錄 模版方法模式模版方法模式結構模版方法模式適合應用場景模版方法模式優缺點練手題目題目描述輸入描述輸出描述題解 模版方法模式 模板方法模式是一種行為設計模式&#xff0c; 它在超類中定義了一個算法的框架&#xff0c; 允許子類在不修改結構的情況下重寫算法的特定步…

《昇思25天學習打卡營第3天|張量 Tensor》

文章目錄 前言&#xff1a;今日所學&#xff1a;1. 創建張量2. 張量的屬性3.張量索引與運算4. NumPy與Tensor的轉換5. 稀疏張量 前言&#xff1a; 張量&#xff1f;張亮&#xff1f;張量是什么&#xff1f; 張量是一個可以用來表示在一些矢量、標量和其他張量之間的線性關系的…

高并發部署:基于 Gunicorn、Flask 和 Docker

一、準備工作 確保已經安裝以下軟件&#xff1a; DockerDocker ComposePython 3.x 二、創建 Flask 應用 首先&#xff0c;創建一個簡單的 Flask 應用。創建一個新的目錄并在其中創建以下文件&#xff1a; 1. app.py python fromflask importFlask, jsonifyapp Flask(__…

leetcode 第133場雙周賽 100333.統計逆序對的數目【計數dp/滾動數組/前綴和優化】

分析&#xff1a; 先考慮如下問題。 求長度為n&#xff0c;逆序對為m的排列數量。 可以考慮dp&#xff0c;dp[i][j]定義為長度為i&#xff0c;逆序對為j的排列數量。 dp[1][0] 1; //枚舉排列長度&#xff0c;或者認為枚舉當前需要插到長度為i-1的排列中的數字 for(int i 1…

OpenAI封殺不支持地區API:違規封號,7月9日生效

OpenAI 在檢測用戶使用其 API 的地區后&#xff0c;提示所有不支持位置的用戶 昨晚&#xff0c;很多大模型應用的開發者、程序員都收到了 OpenAI 的警告信&#xff0c;心里一驚。 OpenAI 在檢測用戶使用其 API 的地區后&#xff0c;提示所有不支持位置的用戶&#xff1a;即將封…

冒泡排序、選擇排序、插入排序~java版

1、冒泡排序&#xff08;Bubble Sort&#xff09; 冒泡排序的基本思想是多次遍歷待排序序列&#xff0c;每次遍歷時兩兩比較相鄰元素&#xff0c;如果順序不對則交換&#xff0c;直到整個序列有序為止。 public class BubbleSort {public static void bubbleSort(int[] arr) …

圖書管理系統(附源碼)

前言&#xff1a;前面一起和小伙伴們學習了較為完整的Java語法體系&#xff0c;那么本篇將運用這些知識連串在一起實現圖書管理系統。 目錄 一、總體設計 二、書籍與書架 書籍&#xff08;Book&#xff09; 書架&#xff08;Booklist&#xff09; 三、對圖書的相關操作 I…

已解決問題 | 該擴展程序未列在 Chrome 網上應用店中,并可能是在您不知情的情況下添加的

在Chrome瀏覽器中&#xff0c;如果你看到“該擴展程序未列在 Chrome 網上應用店中&#xff0c;并可能是在您不知情的情況下添加的”這樣的提示&#xff0c;通常是因為該擴展程序沒有通過Chrome網上應用店進行安裝。以下是解決這個問題的步驟&#xff1a; 解決辦法&#xff1a;…

Spring Boot整合Redis緩存的最佳實踐

Spring Boot整合Redis緩存的最佳實踐 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在現代應用開發中&#xff0c;緩存是提升系統性能和響應速度的關鍵技術之…

kali/ubuntu安裝vulhub

無須更換源&#xff0c;安裝docker-compose apt install docker.io docker -vdocker-compose #提示沒有&#xff0c;輸入y安裝mkdir -p /etc/docker vi /etc/docker/daemon.json #更換dockerhub國內源┌──(root?kali)-[/home/kali/vulhub-master/tomcat/CVE-2017-12615] …