SpringBoot以Redis+MySQLhead请求头验证的方式谈话

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: SpringBoot以Redis+MySQLhead请求头验证的方式谈话

主页:写程序的小王叔叔的博客欢迎来访👀

支持:点赞收藏关注


1 配置

1 pom.xml

<!--引用Jedis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>

2 spring.xml

##################Redis配置######### Redis服务器地址spring.redis.host=127.0.0.1
# Redis服务器连接端口spring.redis.port=6379
# Redis服务器连接密码(默认为空)spring.redis.password=123456789
# 连接池最大连接数(使用负值表示没有限制)spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)spring.redis.timeout=0
spring.redis.commandTimeout=5000
#连接的数据库spring.redis.database=0
# redis.clusterspring.redis.cluster.nodes=127.0.0.1:6379
####################################################

3 CacheManager

直接配置会提示错误:

image.png

new RedisCacheManager(redisTemplate)没有此构造

现在这么写会有报错

The constructor RedisCacheManager(RedisTemplate) is undefined。

这是因为Spring Boot 2.x版本删除了RedisCacheManager这个构造器, 也不可以通过之前的setDefaultExpiration方法设置默认的缓存过期时间等。

通过设置RedisConnectionFactory factory进行解决,最后RedisConfig.java如下:

/**** 配置redis缓存* @author Administrator**/@Configuration@EnableCaching//启用缓存publicclassRedisConfigextendsCachingConfigurerSupport{
//注入 RedisConnectionFactory@AutowiredpublicRedisConnectionFactoryredisConnectionFactory;
//实例化 RedisTemplate 对象 设置数据存入 redis 的序列化方式@BeanpublicRedisTemplate<String, Object>functionDomainRedisTemplate() {
RedisTemplate<String, Object>redisTemplate=newRedisTemplate<>();
//定义key生成策略redisTemplate.setKeySerializer(newStringRedisSerializer());
redisTemplate.setHashKeySerializer(newStringRedisSerializer());
redisTemplate.setHashValueSerializer(newJdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(newJdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
returnredisTemplate;
    }
//缓存管理器 --》配置缓存时间@BeanpublicCacheManagercacheManager(RedisConnectionFactoryfactory) {
RedisCacheConfigurationconfig=RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(-1));
RedisCacheManagercacheManager=RedisCacheManager.builder(factory).cacheDefaults(config).build();
returncacheManager;
    }
}

image.png

创建实体类,一定要实现Serializable序列化,因为redis保存对象的时候要求对象是序列化

如:


实体类配置好后,将redis的操作的接口类进行封装后,进行使用:

