springboot项目浏览次数增加实现方案

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 在现实开发工作中,一定会遇到过类似于浏览量统计的需求,关于实现方案有很多,下面结合业务实际场景说下实现方案以及处理过程,希望对有同样需求的同学可以作为参考、有所帮助。

1.背景说明


   在现实开发工作中,一定会遇到过类似于浏览量统计的需求,关于实现方案有很多,下面结合业务实际场景说下实现方案以及处理过程,希望对有同样需求的同学可以作为参考、有所帮助。

   简单交代一下业务场景:

   现在有自研的招聘平台,招聘端发布岗位之后求职端可以实时查看,现在需要统计每个岗位的浏览次数,只要进入到岗位详情页就算一次有效的浏览。


2.实现方案分析


   这类需求最简单的实现方式就是进入到页面之后,调用岗位查询接口,接口中除了返回岗位详情信息之外,再进行浏览次数加一的入表逻辑即可。实现起来是简单了但是考虑一下这种方式有什么弊端?由于岗位详情查看这个动作触发的次数会很多,频繁的调用接口务必会给服务器带来很大的压力,另外浏览量增加这种数据对于主要业务岗位详情查询来讲并不是必要的,架构上可以考虑进行业务分离,降低耦合度之后后期维护也会方便。不进行过多铺垫了,直接说自己的实现方案:

   aop进行业务分离,降低耦合

   redis代替数据库频繁写入缓解服务器压力

   定期缓存处理,批量写入,保证数据同步;


3.处理过程


   下面按照实现思路进行代码实现:

   aop进行业务分离,降低耦合;

自定义切面BrowCountAspect :


@Component
@Aspect
@Slf4j
public class BrowCountAspect {
    @Autowired
    private RedisTemplate redisTemplate;
    // add by txm 2022/12/17 仅对findPostDetailInfoVo方法进行拦截
    @Pointcut("execution(* com.XXX.XXX.XXX.XXX.controller.WantedJobPostController.findPostDetailInfoVo(..))")
    public void browseTimePoint() {
    }
  /**
     * @Author: txm
     * @Description: 接口响应成功之后触发
     * @Param: [responsePostDetailInfoVo]
     * @return: void
     * @Date:  2022/12/17 11:13
     **/
    @AfterReturning(returning = "result",pointcut = "browseTimePoint()")
    public void doAfterRuturn(JoinPoint joinPoint,Object result) {
        ResultVo<PostDetailInfoVo> responsePostDetailInfoVo=(ResultVo<PostDetailInfoVo>) result;
        if(ObjectUtil.isNotNull(responsePostDetailInfoVo) && ObjectUtil.isNotNull(responsePostDetailInfoVo.getData())){
            handleBrowseCount(responsePostDetailInfoVo.getData().getPostId(),responsePostDetailInfoVo.getData().getBrowseCount());
        }
    }
    /**
     * @Author: txm
     * @Description: 浏览次数加一
     * @Param: [responsePostDetailInfoVo]
     * @return: void
     * @Date:  2022/12/17 11:13
     **/
    private synchronized void handleBrowseCount(Long postId,Integer browseCount) {
        // 设置岗位浏览数为数据库中实际的浏览次数,setIfAbsent方法作用:添加过一次之后不会重新添加,每天第一次浏览岗位会记录岗位信息以及浏览次数,在此浏览只会浏览次数加一处理.定时任务会在每天凌晨进行获取当天每个岗位的浏览次数然后批量写入数据库,最后清除缓存中岗位浏览次数
      redisTemplate.opsForValue().setIfAbsent(String.format("jobBrowseCount:post_%s",postId),browseCount));
        redisTemplate.opsForValue().increment(String.format("jobBrowseCount:post_%s",postId));
    }
}


说明

   业务场景只有对岗位详情查看是才实现浏览次数加一,所以此处切入点表达式直接限制到具体的方法即可.

@Pointcut("execution(* com.XXX.XXX.XXX.XXX.controller.WantedJobPostController.findPostDetailInfoVo(..))")
    public void browseTimePoint() {
    }


   aop实现浏览次数加一处理,切面处理逻辑放到方法执行之后.实现逻辑是每次需要设置岗位id以及对应的浏览次数,如果岗位信息已经添加过则直接进行浏览次数加一处理.其中result对象为接口响应返回参数.需要强转成岗位信息获取岗位信息中的浏览次数.

   相关的实体类PostDetailInfoVo以及接口固定的响应参数ResultVo:

