• (仿牛客社区项目)Java开发笔记7.6:热帖排行


    热帖排行

    NowCoder_35_1

    1.util包

    RedisKeyUtil类添加相关键。

    package com.gerrard.community.util;
    
    public class RedisKeyUtil {
    
        private static final String PREFIX_POST = "post";
    
       //帖子分数 post:score->【需要重新计算分数的帖子id集合】
        public static String getPostScoreKey(){
            return PREFIX_POST+SPLIT+"score";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.dao层

    DiscussPostMapper类中添加updateScore方法,重构selectDiscussPosts方法,方法中添加orderMode字段。

    package com.gerrard.community.dao;
    
    import com.gerrard.community.entity.DiscussPost;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    @Mapper
    public interface DiscussPostMapper {
    
        List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);
    
        // @Param注解用于给参数取别名,
        // 如果只有一个参数,并且在里使用,则必须加别名.
        int selectDiscussPostRows(@Param("userId") int userId);
    
        int insertDiscussPost(DiscussPost discussPost);
    
        DiscussPost selectDiscussPostById(int id);
    
        int updateCommentCount(int id, int commentCount);
    
        int updateType(int id, int type);
    
        int updateStatus(int id, int status);
    
        int updateScore(int id, double score);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    discusspost-mapper.xml:

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.gerrard.community.dao.DiscussPostMapper">
    
        <sql id="selectFields">
            id, user_id, title, content, type, status, create_time, comment_count, score
        sql>
    
        <sql id="insertFields">
            user_id, title, content, type, status, create_time, comment_count, score
        sql>
    
        <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>
    
    
        <update id="updateScore">
            update discuss_post set score = #{score} where id = #{id}
        update>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3.service层

    DiscussPostService类中重构findDiscussPosts方法,DiscussPostService类中添加updateScore方法。

    package com.gerrard.community.service;
    
    import com.gerrard.community.dao.DiscussPostMapper;
    import com.gerrard.community.entity.DiscussPost;
    import com.gerrard.community.util.SensitiveFilter;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.util.HtmlUtils;
    
    import java.util.List;
    
    @Service
    public class DiscussPostService {
    
        @Autowired
        private DiscussPostMapper discussPostMapper;
    
        @Autowired
        private SensitiveFilter sensitiveFilter;
    
        public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit, int orderMode) {
            return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);
        }
    
        public int updateScore(int id, double score) {
            return discussPostMapper.updateScore(id, score);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    4.controller层

    (1)DiscusspostController类:发帖,加精方法添加“计算帖子分数”代码。

    package com.gerrard.community.controller;
    
    import com.gerrard.community.entity.*;
    import com.gerrard.community.event.EventProducer;
    import com.gerrard.community.service.CommentService;
    import com.gerrard.community.service.DiscussPostService;
    import com.gerrard.community.service.LikeService;
    import com.gerrard.community.service.UserService;
    import com.gerrard.community.util.CommunityConstant;
    import com.gerrard.community.util.CommunityUtil;
    import com.gerrard.community.util.HostHolder;
    import com.gerrard.community.util.RedisKeyUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.*;
    
    @Controller
    @RequestMapping("/discuss")
    public class DiscussPostController implements CommunityConstant {
    
        @Autowired
        private DiscussPostService discussPostService;
    
        @Autowired
        private HostHolder hostHolder;
    
        @Autowired
        private UserService userService;
    
        @Autowired
        private CommentService commentService;
    
        @Autowired
        private LikeService likeService;
    
        @Autowired
        private EventProducer eventProducer;
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @RequestMapping(path = "/add", method = RequestMethod.POST)
        @ResponseBody
        public String addDiscussPost(String title, String content) {
            User user = hostHolder.getUser();
            if (user == null) {
                return CommunityUtil.getJSONString(403, "你还没有登录哦!");
            }
    
            DiscussPost post = new DiscussPost();
            post.setUserId(user.getId());
            post.setTitle(title);
            post.setContent(content);
            post.setCreateTime(new Date());
            discussPostService.addDiscussPost(post);
    
            // 触发发帖事件
            Event event = new Event()
                    .setTopic(TOPIC_PUBLISH)
                    .setUserId(user.getId())
                    .setEntityType(ENTITY_TYPE_POST)
                    .setEntityId(post.getId());
            eventProducer.fireEvent(event);
    
            // 计算帖子分数
            String redisKey = RedisKeyUtil.getPostScoreKey();
            redisTemplate.opsForSet().add(redisKey, post.getId());
    
            // 报错的情况,将来统一处理.
            return CommunityUtil.getJSONString(0, "发布成功!");
        }
    
        // 置顶
        @RequestMapping(path = "/top", method = RequestMethod.POST)
        @ResponseBody
        public String setTop(int id) {
            discussPostService.updateType(id, 1);
    
            // 触发发帖事件
            Event event = new Event()
                    .setTopic(TOPIC_PUBLISH)
                    .setUserId(hostHolder.getUser().getId())
                    .setEntityType(ENTITY_TYPE_POST)
                    .setEntityId(id);
            eventProducer.fireEvent(event);
    
            return CommunityUtil.getJSONString(0);
        }
    
        // 加精
        @RequestMapping(path = "/wonderful", method = RequestMethod.POST)
        @ResponseBody
        public String setWonderful(int id) {
            discussPostService.updateStatus(id, 1);
    
            // 触发发帖事件
            Event event = new Event()
                    .setTopic(TOPIC_PUBLISH)
                    .setUserId(hostHolder.getUser().getId())
                    .setEntityType(ENTITY_TYPE_POST)
                    .setEntityId(id);
            eventProducer.fireEvent(event);
    
            // 计算帖子分数
            String redisKey = RedisKeyUtil.getPostScoreKey();
            redisTemplate.opsForSet().add(redisKey, id);
    
            return CommunityUtil.getJSONString(0);
        }
    
        // 删除
        @RequestMapping(path = "/delete", method = RequestMethod.POST)
        @ResponseBody
        public String setDelete(int id) {
            discussPostService.updateStatus(id, 2);
    
            // 触发删帖事件
            Event event = new Event()
                    .setTopic(TOPIC_DELETE)
                    .setUserId(hostHolder.getUser().getId())
                    .setEntityType(ENTITY_TYPE_POST)
                    .setEntityId(id);
            eventProducer.fireEvent(event);
    
            return CommunityUtil.getJSONString(0);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135

    (2)CommentController类:addComment方法添加“计算帖子分数”代码。

    package com.gerrard.community.controller;
    
    import com.gerrard.community.entity.Comment;
    import com.gerrard.community.entity.DiscussPost;
    import com.gerrard.community.entity.Event;
    import com.gerrard.community.event.EventProducer;
    import com.gerrard.community.service.CommentService;
    import com.gerrard.community.service.DiscussPostService;
    import com.gerrard.community.util.CommunityConstant;
    import com.gerrard.community.util.HostHolder;
    import com.gerrard.community.util.RedisKeyUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import java.util.Date;
    
    @Controller
    @RequestMapping("/comment")
    public class CommentController implements CommunityConstant {
    
        @Autowired
        private CommentService commentService;
    
        @Autowired
        private HostHolder hostHolder;
    
        @Autowired
        private EventProducer eventProducer;
    
        @Autowired
        private DiscussPostService discussPostService;
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @RequestMapping(path = "/add/{discussPostId}", method = RequestMethod.POST)
        public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment) {
            comment.setUserId(hostHolder.getUser().getId());
            comment.setStatus(0);
            comment.setCreateTime(new Date());
            commentService.addComment(comment);
    
            // 触发评论事件
            Event event = new Event()
                    .setTopic(TOPIC_COMMENT)
                    .setUserId(hostHolder.getUser().getId())
                    .setEntityType(comment.getEntityType())
                    .setEntityId(comment.getEntityId())
                    .setData("postId", discussPostId);
            if (comment.getEntityType() == ENTITY_TYPE_POST) {
                DiscussPost target = discussPostService.findDiscussPostById(comment.getEntityId());
                event.setEntityUserId(target.getUserId());
            } else if (comment.getEntityType() == ENTITY_TYPE_COMMENT) {
                Comment target = commentService.findCommentById(comment.getEntityId());
                event.setEntityUserId(target.getUserId());
            }
            eventProducer.fireEvent(event);
    
            if (comment.getEntityType() == ENTITY_TYPE_POST) {
                // 触发发帖事件
                event = new Event()
                        .setTopic(TOPIC_PUBLISH)
                        .setUserId(comment.getUserId())
                        .setEntityType(ENTITY_TYPE_POST)
                        .setEntityId(discussPostId);
                eventProducer.fireEvent(event);
                // 计算帖子分数
                String redisKey = RedisKeyUtil.getPostScoreKey();
                redisTemplate.opsForSet().add(redisKey, discussPostId);
            }
    
            return "redirect:/discuss/detail/" + discussPostId;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    (3)LikeController类:like方法添加“计算帖子分数”代码。

    package com.gerrard.community.controller;
    
    import com.gerrard.community.entity.Event;
    import com.gerrard.community.entity.User;
    import com.gerrard.community.event.EventProducer;
    import com.gerrard.community.service.LikeService;
    import com.gerrard.community.util.CommunityConstant;
    import com.gerrard.community.util.CommunityUtil;
    import com.gerrard.community.util.HostHolder;
    import com.gerrard.community.util.RedisKeyUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Controller
    public class LikeController implements CommunityConstant {
    
        @Autowired
        private LikeService likeService;
    
        @Autowired
        private HostHolder hostHolder;
    
        @Autowired
        private EventProducer eventProducer;
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @RequestMapping(path = "/like", method = RequestMethod.POST)
        @ResponseBody
        public String like(int entityType, int entityId, int entityUserId, int postId) {
            User user = hostHolder.getUser();
    
            // 点赞
            likeService.like(user.getId(), entityType, entityId, entityUserId);
    
            // 数量
            long likeCount = likeService.findEntityLikeCount(entityType, entityId);
            // 状态
            int likeStatus = likeService.findEntityLikeStatus(user.getId(), entityType, entityId);
            // 返回的结果
            Map<String, Object> map = new HashMap<>();
            map.put("likeCount", likeCount);
            map.put("likeStatus", likeStatus);
    
            // 触发点赞事件
            if (likeStatus == 1) {
                Event event = new Event()
                        .setTopic(TOPIC_LIKE)
                        .setUserId(hostHolder.getUser().getId())
                        .setEntityType(entityType)
                        .setEntityId(entityId)
                        .setEntityUserId(entityUserId)
                        .setData("postId", postId);
                eventProducer.fireEvent(event);
            }
    
            if(entityType == ENTITY_TYPE_POST) {
                // 计算帖子分数
                String redisKey = RedisKeyUtil.getPostScoreKey();
                redisTemplate.opsForSet().add(redisKey, postId);
            }
    
            return CommunityUtil.getJSONString(0, null, map);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    (4)HomeController类中修改getIndexPage方法,添加orderMode字段。

    package com.gerrard.community.controller;
    
    import com.gerrard.community.entity.DiscussPost;
    import com.gerrard.community.entity.Page;
    import com.gerrard.community.entity.User;
    import com.gerrard.community.service.DiscussPostService;
    import com.gerrard.community.service.LikeService;
    import com.gerrard.community.service.UserService;
    import com.gerrard.community.util.CommunityConstant;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Controller
    public class HomeController implements CommunityConstant {
    
        @Autowired
        private DiscussPostService discussPostService;
    
        @Autowired
        private UserService userService;
    
        @Autowired
        private LikeService likeService;
    
        @RequestMapping(path = "/index", method = RequestMethod.GET)
        public String getIndexPage(Model model, Page page,
                                   @RequestParam(name = "orderMode", defaultValue = "0") int orderMode) {
            // 方法调用钱,SpringMVC会自动实例化Model和Page,并将Page注入Model.
            // 所以,在thymeleaf中可以直接访问Page对象中的数据.
            page.setRows(discussPostService.findDiscussPostRows(0));
            page.setPath("/index?orderMode=" + orderMode);
    
            List<DiscussPost> list = discussPostService
                    .findDiscussPosts(0, page.getOffset(), page.getLimit(), orderMode);
            List<Map<String, Object>> discussPosts = new ArrayList<>();
            if (list != null) {
                for (DiscussPost post : list) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("post", post);
                    User user = userService.findUserById(post.getUserId());
                    map.put("user", user);
    
                    long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());
                    map.put("likeCount", likeCount);
    
                    discussPosts.add(map);
                }
            }
            model.addAttribute("discussPosts", discussPosts);
            model.addAttribute("orderMode", orderMode);
    
            return "/index";
        }
    
        @RequestMapping(path = "/error", method = RequestMethod.GET)
        public String getErrorPage() {
            return "/error/500";
        }
    
        @RequestMapping(path = "/denied", method = RequestMethod.GET)
        public String getDeniedPage() {
            return "/error/404";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    5.config包

    在QuartzConfig类中新配置刷新帖子分数任务。

    package com.gerrard.community.config;
    
    import com.gerrard.community.quartz.AlphaJob;
    import com.gerrard.community.quartz.PostScoreRefreshJob;
    import org.quartz.JobDataMap;
    import org.quartz.JobDetail;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.quartz.JobDetailFactoryBean;
    import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
    
    // 配置 -> 数据库 -> 调用
    @Configuration
    public class QuartzConfig {
    
        // FactoryBean可简化Bean的实例化过程:
        // 1.通过FactoryBean封装Bean的实例化过程.
        // 2.将FactoryBean装配到Spring容器里.
        // 3.将FactoryBean注入给其他的Bean.
        // 4.该Bean得到的是FactoryBean所管理的对象实例.
    
        // 配置JobDetail
        // @Bean
        public JobDetailFactoryBean alphaJobDetail() {
            JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
            factoryBean.setJobClass(AlphaJob.class);
            factoryBean.setName("alphaJob");
            factoryBean.setGroup("alphaJobGroup");
            factoryBean.setDurability(true);
            factoryBean.setRequestsRecovery(true);
            return factoryBean;
        }
    
        // 配置Trigger(SimpleTriggerFactoryBean, CronTriggerFactoryBean)
        // @Bean
        public SimpleTriggerFactoryBean alphaTrigger(JobDetail alphaJobDetail) {
            SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
            factoryBean.setJobDetail(alphaJobDetail);
            factoryBean.setName("alphaTrigger");
            factoryBean.setGroup("alphaTriggerGroup");
            factoryBean.setRepeatInterval(3000);
            factoryBean.setJobDataMap(new JobDataMap());
            return factoryBean;
        }
    
        // 刷新帖子分数任务
        @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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    6.quartz包

    在quarz包下新建PostScoreRefreshJob类。

    package com.gerrard.community.quartz;
    
    import com.gerrard.community.entity.DiscussPost;
    import com.gerrard.community.service.DiscussPostService;
    import com.gerrard.community.service.ElasticsearchService;
    import com.gerrard.community.service.LikeService;
    import com.gerrard.community.util.CommunityConstant;
    import com.gerrard.community.util.RedisKeyUtil;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.BoundSetOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    7. view层

    修改index.html页面。

    NowCoder_35_2

    8.功能分析

    8.1 将需要更新分数的帖子添加到Redis数据库中

    用户发帖;版主加精;用户评论,用户点赞【都是针对帖子】,将帖子id添加到Redis数据库中。

    		// 计算帖子分数
            String redisKey = RedisKeyUtil.getPostScoreKey();
            redisTemplate.opsForSet().add(redisKey, post.getId());
    
    		//post:score->【需要重新计算分数的帖子id集合】
    
    • 1
    • 2
    • 3
    • 4
    • 5

    8.2 借助quartz更新帖子分数

    每隔5分钟执行PostScoreRefreshJob类中的refresh方法:

    1.查看Redis数据库中post:score键中是否存有帖子id,没有则结束;

    2.如果存有帖子id集合,则pop遍历集合,对每个帖子计算对应指标,算出帖子的分数,再更新帖子的分数。

    8.3 主页按热度查看帖子

    在index主页点击最热按钮,则帖子展示顺序为帖子种类,帖子得分,帖子创建时间。

    		<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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    9.功能测试

    NowCoder_35_3

    进行加精操作:

    NowCoder_35_4

    查看Redis数据库:

    NowCoder_35_5

    更新分数:

    NowCoder_35_6

    再次查看Redis数据库:
    NowCoder_35_7

    查看主页:

    NowCoder_35_8

    NowCoder_35_9

  • 相关阅读:
    C++ string类
    java学习--day15(泛型、集合)
    异步编程
    Leetcode 377. Combination Sum IV
    RT-DETR手把手教程,注意力机制如何添加在网络的不同位置进行创新优化
    CTO(技术总监)平时都在做些什么?
    linux 系统下文本编辑常用的命令
    手写maxpooling
    SpringTask ----定时任务框架 ----苍穹外卖day10
    MIPI CSI-2笔记(6) -- Low Level Protocol(D-PHY物理层包头ECC)
  • 原文地址:https://blog.csdn.net/weixin_45700663/article/details/125996111