牛客网项目——项目开发(十):热帖排行,生成长图,上传云服务器,性能优化


在这里插入图片描述

1. 热帖排行

1.1 统计发生分数变化帖子

把一段时间内分数发生变化的帖子放入一个set

1.1.1 RedisKeyUtil

  1. 定义前缀
private static final String PREFIX_POST = "post";
  1. 添加方法统计帖子分数
// 帖子分数
public static String getPostScoreKey() {
   
    return PREFIX_POST + SPLIT + "score";
}

1.1.2 DiscussPostController

  1. addDiscussPost新增帖子时做处理,把新增的帖子放入redis,不重复,无序,存入set
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, post.getId());
  1. 置顶不做处理,直接加到最上面
  2. setWonderful加精做处理
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, id);

1.1.3 CommentController

addComment添加评论时做处理

// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, discussPostId);

1.1.4 LikeController

处理逻辑同上

if(entityType == ENTITY_TYPE_POST) {
   
    // 计算帖子分数
    String redisKey = RedisKeyUtil.getPostScoreKey();
    redisTemplate.opsForSet().add(redisKey, postId);
}

1.2 定时任务

1.2.1 PostScoreRefreshJob

  1. 打日志,养成习惯
  2. 注入redis,DiscussPostService,LikeService,ElasticsearchService
  3. 声明静态常量牛客纪元private static final Date epoch;
  4. 重写execute
    1. 取到上一步存的rediskey
    2. 如果没有数据变化,打个日志任务取消
    3. 否则开始刷新前刷新后都记日志
    4. 遍历刷新
  5. 刷新方法
    1. 得到帖子id
    2. 如果帖子不在了打个日志
    3. 更新帖子分数,同步es搜索数据(在相应的Mapper和Config里添加响应方法)
public class PostScoreRefreshJob implements Job, CommunityConstant {
   

    private static final Logger logger = LoggerFactory.getLogger(PostScoreRefreshJob.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private LikeService likeService;

    @Autowired
    private ElasticsearchService elasticsearchService;

    // 牛客纪元
    private static final Date epoch;

    static {
   
        try {
   
            epoch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-08-01 00:00:00");
        } catch (ParseException e) {
   
            throw new RuntimeException("初始化牛客纪元失败!", e);
        }
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
   
        String redisKey = RedisKeyUtil.getPostScoreKey();
        BoundSetOperations operations = redisTemplate.boundSetOps(redisKey);

        if (operations.size() == 0) {
   
            logger.info("[任务取消] 没有需要刷新的帖子!");
            return;
        }

        logger.info("[任务开始] 正在刷新帖子分数: " + operations.size());
        while (operations.size() > 0) {
   
            this.refresh((Integer) operations.pop());
        }
        logger.info("[任务结束] 帖子分数刷新完毕!");
    }

    private void refresh(int postId) {
   
        DiscussPost post = discussPostService.findDiscussPostById(postId);

        if (post == null) {
   
            logger.error("该帖子不存在: id = " + postId);
            return;
        }

        // 是否精华
        boolean wonderful = post.getStatus() == 1;
        // 评论数量
        int commentCount = post.getCommentCount();
        // 点赞数量
        long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);

        // 计算权重
        double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
        // 分数 = 帖子权重 + 距离天数
        double score = Math.log10(Math.max(w, 1))
                + (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);
        // 更新帖子分数
        discussPostService.updateScore(postId, score);
        // 同步搜索数据
        post.setScore(score);
        elasticsearchService.saveDiscussPost(post);
    }

}

1.2.2 QuartzConfig

  1. JobDetailFactoryBean
  2. SimpleTriggerFactoryBean
// 刷新帖子分数任务
@Bean
public JobDetailFactoryBean postScoreRefreshJobDetail() {
   
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(PostScoreRefreshJob.class);
    factoryBean.setName("postScoreRefreshJob");
    factoryBean.setGroup("communityJobGroup");
    factoryBean.setDurability(true);
    factoryBean.setRequestsRecovery(true);
    return factoryBean;
}

@Bean
public SimpleTriggerFactoryBean postScoreRefreshTrigger(JobDetail postScoreRefreshJobDetail) {
   
    SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
    factoryBean.setJobDetail(postScoreRefreshJobDetail);
    factoryBean.setName("postScoreRefreshTrigger");
    factoryBean.setGroup("communityTriggerGroup");
    factoryBean.setRepeatInterval(1000 * 60 * 5);
    factoryBean.setJobDataMap(new JobDataMap());
    return factoryBean;
}

1.3 页面展现

1.3.1 DiscussPostMapper

添加参数 orderMode,默认值是0按照原先的排,如果1就按照热度排

List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);

1.3.2 discusspost-mapper.xml

完成下面修改后通过finduse把用到这个方法的地方都改一下

<select id="selectDiscussPosts" resultType="DiscussPost">
    select <include refid="selectFields"></include>
    from discuss_post
    where status != 2
    <if test="userId!=0">
        and user_id = #{userId}
    </if>
    <if test="orderMode==0">
        order by type desc, create_time desc
    </if>
    <if test="orderMode==1">
        order by type desc, score desc, create_time desc
    </if>
    limit #{offset}, #{limit}
</select>

1.3.3 HomeController

  1. 添加参数ordermode
  2. 第一次访问,还没有值,所以需要默认参数是0
  3. 在路径上拼上参数page.setPath("/index?orderMode=" + orderMode);
  4. 最后ordermode再装到模板,模板要用
@RequestMapping(path = "/index", method = RequestMethod.GET)
public String getIndexPage(Model model, Page page,
                           @RequestParam(name = "orderMode", defaultValue = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平什么阿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值