(Original) Redis-[2] SpringBoot + Redis + Mysql configuration head request header verification

1. Effect

Two, placement

1. Configure 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. Configure 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. Configure CacheManager

Direct configuration will prompt an error:

new RedisCacheManager(redisTemplate) does not have this structure

Now writing this way will report an error The constructor RedisCacheManager(RedisTemplate<capture#1-of ?,capture#2-of ?>) is undefined .

This is because Spring Boot 2.x deletes the RedisCacheManager constructor, and the default cache expiration time cannot be set through the previous setDefaultExpiration method. Solved
 by setting the RedisConnectionFactory factory , and finally RedisConfig.java is as follows:

   /***
 * 配置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;
    }

 

 
}

Creating an entity class must implement Serializable serialized, because redis save the object when the object is serialized requirements such as:

After the entity class is configured, the interface class of the redis operation is encapsulated and used:

 

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);
    }
	 

}

 

It is convenient to organize redis-key, create a key management file, and perform unified management of all business classes to be cached, such as

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


}

The basic configuration is complete and ready to start.

All configuration files are in the resource: [  https://download.csdn.net/download/qq_31653405/12440229  ]


Problems that may be encountered after startup :

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

solve

As shown above, add port 127.0.0.1:6379

Expansion: host becomes ip:port, multiple ips and ports of the cluster are separated by ",",

2 . The problem : the problem starts again: org.springframework.data.redis.core.HashOperations

Solve :

The reason is that the lack of HashOperationsbean in redis is actually prompted below, so inject the bean in redisconfig and call it again at the same time.

  //实例化 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();
    }

In the * Service.java file as shown in the figure above

Visit this article [ https://blog.csdn.net/hello_world_qwp/article/details/81205921  ]

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

The current question says: When configuring the redis cluster, the address is 127 IP

Solution: When configuring the cluster, be sure to use the IP address, do not use 127/localhost, etc. instead of IP

4. Problem: Command timed out connection request timed out

Set the time in spring.xml to be longer

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

The above configuration completely solves this problem.


3. Explanation of annotations used

 

Four, Springboot implements CRUD through redis

4.1 Save list

ListOperations<String, Object> in Redis                                --------->                 Save list

Introduce RedisTemplate in controller.java

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

After the current method is executed successfully, check the value of the corresponding redis-key in the redis viewing tool [ (original) Redis-[1] Redis initial, installation, operation and use ]: (There may be garbled characters, if it occurs, proceed Modify the attribute of setValueSerializer() in RedisConfig.java)

 @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;
    }

Attachment: Springboot, redis, jwt realize token verification

  1. Why should Token be stored in Redis?
  2. 1. Token is time-sensitive. Simply put, it is the validity period. After this period, the token will become invalid and the user needs to log in again. But how to achieve this timeliness in the project? Redis is used at this time. Redis naturally supports setting the expiration time and reaching the automatic renewal effect through some third-party provided package APIs.
  3. 2. Redis adopts NoSQL technology, which can support hundreds of thousands of read/write operations per second, and its performance far exceeds that of databases. Redis can also deal with it calmly when the number of requests is large.
  4. 3. User login information generally does not need to be stored for a long time, and stored in memory, which can reduce the pressure on the database;

4.2 Take list 

Redis is taken out just stored List ------------------------------>

                   It determines whether there redisTemplate. HasKey (Constants.USER_TOKEN_KEY);

                   If it exists, remove 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()){
              	  WxUsers wxUser = it.next();
               	  if(!token.equals(wxUser.getWx_userOpenId())) {
                		  throw new RuntimeException(ErrorMessage.error_login_no_user);    
            	  }
           }

4.3 Compare whether a value in the foreground is the same as a value in the list in redis

By introducing the configuration of the redis caching mechanism in the interceptor to compare whether the values ​​in redis are the same

            /***
             * 存入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);
            }

The above code is required for comparison, but when starting the project, the following error will be prompted,

the reason:

      The springboot interceptor is executed before the Bean is instantiated, so the Bean instance cannot be injected, that is, when we want to get the value of the token in redis, we find that the redisTemplate is not empty and not injected.

solve:

     Knowing that the interceptor is executed before the bean is instantiated, then we let the interceptor instantiate the interceptor bean when the interceptor is executed, and then instantiate the interceptor in the interceptor configuration class, and then obtain it.

  Interceptor configuration : WebAppConfig.java

@Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {	 
    //访问图片方法
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {      
        String os = System.getProperty("os.name");        
        if (os.toLowerCase().startsWith("win")) {  //如果是Windows系统
            registry.addResourceHandler("/images/**")
                  // /apple/**表示在磁盘apple目录下的所有资源会被解析为以下的路径
                  .addResourceLocations("file:/D:/images/"); //媒体资源
         } else {  //linux 和mac
            registry.addResourceHandler("/images/**")
                  .addResourceLocations("file:/usr/local/wwwroot/images/");   //媒体资源
         }
        super.addResourceHandlers(registry);
    }
//引用拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor()).addPathPatterns( "/**");
    }
//注册拦截器
    @Bean
    public HandlerInterceptor handlerInterceptor(){
        return new HandlerInterceptor();
    }  
}

Filter configuration : 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 Passing Parameter Call

Enter the parameter value to be passed in the head of the applet:

      //获取小程序平台基本信息
      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
          }); 
        }
      }), 

Then in the background server, take the wx_userOpenId in the head through the interceptor and verify whether the verification is passed.

 

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集合

 


The above is arranged by myself in the project, and I have tested it and can be used directly;

Next, update redis in springboot if it implements basic CRUD, and the basic functional content !

-------------------------------------------------- -------------------------------------------------- ------------

The remaining problem is that the key displayed by the redis client tool is garbled, which is being solved. Anyone who knows please help. Thank you! ! !

If you have any questions in the article, you can comment in the comment area to discuss the mysteries of programming together!

 -------------------------------------------------- ------------------------------------------------- ------------

If my article is helpful to you, please give me a reward and encourage bloggers .
 
  

 

 

 

Guess you like

Origin blog.csdn.net/qq_31653405/article/details/106216460