publicinterfaceRedisService{
publicbooleanset(finalStringkey, Objectvalue);
publicbooleanset(finalStringkey, Objectvalue, LongexpireTime);
publicvoidremove(finalString... keys);
publicvoidremovePattern(finalStringpattern);
publicvoidremove(finalStringkey);
publicbooleanexists(finalStringkey);
publicObjectget(finalStringkey);
publicvoidhmSet(Stringkey, ObjecthashKey, Objectvalue);
publicObjecthmGet(Stringkey, ObjecthashKey);
publicvoidlPush(Stringk,Objectv);
publicList<Object>lRange(Stringk, longl, longl1);
publicvoidadd(Stringkey,Objectvalue);
publicSet<Object>setMembers(Stringkey);
publicvoidzAdd(Stringkey,Objectvalue,doublescoure);
publicSet<Object>rangeByScore(Stringkey,doublescoure,doublescoure1);
}
package***;
importjava.io.Serializable;
importjava.util.List;
importjava.util.Set;
importjava.util.concurrent.TimeUnit;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.redis.core.HashOperations;
importorg.springframework.data.redis.core.ListOperations;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.core.SetOperations;
importorg.springframework.data.redis.core.ValueOperations;
importorg.springframework.data.redis.core.ZSetOperations;
importorg.springframework.stereotype.Service;
@SuppressWarnings("all")
@ServicepublicclassRedisServiceImplimplementsRedisService{
@AutowiredprivateRedisTemplateredisTemplate;
/*** 写入缓存* @param key* @param value* @return*/publicbooleanset(finalStringkey, Objectvalue) {
booleanresult=false;
try {
ValueOperations<Serializable, Object>operations=redisTemplate.opsForValue();
operations.set(key, value);
result=true;
        } catch (Exceptione) {
e.printStackTrace();
        }
returnresult;
    }
/*** 写入缓存设置时效时间* @param key* @param value* @return*/publicbooleanset(finalStringkey, Objectvalue, LongexpireTime) {
booleanresult=false;
try {
ValueOperations<Serializable, Object>operations=redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result=true;
        } catch (Exceptione) {
e.printStackTrace();
        }
returnresult;
    }
/*** 批量删除对应的value* @param keys*/publicvoidremove(finalString... keys) {
for (Stringkey : keys) {
remove(key);
        }
    }
/*** 批量删除key* @param pattern*/publicvoidremovePattern(finalStringpattern) {
Set<Serializable>keys=redisTemplate.keys(pattern);
if (keys.size() >0)
redisTemplate.delete(keys);
    }
/*** 删除对应的value* @param key*/publicvoidremove(finalStringkey) {
if (exists(key)) {
redisTemplate.delete(key);
        }
    }
/*** 判断缓存中是否有对应的value* @param key* @return*/publicbooleanexists(finalStringkey) {
returnredisTemplate.hasKey(key);
    }
/*** 读取缓存* @param key* @return*/publicObjectget(finalStringkey) {
Objectresult=null;
ValueOperations<Serializable, Object>operations=redisTemplate.opsForValue();
result=operations.get(key);
returnresult;
    }
/*** 哈希 添加* @param key* @param hashKey* @param value*/publicvoidhmSet(Stringkey, ObjecthashKey, Objectvalue){
HashOperations<String, Object, Object>hash=redisTemplate.opsForHash();
hash.put(key,hashKey,value);
    }
/*** 哈希获取数据* @param key* @param hashKey* @return*/publicObjecthmGet(Stringkey, ObjecthashKey){
HashOperations<String, Object, Object>hash=redisTemplate.opsForHash();
returnhash.get(key,hashKey);
    }
/*** 列表添加* @param k* @param v*/publicvoidlPush(Stringk,Objectv){
ListOperations<String, Object>list=redisTemplate.opsForList();
list.rightPush(k,v);
    }
/*** 列表获取* @param k* @param l* @param l1* @return*/publicList<Object>lRange(Stringk, longl, longl1){
ListOperations<String, Object>list=redisTemplate.opsForList();
returnlist.range(k,l,l1);
    }
/*** 集合添加* @param key* @param value*/publicvoidadd(Stringkey,Objectvalue){
SetOperations<String, Object>set=redisTemplate.opsForSet();
set.add(key,value);
    }
/*** 集合获取* @param key* @return*/publicSet<Object>setMembers(Stringkey){
SetOperations<String, Object>set=redisTemplate.opsForSet();
returnset.members(key);
    }
/*** 有序集合添加* @param key* @param value* @param scoure*/publicvoidzAdd(Stringkey,Objectvalue,doublescoure){
ZSetOperations<String, Object>zset=redisTemplate.opsForZSet();
zset.add(key,value,scoure);
    }
/*** 有序集合获取* @param key* @param scoure* @param scoure1* @return*/publicSet<Object>rangeByScore(Stringkey,doublescoure,doublescoure1){
ZSetOperations<String, Object>zset=redisTemplate.opsForZSet();
returnzset.rangeByScore(key, scoure, scoure1);
    }
}

redis-key的整理,创建一个key的管理文件,进行将所有要缓存的业务类进行统一管理,如

/***** 整合redis缓存key文件* @author Administrator**/publicclassRedisServiceKey  {
publicstaticfinalStringProduct_REDIS_KEY="Product_KEY"; 
}

基本配置就全部完成,可以启动。


启动后可能遇见的问题:

1.问题:HostAndPort need to be seperated by ':'.

image.png

解决:如上图,添加端口127.0.0.1:6379

扩展:host变成ip:port,集群多个ip和端口用“,”分割,

2.问题:再次启动出现问题:org.springframework.data.redis.core.HashOperations

image.png

解决:缺少redis中HashOperationsbean,其实在下面已经提示了,所以在redisconfig中注入bean,并同时在再调用下就可以了

//实例化 HashOperations 对象,可以使用 Hash 类型操作

 

@BeanpublicHashOperations<String, String, Object>hashOperations(RedisTemplate<String, Object>redisTemplate) {
returnredisTemplate.opsForHash();
    }
//实例化 ValueOperations 对象,可以使用 String 操作@BeanpublicValueOperations<String, Object>valueOperations(RedisTemplate<String, Object>redisTemplate) {
returnredisTemplate.opsForValue();
    }
//实例化 ListOperations 对象,可以使用 List 操作@BeanpublicListOperations<String, Object>listOperations(RedisTemplate<String, Object>redisTemplate) {
returnredisTemplate.opsForList();
    }
