code: public void browse(String id, String token, Function<String, Boolean> function) {
          // 判断toke值
          if (StringUtils.isBlank(token)) {
              throw new ParameterException(" token is null. ");
          }
          if (log.isDebugEnabled()) {
              log.debug("get token = " + token);
  
          }
  
          String key = this.key(id, token);
          String isRecord = redisTemplate.opsForValue().get(key);
          // 如果已经记录，结束
          if (StringUtils.isNotBlank(isRecord)) {
              return;
          }
  
          // 处理并发的问题
          Boolean result = redisTemplate.opsForValue().setIfAbsent(key, "1");
          if (result != null && result) {
              try {
                  boolean handle = function.apply(id);
                  if (handle) {
                      // 过期时间
                      Instant now = Instant.now().plus(browseProperties.getInterval() * 1000 + new Random().nextInt(1000), ChronoUnit.MILLIS);
                      redisTemplate.expireAt(key, Date.from(now));
                      return;
                  }
                  redisTemplate.delete(key);
              } catch (Exception e) {
                  log.error(e.getMessage(), e);
                  redisTemplate.delete(key);
              }
          }
      }
docs: 记录数据的浏览量
  
  @param id       要记录数据的id
  @param token    用户唯一标识
  @param function 记录浏览数的真正方法