实现功能
• 通知列表
- 显示评论、点赞、关注三种类型的通知
• 通知详情
- 分页显示某一类主题所包含的通知
• 未读消息
- 在页面头部显示所有的未读消息数量
dao
//查询某个主题下的最新通知
Message selectLatestNotice(int userId,String topic);
//查询某个主题未读通知数
//当topic==null时,查询的是所有通知数
int selectNoticeUnreadCount(int userId,String topic);
//查询某个主题的所有通知数
int selectNoticeCount(int userId,String topic);
//查询某个主题下的所有通知
List<Message> selectNotices(int userId,String topic,int offset,int limit);
mapper.xml
<!--提取查询字段-->
<sql id="selectFields">
id,from_id,to_id,conversation_id,content,status,create_time
</sql>
<!-- Message selectLatestNotice(int userId,String topic); -->
<select id="selectLatestNotice" resultType="Message">
select <include refid="selectFields"></include>
from message
where id in(
select max(id) from message
where status!=2
and conversation_id=#{topic}
and from_id=1
and to_id=#{userId}
)
</select>
<!-- int selectNoticeUnreadCount(int userId,String topic); -->
<select id="selectNoticeUnreadCount" resultType="int">
select count(id) from message
where status=0
and from_id=1
and to_id=#{userId}
<if test="topic!=null">
and conversation_id=#{topic}
</if>
</select>
<!-- int selectNoticeCount(int userId,String topic); -->
<select id="selectNoticeCount" resultType="int">
select count(id) from message
where status!=2
and conversation_id=#{topic}
and from_id=1
and to_id=#{userId}
</select>
<!-- //查询某个主题下的所有通知 -->
<!-- List<Message> selectNotices(int userId,String topic,int offset,int limit); -->
<select id="selectNotices" resultType="Message">
select <include refid="selectFields"></include>
from message
where status!=2
and from_id=1
and to_id=#{userId}
and conversation_id=#{topic}
order by create_time desc
limit #{offset}, #{limit}
</select>
service
//查询某个主题下的最新通知
public Message findLatestNotice(int userId,String topic){
return messageMapper.selectLatestNotice(userId,topic);
}
//查询某个主题未读通知数
//当topic==null时,查询的是所有通知数
public int findNoticeUnreadCount(int userId,String topic){
return messageMapper.selectNoticeUnreadCount(userId,topic);
}
//查询某个主题的所有通知数
public int findNoticeCount(int userId,String topic){
return messageMapper.selectNoticeCount(userId,topic);
}
//查询某个主题下的所有通知
public List<Message> findNotices(int userId,String topic,int offset,int limit){
return messageMapper.selectNotices(userId,topic,offset,limit);
}
controller
//显示通知页面
@RequestMapping(value = "/notice/list",method = RequestMethod.GET)
public String getNoticeList(Model model){
User user = hostHolder.getUser();
//查询评论类通知
Message message = messageService.findLatestNotice(user.getId(), TOPIC_COMMENT);
Map<String,Object> messageVO=new HashMap<>();
messageVO.put("message",message);
if(message!=null){
//将content内容还原
String content = HtmlUtils.htmlUnescape(message.getContent());
Map<String,Object> data = JSONObject.parseObject(content, HashMap.class);
messageVO.put("user",userService.findUserById((Integer) data.get("userId")));
messageVO.put("entityType",data.get("entityType"));
messageVO.put("entityId",data.get("entityId"));
messageVO.put("postId",data.get("postId"));
//评论通知数量、未读通知数量
int count = messageService.findNoticeCount(user.getId(), TOPIC_COMMENT);
int unread = messageService.findNoticeUnreadCount(user.getId(), TOPIC_COMMENT);
messageVO.put("count",count);
messageVO.put("unread",unread);
}
model.addAttribute("commentNotice",messageVO);
//查询点赞类通知
message = messageService.findLatestNotice(user.getId(), TOPIC_LIKE);
messageVO=new HashMap<>();
messageVO.put("message",message);
if(message!=null){
//将content内容还原
String content = HtmlUtils.htmlUnescape(message.getContent());
Map<String,Object> data = JSONObject.parseObject(content, HashMap.class);
messageVO.put("user",userService.findUserById((Integer) data.get("userId")));
messageVO.put("entityType",data.get("entityType"));
messageVO.put("entityId",data.get("entityId"));
messageVO.put("postId",data.get("postId"));
//评论通知数量、未读通知数量
int count = messageService.findNoticeCount(user.getId(), TOPIC_LIKE);
int unread = messageService.findNoticeUnreadCount(user.getId(), TOPIC_LIKE);
messageVO.put("count",count);
messageVO.put("unread",unread);
}
model.addAttribute("likeNotice",messageVO);
//查询关注类通知
message = messageService.findLatestNotice(user.getId(), TOPIC_FOLLOW);
messageVO=new HashMap<>();
messageVO.put("message",message);
if(message!=null){
//将content内容还原
String content = HtmlUtils.htmlUnescape(message.getContent());
Map<String,Object> data = JSONObject.parseObject(content, HashMap.class);
messageVO.put("user",userService.findUserById((Integer) data.get("userId")));
messageVO.put("entityType",data.get("entityType"));
messageVO.put("entityId",data.get("entityId"));
//评论通知数量、未读通知数量
int count = messageService.findNoticeCount(user.getId(), TOPIC_FOLLOW);
int unread = messageService.findNoticeUnreadCount(user.getId(), TOPIC_FOLLOW);
messageVO.put("count",count);
messageVO.put("unread",unread);
}
model.addAttribute("followNotice",messageVO);
//查询全部通知的未读消息数
int noticeUnreadCount = messageService.findNoticeUnreadCount(user.getId(), null);
model.addAttribute("noticeUnreadCount",noticeUnreadCount);
//查询全部私信的未读消息数
int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);
model.addAttribute("letterUnreadCount",letterUnreadCount);
return "/site/notice";
}
@RequestMapping(value = "/notice/detail/{topic}",method = RequestMethod.GET)
public String getNoticeDetail(@PathVariable("topic") String topic,Page page,Model model){
User user = hostHolder.getUser();
//设置分页
page.setRows(5);
page.setPath("/notice/detail/"+topic);
page.setRows(messageService.findNoticeCount(user.getId(),topic));
List<Message> noticeList = messageService.findNotices(user.getId(), topic, page.getOffset(), page.getLimit());
List<Map<String,Object>> noticeVoList=new ArrayList<>();
if(noticeList!=null){
for(Message notice:noticeList){
Map<String,Object> map=new HashMap<>();
//通知
map.put("notice",notice);
//通知内容
String content = HtmlUtils.htmlUnescape(notice.getContent());
HashMap<String,Object> data = JSONObject.parseObject(content, HashMap.class);
map.put("user",userService.findUserById((Integer) data.get("userId")));
map.put("entityType",data.get("entityType"));
map.put("entityId",data.get("entityId"));
map.put("postId",data.get("postId"));
//通知作者
map.put("fromUser",userService.findUserById(notice.getFromId()));
noticeVoList.add(map);
}
}
model.addAttribute("notices",noticeVoList);
//设置已读
List<Integer> ids=getLetterIds(noticeList);
if(!ids.isEmpty()){
messageService.readMessage(ids);
}
return "/site/notice-detail";
}
intercepter
@Component
public class MessageInterceptor implements HandlerInterceptor {
@Autowired
private HostHolder hostHolder;
@Autowired
private MessageService messageService;
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
User user = hostHolder.getUser();
if(user!=null&&modelAndView!=null){
int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);
int noticeUnreadCount = messageService.findNoticeUnreadCount(user.getId(), null);
modelAndView.addObject("allUnreadCount",letterUnreadCount+noticeUnreadCount);
}
}
}
config
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginTicketInterceptor loginTicketInterceptor;//将拦截器注入
@Autowired
private LoginRequiredInterceptor loginRequiredInterceptor;
@Autowired
private MessageInterceptor messageInterceptor;
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(loginTicketInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.jpg","/**/*.jpeg","/**/*.png");
registry.addInterceptor(loginRequiredInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.jpg","/**/*.jpeg","/**/*.png");
registry.addInterceptor(messageInterceptor)
.excludePathPatterns("/**/*.css","/**/*.js","/**/*.jpg","/**/*.jpeg","/**/*.png");
}
}
notice.html
<!-- 通知列表 -->
<ul class="list-unstyled">
<!-- 评论类通知 -->
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${commentNotice.message!=null}">
<span class="badge badge-danger" th:text="${commentNotice.unread!=0?commentNotice.unread:''}">3</span>
<img src="http://static.nowcoder.com/images/head/reply.png" class="mr-4 user-header" alt="通知图标">
<div class="media-body">
<h6 class="mt-0 mb-3">
<span>评论</span>
<span class="float-right text-muted font-size-12"
th:text="${#dates.format(commentNotice.message.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-28 14:13:25</span>
</h6>
<div>
<a th:href="@{/notice/detail/comment}">
用户
<i th:utext="${commentNotice.user.userName}">nowcoder</i>
评论了你的
<b th:text="${commentNotice.entityType==1?'帖子':'回复'}">帖子</b> ...</a>
<ul class="d-inline font-size-12 float-right">
<li class="d-inline ml-2"><span class="text-primary">共 <i th:text="${commentNotice.count}">3</i> 条会话</span></li>
</ul>
</div>
</div>
</li>
<!-- 点赞类通知 -->
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${likeNotice.message!=null}">
<span class="badge badge-danger" th:text="${likeNotice.unread!=0?likeNotice.unread:''}">3</span>
<img src="http://static.nowcoder.com/images/head/like.png" class="mr-4 user-header" alt="通知图标">
<div class="media-body">
<h6 class="mt-0 mb-3">
<span>赞</span>
<span class="float-right text-muted font-size-12"
th:text="${#dates.format(likeNotice.message.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-28 14:13:25</span>
</h6>
<div>
<a th:href="@{/notice/detail/like}">
用户
<i th:utext="${likeNotice.user.userName}">nowcoder</i>
点赞了你的<b th:text="${likeNotice.entityType==1?'帖子':'回复'}">帖子</b> ...</a>
<ul class="d-inline font-size-12 float-right">
<li class="d-inline ml-2"><span class="text-primary">共 <i th:text="${likeNotice.count}">3</i> 条会话</span></li>
</ul>
</div>
</div>
</li>
<!-- 关注类通知 -->
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${followNotice.message!=null}">
<span class="badge badge-danger" th:text="${followNotice.unread!=0?followNotice.unread:''}">3</span>
<img src="http://static.nowcoder.com/images/head/follow.png" class="mr-4 user-header" alt="通知图标">
<div class="media-body">
<h6 class="mt-0 mb-3">
<span>关注</span>
<span class="float-right text-muted font-size-12"
th:text="${#dates.format(followNotice.message.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-28 14:13:25</span>
</h6>
<div>
<a th:href="@{/notice/detail/follow}">
用户
<i th:utext="${followNotice.user.userName}">nowcoder</i>
关注了你 ...</a>
<ul class="d-inline font-size-12 float-right">
<li class="d-inline ml-2"><span class="text-primary">共 <i th:text="${followNotice.count}">3</i> 条会话</span></li>
</ul>
</div>
</div>
</li>
</ul>
notice-detail.html
<!-- 通知列表 -->
<ul class="list-unstyled mt-4">
<li class="media pb-3 pt-3 mb-2" th:each="map:${notices}">
<img th:src="${map.fromUser.headerUrl}" class="mr-4 rounded-circle user-header" alt="系统图标">
<div class="toast show d-lg-block" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto" th:utext="${map.fromUser.userName}">落基山脉下的闲人</strong>
<small th:text="${#dates.format(map.notice.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-25 15:49:32</small>
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="toast-body">
<span th:if="${topic.equals('comment')}">
用户
<i th:utext="${map.user.userName}">nowcoder</i>
评论了你的<b th:text="${map.entityType==1?'帖子':'回复'}">帖子</b>,
<a class="text-primary" th:href="@{|/discuss/detail/${map.postId}|}">点击查看</a> !
</span>
<span th:if="${topic.equals('like')}">
用户
<i th:utext="${map.user.userName}">nowcoder</i>
赞了你的<b th:text="${map.entityType==1?'帖子':'回复'}">帖子</b>,
<a class="text-primary" th:href="@{|/discuss/detail/${map.postId}|}">点击查看</a> !
</span>
<span th:if="${topic.equals('follow')}">
用户
<i th:utext="${map.user.userName}">nowcoder</i>
关注了你,
<a class="text-primary" th:href="@{|/user/profile/${map.user.id}|}">点击查看</a> !
</span>
</div>
</div>
</li>
</ul>