springboot+redis+aop实现页⾯访问量统计功能
springboot实现页⾯统计
使⽤springboot+redis+spring aop+spring schedule实现页⾯访问量统计功能
思路介绍
页⾯访问访问量统计,常⽤的springboot项⽬中,我们的controller的获取⽂章的⽅法主要是
public class Controller{
@GetMapping("/blogs/get/{blogId}")
public String get(Model model,@PathVariable("blogId") Integer blogId){
Blog blog = ById(blogId);
model.addAttribute("blog",blog);
return"/admin/blog";
}
}
每调⽤⼀次该⽅法可以认为,就有⼀次⽤户访问了该页⾯,那么只需要统计访问接⼝的⽤户数量或者调⽤次数即可,如果为了真实,可以统计真实访问量,也可以统计接⼝调⽤次数
那么如何统计呢?
页⾯访问功能是⼀个独⽴的功能,就想⽇志系统,为了避免侵⼊代码,这⾥使⽤spring AOP进⾏切⾯操作
AOP切⾯获取⽅法调⽤次数
具体AOP的使⽤⽅法就不介绍了,为了灵活性,我使⽤注解⽅式进⾏切⾯,也可以直接切get()⽅法
package deblog.aop;
slf4j.Slf4j;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.t.request.RequestContextHolder;
import org.t.request.ServletRequestAttributes;
import deblog.scheduled.RedisToMySQL;
import deblog.service.RedisService;
import javax.servlet.http.HttpServletRequest;
@Component
@Aspect
@Slf4j
public class UvAspect {
@Autowired
private RedisService redisService;
// 拿到@UVlog注解注释的⽅法,这⾥就是切点
@Pointcut("@annotation(deblog.aop.UVlog)")
private void weblog(){
}
// 调⽤⽅法后都会进⾏统计操作,写⼊redis
@After("weblog()")
public void afterMethod(JoinPoint joinpoint){
ServletRequestAttributes attributes =(ServletRequestAttributes) RequestAttributes();
assert attributes != null;
HttpServletRequest request = Request();
Object[] args = Args();
String host = RemoteHost();
String value ="IP:"+ host;
if(RedisToMySQL.prefixDate == null){
try{
Thread.sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
String key ="BLOG:"+args[0]+":"+ RedisToMySQL.prefixDate;
log.info("⽣成key = "+key);
redisService.add(key,value);
}
}
⾃定义的注解
package deblog.aop;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface UVlog {
String type()default"";
}
然后在⽅法上添加注解,这时apring就会接管该⽅法,每次⽤户调⽤该⽅法后,就会进⾏某种操作,也就是加到redis中
public class Controller{
@UVlog
@GetMapping("/blogs/get/{blogId}")
public String get(Model model,@PathVariable("blogId") Integer blogId){
Blog blog = ById(blogId);
model.addAttribute("blog",blog);
return"/admin/blog";
}
}
redis统计访问量
使⽤aop可以对⽅法进⾏操作,⾯对每天数万的访问量,不可能每次都要进⾏数据库操作,这时可以利⽤redis实现⾼性能的读写,然后定时写⼊到数据库中
因为页⾯访问量并不是很重要的数据,不像货币数字或者商业机密,因此可以使⽤hyperloglog数据结构进⾏统计
本⼈博客的访问量设置为每⼀⼩时更新⼀次访问量
这⾥使⽤spring data redis进⾏redis的操作
要点
需要对key进⾏设计,格式为BLOG:1:20200517,表⽰的是2020年5⽉17⽇,⽂章id=1的⽂章
value使⽤的是IP:127.0.0.1,表⽰真实的⽤户数量,hyperloglog有⾃动去重功能,因此重复的⽤户不会被计⼊
最后统计下当前时段value的数量,就是当前页⾯的真实⽤户访问数量了
定时落盘以及更新当天的键值
package deblog.scheduled;
slf4j.Slf4j;
import org.apachemons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import deblog.dao.BlogDao;
import ity.Blog;
import deblog.service.RedisService;
import deblog.util.HLLUtil;
import java.util.Date;
import java.util.Set;
@Component
@Slf4j
public class RedisToMySQL {
public static String prefixDate = null;
@Autowired
private RedisService redisService;
@Autowired
private BlogDao blogDao;
/**
* 每6个⼩时将redis的key添加到mysql
* 先读取,将数量统计并落盘
* 后删除键,等待下⼀个调⽤
*/
@Scheduled(initialDelay =5000,fixedDelay =6*DateUtils.MILLIS_PER_HOUR)
private void redisToMySQL(){
Set<String> keys = redisService.listAllKeys();
if(!keys.isEmpty()){
// 读取key,然后取出⽂章id,进⾏数据库操作更新views
for(String key:keys){
String blogId = key.split(":")[1];
Blog blog = blogDao.selectById(Integer.parseInt(blogId));
Long blogViews = BlogViews();
Long count = redisService.size(key);
blog.setBlogViews(blogViews+count);
blogDao.updateById(blog);
}
redisService.deleteKeys(keys);
}else{
log.info("该时间段⽆新访问者访问⽂章");
}
}
// 更新每天的键值
springboot aop@Scheduled(initialDelay =1000,cron ="1 0 0 * * ?")
private static void updatePrefixDate(){
log.info("当前prefixDate为 "+prefixDate);
prefixDate = Prefix(new Date());
log.info("更新prefixDate为 "+prefixDate);
}
}
缺点
性能差,实时性不⾼(这个主要是没测过,不过凭直觉,这个两个肯定是⽭盾的,性能和实时性的取舍)⽆法形成统计,⽐如回顾每天的访问量,每⼩时的访问量等,这个以后再细想
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论