




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
若依框架(ruoyi)Vue3+ElementPlus移除Redis缓存方案(完整步骤)目录一、 背景介绍 2二、 部署问题 2三、 需要解决的问题 3四、 实施步骤 31. 更改ruoyi-admin目录下application.yml文件 32. 更改ruoyi-framework下的RedisConfig文件 33. 修改RedisCache类 64. 登录校验时删除过期缓存,防止占用内存 85. 处理用户信息垃圾缓存问题 96. 处理在线用户列表 97. 处理缓存读取问题 108. 更改SysConfigServiceImpl文件 129. 去掉redisCache.setCacheObject方法后两个参数 1310. 处理异常问题 13五、 项目启动效果图 14六、 系统扩展集成了MybatisPlus 14背景介绍公司运维的某些项目需要进行“国产化”改造,经过反复技术选型,终合考虑了技术的先进性、可维护性,并着重考虑后期能更好地进行二次开发,最终选择了若依(RuoYI)这个开源框架,这个框架的Vue3版本,核心使用了Vue3、ElementPlus、Vite构建工具等相对较新的技术,无关的功能相对较少,通过对其改造,在此基础上进行二次开发后,有助于掌握当前主流的开发技术和构建模式,能够为公司的其他项目后续改造储备相关技术。部署问题项目部署过程依据官方文档还算顺利,但编译和启动过程中,总是提示在6379端口的服务启动失败,后来知道是redis缓存服务的原因,因为大部分项目比较小,没有并发问题需要考虑,如果再部署Redis服务器的话,无疑增加了额外的运维成本和不稳定性,于是决定采用ConcurrentHashMap对其进行替换,但在实际操作过程中遇到了不少问题,网上查的的解决方案没有一个是完整可用的,所以在成功解决这个问题后,就此形成一个完整的记录文档,供有此需求的人参考。需要解决的问题用ConcurrentHashMap替换后,项目运行不能有任何报错系统缓存模块和在线用户模块能正常显示数据解决ConcurrentHashMap非正常退出所产生的冗余缓存等一系列不合理问题实施步骤更改ruoyi-admin目录下application.yml文件注释掉文件内的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<>();
/**
*每个缓存生效时间12小时
*/
//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);
//注意返回的数据,要和存放时接收到数据保持一致,要将数据反序列化回来。
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类整个文件,使用下面代码段覆盖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;
/**
*缓存基本的对象,Integer、String、实体类等
*
*@paramkey缓存的键值
*@paramvalue缓存的值
*/
public<T>voidsetCacheObject(finalStringkey,finalTvalue)
{
myCache.put(key,value);
}
/**
*判断key是否存在
*
*@paramkey键
*@returntrue存在false不存在
*/
publicBooleanhasKey(Stringkey)
{
returnmyCache.hasKey(key);
}
/**
*获得缓存的基本对象。
*
*@paramkey缓存键值
*@return缓存键值对应的数据
*/
public<T>TgetCacheObject(finalStringkey)
{
Cache.ValueWrappervalueWrapper=myCache.get(key);
if(valueWrapper==null){
returnnull;
}else{
return(T)valueWrapper.get();
}
}
/**
*删除单个对象
*
*@paramkey
*/
publicbooleandeleteObject(finalStringkey)
{
myCache.evict(key);
returntrue;
}
/**
*删除集合对象
*
*@paramcollection多个对象
*@return
*/
publicbooleandeleteObject(finalCollectioncollection)
{
returnmyCache.deleteObject(collection);
}
/**
*获得缓存的基本对象列表
*
*@parampattern字符串前缀
*@return对象列表
*/
publicCollection<String>keys(finalStringpattern)
{
returnmyCache.keys(pattern);
}
}登录校验时删除过期缓存,防止占用内存更改ruoyi-framework目录下web/service/TokenService文件,使用下面方法替换原有方法/**
*验证令牌有效期,相差不足20分钟,自动刷新缓存
*
*@paramloginUser
*@return令牌
*/
publicvoidverifyToken(LoginUserloginUser)
{
longexpireTime=loginUser.getExpireTime();
longcurrentTime=System.currentTimeMillis();
if(expireTime-currentTime<0){
//editbywjl过期删除token
StringuserKey=getTokenKey(loginUser.getToken());
redisCache.deleteObject(userKey);
thrownewServiceException("登录超时",HttpStatus.UNAUTHORIZED);
}
elseif(expireTime-currentTime<=MILLIS_MINUTE_TEN)
{
refreshToken(loginUser);
}
}处理用户信息垃圾缓存问题继续更改上一条修改过的TokenService文件,修改文件当中的createToken(LoginUserloginUser)方法保证每个用户只缓存一个键值对,防止反复登录或直接关闭浏览器产生垃圾缓存//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由于更改太多,直接使用下面整个类替换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;
/**
*缓存监控
*
*@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,"数据字典"));
caches.add(newSysCache(CacheConstants.CAPTCHA_CODE_KEY,"验证码"));
caches.add(newSysCache(CacheConstants.REPEAT_SUBMIT_KEY,"防重提交"));
caches.add(newSysCache(CacheConstants.RATE_LIMIT_KEY,"限流处理"));
caches.add(newSysCache(CacheConstants.PWD_ERR_CNT_KEY,"密码错误次数"));
}
@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等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 中外教育史试题及答案
- 中医消化内科试题及答案
- 浙江省安吉县上墅私立高级中学2024-2025学年高二生物第二学期期末调研试题含解析
- 西宁市重点中学2025届数学高二下期末考试试题含解析
- 矿业临时彩钢房设计与安全监管合同范本
- 绿色建筑财务代理与节能减排合同
- 精养肉牛代养服务合同
- 采棉机操作员安全责任合同书
- 车辆销售与广告宣传合作合同
- 智能家居产品采购合同知识产权及用户隐私保密协议
- 贵州省毕节市2025届高三下学期第四次适应性考试 历史 含答案
- 湖南省邵阳市2025届高三下学期第三次联考生物试题(含答案)
- 承包茶园合同协议书
- 2025年苏教版小学数学五年级下册(全册)知识点复习要点归纳
- 焦虑症病人的护理课件
- 卡尔曼滤波教学课件
- 2025年高考政治抢押秘籍(江苏专用)时政热点02政府工作报告(学生版+解析)
- 正畸治疗中的口腔健康维护
- 2024年江苏省扬州市广陵区小升初语文试卷
- 租赁换电定制合同协议
- 2025标准技术咨询服务合同模板
评论
0/150
提交评论