商道如狼道 发表于 2024-6-11 09:01:10

使用Spring Boot实现Redis多数据库缓存

Redis多数据库存储实现用户行为缓存

在我的系统中,为了优化用户行为数据的存储与访问服从,我引入了Redis缓存,并将数据分布在不同的Redis数据库中。通过这种方式,可以淘汰单一数据库的负载,进步系统的整体性能。
紧张实现步骤


[*] Redis配置

[*]配置两个Redis毗连工厂,分别用于存储Token和用户行为数据。
[*]创建对应的RedisTemplate实例,指定不同的毗连工厂及序列化方式。

[*] 用户行为服务

[*]通过UserBehaviorService接口及实在现类UserBehaviorServiceImpl,实现对用户点赞、收藏、品评、浏览行为的记录。
[*]在操作数据库的同时,将用户行为数据存储到Redis中以进步读取服从。

[*] Token拦截器

[*]使用TokenInterceptor类在每次请求前验证Token。
[*]验证通过后,将用户信息存储到ThreadLocal中,供后续操作使用。

代码实现

Redis配置类

@Configuration
public class RedisConfig {

    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")
    private String redisPassword;

    @Bean(name = "tokenRedisConnectionFactory")
    public RedisConnectionFactory tokenRedisConnectionFactory() {
      RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
      config.setPassword(redisPassword);
      config.setDatabase(0);
      return new LettuceConnectionFactory(config);
    }

    @Bean(name = "userBehaviorRedisConnectionFactory")
    public RedisConnectionFactory userBehaviorRedisConnectionFactory() {
      RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
      config.setPassword(redisPassword);
      config.setDatabase(1);
      return new LettuceConnectionFactory(config);
    }

    @Bean(name = "redisTemplate")
    public StringRedisTemplate redisTemplate(@Qualifier("tokenRedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
      StringRedisTemplate template = new StringRedisTemplate();
      template.setConnectionFactory(redisConnectionFactory);
      template.setKeySerializer(new StringRedisSerializer());
      template.setValueSerializer(new StringRedisSerializer());
      return template;
    }

    @Bean(name = "userBehaviorRedisTemplate")
    public RedisTemplate<String, Map<String, Integer>> userBehaviorRedisTemplate(@Qualifier("userBehaviorRedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
      RedisTemplate<String, Map<String, Integer>> template = new RedisTemplate<>();
      template.setConnectionFactory(redisConnectionFactory);
      template.setKeySerializer(new StringRedisSerializer());
      template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Map.class));
      return template;
    }
}
用户行为服务实现类

@Service
public class UserBehaviorServiceImpl implements UserBehaviorService {

    private static final long CACHE_EXPIRATION_DAYS = 1;
    private static final String CACHE_PREFIX = "articleCounts:";

    @Autowired
    private UserBehaviorMapper userBehaviorMapper;

    @Autowired
    @Qualifier("userBehaviorRedisTemplate")
    private RedisTemplate<String, Map<String, Integer>> userBehaviorRedisTemplate;

    @Override
    public void setLikeArticle(Likes likes) {
      likes.setCreateTime(LocalDateTime.now());
      Integer userId = ThreadLocalUtil.getUser("id");
      if (userId != null) {
            likes.setUserId(userId);
      }
      userBehaviorMapper.insertLike(likes);
    }

    @Override
    public void setFavoriteArticle(Favorites favorites) {
      favorites.setCreateTime(LocalDateTime.now());
      Integer userId = ThreadLocalUtil.getUser("id");
      if (userId != null) {
            favorites.setUserId(userId);
      }
      userBehaviorMapper.insertFavorite(favorites);
    }

    @Override
    public void setCommentArticle(Comments comments) {
      comments.setCreateTime(LocalDateTime.now());
      Integer userId = ThreadLocalUtil.getUser("id");
      if (userId != null) {
            comments.setUserId(userId);
      }
      userBehaviorMapper.insertComment(comments);
    }

    @Override
    public void setViewArticle(Views views) {
      views.setCreateTime(LocalDateTime.now());
      Integer userId = ThreadLocalUtil.getUser("id");
      if (userId != null) {
            views.setUserId(userId);
      }
      userBehaviorMapper.insertView(views);
    }

    @Override
    public Map<String, Integer> getArticleCounts(Integer articleId) {
      String key = CACHE_PREFIX + articleId;
      Map<String, Integer> counts = userBehaviorRedisTemplate.opsForValue().get(key);
      if (counts == null) {
            counts = fetchArticleCountsFromDB(articleId);
            cacheArticleCounts(articleId, counts);
      }
      return counts;
    }

    private Map<String, Integer> fetchArticleCountsFromDB(Integer articleId) {
      Map<String, Integer> counts = new HashMap<>();
      counts.put("likesCount", userBehaviorMapper.selectLikesCount(articleId));
      counts.put("favoritesCount", userBehaviorMapper.selectFavoritesCount(articleId));
      counts.put("commentsCount", userBehaviorMapper.selectCommentsCount(articleId));
      counts.put("viewsCount", userBehaviorMapper.selectViewsCount(articleId));
      return counts;
    }

    private void cacheArticleCounts(Integer articleId, Map<String, Integer> counts) {
      String key = CACHE_PREFIX + articleId;
      userBehaviorRedisTemplate.opsForValue().set(key, counts, CACHE_EXPIRATION_DAYS, TimeUnit.DAYS);
    }
}
Token拦截器

@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
      String token = request.getHeader("Authorization");
      if (token == null || token.isEmpty()) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
      }

      try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            String redisToken = operations.get(token);
            if (redisToken == null) {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                return false;
            }

            Map<String, Object> claims = JwtUtil.parseToken(token);
            ThreadLocalUtil.setUser(claims);
            return true;
      } catch (Exception e) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
      }
    }

    @Override
    public void postHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception {
      ThreadLocalUtil.remove();
    }
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 使用Spring Boot实现Redis多数据库缓存