PostDetailInfoVo.java:

/**
 * @ClassName: PostDetailInfoVo
 * @Desc:岗位详情信息
 * @Author: txm
 * @Date: 2022/6/21 16:23
 **/
@ApiModel("岗位详情信息")
@Data
@ToString
public class PostDetailInfoVo implements Serializable {
    private static final long serialVersionUID = -3411333643335244983L;
    @ApiModelProperty(value = "求职岗位id",example = "1",dataType = "Long")
    private Long postId;
    // add by txm 2022/12/17 添加岗位浏览次数
    @ApiModelProperty(value = "岗位浏览次数",dataType = "Integer" ,example = "2")
    private Integer browseCount=0;
// 省略其余岗位属性信息
}


ResultVo.java:

@Data
@Builder
@Accessors(chain = true)
@ApiModel("响应参数")
public class ResultVo<T> implements Serializable {
    private static final long serialVersionUID = -8054007511410819665L;
    @ApiModelProperty(value = "响应状态码",example = "1",dataType = "Integer")
    private int code;
    // 是否成功标识.true表示成功,false表示失败
    @ApiModelProperty("success标识,true表示成功,false表示失败")
    private boolean success;
    // 操作成功时需要响应给客户端的响应数据
    @ApiModelProperty("响应信息")
    private String msg;
    // 返回给客户端的具体数据内容,NON_NULL:如果为null就不返回data,NON_EMPTY:如果为空字符串就不返回data
    @ApiModelProperty("响应数据")
//    @JsonInclude(JsonInclude.Include.NON_NULL)
    //@JsonInclude(JsonInclude.Include.NON_EMPTY)
    private T data;
    @ApiModelProperty("当前时间")
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date time;
}


   后台每天会读取前一天的岗位浏览次数,并更新到数据库,并将前一天的缓存数据清除.


@Slf4j
@Component
public class ScheduleHandle {
    @Autowired
    private RedisTemplate redisTemplate;
    @Scheduled(cron = "0 5 0 * * *")  // 每天凌晨5分
    public void handle(){
        handleBrowseCount();
    }
    /**
     * @Author: txm
     * @Description: 批量更新岗位浏览次数
     * @Param: []
     * @return: void
     * @Date:  2022/12/17 15:38
     **/
    public void handleBrowseCount() {
        Set<String> browseCountPostSet = redisTemplate.keys("jobBrowseCount:post_*");
        ArrayList<BrowseCountDto> browseCountDtos = new ArrayList<>();
        BrowseCountDto browseCountDto=null;
        if(CollectionUtil.isNotEmpty(browseCountPostSet)){
            for (String postIdInfo : browseCountPostSet) {
                Long postId =Long.valueOf(postIdInfo.substring(20));
                Integer browseCount = (Integer)redisTemplate.opsForValue().get(String.format("jobBrowseCount:post_%s", postId));
                browseCountDto=new BrowseCountDto(browseCount,postId);
                browseCountDtos.add(browseCountDto);
            }
            // 批量更新岗位浏览量,此处入表逻辑不进行展开
            // 删除缓存的浏览次数信息
            redisTemplate.delete(browseCountPostSet);
        }
    }
}


涉及的实体类:

@ApiModel("浏览次数")
@Data
@AllArgsConstructor
public class BrowseCountDto implements Serializable {
    private static final long serialVersionUID = -5948133205817407204L;
    @ApiModelProperty(value = "浏览次数",example = "1",dataType = "Integer")
    private Integer browseCount;
    @ApiModelProperty(value = "岗位id",example = "1",dataType = "Long")
    private Long postId;
}


   至此,以实际项目为例介绍了浏览次数增加的完整实现方案,看到这里如果感觉有帮助欢迎点赞或是评论区留言!


