355 lines
10 KiB
Markdown
355 lines
10 KiB
Markdown
|
# 私信列表
|
||
|
|
||
|
---
|
||
|
|
||
|
本节实现的功能:
|
||
|
|
||
|
- 私信列表:
|
||
|
- 查询当前用户的会话列表
|
||
|
- 每个会话只显示一条最新的私信
|
||
|
- 支持分页显示
|
||
|
- 私信详情
|
||
|
- 查询某个会话所包含的私信
|
||
|
- 支持分页显示
|
||
|
- 访问私信详情时,将显示的私信设为已读状态
|
||
|
|
||
|
`message` 表中有个字段 `conservation_id` ,这个字段的设计方式是:比如用户 id 112 给 113 发消息,或者 113 给 112 发消息,这两个会话的 `conservation_id` 都是 `112_113`。当然,这个字段是冗余的,我们可以通过 from_id 和 to_id 推演出来,但是有了这个字段方便于后面的查询等操作
|
||
|
|
||
|
注意:`from_id = 1` 代表这是一个系统通知,后续会开发此功能
|
||
|
|
||
|
## DAO
|
||
|
|
||
|
```java
|
||
|
@Mapper
|
||
|
public interface MessageMapper {
|
||
|
|
||
|
/**
|
||
|
* 查询当前用户的会话列表,针对每个会话只返回一条最新的私信
|
||
|
* @param userId 用户 id
|
||
|
* @param offset 每页的起始索引
|
||
|
* @param limit 每页显示多少条数据
|
||
|
* @return
|
||
|
*/
|
||
|
List<Message> selectConversations(int userId, int offset, int limit);
|
||
|
|
||
|
/**
|
||
|
* 查询当前用户的会话数量
|
||
|
* @param userId
|
||
|
* @return
|
||
|
*/
|
||
|
int selectConversationCount(int userId);
|
||
|
|
||
|
/**
|
||
|
* 查询某个会话所包含的私信列表
|
||
|
* @param conversationId
|
||
|
* @param offset
|
||
|
* @param limit
|
||
|
* @return
|
||
|
*/
|
||
|
List<Message> selectLetters(String conversationId, int offset, int limit);
|
||
|
|
||
|
/**
|
||
|
* 查询某个会话所包含的私信数量
|
||
|
* @param conversationId
|
||
|
* @return
|
||
|
*/
|
||
|
int selectLetterCount(String conversationId);
|
||
|
|
||
|
/**
|
||
|
* 查询未读私信的数量
|
||
|
* @param userId
|
||
|
* @param conversationId conversationId = null, 则查询该用户所有会话的未读私信数量
|
||
|
* conversationId != null, 则查询该用户某个会话的未读私信数量
|
||
|
* @return
|
||
|
*/
|
||
|
int selectLetterUnreadCount(int userId, String conversationId);
|
||
|
|
||
|
/**
|
||
|
* 修改消息的状态
|
||
|
* @param ids
|
||
|
* @param status
|
||
|
* @return
|
||
|
*/
|
||
|
int updateStatus(List<Integer> ids, int status);
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
对应的 `mapper.xml`
|
||
|
|
||
|
```xml
|
||
|
<mapper namespace="com.greate.community.dao.MessageMapper">
|
||
|
|
||
|
<sql id="selectFields">
|
||
|
id, from_id, to_id, conversation_id, content, status, create_time
|
||
|
</sql>
|
||
|
|
||
|
<!--查询当前用户的会话列表(针对每个会话只返回一条最新的私信)-->
|
||
|
<select id="selectConversations" resultType="Message">
|
||
|
select <include refid="selectFields"></include>
|
||
|
from message
|
||
|
where id in (
|
||
|
select max(id)
|
||
|
from message
|
||
|
where status != 2
|
||
|
and from_id != 1
|
||
|
and (from_id = #{userId} or to_id = #{userId})
|
||
|
group by conversation_id
|
||
|
)
|
||
|
order by id desc
|
||
|
limit #{offset}, #{limit}
|
||
|
</select>
|
||
|
|
||
|
<!--查询当前用户的会话数量-->
|
||
|
<select id="selectConversationCount" resultType="int">
|
||
|
select count(m.maxid) from (
|
||
|
select max(id) as maxid
|
||
|
from message
|
||
|
where status != 2
|
||
|
and from_id != 1
|
||
|
and (from_id = #{userId} or to_id = #{toId})
|
||
|
group by conversation_id
|
||
|
) as m
|
||
|
</select>
|
||
|
|
||
|
<!--查询某个会话所包含的私信列表-->
|
||
|
<select id="selectLetters" resultType="Message">
|
||
|
select <include refid="selectFields"></include>
|
||
|
from message
|
||
|
where status != 2
|
||
|
and from_id != 1
|
||
|
and conversation_id = #{conversationId}
|
||
|
order by id desc
|
||
|
limit #{offset}, #{limit}
|
||
|
</select>
|
||
|
|
||
|
<!--查询某个会话所包含的私信数量-->
|
||
|
<select id="selectLetterCount" resultType="int">
|
||
|
select count(id)
|
||
|
from message
|
||
|
where status != 2
|
||
|
and from_id != 1
|
||
|
and conversation_id = #{conversationId}
|
||
|
</select>
|
||
|
|
||
|
<!--查询未读私信的数量-->
|
||
|
<select id="selectLetterUnreadCount" resultType="int">
|
||
|
select count(id)
|
||
|
from message
|
||
|
where status = 0
|
||
|
and from_id != 1
|
||
|
and to_id = #{userId}
|
||
|
<if test="conversationId != null">
|
||
|
and conversation_id = #{conversationId}
|
||
|
</if>
|
||
|
</select>
|
||
|
|
||
|
<!--修改消息的状态-->
|
||
|
<update id="updateStatus">
|
||
|
update message
|
||
|
set status = #{status}
|
||
|
where id in
|
||
|
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||
|
#{id}
|
||
|
</foreach>
|
||
|
</update>
|
||
|
|
||
|
</mapper>
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
## Service
|
||
|
|
||
|
```java
|
||
|
@Service
|
||
|
public class MessageService {
|
||
|
|
||
|
@Autowired
|
||
|
private MessageMapper messageMapper;
|
||
|
|
||
|
// 查询当前用户的会话列表,针对每个会话只返回一条最新的私信
|
||
|
public List<Message> findConversations(int userId, int offset, int limit) {
|
||
|
return messageMapper.selectConversations(userId, offset, limit);
|
||
|
}
|
||
|
|
||
|
// 查询当前用户的会话数量
|
||
|
public int findConversationCout(int userId) {
|
||
|
return messageMapper.selectConversationCount(userId);
|
||
|
}
|
||
|
|
||
|
// 查询某个会话所包含的私信列表
|
||
|
public List<Message> findLetters(String conversationId, int offset, int limit) {
|
||
|
return messageMapper.selectLetters(conversationId, offset, limit);
|
||
|
}
|
||
|
|
||
|
// 查询某个会话所包含的私信数量
|
||
|
public int findLetterCount(String conversationId) {
|
||
|
return messageMapper.selectLetterCount(conversationId);
|
||
|
}
|
||
|
|
||
|
// 查询未读私信的数量
|
||
|
public int findLetterUnreadCount(int userId, String conversationId) {
|
||
|
return messageMapper.selectLetterUnreadCount(userId, conversationId);
|
||
|
}
|
||
|
|
||
|
// 读取私信(将私信状态设置为已读)
|
||
|
public int readMessage(List<Integer> ids) {
|
||
|
return messageMapper.updateStatus(ids, 1);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
## Controller
|
||
|
|
||
|
```java
|
||
|
@Controller
|
||
|
public class MessageController {
|
||
|
|
||
|
@Autowired
|
||
|
private HostHolder hostHolder;
|
||
|
|
||
|
@Autowired
|
||
|
private MessageService messageService;
|
||
|
|
||
|
@Autowired
|
||
|
private UserService userService;
|
||
|
|
||
|
/**
|
||
|
* 私信列表
|
||
|
* @param model
|
||
|
* @param page
|
||
|
* @return
|
||
|
*/
|
||
|
@GetMapping("/letter/list")
|
||
|
public String getLetterList(Model model, Page page) {
|
||
|
User user = hostHolder.getUser();
|
||
|
// 分页信息
|
||
|
page.setLimit(5);
|
||
|
page.setPath("/letter/list");
|
||
|
page.setRows(messageService.findConversationCout(user.getId()));
|
||
|
// 会话列表
|
||
|
List<Message> conversationList = messageService.findConversations(
|
||
|
user.getId(), page.getOffset(), page.getLimit());
|
||
|
|
||
|
List<Map<String, Object>> conversations = new ArrayList<>();
|
||
|
if (conversationList != null) {
|
||
|
for (Message message : conversationList) {
|
||
|
Map<String, Object> map = new HashMap<>();
|
||
|
map.put("conversation", message); // 私信
|
||
|
map.put("letterCount", messageService.findLetterCount(
|
||
|
message.getConversationId())); // 私信数量
|
||
|
map.put("unreadCount", messageService.findLetterUnreadCount(
|
||
|
user.getId(), message.getConversationId())); // 未读私信数量
|
||
|
int targetId = user.getId() == message.getFromId() ? message.getToId() : message.getFromId();
|
||
|
map.put("target", userService.findUserById(targetId)); // 私信对方
|
||
|
|
||
|
conversations.add(map);
|
||
|
}
|
||
|
}
|
||
|
model.addAttribute("conversations", conversations);
|
||
|
|
||
|
// 查询当前用户的所有未读私信数量
|
||
|
int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);
|
||
|
model.addAttribute("letterUnreadCount", letterUnreadCount);
|
||
|
|
||
|
return "/site/letter";
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 私信详情页
|
||
|
* @param conversationId
|
||
|
* @param page
|
||
|
* @param model
|
||
|
* @return
|
||
|
*/
|
||
|
@GetMapping("/letter/detail/{conversationId}")
|
||
|
public String getLetterDetail(@PathVariable("conversationId") String conversationId, Page page, Model model) {
|
||
|
// 分页信息
|
||
|
page.setLimit(5);
|
||
|
page.setPath("/letter/detail/" + conversationId);
|
||
|
page.setRows(messageService.findLetterCount(conversationId));
|
||
|
|
||
|
// 私信列表
|
||
|
List<Message> letterList = messageService.findLetters(conversationId, page.getOffset(), page.getLimit());
|
||
|
|
||
|
List<Map<String, Object>> letters = new ArrayList<>();
|
||
|
if (letterList != null) {
|
||
|
for (Message message : letterList) {
|
||
|
Map<String, Object> map = new HashMap<>();
|
||
|
map.put("letter", message);
|
||
|
map.put("fromUser", userService.findUserById(message.getFromId()));
|
||
|
letters.add(map);
|
||
|
}
|
||
|
}
|
||
|
model.addAttribute("letters", letters);
|
||
|
|
||
|
// 私信目标
|
||
|
model.addAttribute("target", getLetterTarget(conversationId));
|
||
|
|
||
|
// 将私信列表中的未读消息改为已读
|
||
|
List<Integer> ids = getUnreadLetterIds(letterList);
|
||
|
if (!ids.isEmpty()) {
|
||
|
messageService.readMessage(ids);
|
||
|
}
|
||
|
|
||
|
return "/site/letter-detail";
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 获取私信对方对象
|
||
|
* @param conversationId
|
||
|
* @return
|
||
|
*/
|
||
|
private User getLetterTarget(String conversationId) {
|
||
|
String[] ids = conversationId.split("_");
|
||
|
int id0 = Integer.parseInt(ids[0]);
|
||
|
int id1 = Integer.parseInt(ids[1]);
|
||
|
|
||
|
if (hostHolder.getUser().getId() == id0) {
|
||
|
return userService.findUserById(id1);
|
||
|
}
|
||
|
else {
|
||
|
return userService.findUserById(id0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 获取当前登录用户未读私信的 id
|
||
|
* @param letterList
|
||
|
* @return
|
||
|
*/
|
||
|
private List<Integer> getUnreadLetterIds(List<Message> letterList) {
|
||
|
List<Integer> ids = new ArrayList<>();
|
||
|
|
||
|
if (letterList != null) {
|
||
|
for (Message message : letterList) {
|
||
|
// 当前用户是私信的接收者且该私信处于未读状态
|
||
|
if (hostHolder.getUser().getId() == message.getToId() && message.getStatus() == 0) {
|
||
|
ids.add(message.getId());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ids;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## 前端
|
||
|
|
||
|
`letter-detail`
|
||
|
|
||
|
```html
|
||
|
li th:each="map:${letters}">
|
||
|
<img th:src="${map.fromUser.headerUrl}" alt="用户头像" >
|
||
|
<strong th:utext="${map.fromUser.username}"></strong>
|
||
|
<div th:utext="${map.letter.content}"></div>
|
||
|
</li>
|
||
|
```
|