用redis和jpa实现缓存文章和点击量-SpringBoot(23)

打印 上一主题 下一主题

主题 999|帖子 999|积分 2997

实现流程


1. 实现缓存文章

  1.1 实体类
  1. package com.intehel.demo.domain;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import java.io.Serializable;
  6. @Data
  7. @NoArgsConstructor
  8. @AllArgsConstructor
  9. public class Article implements Serializable {
  10.     private Integer id;
  11.     private Integer num;
  12. }
复制代码
  1.2 数据库持久层
  1. package com.intehel.demo.mapper;
  2. import com.intehel.demo.domain.Article;
  3. import org.apache.ibatis.annotations.*;
  4. import org.springframework.stereotype.Repository;
  5. @Repository
  6. @Mapper
  7. public interface ArticleMapper {
  8.     Article findArticleById(Long id);
  9.     Long updateArticle(@Param("lviews") Long lviews, @Param("lid") Long lid);
  10. }
复制代码
  1.3 mybatis映射文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="com.intehel.demo.mapper.ArticleMapper" >
  4.     <resultMap id="BaseResultMap" type="com.intehel.demo.domain.Article" >
  5.         <id column="id" property="id" jdbcType="INTEGER"/>
  6.         <result column="num" property="num" jdbcType="BIGINT"/>
  7.     </resultMap>
  8.    
  9.     <select id="findArticleById" resultMap="BaseResultMap" parameterType="java.lang.Long" >
  10.         select * from article where id = #{id}
  11.     </select>
  12.    
  13.     <update id="updateArticle" parameterType="java.lang.Long">
  14.         update article set num = #{lviews} where id = #{lid}
  15.     </update>
  16. </mapper>
复制代码
  1.4 实现服务层的缓存设置
  1. package com.intehel.demo.service;
  2. import com.intehel.demo.domain.Article;
  3. import com.intehel.demo.mapper.ArticleMapper;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cache.annotation.CacheConfig;
  7. import org.springframework.cache.annotation.CachePut;
  8. import org.springframework.cache.annotation.Cacheable;
  9. import org.springframework.stereotype.Service;
  10. @Service
  11. @CacheConfig(cacheNames = "articleService")
  12. public class ArticleService {
  13.     @Autowired
  14.     private ArticleMapper articleMapper;
  15.     @Cacheable(key = "#id")
  16.     public Article findArticleById(Long id) {
  17.         return articleMapper.findArticleById(id);
  18.     }
  19.     @CachePut(key = "#lid")
  20.     public Article updateArticle(@Param("lviews") Long lviews, @Param("lid") Long lid) {
  21.         articleMapper.updateArticle(lviews,lid);
  22.         return articleMapper.findArticleById(lid);
  23.     }
  24. }