//实例化 SetOperations 对象,可以使用 Set 操作@BeanpublicSetOperations<String, Object>setOperations(RedisTemplate<String, Object>redisTemplate) {
returnredisTemplate.opsForSet();
    }
//实例化 ZSetOperations 对象,可以使用 ZSet 操作@BeanpublicZSetOperations<String, Object>zSetOperations(RedisTemplate<String, Object>redisTemplate) {
returnredisTemplate.opsForZSet();
    }

如上图的Service.java文件中

image.png

3.问题:Cannot retrieve initial cluster partitions from initial URIs [RedisURI [host='127.0.0.1', port=6379]]

当前问题说:在配置redis集群时,地址用的是127的IP

解决 :在配置集群时,一定要用IP地址,不要用127/localhost等代替IP

4.问题:Command timed out 连接请求超时

将spring.xml中时间设长一点

# 连接超时时间(毫秒)
spring.redis.timeout=200
spring.redis.commandTimeout=500000

通过上面的配置完全解决这个问题的所在.

2、通过redis实现CRUD

1 存list

Redis中的 ListOperations ---------> 存list

在controller.java中引入RedisTemplate

@Autowired
  protected RedisTemplate<String,Object> redisTemplate;
List<WxUsers> wxUserList = wxUsersService.findAll();
 redisTemplate.opsForList().rightPushAll(RedisServiceKey.WxMemberList_REDIS_KEY, wxUserList);

当前方法执行成功之后,在redis查看工具【Redis的初始,安装及运行和使用】中进行查看对应的redis-key的值:(可能会出现乱码情况,出现则进行修改RedisConfig.java中的setValueSerializer()的属性)

image.png

@Bean
    public RedisTemplate<String,Object> functionDomainRedisTemplate() {
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
       //定义key生成策略
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

附 : Springboot 、redis 、 jwt 实现token验证

  1. Token 为什么要存储到Redis?
  2. 1.Token 具有时效性,简单来说就是有效期,超过了这个期限Token 就会失效,需要用户重新登录。但是怎么在项目中实现这个时效性,这个时候就用到Redis,Redis天然支持支持设置过期时间以及通过一些第三方提供包的API到达自动续时效果。
  3. 2.Redis采用NoSQL技术,可以支持每秒十几万此的读/写操作,其性能远超数据库,在请求数量较多的时候,Redis也可以从容应对
  4. 3.用户登录信息一般不需要长效储存,放在内存中,可以减少数据库的压力;

2 取list

Redis中的 取出刚存的 list 判断是否存在 redisTemplate.hasKey(Constants.USER_TOKEN_KEY );

存在就取出 redisTemplate.opsForValue().get( Constants.USER_TOKEN_KEY );

List<WxUsers>wxUserList=redisTemplate.opsForList().range(RedisServiceKey.WxMemberList_REDIS_KEY, 0, -1);
log.info(">>>>>>>>>>>>>>>list = {}", wxUserList);
Iterator<WxUsers>it=wxUserList.iterator();
while(it.hasNext()){
WxUserswxUser=it.next();
if(!token.equals(wxUser.getWx_userOpenId())) {
thrownewRuntimeException(ErrorMessage.error_login_no_user);    
                }
           }

3 比对某个值

通过引入 在拦截器中配置redis缓存机制 实现比对redis中值是否相同

/**** 存入list- redis 并取出 list - redis  - openid*/booleanhasKey=redisTemplate.hasKey(RedisServiceKey.WxMemberList_REDIS_KEY);
if(hasKey) {  
//取listList<WxUsers>wxUserList=redisTemplate.opsForList().range(RedisServiceKey.WxMemberList_REDIS_KEY, 0, -1);
log.info(">>>>>>>>>>>>>>>list = {}", wxUserList);
Iterator<WxUsers>it=wxUserList.iterator();
while(it.hasNext()){
WxUserswxUser=it.next();
if(token.equals(wxUser.getWx_userOpenId())) {
break;
                    } 
//                    // 验证 token//                      JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(token)).build();//                      try {//                          jwtVerifier.verify(token);//                      } catch (JWTVerificationException e) {//                          throw new RuntimeException("401");//                      }                  }
            }else {
//存listList<WxUsers>wxUserList=wxUsersService.findAll();
redisTemplate.opsForList().rightPushAll(RedisServiceKey.WxMemberList_REDIS_KEY, wxUserList);
thrownewRuntimeException(ErrorMessage.error_login_no_user);
            }

以上代码是比对的所需内容,但是在启动项目时,会提示下面错误,

image.png

原因

springboot拦截器是在Bean实例化之前执行的,所以Bean实例无法注入,也就是当我们想获取redis里面key是token的值时,发现redisTemplate没有是空的没有注入进来

解决

知道拦截器执行在bean实例化前执行的,那么我们就让拦截器执行的时候实例化拦截器Bean,在拦截器配置类里面先实例化拦截器,然后再获取。

拦截器配置:WebAppConfig.java

@ConfigurationpublicclassWebAppConfigextendsWebMvcConfigurerAdapter {  
//访问图片方法@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistryregistry) {      
Stringos=System.getProperty("os.name");        
if (os.toLowerCase().startsWith("win")) {  //如果是Windows系统registry.addResourceHandler("/images/**")
// /apple/**表示在磁盘apple目录下的所有资源会被解析为以下的路径                  .addResourceLocations("file:/D:/images/"); //媒体资源         } else {  //linux 和macregistry.addResourceHandler("/images/**")
                  .addResourceLocations("file:/usr/local/wwwroot/images/");   //媒体资源         }
super.addResourceHandlers(registry);
    }
//引用拦截器@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry) {
registry.addInterceptor(handlerInterceptor()).addPathPatterns( "/**");
    }
//注册拦截器@BeanpublicHandlerInterceptorhandlerInterceptor(){
returnnewHandlerInterceptor();
    }  
}

