推荐视频视频封面获取工具已经上线许久了,突发奇想看看每天是否有其他人在用呢,还是真的只有我和朋友在用。于是速速利用AOP1整了个统计功能,又利用echarts显示出来。

首先引入AOP需要的依赖

        <!--引入AOP依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--AOP-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.12</version>
        </dependency>

随后在启动类中添加相应注解

@EnableAspectJAutoProxy //AOP
@EnableScheduling //开启定时的注解,后面要用到

新建切面类ApiCallAdvice

@Component
@Aspect // 把类定义为切面供容器读取
@RequiredArgsConstructor
public class ApiCallAdvice {
    private final RedisTemplate<String, String> redisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final String FORMAT_PATTERN_DAY = "yyyy-MM-dd";

    private Logger log = LoggerFactory.getLogger(ApiCallAdvice.class);

    /**
     * 如果有返回结果,代表一次调用,则对应接口的调用次数加一,统计维度为天
     * (Redis使用Hash结构)
     * key = URI
     * key = date (精确到天)
     * value = 调用次数
     */
    @AfterReturning("execution(* com.java.service.controller.*.*(..))") //对controller下的所有接口进行监控
    public void afterReturning() {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //获取请求的request
        HttpServletRequest request = attributes.getRequest();

        String uri = request.getRequestURI();
        String date = dateFormat(FORMAT_PATTERN_DAY);
        
        // 计数存入redis中
        if (redisTemplate.hasKey(uri)) {
            redisTemplate.opsForHash().increment(uri, date, 1);
        } else {
            redisTemplate.opsForHash().put(uri, date, "1");
            redisTemplate.opsForHash().getOperations().expire(uri, 30, TimeUnit.DAYS);
        }
    }

    private String dateFormat(String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.format(new Date());
    }
}

随后写进service里作为一个接口输出,方便前端获取统计的数据

最终获取到的JSON格式是这样的

"视频推荐工具": [
      {
        "count": "17", // 当天的统计量与时间,方便前端使用
        "time": "2023-06-05"
      },
      {
        "count": "68",
        "time": "2023-06-06"
      },
      {
        "count": "53",
        "time": "2023-06-07"
      }

后面测试发现,如果某天确实是没人用的话,没有调用接口,也就没有新一天的数据存入redis里,数据在echarts上就会有确实很难看,于是决定在每天的0点01秒给redis中添加上一个占位的数据,计数为0

新建ScheduleTask

@Component
@RequiredArgsConstructor
public class ScheduleTask {
    private final RedisTemplate<String, String> redisTemplate;

    private static final String FORMAT_PATTERN_DAY = "yyyy-MM-dd";
    
    @Scheduled(cron = "1 0 0 * * ?") // cron表达式,代表每天的0点0分1秒触发
    public void CounterPlaceholder(){
        ArrayList<String> list = new ArrayList<>();
        list.add("/bili/推荐视频");
        list.add("/bili/获取封面");
        list.add("/bili/稍后再看");
        String date = dateFormat(FORMAT_PATTERN_DAY);

        for (String key : list){
            // 如果已经有数据了的话...那就加一吧嘿嘿
            if (redisTemplate.opsForHash().hasKey(key, date)) {
                redisTemplate.opsForHash().increment(key, date, 1);
            } else {
                   // 添加进redis占位
                redisTemplate.opsForHash().put(key, date, "0");
                redisTemplate.opsForHash().getOperations().expire(key, 30, TimeUnit.DAYS);
            }
        }
    }

    private String dateFormat(String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.format(new Date());
    }
}

至此,大功告成!

最终效果 API使用统计

最终效果
最终效果


  1. 面向切面编程