复制代码
  1.5 配置redis
  1. package com.intehel.demo.config;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import org.springframework.cache.CacheManager;
  6. import org.springframework.cache.annotation.CachingConfigurerSupport;
  7. import org.springframework.cache.interceptor.KeyGenerator;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. import org.springframework.data.redis.cache.RedisCacheConfiguration;
  11. import org.springframework.data.redis.cache.RedisCacheManager;
  12. import org.springframework.data.redis.connection.RedisConnectionFactory;
  13. import org.springframework.data.redis.core.RedisTemplate;
  14. import org.springframework.data.redis.core.StringRedisTemplate;
  15. import org.springframework.data.redis.serializer.*;
  16. import java.lang.reflect.Method;
  17. import java.time.Duration;
  18. @Configuration
  19. public class RedisConfig extends CachingConfigurerSupport {
  20.     //在缓存对象集合中,缓存是以key-value形式保存的
  21.     //如果没有指定缓存的key,则Spring Boot 会使用SimpleKeyGenerator生成key
  22.     @Override
  23.     @Bean
  24.     public KeyGenerator keyGenerator() {
  25.         return new KeyGenerator() {
  26.             @Override
  27.             //定义缓存key的生成策略
  28.             public Object generate(Object target, Method method, Object... params) {
  29.                 StringBuilder sb = new StringBuilder();
  30.                 sb.append(target.getClass().getName());
  31.                 sb.append(method.getName());
  32.                 for (Object obj : params) {
  33.                     sb.append(obj.toString());
  34.                 }
  35.                 return sb.toString();
  36.             }
  37.         };
  38.     }
  39.     @SuppressWarnings("rawtypes")
  40.     @Bean
  41.     //缓存管理器 2.X版本
  42.     public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
  43.         RedisSerializer<String> strSerializer = new StringRedisSerializer();
  44.         Jackson2JsonRedisSerializer jacksonSeial =
  45.                 new Jackson2JsonRedisSerializer(Object.class);
  46.         // 解决查询缓存转换异常的问题
  47.         ObjectMapper om = new ObjectMapper();
  48.         om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  49.         om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  50.         jacksonSeial.setObjectMapper(om);
  51.         // 定制缓存数据序列化方式及时效
  52.         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
  53.                 .entryTtl(Duration.ofDays(1))
  54.                 .serializeKeysWith(RedisSerializationContext.SerializationPair
  55.                         .fromSerializer(strSerializer))
  56.                 .serializeValuesWith(RedisSerializationContext.SerializationPair
  57.                         .fromSerializer(jacksonSeial))
  58.                 .disableCachingNullValues();
  59.         RedisCacheManager cacheManager = RedisCacheManager
  60.                 .builder(connectionFactory).cacheDefaults(config).build();
  61.         return cacheManager;
  62.     }
  63.     //缓存管理器 1.X版本
  64. /*    public CacheManager cacheManager(@SuppressWarnings("rawtypes")RedisTemplate redisTemplate){
  65.         return new RedisCacheManager(redisTemplate);
  66.     }*/
  67.     @Bean
  68.     //注册成Bean被Spring管理,如果没有这个Bean,则Redis可视化工具中的中文内容都会以二进制存储,不易检查
  69.     public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
  70.         RedisTemplate<String, Object> template = new RedisTemplate<>();
  71.         template.setConnectionFactory(factory);
  72.         // 创建JSON格式序列化对象,对缓存数据的key和value进行转换
  73.         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  74.         // 解决查询缓存转换异常的问题
  75.         ObjectMapper om = new ObjectMapper();
  76.         om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  77.         om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  78.         jackson2JsonRedisSerializer.setObjectMapper(om);
  79.         //设置redisTemplate模板API的序列化方式为json
  80.         template.setDefaultSerializer(jackson2JsonRedisSerializer);
  81.         return template;
  82.     }
  83.     @Bean
  84.     public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory){
  85.         StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
  86.         stringRedisTemplate.setConnectionFactory(factory);
  87.         return stringRedisTemplate;
  88.     }
  89.     private RedisSerializer<?> keySerializer() {
  90.         return new StringRedisSerializer();
  91.     }
  92.     // 值使用jackson进行序列化
  93.     private RedisSerializer<?> valueSerializer() {
  94.         return new GenericJackson2JsonRedisSerializer();
  95.         // return new JdkSerializationRedisSerializer();
  96.     }
  97. }
复制代码
2. 实现统计点击量
  1. package com.intehel.demo.controller;
  2. import com.intehel.demo.domain.Article;
  3. import com.intehel.demo.service.ArticleService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. @RestController
  10. @RequestMapping("/article")
  11. public class ArticleController {
  12.     @Autowired
  13.     private ArticleService articleService;
  14.     @Autowired
  15.     private RedisTemplate<String,Object> redisTemplate;
  16.     @RequestMapping("/{id}")
  17.     public Article testPathVariable(@PathVariable("id") Integer id){
  18.         Article article = articleService.findArticleById(Long.valueOf(id));
  19.         System.out.println(article);
  20.         if (article.getNum()>0){
  21.             if (redisTemplate.opsForValue().get("num::"+id)!=null){
  22.                 redisTemplate.opsForValue().increment("num::"+id, 1);
  23.             }else {
  24.                 redisTemplate.boundValueOps("num::"+id).increment(article.getNum()+1);
  25.             }
  26.         }else {
  27.             redisTemplate.boundValueOps("num::"+id).increment(1);
  28.         }
  29.         return article;
  30.     }
  31. }
复制代码
3.实现定时同步
  1. package com.intehel.demo.config;
  2. import com.intehel.demo.service.ArticleService;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.data.redis.core.RedisTemplate;
  5. import org.springframework.scheduling.annotation.Scheduled;
  6. import org.springframework.stereotype.Component;
  7. import javax.annotation.Resource;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import java.util.Set;
  11. @Component
  12. public class CountScheduledTasks {
  13.     @Autowired
  14.     private ArticleService articleService;
  15.     @Resource
  16.     private RedisTemplate<String,Object> redisTemplate;
  17.     @Scheduled(cron = "0/10 * * * * ?" )
  18.     public void syncPostViews(){
  19.         Long StartTime = System.nanoTime();
  20.         List dtolist = new ArrayList();
  21.         Set<String> keySet = redisTemplate.keys("num::*");
  22.         System.out.println(keySet);
  23.         for (String key : keySet) {
  24.             String view = redisTemplate.opsForValue().get(key).toString();
  25.             String sid = key.replaceAll("num::", "");
  26.             Long lid = Long.valueOf(sid);
  27.             Long lviews = Long.valueOf(view);
  28.             articleService.updateArticle(lviews,lid);
  29.             redisTemplate.delete(key);
  30.         }
  31.     }
  32. }
复制代码
  同时要在启动类中添加注解,开启redis缓存和定时任务:
  1. @SpringBootApplication
  2. @EnableCaching
  3. @EnableScheduling
  4. @MapperScan("com.intehel.demo")
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

愛在花開的季節

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表