51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

完成回复通知的功能

当有人回复了你的问题时,肯定需要有通知能让我们看到,今天就来完成最后一个大功能--回复通知。具体的效果如下:

当有未读通知时,在导航栏上会显示未读通知的数量,点进去后能看到未读的信息,点击每条未读信息后,未读标志就会消失,通知上的数字也相应减少,通知的数据还是以分页的方式给出,这里就可以使用前面写好的分页代码。

# (一)搭建Notification数据库 {#一-搭建notification数据库}

我们需要为通知搭建一个数据库,里面需要包含的数据有:id(主键,唯一标识通知),notifier(发起通知的人,也就是评论的人),receiver(收到通知的用户,也就是问题的发起者),outerid(当用户评论问题时,outerid为问题的id;当用户回复评论时,outerid就是评论的id),type(用来标识用户回复的是问题还是评论),createtime(通知的时间),status(该通知是否已读)

CREATE TABLE `notification` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `notifier` int(11) NOT NULL,
  `receiver` int(11) NOT NULL,
  `outerid` int(11) NOT NULL,
  `type` int(11) NOT NULL,
  `createtime` bigint(20) NOT NULL,
  `status` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
)

写完数据库后下一步就是建实体类了,新建notification.class,里面包含上面的所有属性和setter and getter方法,代码就不放了。

我们最终需要把数据拿给前端使用,因此需要封装一个NotificationDto,里面包含了所有给到前端的数据,在notification的基础上,加上了User类型的notifier(发起通知者的所有信息,通过id查到)和String类型的outercontent(通过拿到的outerid读取到具体的内容),再加上questionid,用于点击后跳转到具体的问题详情页。

public class NotificationDto {
    private int id;
    private int receiver;
    private int type;
    private long createtime;
    private int status;
    private User notifier;
    private String outercontent;
    private int questionid;
    //省略了setter and getter方法
}

# (二)将通知数据传递给前端 {#二-将通知数据传递给前端}

我的通知和我的消息放在一起,之前是在PersonalController中写的,我们回到PersonalController中,增加两条代码:

PageDto<NotificationDto> notifications= notificationService.list(user.getId(),page,size);
model.addAttribute("notifications",notifications);

notifications中包含的内容有NotificationDto里的所有东西,还包括了之前写的页面信息,是否显示上一页,是否显示下一页等等。对于这个功能具体的实现形式我放在了notificationService里去写。传入三个数据,当前用户的id,当前的page页码和每一页要展示的内容数量,分页的代码基本上和之前首页的分页代码一致,就不再详细讲了,大家可以看第五篇博客。

@Service
public class NotificationService {
    @Resource
    private NotificationMapper notificationMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private QuestionMapper questionMapper;
    @Resource
    private CommentMapper commentMapper;
    //返回一个PageDto
    public PageDto list(int id, int page, int size) {
        PageDto pageDto = new PageDto();
        int totalcount = notificationMapper.count(id);
        pageDto.setPagination(totalcount, page, size);
        int offset = size * (page - 1);
        List<Notification> notifications = notificationMapper.list(id, offset, size);
        List<NotificationDto> notificationDtoList = new ArrayList<>();
        
        //将notification插入到notificationDto中,再将user信息也插入到notificationDto中
        //最后插入到notificationDtoList列表里
        for (Notification notification : notifications) {
            User user = userMapper.findById(notification.getNotifier());
            NotificationDto notificationDto = new NotificationDto();
            BeanUtils.copyProperties(notification, notificationDto);
            notificationDto.setNotifier(user);
            String outercontent;
            if (notification.getType() == notificationEnum.NOTIFICATION_QUESTION.getType()) {
                outercontent = questionMapper.gettitlebyid(notification.getOuterid());
                //插入问题的id
                notificationDto.setQuestionid(notification.getOuterid());
            } else {
                outercontent = commentMapper.getcontentbyid(notification.getOuterid());
                //插入问题的id
                Comment comment=commentMapper.getparentbyid(notification.getOuterid());
                notificationDto.setQuestionid(comment.getParent_id());
            }
            notificationDto.setOutercontent(outercontent);
            notificationDtoList.add(notificationDto);
        }
        //在pageDto中插入notificationDtoList
        pageDto.setData(notificationDtoList);
        return pageDto;
    }
}

# (三)前端页面对收到的数据进行展示 {#三-前端页面对收到的数据进行展示}

前端数据的展示依旧用到Thymeleaf展示,用th:each的方式循环所有内容,用th:text打印内容,如果查到notification.status=0,则显示未读标签,当点击问题后,通过具体的通知id进入NotificationController处理逻辑。

<div class="media" th:each="notification:${notifications.data}">
    <span th:text="${notification.notifier.name}"></span>
    <span th:if="${notification.type==1}">回复了你的评论</span>
    <span th:if="${notification.type==2}">回复了你的问题</span>
    <a th:href="@{'/notification/'+${notification.id}}">
        <span th:text="${notification.outercontent}"></span>
    </a>
    <span class="label label-danger" th:if="${notification.status==0}">未读</span>
    <br>
    <span th:text="${#dates.format(notification.createtime,'yyyy-MM-dd')}"></span>
    <hr>
</div>

# (四)通知的后端处理逻辑 {#四-通知的后端处理逻辑}

新建NotificationController用来处理通知的后端逻辑,主要的思路是当用户点击这条通知时,把该通知的status修改1(已读),并且根据outerid跳转到相应的问题详情页面

//将通知设置为已读,并且跳转到问题页面
@Controller
public class NotificationController {

    @Resource
    private NotificationMapper notificationMapper;
    @Resource
    private CommentMapper commentMapper;

    @GetMapping("/notification/{action}")
    public String notification(@PathVariable("action")int id,
                               HttpServletRequest request){
        //将通知设置为已读
        notificationMapper.updatestatus(id);
        //获取type,检验是回复评论还是回复问题
        int type=notificationMapper.gettypebyid(id);
        int outerid=notificationMapper.getouteridbyid(id);
        int questionid;
        if(type== notificationEnum.NOTIFICATION_QUESTION.getType()){
            questionid=outerid;
        }else {
            questionid=commentMapper.getparentidbyid(id);
        }
        return "redirect:/question/"+questionid;
    }
}

最后还需要展示给用户有几条未读信息,为了能在任何地方都看到未读信息,我把它放进session里,修改session相关的代码,添加这样两行:

//获取未读的消息数量
int unreadnum=notificationMapper.getunreadcount(user.getId());
request.getSession().setAttribute("unreadnum",unreadnum);

最后在前端需要用到的地方直接从session中调取即可。 至此,关于论坛的所有大功能就全部完成了,接下来是一些页面的布局和小功能的修复

赞(2)
未经允许不得转载:工具盒子 » 完成回复通知的功能