Merge "Merge branch 'whx'"
diff --git a/src/main/java/com/example/g8backend/controller/PostController.java b/src/main/java/com/example/g8backend/controller/PostController.java
index 3557af2..f373539 100644
--- a/src/main/java/com/example/g8backend/controller/PostController.java
+++ b/src/main/java/com/example/g8backend/controller/PostController.java
@@ -1,5 +1,6 @@
package com.example.g8backend.controller;
+import com.example.g8backend.dto.PostCreateDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
@@ -17,11 +18,18 @@
private IPostService postService;
@PostMapping("")
- public ResponseEntity<?> createPost(@RequestBody Post post) {
+ 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);
- postService.save(post);
+ if (tagIds.length > 0){
+ postService.createPost(post, tagIds);
+ } else {
+ postService.createPost(post);
+ }
return ResponseEntity.ok().build();
}
diff --git a/src/main/java/com/example/g8backend/dto/PostCreateDTO.java b/src/main/java/com/example/g8backend/dto/PostCreateDTO.java
new file mode 100644
index 0000000..a14deea
--- /dev/null
+++ b/src/main/java/com/example/g8backend/dto/PostCreateDTO.java
@@ -0,0 +1,10 @@
+package com.example.g8backend.dto;
+
+import com.example.g8backend.entity.Post;
+import lombok.Data;
+
+@Data
+public class PostCreateDTO {
+ private Post post;
+ private Long[] tagIds;
+}
diff --git a/src/main/java/com/example/g8backend/entity/PostTag.java b/src/main/java/com/example/g8backend/entity/PostTag.java
new file mode 100644
index 0000000..804faaa
--- /dev/null
+++ b/src/main/java/com/example/g8backend/entity/PostTag.java
@@ -0,0 +1,18 @@
+package com.example.g8backend.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("post_tag")
+public class PostTag {
+ private Long postId;
+ private Long tagId;
+
+ public PostTag(Long postId, Long tagId) {
+ this.postId = postId;
+ this.tagId = tagId;
+ }
+}
diff --git a/src/main/java/com/example/g8backend/entity/Tag.java b/src/main/java/com/example/g8backend/entity/Tag.java
new file mode 100644
index 0000000..75eaa38
--- /dev/null
+++ b/src/main/java/com/example/g8backend/entity/Tag.java
@@ -0,0 +1,25 @@
+package com.example.g8backend.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("tags")
+public class Tag {
+ @TableId(type = IdType.AUTO)
+ private Long tagId;
+
+ private String name;
+ private Long parentId;
+
+ @Override
+ public String toString() {
+ return "Tag{" +
+ "tagId=" + tagId +
+ ", name='" + name + '\'' +
+ ", parentId=" + parentId +
+ '}';
+ }
+}
diff --git a/src/main/java/com/example/g8backend/mapper/PostTagMapper.java b/src/main/java/com/example/g8backend/mapper/PostTagMapper.java
new file mode 100644
index 0000000..184feb2
--- /dev/null
+++ b/src/main/java/com/example/g8backend/mapper/PostTagMapper.java
@@ -0,0 +1,17 @@
+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 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);
+}
diff --git a/src/main/java/com/example/g8backend/mapper/TagMapper.java b/src/main/java/com/example/g8backend/mapper/TagMapper.java
new file mode 100644
index 0000000..f959dd8
--- /dev/null
+++ b/src/main/java/com/example/g8backend/mapper/TagMapper.java
@@ -0,0 +1,9 @@
+package com.example.g8backend.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.g8backend.entity.Tag;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface TagMapper extends BaseMapper<Tag> {
+}
diff --git a/src/main/java/com/example/g8backend/service/IPostService.java b/src/main/java/com/example/g8backend/service/IPostService.java
index f81053e..f914946 100644
--- a/src/main/java/com/example/g8backend/service/IPostService.java
+++ b/src/main/java/com/example/g8backend/service/IPostService.java
@@ -2,11 +2,13 @@
import com.example.g8backend.entity.Post;
import com.baomidou.mybatisplus.extension.service.IService;
+
import java.util.List;
public interface IPostService extends IService<Post> {
List<Post> getPostsByUserId(Long userId);
- Post createPost(Post post);
+ void createPost(Post post);
+ void createPost(Post post, Long[] tagIds);
Post updatePost(Post post);
List<Post> getPostsByType(String postType);
Long getPostLikeCount(Long postId);
diff --git a/src/main/java/com/example/g8backend/service/IPostTagService.java b/src/main/java/com/example/g8backend/service/IPostTagService.java
new file mode 100644
index 0000000..03b16fa
--- /dev/null
+++ b/src/main/java/com/example/g8backend/service/IPostTagService.java
@@ -0,0 +1,16 @@
+package com.example.g8backend.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.g8backend.entity.Tag;
+import com.example.g8backend.entity.Post;
+import com.example.g8backend.entity.PostTag;
+
+import java.util.List;
+
+public interface IPostTagService extends IService<PostTag> {
+ boolean save(PostTag postTag);
+ List<Post> getPostsByTagIds(Long[] tagIds);
+ List<Tag> getTagsByPostId(Long postId);
+ boolean removeByIds(PostTag postTag);
+}
diff --git a/src/main/java/com/example/g8backend/service/ITagService.java b/src/main/java/com/example/g8backend/service/ITagService.java
new file mode 100644
index 0000000..0fc589f
--- /dev/null
+++ b/src/main/java/com/example/g8backend/service/ITagService.java
@@ -0,0 +1,7 @@
+package com.example.g8backend.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.g8backend.entity.Tag;
+
+public interface ITagService extends IService<Tag> {
+}
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 09a471e..d40ddd6 100644
--- a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
+++ b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
@@ -3,9 +3,11 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.g8backend.entity.Post;
+import com.example.g8backend.entity.PostTag;
import com.example.g8backend.mapper.PostMapper;
import com.example.g8backend.service.IPostService;
-import jakarta.annotation.Resource;
+import com.example.g8backend.service.IPostTagService;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.List;
@@ -15,6 +17,9 @@
private final PostMapper postMapper;
+ @Autowired
+ private IPostTagService postTagService;
+
public PostServiceImpl(PostMapper postMapper) {
this.postMapper = postMapper;
this.baseMapper = postMapper; // 重要:设置 baseMapper
@@ -26,10 +31,18 @@
}
@Override
- public Post createPost(Post post) {
+ public void createPost(Post post) {
post.setCreatedAt(new Timestamp(System.currentTimeMillis()));
save(post);
- return post;
+ }
+
+ @Override
+ public void createPost(Post post, Long[] tagIds) {
+ post.setCreatedAt(new Timestamp(System.currentTimeMillis()));
+ save(post);
+ for (long tagId : tagIds) {
+ postTagService.save(new PostTag(post.getPostId(), tagId));
+ }
}
@Override
diff --git a/src/main/java/com/example/g8backend/service/impl/PostTagServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/PostTagServiceImpl.java
new file mode 100644
index 0000000..0aa0647
--- /dev/null
+++ b/src/main/java/com/example/g8backend/service/impl/PostTagServiceImpl.java
@@ -0,0 +1,42 @@
+package com.example.g8backend.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.g8backend.entity.Post;
+import com.example.g8backend.entity.PostTag;
+import com.example.g8backend.entity.Tag;
+import com.example.g8backend.mapper.PostTagMapper;
+import com.example.g8backend.service.IPostTagService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class PostTagServiceImpl extends ServiceImpl<PostTagMapper, PostTag> implements IPostTagService {
+
+ @Autowired
+ private PostTagMapper postTagMapper;
+
+ @Override
+ public boolean save(PostTag postTag) {
+ return postTagMapper.insert(postTag) > 0;
+ }
+
+ @Override
+ public List<Post> getPostsByTagIds(Long[] tagIds) {
+ if (tagIds == null || tagIds.length == 0) return new ArrayList<>();
+ return postTagMapper.getPostsByTagIds(tagIds);
+ }
+
+ @Override
+ public List<Tag> getTagsByPostId(Long postId) {
+ if (postId == null) return new ArrayList<>();
+ return postTagMapper.getTagsByPostId(postId);
+ }
+
+ @Override
+ public boolean removeByIds(PostTag postTag) {
+ return postTagMapper.deleteByIds(postTag.getPostId(), postTag.getTagId()) > 0;
+ }
+}
diff --git a/src/main/java/com/example/g8backend/service/impl/TagServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/TagServiceImpl.java
new file mode 100644
index 0000000..41b95a3
--- /dev/null
+++ b/src/main/java/com/example/g8backend/service/impl/TagServiceImpl.java
@@ -0,0 +1,12 @@
+package com.example.g8backend.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.g8backend.entity.Tag;
+import com.example.g8backend.mapper.TagMapper;
+import com.example.g8backend.service.ITagService;
+import jakarta.annotation.Resource;
+
+public class TagServiceImpl extends ServiceImpl<TagMapper, Tag> implements ITagService {
+ @Resource
+ private TagMapper tagMapper;
+}
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index 0907033..607d353 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -1 +1,11 @@
-# 后面统一数据库数据用
\ No newline at end of file
+# # 后面统一数据库数据用
+#
+# # tags表父标签
+# INSERT INTO `tags` (tag_id, tag_name, parent_id) VALUES (1, '电影', NULL);
+# INSERT INTO `tags` (tag_id, tag_name, parent_id) VALUES (2, '游戏', NULL);
+# INSERT INTO `tags` (tag_id, tag_name, parent_id) VALUES (3, '音乐', NULL);
+#
+# # tags表子标签
+# INSERT INTO `tags` (tag_id, tag_name, parent_id) VALUES (4, '动作', 1);
+# INSERT INTO `tags` (tag_id, tag_name, parent_id) VALUES (5, '喜剧', 1);
+# INSERT INTO `tags` (tag_id, tag_name, parent_id) VALUES (6, '科幻', 1);
\ No newline at end of file
diff --git a/src/main/resources/mapper/PostTagMapper.xml b/src/main/resources/mapper/PostTagMapper.xml
new file mode 100644
index 0000000..b2cfc69
--- /dev/null
+++ b/src/main/resources/mapper/PostTagMapper.xml
@@ -0,0 +1,22 @@
+<?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.entity.PostTag">
+ <select id="getPostsByTagIds" resultType="com.example.g8backend.entity.Post">
+ SELECT DISTINCT p.* FROM posts p JOIN post_tag pt ON p.post_id = pt.post_id
+ WHERE pt.tag_id IN
+ <foreach collection="tagIds" item="tagId" open="(" separator="," close=")">
+ #{tagId}
+ </foreach>
+ </select>
+
+ <select id="getTagsByPostId">
+ SELECT DISTINCT t.* FROM tags t JOIN post_tag pt ON t.tag_id = pt.tag_id
+ </select>
+
+ <delete id="deleteByIds">
+ DELETE FROM post_tag
+ WHERE post_id = #{postId} AND tag_id = #{tagId}
+ </delete>
+</mapper>
\ No newline at end of file
diff --git a/src/test/java/com/example/g8backend/service/PostTagServiceTest.java b/src/test/java/com/example/g8backend/service/PostTagServiceTest.java
new file mode 100644
index 0000000..6ec9055
--- /dev/null
+++ b/src/test/java/com/example/g8backend/service/PostTagServiceTest.java
@@ -0,0 +1,96 @@
+package com.example.g8backend.service;
+
+import com.example.g8backend.entity.Post;
+import com.example.g8backend.entity.PostTag;
+import com.example.g8backend.entity.Tag;
+import com.example.g8backend.mapper.PostTagMapper;
+import com.example.g8backend.service.impl.PostTagServiceImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class PostTagServiceTest {
+
+ @InjectMocks
+ private PostTagServiceImpl postTagService;
+
+ @Mock
+ private PostTagMapper postTagMapper;
+
+ private PostTag samplePostTag;
+
+ @BeforeEach
+ public void setUp() {
+ samplePostTag = new PostTag(1L, 2L);
+ }
+
+ @Test
+ public void testSave() {
+ when(postTagMapper.insert(any(PostTag.class))).thenReturn(1);
+
+ boolean result = postTagService.save(samplePostTag);
+
+ assertTrue(result);
+ verify(postTagMapper, times(1)).insert(samplePostTag);
+ }
+
+ @Test
+ public void testGetPostsByTagIds() {
+ Long[] tagIds = {1L, 2L};
+ List<Post> expectedPosts = List.of(new Post());
+ when(postTagMapper.getPostsByTagIds(tagIds)).thenReturn(expectedPosts);
+
+ List<Post> result = postTagService.getPostsByTagIds(tagIds);
+
+ assertEquals(expectedPosts, result);
+ verify(postTagMapper, times(1)).getPostsByTagIds(tagIds);
+ }
+
+ @Test
+ public void testGetPostsByTagIds_EmptyInput() {
+ List<Post> result = postTagService.getPostsByTagIds(new Long[]{});
+
+ assertTrue(result.isEmpty());
+ verify(postTagMapper, never()).getPostsByTagIds(any());
+ }
+
+ @Test
+ public void testGetTagsByPostId() {
+ Long postId = 1L;
+ List<Tag> expectedTags = List.of(new Tag());
+ when(postTagMapper.getTagsByPostId(postId)).thenReturn(expectedTags);
+
+ List<Tag> result = postTagService.getTagsByPostId(postId);
+
+ assertEquals(expectedTags, result);
+ verify(postTagMapper, times(1)).getTagsByPostId(postId);
+ }
+
+ @Test
+ public void testGetTagsByPostId_Null() {
+ List<Tag> result = postTagService.getTagsByPostId(null);
+
+ assertTrue(result.isEmpty());
+ verify(postTagMapper, never()).getTagsByPostId(any());
+ }
+
+ @Test
+ public void testRemoveByIds() {
+ when(postTagMapper.deleteByIds(1L, 2L)).thenReturn(1);
+
+ boolean result = postTagService.removeByIds(samplePostTag);
+
+ assertTrue(result);
+ verify(postTagMapper, times(1)).deleteByIds(1L, 2L);
+ }
+}