【问题标题】:Calculate hits per day计算每天的点击次数
【发布时间】:2020-01-19 14:14:04
【问题描述】:

我需要帮助才能根据用户选择的包实现每天的点击量。这是我到目前为止所做的,但它不能正常工作:

实体:

@Entity
@Table(name = "users")
public class UsersModel implements Serializable {

    @Column(name = "plan")
    private String plan;

    @Column(name = "plan_last_activity")
    @Convert(converter = LocalDateTimeConverter.class)
    private LocalDateTime planLastActivity;
}

代码:

public boolean calculateClickTimes() {

    String userName = SecurityUtils.getSubject().getPrincipal().toString();
    QueryDashboardHelper queryHelper = new QueryDashboardHelper();
    UsersModel user = queryHelper.getUserByUserName(userName);

    String plan = user.getPlan(); // silver/gold/platinum/diamond
    int todayHits = user.getTradesPerDay();
    LocalDateTime lastHit = user.getPlanLastActivity();

    LocalDateTime now = LocalDateTime.now();
    LocalDateTime tenSecondsLater = now.plusDays(1);

    long diff = ChronoUnit.DAYS.between(lastHit, tenSecondsLater);

    switch(plan) {

      case "diamond":

        if(diff >= 1 && todayHits >= 20) {
            todayHits = 0;
            return true;
        }       
        break;

      case "platinum":

        if(diff >= 1 && todayHits >= 15) {
            todayHits = 0;
            return true;
        }       
        break;  

      case "gold":

        if(diff >= 1 && todayHits >= 10) {
            todayHits = 0;
            return true;
        }             
        break;  

      case "silver":

        if(diff >= 1 && todayHits >= 5) {
            // User has clicked 5 times today
            todayHits = 0;
            return true;
        }
        break;

      default:

    }

    return false;
}

一般的想法是,应该限制用户在网页中根据所选包(银/金/铂/钻石)和数据库plantradesPerDay和@987654326中的数据执行点击@ 当天允许的点击数应该是有限的。 请给我一些建议如何正确实现此代码?

【问题讨论】:

  • 上面代码中的第一个也是明显的错误,即 silver 计划的条件也适用于所有其他计划,即 todayHits >= 5todayHits >= 10 也适用等。所以你应该通过下降值来改变大小写:case "diamond" -> case "platinum" etc.
  • 您可能想重新访问this
  • 我更新了代码。你能给我更多的建议如何实现吗?

标签: java sql if-statement java-8 switch-statement


【解决方案1】:

这是一个建议机制框架,可以让您了解如何使用 Spring aspect 来处理此类场景

创建注释,例如 TrackHit:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TrackHit{
    
}

并创建一个方面

@Aspect
@Component
public class HitTrackerAspect {
    private final HitTrackerService hitTrackerService;

    public HitTrackerAspect(HitTrackerService hitTrackerService) {
        this.hitTrackerService = hitTrackerService;
    }
    
    // annotation package also should provided if present e.g @annotation(x.y.TrackHit)
    @Around(value = "@annotation(TrackHit)")
    public Object TrackUserHit(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        TrackHit trackHit = method.getAnnotation(TrackHit.class);
        if(trackHit !=null){
            String userName = SecurityUtils.getSubject().getPrincipal().toString();
            if (userName!=null) {
                // hitTrack service is used to check user plan , logic implemented inside isUserAllowed method 
                // of HitTrackerService 
                boolean allowed = hitTrackerService.isUserAllowed(userName)
                if(allowed){
                    return proceedingJoinPoint.proceed();
                }
            }
        }
    }
}

在需要用户调用的服务中添加TrackHit注解,aspect会检查是否允许继续进行

例如,调用受方面登录限制的最新价格,应在调用前检查

@Service
public class PriceInquiryService {
    
    @TrackHit
    public long getLatestPrice(Long itemCode){
        // latest price logic here 
    }
}

【讨论】:

  • 谢谢。但是您可以提出什么算法来限制每天的点击次数?
  • 使用命中历史表,用户 => 命中时间戳映射,每次我都会在上面提供的示例方面方法中插入一条新记录,每次用户调用 api。当我想检查时,我将调用受用户 ID 限制的计数聚合查询,以及今天开始时间和今天结束时间之间的时间意味着今天 00:00 到今天 23:59 然后根据命中数检查我的计划最近 24 小时内的用户计数
【解决方案2】:

你可以在数据库级别做到这一点:

create table users (
    id bigint primary key ,
    plan character varying,
    trades_today int
);

insert into users (id, plan, trades_today)
values (1, 'diamond', 15),
       (2, 'silver', 5),
       (3, 'gold', 0);

with packages(package_type, max_hits) as (
    values ('diamond', 20),
           ('platinum', 15),
           ('gold', 10),
           ('silver', 5)
)

select u.id, trades_today < p.max_hits
from users u
inner join packages p on u.plan = p.package_type;

这会导致:

+--+--------+
|id|?column?|
+--+--------+
|1 |true    |
|2 |false   |
|3 |true    |
+--+--------+

每次点击完成,计数器都会增加。计数器在每个午夜重置

【讨论】:

    最近更新 更多