debug
Change-Id: I5c4de18f786f8cc336d8ad66ae9b424d02ed3674
diff --git a/src/main/java/com/example/g8backend/controller/PostController.java b/src/main/java/com/example/g8backend/controller/PostController.java
index 03687c3..d53db64 100644
--- a/src/main/java/com/example/g8backend/controller/PostController.java
+++ b/src/main/java/com/example/g8backend/controller/PostController.java
@@ -1,5 +1,4 @@
package com.example.g8backend.controller;
-
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.g8backend.dto.PostCreateDTO;
@@ -12,9 +11,7 @@
import org.springframework.web.bind.annotation.*;
import com.example.g8backend.entity.Post;
import com.example.g8backend.service.IPostService;
-
import java.util.List;
-
@RestController
@RequestMapping("/post")
public class PostController {
@@ -22,14 +19,12 @@
private IPostService postService;
@Autowired // ✅ 新增注入
private PostViewMapper postViewMapper;
-
@PostMapping("")
public ResponseEntity<?> createPost(@RequestBody PostCreateDTO postCreateDTO) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
long userId = (long) authentication.getPrincipal();
Post post = postCreateDTO.getPost();
Long[] tagIds = postCreateDTO.getTagIds();
-
post.setUserId(userId);
if (tagIds.length > 0){
postService.createPost(post, tagIds);
@@ -38,20 +33,16 @@
}
return ResponseEntity.ok().build();
}
-
@GetMapping("/{postId}")
public Post getPost(@PathVariable Long postId) {
// 获取当前用户ID
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
long userId = (long) authentication.getPrincipal();
-
// 记录浏览行为
postService.recordViewHistory(userId, postId);
-
// 返回帖子详情
return postService.getById(postId);
}
-
@DeleteMapping("/{postId}")
public ResponseEntity<?> deletePost(@PathVariable("postId") Long postId) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
@@ -66,42 +57,37 @@
postService.removeById(postId);
return ResponseEntity.ok().body("Post deleted successfully.");
}
-
@GetMapping("/getAll")
public List<Post> getAllPosts() {
return postService.list();
}
-
@GetMapping("/getByUserId/{userId}")
public List<Post> getPostsByUserId(@PathVariable("userId") Long userId) {
return postService.getPostsByUserId(userId);
}
-
@PutMapping("/{postId}")
public ResponseEntity<?> updatePost(@PathVariable("postId") Long postId, @RequestBody Post post) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
long userId = (long) authentication.getPrincipal();
Post existingPost = postService.getById(postId);
-
+
if (existingPost == null) {
return ResponseEntity.status(500).body("Post not found.");
}
if (existingPost.getUserId() != userId) {
return ResponseEntity.status(403).body("You are not authorized to update this post.");
}
-
+
post.setPostId(postId);
post.setUserId(userId);
postService.updateById(post);
return ResponseEntity.ok().body("Post updated successfully.");
}
-
@GetMapping("/type/{postType}")
public ResponseEntity<?> getPostsByType(@PathVariable String postType) {
List<Post> posts = postService.getPostsByType(postType);
return ResponseEntity.ok().body(posts);
}
-
@PostMapping("/{postId}/like")
public ResponseEntity<?> likePost(@PathVariable Long postId) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
@@ -109,7 +95,6 @@
postService.likePost(userId, postId);
return ResponseEntity.ok().body("Post liked successfully.");
}
-
@DeleteMapping("/{postId}/like")
public ResponseEntity<?> unlikePost(@PathVariable Long postId) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
@@ -117,51 +102,52 @@
postService.unlikePost(userId, postId);
return ResponseEntity.ok().body("Post unliked successfully.");
}
-
@GetMapping("/{postId}/likes")
public ResponseEntity<?> getPostLikeCount(@PathVariable Long postId) {
Long likeCount = postService.getPostLikeCount(postId);
return ResponseEntity.ok().body(likeCount);
}
-
// 搜索帖子
@GetMapping("/search")
public List<Post> searchPosts(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) List<Long> tags, // 修改为接收多个标签
@RequestParam(required = false) String author) {
-
return postService.searchPosts(keyword, tags, author);
}
-
@GetMapping("/history")
public ResponseEntity<List<PostView>> getViewHistory() {
// 获取当前用户ID
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
long userId = (long) authentication.getPrincipal();
-
// 查询历史记录(按时间倒序)
List<PostView> history = postViewMapper.selectList(
new QueryWrapper<PostView>()
.eq("user_id", userId)
.orderByDesc("view_time")
);
-
return ResponseEntity.ok(history);
}
-
@GetMapping("/recommended")
public ResponseEntity<Page<Post>> getRecommendedPosts(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
-
// 获取当前用户ID
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
long userId = (long) authentication.getPrincipal();
-
// 调用 Service 层方法
Page<Post> pageResult = postService.getRecommendedPosts(page, size, userId);
-
return ResponseEntity.ok(pageResult);
}
-}
+ // PostController.java - 新增标签推荐接口
+ @GetMapping("/recommended-by-tags")
+ public ResponseEntity<Page<Post>> getRecommendedByTags(
+ @RequestParam(defaultValue = "1") int page,
+ @RequestParam(defaultValue = "10") int size) {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ long userId = (long) authentication.getPrincipal();
+ // 调用标签推荐方法
+ Page<Post> result = postService.getRecommendedByTags(page, size, userId);
+ return ResponseEntity.ok(result);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/entity/UserTagPreference.java b/src/main/java/com/example/g8backend/entity/UserTagPreference.java
new file mode 100644
index 0000000..42ac4fd
--- /dev/null
+++ b/src/main/java/com/example/g8backend/entity/UserTagPreference.java
@@ -0,0 +1,15 @@
+
+package com.example.g8backend.entity;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+import java.sql.Timestamp;
+@Data
+@Accessors(chain = true)
+@TableName("user_tag_preference") // 映射数据库表名
+public class UserTagPreference {
+ private Long userId; // 用户ID
+ private Long tagId; // 标签ID
+ private Double weight; // 偏好权重
+ private Timestamp lastUpdated; // 最后更新时间
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/mapper/PostMapper.java b/src/main/java/com/example/g8backend/mapper/PostMapper.java
index b5a5280..baebb17 100644
--- a/src/main/java/com/example/g8backend/mapper/PostMapper.java
+++ b/src/main/java/com/example/g8backend/mapper/PostMapper.java
@@ -1,19 +1,14 @@
package com.example.g8backend.mapper;
-
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.g8backend.entity.Post;
import com.example.g8backend.entity.PostLike;
import org.apache.ibatis.annotations.*;
-
import java.util.List;
-
@Mapper
public interface PostMapper extends BaseMapper<Post> {
-
// 获取用户的帖子
List<Post> getPostsByUserId(@Param("userId") Long userId);
-
// 搜索帖子
@Select("<script>" +
"SELECT p.* " +
@@ -35,32 +30,24 @@
List<Post> searchPosts(@Param("keyword") String keyword,
@Param("tagIds") List<Long> tagIds,
@Param("author") String author);
-
// 检查用户是否已经点赞该帖子
@Select("SELECT EXISTS (SELECT 1 FROM post_likes WHERE user_id = #{userId} AND post_id = #{postId})")
boolean existsByUserIdAndPostId(@Param("userId") Long userId, @Param("postId") Long postId);
-
// 插入一条点赞记录
@Insert("INSERT INTO post_likes (user_id, post_id) VALUES (#{userId}, #{postId})")
void insert(PostLike postLike);
-
// 删除用户对帖子的点赞记录
@Delete("DELETE FROM post_likes WHERE user_id = #{userId} AND post_id = #{postId}")
void deleteLikeByUserIdAndPostId(@Param("userId") Long userId, @Param("postId") Long postId);
-
// 获取某个帖子点赞数
@Select("SELECT COUNT(*) FROM post_likes WHERE post_id = #{postId}")
Long selectCount(@Param("postId") Long postId);
-
@Update("UPDATE posts SET view_count = view_count + 1 WHERE post_id = #{postId}")
void incrementViewCount(Long postId);
-
@Select("SELECT COUNT(*) FROM post_likes WHERE post_id = #{postId}")
Long selectLikeCount(Long postId);
-
@Select("SELECT post_id FROM post_views WHERE user_id = #{userId}")
List<Long> findViewedPostIds(Long userId);
-
@Update({
"<script>",
"UPDATE posts",
@@ -77,4 +64,4 @@
"</script>"
})
int batchUpdateHotScore(@Param("posts") List<Post> posts);
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/mapper/PostTagMapper.java b/src/main/java/com/example/g8backend/mapper/PostTagMapper.java
index 184feb2..4c8cc1e 100644
--- a/src/main/java/com/example/g8backend/mapper/PostTagMapper.java
+++ b/src/main/java/com/example/g8backend/mapper/PostTagMapper.java
@@ -1,17 +1,27 @@
package com.example.g8backend.mapper;
-
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.g8backend.entity.Post;
import com.example.g8backend.entity.PostTag;
import com.example.g8backend.entity.Tag;
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 PostTagMapper extends BaseMapper<PostTag> {
List<Post> getPostsByTagIds(@Param("tagIds") Long[] tagIds);
List<Tag> getTagsByPostId(@Param("postId") Long postId);
int deleteByIds(@Param("postId") Long postId, @Param("tagId") Long tagId);
-}
+ @Select("SELECT tag_id FROM post_tag WHERE post_id = #{postId}")
+ List<Long> findTagIdsByPostId(Long postId);
+ @Select({
+ "<script>",
+ "SELECT post_id FROM post_tag",
+ "WHERE tag_id IN",
+ "<foreach item='tagId' collection='tagIds' open='(' separator=',' close=')'>",
+ "#{tagId}",
+ "</foreach>",
+ "</script>"
+ })
+ List<Long> findPostIdsByTagIds(@Param("tagIds") List<Long> tagIds);
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/mapper/UserTagPreferenceMapper.java b/src/main/java/com/example/g8backend/mapper/UserTagPreferenceMapper.java
new file mode 100644
index 0000000..c59ea8e
--- /dev/null
+++ b/src/main/java/com/example/g8backend/mapper/UserTagPreferenceMapper.java
@@ -0,0 +1,22 @@
+package com.example.g8backend.mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.g8backend.entity.UserTagPreference;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+import java.util.List;
+public interface UserTagPreferenceMapper extends BaseMapper<UserTagPreference> {
+ /**
+ * 插入或更新用户标签偏好权重
+ */
+ @Update("INSERT INTO user_tag_preference (user_id, tag_id, weight) " +
+ "VALUES (#{userId}, #{tagId}, #{increment}) " +
+ "ON DUPLICATE KEY UPDATE weight = weight + #{increment}")
+ void insertOrUpdateWeight(
+ @Param("userId") Long userId,
+ @Param("tagId") Long tagId,
+ @Param("increment") Double increment
+ );
+ @Select("SELECT * FROM user_tag_preference WHERE user_id = #{userId}")
+ List<UserTagPreference> selectByUserId(@Param("userId") Long userId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/service/IPostService.java b/src/main/java/com/example/g8backend/service/IPostService.java
index ca5376b..855952e 100644
--- a/src/main/java/com/example/g8backend/service/IPostService.java
+++ b/src/main/java/com/example/g8backend/service/IPostService.java
@@ -28,4 +28,6 @@
void calculateHotScores();
Page<Post> getRecommendedPosts(int page, int size, Long userId);
+
+ Page<Post> getRecommendedByTags(int page, int size, Long userId);
}
diff --git a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
index ae47d8a..5faa4ac 100644
--- a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
+++ b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
@@ -1,57 +1,47 @@
package com.example.g8backend.service.impl;
-
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.example.g8backend.entity.Post;
-import com.example.g8backend.entity.PostLike;
-import com.example.g8backend.entity.PostTag;
-import com.example.g8backend.entity.PostView;
-import com.example.g8backend.mapper.CommentMapper;
-import com.example.g8backend.mapper.PostMapper;
-import com.example.g8backend.mapper.PostViewMapper;
+import com.example.g8backend.entity.*;
+import com.example.g8backend.mapper.*;
import com.example.g8backend.service.IPostService;
import com.example.g8backend.service.IPostTagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-
import java.sql.Timestamp;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
-
+import java.util.stream.Collectors;
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements IPostService {
-
private final PostMapper postMapper;
-
private final PostViewMapper postViewMapper;
-
private final CommentMapper commentMapper;
-
+ private final UserTagPreferenceMapper userTagPreferenceMapper;
+ private final PostTagMapper postTagMapper;
@Autowired
private IPostTagService postTagService;
-
- public PostServiceImpl(PostMapper postMapper, PostViewMapper postViewMapper, CommentMapper commentMapper) {
+ public PostServiceImpl(PostMapper postMapper, PostViewMapper postViewMapper, CommentMapper commentMapper,
+ UserTagPreferenceMapper userTagPreferenceMapper, PostTagMapper postTagMapper) {
this.postMapper = postMapper;
this.postViewMapper = postViewMapper;
this.commentMapper = commentMapper;
+ this.userTagPreferenceMapper = userTagPreferenceMapper;
+ this.postTagMapper = postTagMapper;
this.baseMapper = postMapper; // 重要:设置 baseMapper
}
-
@Override
public List<Post> getPostsByUserId(Long userId) {
return postMapper.getPostsByUserId(userId);
}
-
public void createPost(Post post) {
post.setHotScore(5.0); // 初始热度
post.setCreatedAt(new Timestamp(System.currentTimeMillis()));
save(post);
}
-
@Override
public void createPost(Post post, Long[] tagIds) {
post.setHotScore(5.0); // 初始热度
@@ -61,20 +51,17 @@
postTagService.save(new PostTag(post.getPostId(), tagId));
}
}
-
@Override
public Post updatePost(Post post) {
updateById(post);
return getById(post.getPostId());
}
-
@Override
public List<Post> getPostsByType(String postType) {
QueryWrapper<Post> wrapper = new QueryWrapper<>();
wrapper.eq("post_type", postType);
return list(wrapper);
}
-
@Override
public void likePost(Long userId, Long postId) {
// 检查用户是否已经点赞该帖子
@@ -85,14 +72,12 @@
postMapper.insert(postLike); // 执行插入点赞记录
}
}
-
// 取消点赞功能
@Override
public void unlikePost(Long userId, Long postId) {
// 删除用户对帖子的点赞记录
postMapper.deleteLikeByUserIdAndPostId(userId, postId); // 使用新的方法删除记录
}
-
// 获取帖子点赞数
@Override
public Long getPostLikeCount(Long postId) {
@@ -103,8 +88,6 @@
public List<Post> searchPosts(String keyword, List<Long> tagIds, String author) {
return postMapper.searchPosts(keyword, tagIds, author); // 调用mapper的搜索方法
}
-
-
@Override
@Transactional
public void recordViewHistory(Long userId, Long postId) {
@@ -114,11 +97,11 @@
.setPostId(postId)
.setViewTime(new Timestamp(System.currentTimeMillis()).toLocalDateTime());
postViewMapper.insert(view);
-
// 2. 原子更新浏览数
postMapper.incrementViewCount(postId); // 直接调用原子操作
+ // 3. 新增:更新用户标签偏好
+ updateUserTagPreference(userId, postId);
}
-
@Override
@Scheduled(cron = "0 */10 * * * *") // 每10分钟执行一次
@Transactional
@@ -126,7 +109,6 @@
// 1. 获取所有帖子
List<Post> posts = postMapper.selectList(new QueryWrapper<>());
Instant now = Instant.now();
-
// 2. 计算每个帖子的热度
posts.forEach(post -> {
// 计算时间衰减因子(以小时为单位)
@@ -134,40 +116,65 @@
post.getCreatedAt().toInstant(),
now
);
-
// 获取互动数据(点赞数、评论数)
Long likeCount = postMapper.selectLikeCount(post.getPostId());
Long commentCount = commentMapper.selectCountByPostId(post.getPostId());
-
// 热度计算公式
double hotScore = (
Math.log(post.getViewCount() + 1) * 0.2 +
likeCount * 0.5 +
commentCount * 0.3
) / Math.pow(hoursSinceCreation + 2, 1.5);
-
post.setHotScore(hotScore);
post.setLastCalculated(new Timestamp(System.currentTimeMillis()));
});
-
// 3. 批量更新热度(自定义SQL实现)
postMapper.batchUpdateHotScore(posts);
}
-
@Override
public Page<Post> getRecommendedPosts(int page, int size, Long userId) {
// 1. 获取用户已浏览的帖子ID列表
List<Long> viewedPostIds = postViewMapper.findViewedPostIds(userId);
-
// 2. 构建查询条件:排除已浏览帖子,按热度降序
QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
if (!viewedPostIds.isEmpty()) {
queryWrapper.notIn("post_id", viewedPostIds);
}
queryWrapper.orderByDesc("hot_score");
-
// 3. 分页查询
return postMapper.selectPage(new Page<>(page, size), queryWrapper);
}
-
+ private void updateUserTagPreference(Long userId, Long postId) {
+ // 获取帖子关联的标签ID列表
+ List<Long> tagIds = postTagMapper.findTagIdsByPostId(postId);
+ // 对每个标签增加权重(示例:每次浏览 +0.1)
+ tagIds.forEach(tagId -> {
+ userTagPreferenceMapper.insertOrUpdateWeight(
+ userId,
+ tagId,
+ 0.1 // 权重增量
+ );
+ });
+ }
+ @Override
+ public Page<Post> getRecommendedByTags(int page, int size, Long userId) {
+ // 获取用户偏好标签
+ List<UserTagPreference> preferences = userTagPreferenceMapper.selectByUserId(userId);
+ if (preferences.isEmpty()) {
+ return new Page<>(page, size);
+ }
+ // 获取标签关联的帖子ID
+ List<Long> tagIds = preferences.stream()
+ .map(UserTagPreference::getTagId)
+ .collect(Collectors.toList());
+ List<Long> postIds = postTagMapper.findPostIdsByTagIds(tagIds);
+ if (postIds.isEmpty()) {
+ return new Page<>(page, size);
+ }
+ // 构建查询条件
+ QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
+ queryWrapper.in("post_id", postIds) // 确保正确添加 IN 条件
+ .orderByDesc("hot_score"); // 确保排序条件正确
+ return postMapper.selectPage(new Page<>(page, size), queryWrapper);
+ }
}
\ No newline at end of file