🌕开发社区核心功能
5.私信列表
5.1 Message
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Message {
private int id;
private int fromId; //消息发送人
private int toId; //消息接受者
private String conversationId; //会话id,用来标识会话的,中间有个_,所以不是int类型;如果没这个字段,利用fromId和toId组合在一起也能查到,只是不方便
//设计这个会话id目的:为了将来在查询会话有关的数据时,以会话为条件进行一个查询筛选的时候方便
private String content;
private int status; //状态: 0未读 1已读 2删除
private Date createTime;
}
5.2 MessageMapper
//@Repository
@Mapper
public interface MessageMapper {
//1.查询当前用户的会话列表,针对每个会话只返回一条最新的私信
public List<Message> selectConversations(int userId,int offset,int limit);
//2.查询当前用户会话的数量
public int selectConversationCount(int userId);
//3.查询某个会话所包含的私信列表(开发详情页面需要用到)
public List<Message> selectLetters(String conversationId,int offset,int limit);
//4.查询某个会话所包含的私信数量
public int selectLetterCount(String conversationId);
//5.查询未读私信的数量
public int selectLetterUnreadCount(int userId,String conversationId);
}
5.3 message-mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yty.community.dao.MessageMapper">
<sql id="selectFields">
id,from_id,to_id,conversation_id,content,status,create_time
</sql>
<!--1.查询当前用户的会话列表,针对每个会话只返回一条最新的私信-->
<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>
<!--2.查询当前用户会话的数量-->
<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 = #{userId})
group by conversation_id
) as m
</select>
<!--3.查询某个会话所包含的私信列表(开发详情页面需要用到)-->
<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>
<!--4.查询某个会话所包含的私信数量-->
<select id="selectLetterCount" resultType="int">
select count(id)
from message
where status != 2
and from_id != 1
and conversation_id = #{conversationId}
</select>
<!--5.查询未读私信的数量-->
<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>
</mapper>
5.3.1 MapperTests —— sql测试
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class MapperTests {
@Resource
private MessageMapper messageMapper;
/*
* MessageMapper方法测试
* */
@Test
//直接一个方法测5个sql语句的方法
public void testSelectLetters(){
//1.查询当前用户的会话列表
List<Message> list = messageMapper.selectConversations(111, 0, 10);
for (Message message : list) {
System.out.println(message);
}
//2.查询当前用户会话的数量
int i = messageMapper.selectConversationCount(111);
System.out.println(i);
//3.查询某个会话所包含的私信列表(开发详情页面需要用到)
List<Message> letters = messageMapper.selectLetters("111_112", 0, 10);
for (Message letter : letters) {
System.out.println(letter);
}
//4.查询某个会话所包含的私信数量
int a = messageMapper.selectLetterCount("111_112");
System.out.println(a);
//5.查询未读私信的数量
int b = messageMapper.selectLetterUnreadCount(131, "111_131");
System.out.println(b);
}
}
5.3.2 结果
sql无任何错误!
5.4 MessageService
@Service
public class MessageService {
@Resource
private MessageMapper messageMapper;
//1.查询当前用户的会话列表,针对每个会话只返回一条最新的私信
public List<Message> findConversations(int userId,int offset,int limit){
return messageMapper.selectConversations(userId, offset, limit);
}
//2.查询当前用户会话的数量
public int findConversationCount(int userId){
return messageMapper.selectConversationCount(userId);
}
//3.查询某个会话所包含的私信列表(开发详情页面需要用到)
public List<Message> findLetters(String conversationId,int offset,int limit){
return messageMapper.selectLetters(conversationId, offset, limit);
}
//4.查询某个会话所包含的私信数量
public int findLetterCount(String conversationId){
return messageMapper.selectLetterCount(conversationId);
}
//5.查询未读私信的数量
public int findLetterUnreadCount(int userId,String conversationId){
return messageMapper.selectLetterUnreadCount(userId, conversationId);
}
}
5.5 MessageController
@Controller
//@RequestMapping("/message")
public class MessageController {
@Resource
private MessageService messageService;
@Resource
private HostHolder hostHolder; //当前用户信息,所有操作肯定都是关于当前用户的,很重要
@Resource
private UserService userService;
//私信列表
@RequestMapping(path = "/letter/list",method = RequestMethod.GET)
public String getLetterList(Model model, Page page){
User user = hostHolder.getUsers();
//分页信息
page.setLimit(5);
page.setPath("/letter/list");
//page.setRows(messageService.findConversationCount(hostHolder.getUsers().getId()));
//这里我就不通过hostHolder.getUsers().getId())获取当前用户id了,后面还会多次用到hostHolder,所以直接在上面一次性获取出来,不用每次都去一大串取,如下
page.setRows(messageService.findConversationCount(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) {
HashMap<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.findByUserId(targetId));
conversations.add(map);
}
}
model.addAttribute("conversations",conversations);
//查询未读消息数量
int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(),null);
model.addAttribute("letterUnreadCount",letterUnreadCount);
return "/site/letter";
}
}
5.6 letter.html页面修改
…
5.7 测试结果
成功!
6.私信详情
数据层、业务层方法在 “私信列表” 的时候就已经全部搞定了,这里只弄表现层代码。
6.1 MessageController
//2.私信详情
@RequestMapping(path = "/letter/detail/{conversationId}",method = RequestMethod.GET)
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*/
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.findByUserId(message.getFromId()));
letters.add(map);
}
}
model.addAttribute("letters",letters);
//*私信目标
model.addAttribute("target",getLetterTargetYTY(conversationId));
return "/site/letter-detail";
}
//*封装一个方法 —— 用于显示谁在跟你发私信,知道和你私信的目标人
private User getLetterTargetYTY(String conversationId){
String[] ids = conversationId.split("_"); //对xxx_xxx拆分,前面小id,后面大id
int id0 = Integer.parseInt(ids[0]); //[0] 代表 前面小的id
int id1 = Integer.parseInt(ids[1]); //[1] 代表 前面大的id
if (hostHolder.getUsers().getId()==id0){
return userService.findByUserId(id1); //如果当前用户id等于小的id,所以和你发消息的就是大的id,取大的id名字作为和你发消息的人
}else {
return userService.findByUserId(id0);
}
}
6.2 letter-detail.html页面修改
…
6.3 测试结果
7.发送私信
7.1 MessageMapper
//发送私信 —— 添加
public int insertMessage(Message message);
//修改消息的状态 —— 1 已读(会用List来,因为可能有多条未读消息)
public int updateStatus(List<Integer> ids,int status);
7.2 message-mapper.xml
<!--发送私信 —— 添加-->
<insert id="insertMessage" parameterType="Message" keyProperty="id">
insert into message (<include refid="insertFields"></include>)
values (#{fromId},#{toId},#{conversationId},#{content},#{status},#{createTime})
</insert>
<!--修改消息的状态 —— 已读-->
<update id="updateStatus">
update message set status = #{status}
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
7.3 MessageService
//发送私信 —— 添加
public int addMessage(Message message){
message.setContent(HtmlUtils.htmlEscape(message.getContent())); //对标签进行转义
message.setContent(sensitiveFilter.filter(message.getContent())); //敏感词过滤
return messageMapper.insertMessage(message);
}
修改消息的状态 —— 1 已读
public int readMessage(List<Integer> ids){
return messageMapper.updateStatus(ids,1);
}
7.4 MessageController
先看3,然后回看2的补充代码,最后看单独的方法。
//2.私信详情
@RequestMapping(path = "/letter/detail/{conversationId}",method = RequestMethod.GET)
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*/
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.findByUserId(message.getFromId()));
letters.add(map);
}
}
model.addAttribute("letters",letters);
//*私信目标
model.addAttribute("target",getLetterTargetYTY(conversationId));
/*功能补充:提取未读消息,将其设为已读*/
List<Integer> ids = getLetterIds(letterList);
if (!ids.isEmpty()){
messageService.readMessage(ids);
}
return "/site/letter-detail";
}
/*功能补充:提取未读消息,将其设为已读*/
//先判断当前用户是不是接受者(toName),只有接受者才能设置已读这种情况。
private List<Integer> getLetterIds(List<Message> letterList){
List<Integer> ids = new ArrayList<>();
if (letterList != null){
for (Message message : letterList) {
if (hostHolder.getUsers().getId() == message.getToId() && message.getStatus() == 0) {
ids.add(message.getId());
}
}
}
return ids;
}
/*3.发送私信*/
@RequestMapping(path = "/letter/send",method = RequestMethod.POST)
@ResponseBody
public String sendLetter(String toName,String content){
//查到我们要私信发送目标的名字
User target = userService.findUserByName(toName);
if (target == null){
return CommunityUtil.getJSONString(1,"发送目标用户不存在!");
}
Message message = new Message();
message.setFromId(hostHolder.getUsers().getId()); //确定正在发私信的用户的id,不是目标用户就是收私信的用户
message.setToId(target.getId());
if (message.getFromId() < message.getToId()){
message.setConversationId(message.getFromId()+"_"+message.getToId());
}else {
message.setConversationId(message.getToId()+"_"+message.getFromId());
}
message.setContent(content);
message.setCreateTime(new Date());
messageService.addMessage(message);
//之后做统一异常处理
return CommunityUtil.getJSONString(0);
}
7.5 letter-detail.html页面修改
…
7.6 测试结果
使用aaa账户发私信给yty1
点进去看详情:
再发一条:
然后切换到yty1的用户,
看详情,并进行回复,然后切回aaa用户查看已读。
成功!