SpringBoot+Redis+MySQL head请求头的验证

举报
写程序的小王叔叔 发表于 2022/05/18 16:27:22 2022/05/18
【摘要】 主页:小王叔叔的博客

主页小王叔叔的博客

支持:点赞👍关注✔️收藏💖


一、效果

   

二、配置

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.cluster
spring.redis.cluster.nodes=127.0.0.1:6379
##########################################################################

3.配置CacheManager

直接配置会提示错误:

new RedisCacheManager(redisTemplate)没有此构造

现在这么写会有报错The constructor RedisCacheManager(RedisTemplate<capture#1-of ?,capture#2-of ?>) is undefined

这是因为Spring Boot 2.x版本删除了RedisCacheManager这个构造器, 也不可以通过之前的setDefaultExpiration方法设置默认的缓存过期时间等。
 通过设置RedisConnectionFactory  factory进行解决,最后RedisConfig.java如下:

   /***
 * 配置redis缓存
 * @author Administrator
 *
 */
@Configuration
@EnableCaching//启用缓存
public class RedisConfig extends CachingConfigurerSupport{

	

    //注入 RedisConnectionFactory
    @Autowired
    public RedisConnectionFactory redisConnectionFactory;
    
    
    //实例化 RedisTemplate 对象 设置数据存入 redis 的序列化方式
    @Bean
    public RedisTemplate<String, Object> functionDomainRedisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
       //定义key生成策略
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    //缓存管理器 --》配置缓存时间
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory  factory) {
        RedisCacheConfiguration config =  RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(-1));
        RedisCacheManager cacheManager =  RedisCacheManager.builder(factory).cacheDefaults(config).build();
        return cacheManager;
    }

 

 
}

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

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

public interface  RedisService{
 
	   public boolean set(final String key, Object value);
	 
	    public boolean set(final String key, Object value, Long expireTime);
	 
	    public void remove(final String... keys);
	 
	    public void removePattern(final String pattern);
	 
	    public void remove(final String key);
	 
	    public boolean exists(final String key);
	 
	    public Object get(final String key);
	 
	    public void hmSet(String key, Object hashKey, Object value);
	    
	    public Object hmGet(String key, Object hashKey);
	 
	    public void lPush(String k,Object v);
	 
	    public List<Object> lRange(String k, long l, long l1);
	 
	    public void add(String key,Object value);
	 
	    public Set<Object> setMembers(String key);
	 
	    public void zAdd(String key,Object value,double scoure);
	  
	    public Set<Object> rangeByScore(String key,double scoure,double scoure1);
	
}
package  ***;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

@SuppressWarnings("all")
@Service
public class RedisServiceImpl  implements  RedisService{

	
	@Autowired
    private RedisTemplate redisTemplate;
    /**
     * 写入缓存
     * @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) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 批量删除对应的value
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }
 
    /**
     * 批量删除key
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }
    /**
     * 删除对应的value
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }
    /**
     * 判断缓存中是否有对应的value
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }
    /**
     * 读取缓存
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }
    /**
     * 哈希 添加
     * @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);
    }
 
    /**
     * 列表添加
     * @param k
     * @param v
     */
    public void lPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k,v);
    }
 
    /**
     * 列表获取
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k,l,l1);
    }
 
    /**
     * 集合添加
     * @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);
    }
 
    /**
     * 有序集合添加
     * @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();
        return zset.rangeByScore(key, scoure, scoure1);
    }
	 

}

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

/****
 * 整合redis缓存key文件
 * @author Administrator
 *
 */
public class RedisServiceKey  {
	public static final String Product_REDIS_KEY = "Product_KEY"; 


}

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

所有配置文件在资源中: 【  新建文件夹-redis+springboot+mysql.zip_redis创建文件夹,redis新建文件夹-Redis文档类资源-CSDN下载 】


启动后可能遇见的问题

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

解决

如上图,添加端口127.0.0.1:6379

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

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

解决

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

  //实例化 HashOperations 对象,可以使用 Hash 类型操作
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }
   
    
    //实例化 ValueOperations 对象,可以使用 String 操作
    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

   //实例化 ListOperations 对象,可以使用 List 操作
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    //实例化 SetOperations 对象,可以使用 Set 操作
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    //实例化 ZSetOperations 对象,可以使用 ZSet 操作
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }

如上图的*Service.java文件中

访问这个文章【 Consider defining a bean of type 'org.springframework.data.redis.core.HashOperations' 解决办法_csdn-华仔的博客-CSDN博客 】

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
通过上面的配置完全解决这个问题的所在.

三、所用注解解释


四、Springboot 通过redis实现CRUD

4.1存list

Redis中的                ListOperations<String, Object>               --------->                 存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的初始,安装及运行和使用     

进行查看对应的redis-key的值:(可能会出现乱码情况,出现则进行修改RedisConfig.java中的setValueSerializer()的属性)

 @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.用户登录信息一般不需要长效储存,放在内存中,可以减少数据库的压力;

4.2取list 

Redis中的 出刚存的list ------------------------------>

                   判断是否存在                                      redisTemplate.hasKey( Constants.USER_TOKEN_KEY );

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


4.3比对前台的某个值 和 redis中list的某个值是否相同一样

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


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

原因:

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

解决:

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

  拦截器配置:WebAppConfig.java


过滤器配置:HandlerInterceptor.java 

@Component
public class HandlerInterceptor extends HandlerInterceptorAdapter {
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HandlerInterceptor.class);


    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
	 
    @Autowired
    private ValueOperations<String,Object> opsForValue;

 
    @Autowired
    private WxUsersService wxUsersService;
    

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = 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.-----");
            return true;
        }

        final HandlerMethod handlerMethod = (HandlerMethod) handler;
        final Method method = handlerMethod.getMethod();
        final Class<?> 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) {
                throw new RuntimeException(ErrorMessage.error_fresh_user_login_all);
            }
            
            /***
             * 存入list- redis 并取出 list - redis  - openid
             */
            boolean hasKey = redisTemplate.hasKey(RedisServiceKey.WxMemberList_REDIS_KEY);
            if(hasKey) {	
            	  //取list
            	  List<WxUsers> wxUserList = redisTemplate.opsForList().range(RedisServiceKey.WxMemberList_REDIS_KEY, 0, -1);
            	  log.info(">>>>>>>>>>>>>>>list = {}", wxUserList);
            	  Iterator<WxUsers> it = wxUserList.iterator();
                  while(it.hasNext()){
                	  WxUsers wxUser = 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 {
            	//存list
            	 List<WxUsers> wxUserList = wxUsersService.findAll();
                 redisTemplate.opsForList().rightPushAll(RedisServiceKey.WxMemberList_REDIS_KEY, wxUserList);
                 throw new RuntimeException(ErrorMessage.error_login_no_user);
            }
            
            return true;
        }
        log.debug("-----Auth----No-----");
        System.out.println("-----Auth----No-----");
        return true;

    }

    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//        System.out.println("执行了TestInterceptor的afterCompletion方法");
    }
}

4.4传参调用

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

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

stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);//向redis里存入数据和设置缓存时间
stringRedisTemplate.opsForValue().get("test") //根据key获取缓存中的val
stringRedisTemplate.boundValueOps("test").increment(-1); //val做-1操作
stringRedisTemplate.boundValueOps("test").increment(1); //val +1
stringRedisTemplate.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在springboot中如果实现基本的CRUD,及基本原理功能内容


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


⚠️注意 ~

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

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

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










【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。