版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
若依框架(ruoyi)Vue3+ElementPlus移除Redis緩存方案(完整步驟)目錄一、 背景介紹 2二、 部署問題 2三、 需要解決的問題 3四、 實(shí)施步驟 31. 更改ruoyi-admin目錄下application.yml文件 32. 更改ruoyi-framework下的RedisConfig文件 33. 修改RedisCache類 64. 登錄校驗(yàn)時(shí)刪除過期緩存,防止占用內(nèi)存 85. 處理用戶信息垃圾緩存問題 96. 處理在線用戶列表 97. 處理緩存讀取問題 108. 更改SysConfigServiceImpl文件 129. 去掉redisCache.setCacheObject方法后兩個(gè)參數(shù) 1310. 處理異常問題 13五、 項(xiàng)目啟動(dòng)效果圖 14六、 系統(tǒng)擴(kuò)展集成了MybatisPlus 14背景介紹公司運(yùn)維的某些項(xiàng)目需要進(jìn)行“國產(chǎn)化”改造,經(jīng)過反復(fù)技術(shù)選型,終合考慮了技術(shù)的先進(jìn)性、可維護(hù)性,并著重考慮后期能更好地進(jìn)行二次開發(fā),最終選擇了若依(RuoYI)這個(gè)開源框架,這個(gè)框架的Vue3版本,核心使用了Vue3、ElementPlus、Vite構(gòu)建工具等相對(duì)較新的技術(shù),無關(guān)的功能相對(duì)較少,通過對(duì)其改造,在此基礎(chǔ)上進(jìn)行二次開發(fā)后,有助于掌握當(dāng)前主流的開發(fā)技術(shù)和構(gòu)建模式,能夠?yàn)楣镜钠渌?xiàng)目后續(xù)改造儲(chǔ)備相關(guān)技術(shù)。部署問題項(xiàng)目部署過程依據(jù)官方文檔還算順利,但編譯和啟動(dòng)過程中,總是提示在6379端口的服務(wù)啟動(dòng)失敗,后來知道是redis緩存服務(wù)的原因,因?yàn)榇蟛糠猪?xiàng)目比較小,沒有并發(fā)問題需要考慮,如果再部署Redis服務(wù)器的話,無疑增加了額外的運(yùn)維成本和不穩(wěn)定性,于是決定采用ConcurrentHashMap對(duì)其進(jìn)行替換,但在實(shí)際操作過程中遇到了不少問題,網(wǎng)上查的的解決方案沒有一個(gè)是完整可用的,所以在成功解決這個(gè)問題后,就此形成一個(gè)完整的記錄文檔,供有此需求的人參考。需要解決的問題用ConcurrentHashMap替換后,項(xiàng)目運(yùn)行不能有任何報(bào)錯(cuò)系統(tǒng)緩存模塊和在線用戶模塊能正常顯示數(shù)據(jù)解決ConcurrentHashMap非正常退出所產(chǎn)生的冗余緩存等一系列不合理問題實(shí)施步驟更改ruoyi-admin目錄下application.yml文件注釋掉文件內(nèi)的redis配置,如下圖更改ruoyi-framework下的RedisConfig文件注釋掉@Bean、@Configuration和@EnableCaching注解在ruoyi-common的core/redis下新建MyCache類packagemon.core.redis;
importorg.springframework.cache.Cache;
importorg.springframework.cache.support.SimpleValueWrapper;
importorg.springframework.stereotype.Component;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.Objects;
importjava.util.concurrent.Callable;
importjava.util.concurrent.ConcurrentHashMap;
@Component
publicclassMyCacheimplementsCache{
privateMap<String,Object>storage=newConcurrentHashMap<>();
/**
*每個(gè)緩存生效時(shí)間12小時(shí)
*/
//publicstaticfinallongCACHE_HOLD_TIME_12H=12*60*60*1000L;
@Override
publicStringgetName(){
returnnull;
}
@Override
publicObjectgetNativeCache(){
returnnull;
}
@Override
public<T>Tget(Objectkey,Class<T>type){
returnnull;
}
@Override
public<T>Tget(Objectkey,Callable<T>valueLoader){
returnnull;
}
@Override
publicvoidclear(){
}
publicbooleanhasKey(Stringkey){
returnstorage.containsKey(key);
}
@Override
publicValueWrapperget(Objectkey){
Stringk=key.toString();
Objectvalue=storage.get(k);
//注意返回的數(shù)據(jù),要和存放時(shí)接收到數(shù)據(jù)保持一致,要將數(shù)據(jù)反序列化回來。
returnObjects.isNull(value)?null:newSimpleValueWrapper(value);
}
@Override
publicvoidput(Objectkey,Objectvalue){
if(Objects.isNull(value)){
return;
}
storage.put(key.toString(),value);
}
@Override
publicvoidevict(Objectkey){
storage.remove(key.toString());
}
//刪除集合
publicbooleandeleteObject(Collection<String>collection){
collection.forEach(item->{
storage.remove(item);
});
returntrue;
}
//獲取所有的keys
publicCollection<String>keys(finalStringpattern){
//editbywjl鍵值查詢
StringpatternStr=pattern.replace(":","");
Map<String,Object>myMap=newHashMap<>();
Collection<String>keys=storage.keySet();
for(Stringkey:keys){
if(key.contains(patternStr)){
myMap.put(key,storage.get(key));
}
}
returnmyMap.keySet();
}
}修改RedisCache類整個(gè)文件,使用下面代碼段覆蓋packagemon.core.redis;
importjava.util.Collection;
importjava.util.concurrent.TimeUnit;
importorg.springframework.cache.Cache;
importorg.springframework.stereotype.Component;
importjavax.annotation.Resource;
/**
*springredis工具類
*
*@authorruoyi
**/
@SuppressWarnings(value={"unchecked","rawtypes"})
@Component
publicclassRedisCache
{
@Resource
publicMyCachemyCache;
/**
*緩存基本的對(duì)象,Integer、String、實(shí)體類等
*
*@paramkey緩存的鍵值
*@paramvalue緩存的值
*/
public<T>voidsetCacheObject(finalStringkey,finalTvalue)
{
myCache.put(key,value);
}
/**
*判斷key是否存在
*
*@paramkey鍵
*@returntrue存在false不存在
*/
publicBooleanhasKey(Stringkey)
{
returnmyCache.hasKey(key);
}
/**
*獲得緩存的基本對(duì)象。
*
*@paramkey緩存鍵值
*@return緩存鍵值對(duì)應(yīng)的數(shù)據(jù)
*/
public<T>TgetCacheObject(finalStringkey)
{
Cache.ValueWrappervalueWrapper=myCache.get(key);
if(valueWrapper==null){
returnnull;
}else{
return(T)valueWrapper.get();
}
}
/**
*刪除單個(gè)對(duì)象
*
*@paramkey
*/
publicbooleandeleteObject(finalStringkey)
{
myCache.evict(key);
returntrue;
}
/**
*刪除集合對(duì)象
*
*@paramcollection多個(gè)對(duì)象
*@return
*/
publicbooleandeleteObject(finalCollectioncollection)
{
returnmyCache.deleteObject(collection);
}
/**
*獲得緩存的基本對(duì)象列表
*
*@parampattern字符串前綴
*@return對(duì)象列表
*/
publicCollection<String>keys(finalStringpattern)
{
returnmyCache.keys(pattern);
}
}登錄校驗(yàn)時(shí)刪除過期緩存,防止占用內(nèi)存更改ruoyi-framework目錄下web/service/TokenService文件,使用下面方法替換原有方法/**
*驗(yàn)證令牌有效期,相差不足20分鐘,自動(dòng)刷新緩存
*
*@paramloginUser
*@return令牌
*/
publicvoidverifyToken(LoginUserloginUser)
{
longexpireTime=loginUser.getExpireTime();
longcurrentTime=System.currentTimeMillis();
if(expireTime-currentTime<0){
//editbywjl過期刪除token
StringuserKey=getTokenKey(loginUser.getToken());
redisCache.deleteObject(userKey);
thrownewServiceException("登錄超時(shí)",HttpStatus.UNAUTHORIZED);
}
elseif(expireTime-currentTime<=MILLIS_MINUTE_TEN)
{
refreshToken(loginUser);
}
}處理用戶信息垃圾緩存問題繼續(xù)更改上一條修改過的TokenService文件,修改文件當(dāng)中的createToken(LoginUserloginUser)方法保證每個(gè)用戶只緩存一個(gè)鍵值對(duì),防止反復(fù)登錄或直接關(guān)閉瀏覽器產(chǎn)生垃圾緩存//Stringtoken=IdUtils.fastUUID();
Stringtoken="WF"+String.format("%08d",loginUser.getUserId());處理在線用戶列表更改ruoyi-admin目錄下\src\main\java\com\ruoyi\web\controller\monitor\SysUserOnlineController.java文件,找到下面方法,可直接替換publicTableDataInfolist(Stringipaddr,StringuserName)
{
Collection<String>keys=redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY);
List<SysUserOnline>userOnlineList=newArrayList<SysUserOnline>();
for(Stringkey:keys)
{
//editbywjl在線用戶
if(key.indexOf(CacheConstants.LOGIN_TOKEN_KEY)>-1){
LoginUseruser=redisCache.getCacheObject(key);
if(StringUtils.isNotEmpty(ipaddr)&&StringUtils.isNotEmpty(userName))
{
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr,userName,user));
}
elseif(StringUtils.isNotEmpty(ipaddr))
{
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr,user));
}
elseif(StringUtils.isNotEmpty(userName)&&StringUtils.isNotNull(user.getUser()))
{
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName,user));
}
else
{
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
}
}
}
Collections.reverse(userOnlineList);
userOnlineList.removeAll(Collections.singleton(null));
returngetDataTable(userOnlineList);
}處理緩存讀取問題更改ruoyi-admin目錄下com\ruoyi\web\controller\monitor\CacheController.java由于更改太多,直接使用下面整個(gè)類替換packagecom.ruoyi.web.controller.monitor;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.List;
importcom.alibaba.fastjson2.JSON;
importmon.core.redis.RedisCache;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.security.access.prepost.PreAuthorize;
importorg.springframework.web.bind.annotation.DeleteMapping;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.PathVariable;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importmon.constant.CacheConstants;
importmon.core.domain.AjaxResult;
importcom.ruoyi.system.domain.SysCache;
/**
*緩存監(jiān)控
*
*@authorruoyi
*/
@RestController
@RequestMapping("/monitor/cache")
publicclassCacheController
{
@Autowired
privateRedisCacheredisCache;
privatefinalstaticList<SysCache>caches=newArrayList<SysCache>();
{
caches.add(newSysCache(CacheConstants.LOGIN_TOKEN_KEY,"用戶信息"));
caches.add(newSysCache(CacheConstants.SYS_CONFIG_KEY,"配置信息"));
caches.add(newSysCache(CacheConstants.SYS_DICT_KEY,"數(shù)據(jù)字典"));
caches.add(newSysCache(CacheConstants.CAPTCHA_CODE_KEY,"驗(yàn)證碼"));
caches.add(newSysCache(CacheConstants.REPEAT_SUBMIT_KEY,"防重提交"));
caches.add(newSysCache(CacheConstants.RATE_LIMIT_KEY,"限流處理"));
caches.add(newSysCache(CacheConstants.PWD_ERR_CNT_KEY,"密碼錯(cuò)誤次數(shù)"));
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getNames")
publicAjaxResultcache()
{
returnAjaxResult.success(caches);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getKeys/{cacheName}")
publicAjaxResultgetCacheKeys(@PathVariableStringcacheName)
{
//editbywjl緩存列表
Collection<String>keys=redisCache.keys(cacheName);
returnAjaxResult.success(keys);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getValue/{cacheName}/{cacheKey}")
publicAjaxResultgetCacheValue(@PathVariableStringcacheName,@PathVariableStringcacheKey)
{
//editbywjl通過鍵值獲取緩存
ObjectcacheValue=redisCache.getCacheObject(cacheKey);
SysCachesysCache=newSysCache(cacheName,cacheKey,JSON.toJSONString(cacheValue));
returnAjaxResult.success(sysCache);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheName/{cacheName}")
publicAjaxResultclearCacheName(@PathVariableStringcacheName)
{
Collection<String>cacheKeys=redisCache.keys(cacheName+"*");
redisCache.deleteObject(cacheKeys);
returnAjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheKey/{cacheKey}")
publicAjaxResultclearCacheKey(@PathVariableStringcacheKey)
{
redisCache.deleteObject(cacheKey);
returnAjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheAll")
publicAjaxResultclearCacheAll()
{
Collection<String>cacheKeys=redisCache.keys("*");
redisCache.deleteObject(cacheKeys);
returnAjaxResult.success();
}
}更改SysConfigServiceImpl文件在ruoyi-system目錄下@Override
publicStringselectConfigByKey(StringconfigKey)
{
//StringconfigValue=Convert.toStr(redisCache.getCacheObject(getCacheKey(configK
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 空壓機(jī)定期檢修與服務(wù)合同
- 物流企業(yè)合同管理制度
- 合同中常見的風(fēng)險(xiǎn)點(diǎn)及相應(yīng)的控制措施
- 《怎樣治療寶寶濕疹》課件
- 經(jīng)濟(jì)全球化的趨勢(shì)教學(xué)課件
- 【初中數(shù)學(xué)課件】與圓相關(guān)的綜合題復(fù)習(xí)課課件
- 《酸棗營銷戰(zhàn)略》課件
- 班組學(xué)習(xí)培訓(xùn)管理制度范文(2篇)
- 值班電工安全技術(shù)規(guī)程(3篇)
- 2025年保險(xiǎn)公司個(gè)人工作總結(jié)參考模板(4篇)
- 云上賞花直播方案
- 數(shù)控生涯發(fā)展展示
- 2024年太平洋人壽保險(xiǎn)股份有限公司招聘筆試參考題庫含答案解析
- 農(nóng)業(yè)裝備與機(jī)械化的經(jīng)濟(jì)效益與社會(huì)效益
- (完整)中醫(yī)癥候積分量表
- 醫(yī)療團(tuán)隊(duì)管理技巧與策略
- 《功能點(diǎn)計(jì)算方法》課件
- 工會(huì)提案培訓(xùn)課件
- 高空拋物法律知識(shí)講座
- 射頻工程師年終總結(jié)
- 2019統(tǒng)編版高中數(shù)學(xué)A版必修第二冊(cè)教學(xué)計(jì)劃含教學(xué)進(jìn)度表(高一下學(xué)期數(shù)學(xué)教學(xué)計(jì)劃)
評(píng)論
0/150
提交評(píng)論