follow+sendMessage
Change-Id: I3e9bbcc89dfc53b9651fd8722da1b445a597629a
diff --git a/src/main/java/com/example/g8backend/controller/UserController.java b/src/main/java/com/example/g8backend/controller/UserController.java
index 2665b4c..3b9ec22 100644
--- a/src/main/java/com/example/g8backend/controller/UserController.java
+++ b/src/main/java/com/example/g8backend/controller/UserController.java
@@ -8,6 +8,8 @@
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
+import java.util.Map;
+
@RestController
@RequestMapping("/user")
public class UserController {
@@ -24,4 +26,21 @@
user.setPassword(null);
return ResponseEntity.ok(user);
}
+ @PostMapping("/follow/{userId}")
+ public ResponseEntity<?> followUser(@PathVariable Long userId) {
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+ Long followerId = (Long) auth.getPrincipal(); // 确保Security返回Long
+ return ResponseEntity.ok(userService.followUser(followerId, userId));
+ }
+
+ @PostMapping("/message/{receiverId}")
+ public ResponseEntity<?> sendMessage(
+ @PathVariable Long receiverId,
+ @RequestBody String content
+ ) {
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+ Long senderId = (Long) auth.getPrincipal();
+ Long messageId = userService.sendMessage(senderId, receiverId, content);
+ return ResponseEntity.ok(Map.of("messageId", messageId));
+ }
}
diff --git a/src/main/java/com/example/g8backend/entity/Follow.java b/src/main/java/com/example/g8backend/entity/Follow.java
new file mode 100644
index 0000000..f3ba6eb
--- /dev/null
+++ b/src/main/java/com/example/g8backend/entity/Follow.java
@@ -0,0 +1,16 @@
+// Follow.java(新增)
+package com.example.g8backend.entity;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("user_follows")
+@Accessors(chain = true)
+public class Follow {
+ private Long followerId; // 保持Long类型
+ private Long followedId;
+ private LocalDateTime createdAt;
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/entity/Message.java b/src/main/java/com/example/g8backend/entity/Message.java
new file mode 100644
index 0000000..e16e244
--- /dev/null
+++ b/src/main/java/com/example/g8backend/entity/Message.java
@@ -0,0 +1,24 @@
+// Message.java(新增)
+package com.example.g8backend.entity;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+@Data
+@Accessors(chain = true)
+@TableName("private_messages")
+public class Message {
+ @TableId(type = IdType.AUTO)
+ private Long messageId;
+ private Long senderId;
+ private Long receiverId;
+ private String content;
+ private LocalDateTime sentAt;
+ @TableField("is_read")
+ private Boolean isRead = false; // ✅ 默认值
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/entity/User.java b/src/main/java/com/example/g8backend/entity/User.java
index 7ba8e03..a9f5746 100644
--- a/src/main/java/com/example/g8backend/entity/User.java
+++ b/src/main/java/com/example/g8backend/entity/User.java
@@ -4,9 +4,11 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
+import lombok.experimental.Accessors;
@Data
@TableName("users")
+@Accessors(chain = true)
public class User {
@TableId(type = IdType.AUTO)
private Long userId;
@@ -24,4 +26,6 @@
", email='" + email + '\'' +
'}';
}
+
+
}
diff --git a/src/main/java/com/example/g8backend/mapper/FollowMapper.java b/src/main/java/com/example/g8backend/mapper/FollowMapper.java
new file mode 100644
index 0000000..f1d03af
--- /dev/null
+++ b/src/main/java/com/example/g8backend/mapper/FollowMapper.java
@@ -0,0 +1,22 @@
+package com.example.g8backend.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.g8backend.entity.Follow;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+@Mapper
+public interface FollowMapper extends BaseMapper<Follow> {
+ @Delete("DELETE FROM user_follows WHERE follower_id=#{followerId} AND followed_id=#{followedId}")
+ int deleteByPair(@Param("followerId") Long followerId, @Param("followedId") Long followedId);
+
+ @Select("SELECT followed_id FROM user_follows WHERE follower_id = #{userId}")
+ List<Long> selectFollowings(Long userId);
+
+ @Select("SELECT follower_id FROM user_follows WHERE followed_id = #{userId}")
+ List<Long> selectFollowers(Long userId);
+}
diff --git a/src/main/java/com/example/g8backend/mapper/MessageMapper.java b/src/main/java/com/example/g8backend/mapper/MessageMapper.java
new file mode 100644
index 0000000..3f2caf4
--- /dev/null
+++ b/src/main/java/com/example/g8backend/mapper/MessageMapper.java
@@ -0,0 +1,23 @@
+package com.example.g8backend.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.g8backend.entity.Message;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+@Mapper
+public interface MessageMapper extends BaseMapper<Message> {
+ @Select("SELECT * FROM private_messages " +
+ "WHERE (sender_id=#{userId1} AND receiver_id=#{userId2}) " +
+ "OR (sender_id=#{userId2} AND receiver_id=#{userId1}) " +
+ "ORDER BY sent_at")
+ List<Message> selectConversation(@Param("userId1") Long userId1, @Param("userId2") Long userId2);
+
+ @Select("SELECT * FROM private_messages " +
+ "WHERE sender_id=#{userId} OR receiver_id=#{userId} " +
+ "ORDER BY sent_at DESC")
+ List<Message> selectUserMessages(Long userId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/service/IUserService.java b/src/main/java/com/example/g8backend/service/IUserService.java
index af94d27..1f178f8 100644
--- a/src/main/java/com/example/g8backend/service/IUserService.java
+++ b/src/main/java/com/example/g8backend/service/IUserService.java
@@ -1,11 +1,25 @@
package com.example.g8backend.service;
import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.g8backend.entity.Message;
import com.example.g8backend.entity.User;
import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
public interface IUserService extends IService<User> {
User getUserByName(@Param("name") String name);
User getUserByEmail(@Param("email") String email);
User getUserByPasskey(@Param("passkey") String passkey);
+
+ // 关注功能
+ boolean followUser(Long followerId, Long followedId);
+ boolean unfollowUser(Long followerId, Long followedId);
+ List<User> getFollowings(Long userId);
+ List<User> getFollowers(Long userId);
+
+ // 私信功能
+ Long sendMessage(Long senderId, Long receiverId, String content);
+ List<Message> getMessages(Long userId, Long partnerId);
+ List<Message> getMessageHistory(Long userId);
}
diff --git a/src/main/java/com/example/g8backend/service/impl/UserServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/UserServiceImpl.java
index e8bcf20..1d1b6dc 100644
--- a/src/main/java/com/example/g8backend/service/impl/UserServiceImpl.java
+++ b/src/main/java/com/example/g8backend/service/impl/UserServiceImpl.java
@@ -1,12 +1,22 @@
package com.example.g8backend.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.g8backend.entity.Follow;
+import com.example.g8backend.entity.Message;
import com.example.g8backend.entity.User;
+import com.example.g8backend.mapper.FollowMapper;
+import com.example.g8backend.mapper.MessageMapper;
import com.example.g8backend.mapper.UserMapper;
import com.example.g8backend.service.IUserService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@@ -22,4 +32,89 @@
@Override
public User getUserByPasskey(String passkey) { return userMapper.getUserByPasskey(passkey);}
+ @Resource
+ private FollowMapper followMapper;
+ @Resource
+ private MessageMapper messageMapper;
+
+ @Override
+ public boolean followUser(Long followerId, Long followedId) {
+ if (followerId.equals(followedId)) return false;
+ Follow follow = new Follow();
+ follow.setFollowerId(followerId);
+ follow.setFollowedId(followedId);
+ return followMapper.insert(follow) > 0;
+ }
+
+ @Override
+ public boolean unfollowUser(Long followerId, Long followedId) {
+ // 删除关注关系
+ return followMapper.deleteByPair(followerId, followedId) > 0;
+ }
+
+ @Override
+ public List<User> getFollowings(Long userId) {
+ // 1. 获取关注ID列表
+ List<Long> followingIds = followMapper.selectFollowings(userId);
+ // 2. 批量查询用户信息
+ return followingIds.isEmpty() ?
+ Collections.emptyList() :
+ this.listByIds(followingIds).stream()
+ .peek(user -> user.setPassword(null)) // 敏感信息脱敏
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<User> getFollowers(Long userId) {
+ // 1. 获取粉丝ID列表
+ List<Long> followerIds = followMapper.selectFollowers(userId);
+ // 2. 批量查询用户信息
+ return followerIds.isEmpty() ?
+ Collections.emptyList() :
+ this.listByIds(followerIds).stream()
+ .peek(user -> user.setPassword(null))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Long sendMessage(Long senderId, Long receiverId, String content) {
+ // 1. 校验接收者是否存在(方案一)
+ if (userMapper.selectById(receiverId) == null) {
+ throw new RuntimeException("接收用户不存在");
+ }
+
+ // 2. 创建消息实体
+ Message message = new Message()
+ .setSenderId(senderId)
+ .setReceiverId(receiverId)
+ .setContent(content)
+ .setSentAt(LocalDateTime.now());
+
+ // 3. 插入数据库
+ messageMapper.insert(message);
+ return message.getMessageId();
+ }
+
+ @Override
+ public List<Message> getMessages(Long userId, Long partnerId) {
+ // 获取双方对话记录
+ return messageMapper.selectConversation(userId, partnerId).stream()
+ .peek(msg -> {
+ // 标记消息为已读
+ if (!msg.getIsRead() && msg.getReceiverId().equals(userId)) {
+ msg.setIsRead(true);
+ messageMapper.updateById(msg);
+ }
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<Message> getMessageHistory(Long userId) {
+ // 获取用户所有相关消息
+ return messageMapper.selectUserMessages(userId).stream()
+ .sorted(Comparator.comparing(Message::getSentAt).reversed())
+ .collect(Collectors.toList());
+ }
+
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 6bde80e..7f85f87 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,4 +1,4 @@
-spring.datasource.password=123456
+spring.datasource.password=12345678
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/g8backend
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
diff --git a/src/main/resources/mapper/PostMapper.xml b/src/main/resources/mapper/PostMapper.xml
index c1dbda7..d1cbcf4 100644
--- a/src/main/resources/mapper/PostMapper.xml
+++ b/src/main/resources/mapper/PostMapper.xml
@@ -1,8 +1,8 @@
-.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.example.g8backend.mapper.PostMapper">
<select id="getPostsByUserId" resultType="com.example.g8backend.entity.Post">
SELECT * FROM posts WHERE user_id = #{userId}
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index 952313e..5e5dd43 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -63,3 +63,25 @@
FOREIGN KEY (post_id) REFERENCES posts(post_id),
PRIMARY KEY (user_id, post_id)
);
+
+-- 关注关系表
+CREATE TABLE IF NOT EXISTS `user_follows` (
+ follower_id INT NOT NULL,
+ followed_id INT NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (follower_id) REFERENCES users(user_id),
+ FOREIGN KEY (followed_id) REFERENCES users(user_id),
+ PRIMARY KEY (follower_id, followed_id)
+);
+
+-- 私信表
+CREATE TABLE IF NOT EXISTS `private_messages` (
+ message_id INT AUTO_INCREMENT PRIMARY KEY,
+ sender_id INT NOT NULL,
+ receiver_id INT NOT NULL,
+ content TEXT NOT NULL,
+ sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ is_read BOOLEAN DEFAULT false,
+ FOREIGN KEY (sender_id) REFERENCES users(user_id),
+ FOREIGN KEY (receiver_id) REFERENCES users(user_id)
+);
\ No newline at end of file