需求
在用户浏览文章时要实现对应文章浏览次数的增加
思路
需要在每次用户浏览博客时更新对应的浏览数即可(查看时,viewCount+1)
直接操作博客表的浏览量的话,在并发量大的情况下会怎样…
- 1.在应用启动时把博客的浏览量存储到redis中
- 2.更新浏览量时去更新redis中的数据
- 3.每隔10分钟把Redis中的浏览量更新到数据库中
- 4.读取文章浏览量时从redis读取
涉及知识
1.CommandLineRunner实现项目启动时预处理
在SpringBoot应用启动时进行一些初始化操作,需要实现CommandLineRunner接口
把对应的bean注入容器,相关初始化的代码重新到需要重新的方法中
2.redis缓存
3.定时任务
操作
1.在应用启动时把博客的浏览量存储到redis中
@Component
@Slf4j
public class ViewCountRunner implements CommandLineRunner {
@Autowired
private ArticleMapper articleMapper;
@Autowired
private RedisCache redisCache;
//在程序启动之后,所有Bean都初始化完,自动执行该方法
@Override
public void run(String... args) throws Exception {
//查询博客信息,id viewCount
List<Article> articles = articleMapper.selectList(null);
Map<String, Integer> viewCountMaper = articles.stream().collect(Collectors.toMap(article -> article.getId().toString(), article -> article.getViewCount().intValue()));
//存储到redis中
redisCache.setCacheMap("article:viewCount",viewCountMaper);
log.info("浏览量从mysql更新到redis中......");
}
}
2.更新浏览量时去更新redis中的数据
ArticleController中增加方法更新阅读数
@PutMapping("/updateViewCount/{id}")
public ResponseResult updateViewCount(@PathVariable("id") Long id){
return articleService.updateViewCount(id);
}
ArticleServiceImpl中实现方法
@Override
public ResponseResult updateViewCount(Long id) {
//更新redis中对应 id的浏览量+1
redisCache.incrementCacheMapValue("article:viewCount",id.toString(),1);
return ResponseResult.okResult();
}
RedisCache中的方法:对redis中的某一个hash值进行递增的操作
/**
* 对redis中的某一个hash值进行递增的操作
*/
public void incrementCacheMapValue(String key,String hKey,int v){
redisTemplate.boundHashOps(key).increment(hKey, v);
}
3.每隔10分钟把Redis中的浏览量更新到数据库中
Article中增加构造方法
public Article(Long id, long viewCount) {
this.id = id;
this.viewCount = viewCount;
}
启动类上加注解@EnableScheduling
@SpringBootApplication
@EnableScheduling
public class SanGengBlogApplication {
public static void main(String[] args) {
SpringApplication.run(SanGengBlogApplication.class,args);
}
}
定时任务中的方法
@Component
public class UpdateViewCountJob {
@Autowired
private RedisCache redisCache;
@Autowired
private ArticleService articleService;
@Scheduled(cron = "0/5 * * * * ?")
public void updateViewCount(){
//获取redis中的浏览量
Map<String, Integer> viewCountMap = redisCache.getCacheMap("article:viewCount");
List<Article> articles = viewCountMap.entrySet()
.stream()
.map(entry -> new Article(Long.valueOf(entry.getKey()), entry.getValue().longValue()))
.collect(Collectors.toList());
//更新到数据库中
articleService.updateBatchById(articles);
}
}
4.读取文章浏览量时从redis读取
ArticleController中查看详情
@GetMapping("/{id}")
public ResponseResult getArticleDetail(@PathVariable("id") Long id){
return articleService.getArticleDetail(id);
}
ArticleServiceImpl中实现方法
@Override
public ResponseResult getArticleDetail(Long id) {
//根据id查询文章
Article article = getById(id);
//从redis中获取viewCount
Integer viewCount = redisCache.getCacheMapValue("article:viewCount", id.toString());
article.setViewCount(viewCount.longValue());
//转换成VO
ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
//根据分类id查询分类名
Long categoryId = articleDetailVo.getCategoryId();
Category category = categoryService.getById(categoryId);
if(category!=null){
articleDetailVo.setCategoryName(category.getName());
}
//封装响应返回
return ResponseResult.okResult(articleDetailVo);
}