过滤器配置:HandlerInterceptor.java

@ComponentpublicclassHandlerInterceptorextendsHandlerInterceptorAdapter {
privatestaticfinalorg.slf4j.Loggerlog=org.slf4j.LoggerFactory.getLogger(HandlerInterceptor.class);
@AutowiredprivateRedisTemplate<String, Object>redisTemplate;
@AutowiredprivateValueOperations<String,Object>opsForValue;
@AutowiredprivateWxUsersServicewxUsersService;
publicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler) {
Stringtoken=request.getHeader(Constants.USER_OPENID_KEY);// 从 http 请求头中取出 token// 如果是handler方法直接继续执行if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) {
log.debug("This is handler.");
System.out.println("-----This is handler.-----");
returntrue;
        }
finalHandlerMethodhandlerMethod= (HandlerMethod) handler;
finalMethodmethod=handlerMethod.getMethod();
finalClass<?>clazz=method.getDeclaringClass();
// 如果有auth注解,进行token登录验证if (clazz.isAnnotationPresent(Auth.class) ||method.isAnnotationPresent(Auth.class)) {
log.debug("-----Auth----token:"+Constants.USER_OPENID_KEY+"-----");
System.out.println("-----Auth----token:"+Constants.USER_OPENID_KEY+"-----");
// 如果没有token进行拦截。if (token==null) {
thrownewRuntimeException(ErrorMessage.error_fresh_user_login_all);
            }
/**** 存入list- redis 并取出 list - redis  - openid*/booleanhasKey=redisTemplate.hasKey(RedisServiceKey.WxMemberList_REDIS_KEY);
if(hasKey) {    
//取listList<WxUsers>wxUserList=redisTemplate.opsForList().range(RedisServiceKey.WxMemberList_REDIS_KEY, 0, -1);
log.info(">>>>>>>>>>>>>>>list = {}", wxUserList);
Iterator<WxUsers>it=wxUserList.iterator();
while(it.hasNext()){
WxUserswxUser=it.next();
if(token.equals(wxUser.getWx_userOpenId())) {
break;
                      } 
//                    // 验证 token//                      JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(token)).build();//                      try {//                          jwtVerifier.verify(token);//                      } catch (JWTVerificationException e) {//                          throw new RuntimeException("401");//                      }                  }
            }else {
//存listList<WxUsers>wxUserList=wxUsersService.findAll();
redisTemplate.opsForList().rightPushAll(RedisServiceKey.WxMemberList_REDIS_KEY, wxUserList);
thrownewRuntimeException(ErrorMessage.error_login_no_user);
            }
returntrue;
        }
log.debug("-----Auth----No-----");
System.out.println("-----Auth----No-----");
returntrue;
    }
/*** 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)*/@OverridepublicvoidafterCompletion(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler, Exceptionex) {
//        System.out.println("执行了TestInterceptor的afterCompletion方法");    }
}

4 传参调用

在小程序端head中输入要传的参数值:

image.png