相关文章
|
5月前
|
前端开发 安全 Java
Spring Boot 便利店销售系统项目分包设计解析
本文深入解析了基于Spring Boot的便利店销售系统分包设计,通过清晰的分层架构(表现层、业务逻辑层、数据访问层等)和模块化设计,提升了代码的可维护性、复用性和扩展性。具体分包结构包括`controller`、`service`、`repository`、`entity`、`dto`、`config`和`util`等模块,职责分明,便于团队协作与功能迭代。该设计为复杂企业级应用开发提供了实践参考。
224 0
|
2月前
|
Java 关系型数据库 MySQL
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
346 2
|
2月前
|
分布式计算 Java 大数据
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
156 2
|
2月前
|
Java 测试技术 Spring
简单学Spring Boot | 博客项目的测试
本内容介绍了基于Spring Boot的博客项目测试实践,重点在于通过测试驱动开发(TDD)优化服务层代码,提升代码质量和功能可靠性。案例详细展示了如何为PostService类编写测试用例、运行测试并根据反馈优化功能代码,包括两次优化过程。通过TDD流程,确保每项功能经过严格验证,增强代码可维护性与系统稳定性。
154 0
|
2月前
|
存储 Java 数据库连接
简单学Spring Boot | 博客项目的三层架构重构
本案例通过采用三层架构(数据访问层、业务逻辑层、表现层)重构项目,解决了集中式开发导致的代码臃肿问题。各层职责清晰,结合依赖注入实现解耦,提升了系统的可维护性、可测试性和可扩展性,为后续接入真实数据库奠定基础。
262 0
|
3月前
|
网络协议 Java
在SpringBoot项目中使用Netty实现远程调用
本文介绍了使用Netty解决网络连接性能问题的方法,重点讲解了Netty的NIO特性及其在SpringBoot中的应用。Netty作为高效的NIO框架,支持非阻塞IO,能通过单线程管理多个客户端连接,简化TCP/UDP套接字服务器开发。文章详细展示了Netty在SpringBoot中实现远程调用的过程,包括服务端与客户端代码实现、依赖配置及测试验证。通过示例代码,如`NettyServer`、`NettyClientUtil`等,清晰说明了Netty的工作原理和实际应用,解决了半包等问题,并提供了完整的测试结果。
509 3
|
5月前
|
SQL 前端开发 Java
深入理解 Spring Boot 项目中的分页与排序功能
本文深入讲解了在Spring Boot项目中实现分页与排序功能的完整流程。通过实际案例,从Service层接口设计到Mapper层SQL动态生成,再到Controller层参数传递及前端页面交互,逐一剖析每个环节的核心逻辑与实现细节。重点包括分页计算、排序参数校验、动态SQL处理以及前后端联动,确保数据展示高效且安全。适合希望掌握分页排序实现原理的开发者参考学习。
341 4
|
5月前
|
Java Spring 容器
两种Spring Boot 项目启动自动执行方法的实现方式
在Spring Boot项目启动后执行特定代码的实际应用场景中,可通过实现`ApplicationRunner`或`CommandLineRunner`接口完成初始化操作,如系统常量或配置加载。两者均支持通过`@Order`注解控制执行顺序,值越小优先级越高。区别在于参数接收方式:`CommandLineRunner`使用字符串数组,而`ApplicationRunner`采用`ApplicationArguments`对象。注意,`@Order`仅影响Bean执行顺序,不影响加载顺序。
450 2
|
5月前
|
安全 前端开发 Java
Spring Boot 项目中触发 Circular View Path 错误的原理与解决方案
在Spring Boot开发中,**Circular View Path**错误常因视图解析与Controller路径重名引发。当视图名称(如`login`)与请求路径相同,Spring MVC无法区分,导致无限循环调用。解决方法包括:1) 明确指定视图路径,避免重名;2) 将视图文件移至子目录;3) 确保Spring Security配置与Controller路径一致。通过合理设定视图和路径,可有效避免该问题,确保系统稳定运行。
363 0
|
6月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——指定项目配置文件
在实际项目中,开发环境和生产环境的配置往往不同。为简化配置切换,可通过创建 `application-dev.yml` 和 `application-pro.yml` 分别管理开发与生产环境配置,如设置不同端口(8001/8002)。在 `application.yml` 中使用 `spring.profiles.active` 指定加载的配置文件,实现环境快速切换。本节还介绍了通过配置类读取参数的方法,适用于微服务场景,提升代码可维护性。课程源码可从 [Gitee](https://gitee.com/eson15/springboot_study) 下载。
234 0