//获取小程序平台基本信息wx.request({       
url: base.path.www+'WxPlatform/SelectWxPlatformInfo',
method: 'post',
data: {  },
header: { 'content-type': 'application/json;charset=UTF-8' , 'wx_userOpenId': wx.getStorageSync('wxMemberOpenId') },
success(res) {                 
wx.setStorageSync('wxPlatformInfo', res.data.data.wxPlatformInfo);
that.setData({
wxPlatformInfo: res.data.data.wxPlatformInfo          }); 
        }
      }),

然后在后台服务器中通过拦截器进行取head中的wx_userOpenId并进行验证是否验证通过

image.png

stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);//向redis里存入数据和设置缓存时间stringRedisTemplate.opsForValue().get("test") //根据key获取缓存中的valstringRedisTemplate.boundValueOps("test").increment(-1); //val做-1操作stringRedisTemplate.boundValueOps("test").increment(1); //val +1stringRedisTemplate.getExpire("test") //根据key获取过期时间stringRedisTemplate.getExpire("test",TimeUnit.SECONDS) //根据key获取过期时间并换算成指定单位stringRedisTemplate.delete("test"); //根据key删除缓存stringRedisTemplate.hasKey("546545"); //检查key是否存在,返回boolean值stringRedisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS); //设置过期时间stringRedisTemplate.opsForSet().add("red_123", "1","2","3");  //向指定key中存放set集合stringRedisTemplate.opsForSet().isMember("red_123", "1")  //根据key查看集合中是否存在指定数据stringRedisTemplate.opsForSet().members("red_123");  //根据key获取set集合


遗留问题就是 redis的客户端工具显示的key是乱码,正在解决,有知道的大佬请帮下谢谢了!!!

image.png

扩展:

@OverridepublicWxPlatformSelectWxDefaultPlatformInfo(StringwxAgentAddrId) {
WxAgentAddresswxAgentAddress=wxAgentAddressService.getDefaultPlatform(wxAgentAddrId);
WxPlatformplatform=wxPlatformRepository.getWxDafaultPlatformInfo(wxAgentAddress.getWx_areaId());
// 判断key是否存在if(!redisServiceImpl.exists(RedisServiceKey.WxPlatform_REDIS_KEY)) {
// 获取key的valueWxPlatformwxPlat= (WxPlatform) redisServiceImpl.get(RedisServiceKey.WxPlatform_REDIS_KEY);
if(wxPlat!=null&&!wxPlat.getWx_agentAddressId().equals(wxAgentAddrId)) {
// 删除keyredisServiceImpl.remove(RedisServiceKey.WxPlatform_REDIS_KEY);
      }
    } 
// 保存keyredisServiceImpl.set(RedisServiceKey.WxPlatform_REDIS_KEY, platform);  
//WxPlatform wxPlat = (WxPlatform) redisServiceImpl.get(RedisServiceKey.WxPlatform_REDIS_KEY);    returnplatform;
  }


在操作redis中的key时,每个key都要去判断下hashkey是否存在,然后进行业务的相关操作


⚠️注意 ~

💯本期内容就结束了,如果内容有误,麻烦大家评论区指出!

如有疑问❓可以在评论区💬或私信💬,尽我最大能力🏃‍♀️帮大家解决👨‍🏫!

如果我的文章有帮助到您,欢迎关注+点赞✔️鼓励博主🏃,您的鼓励是我分享的动力🏃🏃🏃~


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
23天前
|
NoSQL Java Redis
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
246 0
|
1月前
|
消息中间件 NoSQL Java
springboot redis 实现消息队列
springboot redis 实现消息队列
39 1
|
28天前
|
NoSQL Java Redis
SpringBoot集成Redis
SpringBoot集成Redis
394 0
|
7天前
|
NoSQL 数据可视化 Java
Springboot整合redis
Springboot整合redis
|
7天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
146 10
|
16天前
|
NoSQL Java Redis
Springboot整合redis
Springboot整合redis
|
24天前
|
NoSQL Java Redis
SpringBoot集成Redis
SpringBoot集成Redis
53 1
|
1月前
|
缓存 NoSQL Java
springboot中集成redis,二次封装成工具类
springboot中集成redis,二次封装成工具类
174 0
|
1月前
|
缓存 NoSQL Java
spring cache整合redis实现springboot项目中的缓存功能
spring cache整合redis实现springboot项目中的缓存功能
46 1
|
1月前
|
监控 NoSQL Java
Spring Boot集成Redis启动失败【Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.G】
Spring Boot集成Redis启动失败【Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.G】