From d20e9ba3e2019a45f7ed2f796fe7bea4964e0907 Mon Sep 17 00:00:00 2001 From: many2many <6168830@qq.com> Date: Thu, 23 May 2024 10:13:12 +0800 Subject: [PATCH] add --- .../lk/paopao/controller/PostController.java | 60 +++++ .../paopao/controller/SuggestController.java | 39 ++++ .../repository/PostCollectionRepository.java | 3 + .../paopao/repository/PostStarRepository.java | 3 + .../lk/paopao/repository/TagRepository.java | 4 +- .../com/lk/paopao/service/PostService.java | 208 ++++++++++++++++++ 6 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/lk/paopao/controller/PostController.java create mode 100644 src/main/java/com/lk/paopao/controller/SuggestController.java create mode 100644 src/main/java/com/lk/paopao/service/PostService.java diff --git a/src/main/java/com/lk/paopao/controller/PostController.java b/src/main/java/com/lk/paopao/controller/PostController.java new file mode 100644 index 0000000..ec84ee5 --- /dev/null +++ b/src/main/java/com/lk/paopao/controller/PostController.java @@ -0,0 +1,60 @@ +package com.lk.paopao.controller; + + +import com.lk.paopao.dto.CommentDto; +import com.lk.paopao.dto.PostDto; +import com.lk.paopao.dto.rest.request.PostRequest; +import com.lk.paopao.dto.rest.response.DataResult; +import com.lk.paopao.dto.rest.response.Paged; +import com.lk.paopao.dto.rest.response.ResultUtil; +import com.lk.paopao.service.PostService; +import jakarta.websocket.server.PathParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("${app.version}") +public class PostController { + + @Autowired + PostService postService; + + // https://iibiubiu.com/v1/posts?style=newest&page=1&page_size=20 + @GetMapping("/posts") + public DataResult> getPosts(@PathParam("type") Long type, @PathParam("style") String style, @PathParam("page") Integer page, @PathParam("page_size") Integer pageSize) { + return ResultUtil.ok(postService.getPosts(type, style, page, pageSize)); + + } + @GetMapping("/post") + public DataResult getPost(@PathParam("id") Long id) { + return ResultUtil.ok(postService.getPost(id)); + } + @PostMapping("/post") + public DataResult createPost(@RequestBody PostRequest postRequest) { + return ResultUtil.ok(postService.createPost(postRequest)); + } + + @GetMapping("/post/comments") + public DataResult> getPostComments(@PathParam("id") Long id, @PathParam("style") String style, @PathParam("page") Integer page, @PathParam("page_size") Integer pageSize) { + Paged paged = new Paged<>(new ArrayList<>(),0L,1,10); + return ResultUtil.ok(paged); + } + + @GetMapping("/post/star") + public DataResult> currentHasStarred(@PathParam("id") Long postId) { + Map result = new HashMap<>(); + result.put("status", postService.currentUserHasStarred(postId)); + return ResultUtil.ok(result); + } + + @GetMapping("/post/collection") + public DataResult> currentHasCollected(@PathParam("id") Long postId) { + Map result = new HashMap<>(); + result.put("status", postService.currentUserHasCollected(postId)); + return ResultUtil.ok(result); + } +} diff --git a/src/main/java/com/lk/paopao/controller/SuggestController.java b/src/main/java/com/lk/paopao/controller/SuggestController.java new file mode 100644 index 0000000..df232fb --- /dev/null +++ b/src/main/java/com/lk/paopao/controller/SuggestController.java @@ -0,0 +1,39 @@ +package com.lk.paopao.controller; + + +import com.lk.paopao.dto.rest.response.DataResult; +import com.lk.paopao.dto.rest.response.ResultUtil; +import com.lk.paopao.service.PostService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("${app.version}/suggest") +public class SuggestController { + @Autowired + private PostService postService; + + @GetMapping("/users") + public DataResult>> suggestUsers(@RequestParam("k") String keyword){ + List names = postService.getSuggestUsers(keyword); + Map> res = new HashMap<>(); + res.put("suggest", names); + return ResultUtil.ok(res); + } + + @GetMapping("/tags") + public DataResult>> suggestTags(@RequestParam("k") String keyword){ + List tags = postService.getSuggestTags(keyword); + Map> res = new HashMap<>(); + res.put("suggest", tags); + return ResultUtil.ok(res); + } + +} diff --git a/src/main/java/com/lk/paopao/repository/PostCollectionRepository.java b/src/main/java/com/lk/paopao/repository/PostCollectionRepository.java index 708f050..4af61d1 100644 --- a/src/main/java/com/lk/paopao/repository/PostCollectionRepository.java +++ b/src/main/java/com/lk/paopao/repository/PostCollectionRepository.java @@ -3,5 +3,8 @@ package com.lk.paopao.repository; import com.lk.paopao.entity.PostCollection; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface PostCollectionRepository extends JpaRepository { + Optional findByUserIdAndPostId(Long userId, Long postId); } \ No newline at end of file diff --git a/src/main/java/com/lk/paopao/repository/PostStarRepository.java b/src/main/java/com/lk/paopao/repository/PostStarRepository.java index 38371f9..4ca88d4 100644 --- a/src/main/java/com/lk/paopao/repository/PostStarRepository.java +++ b/src/main/java/com/lk/paopao/repository/PostStarRepository.java @@ -3,5 +3,8 @@ package com.lk.paopao.repository; import com.lk.paopao.entity.PostStar; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface PostStarRepository extends JpaRepository { + Optional findByUserIdAndPostId(Long postId, Long userId); } \ No newline at end of file diff --git a/src/main/java/com/lk/paopao/repository/TagRepository.java b/src/main/java/com/lk/paopao/repository/TagRepository.java index 914a978..245fcfe 100644 --- a/src/main/java/com/lk/paopao/repository/TagRepository.java +++ b/src/main/java/com/lk/paopao/repository/TagRepository.java @@ -10,8 +10,8 @@ import java.util.Optional; public interface TagRepository extends JpaRepository { - @Query("SELECT t.tag FROM Tag t WHERE t.tag LIKE CONCAT('%', :key, '%') ORDER BY t.tag ASC limit 20") - List findByTagContainingOrderByTagAsc(@Param("key") String key); + @Query("SELECT t.tag FROM Tag t WHERE t.tag LIKE CONCAT('%', :key, '%') ORDER BY t.quoteNum DESC limit 20") + List findByTagContainingOrderByQuoteNumDesc(@Param("key") String key); Optional findByTag(String tag); diff --git a/src/main/java/com/lk/paopao/service/PostService.java b/src/main/java/com/lk/paopao/service/PostService.java new file mode 100644 index 0000000..a1b87fe --- /dev/null +++ b/src/main/java/com/lk/paopao/service/PostService.java @@ -0,0 +1,208 @@ +package com.lk.paopao.service; + +import com.lk.paopao.dto.PostDto; +import com.lk.paopao.dto.rest.request.PostRequest; +import com.lk.paopao.dto.rest.response.Paged; +import com.lk.paopao.entity.Post; +import com.lk.paopao.entity.PostContent; +import com.lk.paopao.entity.Tag; +import com.lk.paopao.entity.User; +import com.lk.paopao.exception.ResourceNotFoundException; +import com.lk.paopao.mapper.PostMapper; +import com.lk.paopao.mapper.TagMapper; +import com.lk.paopao.repository.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +import java.util.ArrayList; +import java.util.List; + +/** + * 文章服务类,提供文章相关的业务逻辑处理 + */ +@Service +@Transactional +public class PostService { + // 注入所需的仓库和Mapper类以及其他服务 + @Autowired + UserRepository userRepository; + @Autowired + PostRepository postRepository; + + @Autowired + TagRepository tagRepository; + + @Autowired + PostMapper postMapper; + @Autowired + TagMapper tagMapper; + + @Autowired + AuthService authService; + @Autowired + PostStarRepository postStarRepository; + @Autowired + PostCollectionRepository postCollectionRepository; + + private static final Logger log = LoggerFactory.getLogger(PostService.class); + /** + * 根据文章ID获取文章详情 + * @param id 文章ID + * @return 文章DTO + */ + public PostDto getPost(Long id){ + Post post = postRepository.findById(id).orElseThrow(()->new ResourceNotFoundException("Post","id="+id)); + return postMapper.toDto(post); + } + + /** + * 获取文章列表 + * @param type 文章类型 + * @param style 文章样式 + * @param page 页码 + * @param size 每页大小 + * @return 文章DTO的分页数据 + */ + public Paged getPosts(Long type, String style, Integer page, Integer size){ + size = size==null?10:size; // 如果未指定每页大小,默认为10 + + Sort sort = Sort.by(Sort.Direction.DESC, "createdOn"); // 按创建时间倒序排序 + Pageable pageable = PageRequest.of(page-1, size, sort); // 创建分页请求 + Page posts = postRepository.findAll(pageable); // 执行分页查询 + List dtos = new ArrayList<>(); // 用于存储转换后的DTO对象的列表 + posts.getContent().forEach((post)->{ + dtos.add(postMapper.toDto(post)); // 将查询结果转换为DTO + }); + return new Paged<>(dtos,posts.getTotalElements(),page,posts.getSize()); // 构建并返回分页数据 + } + + /** + * 创建文章 + * @param postRequest 创建文章的请求参数 + * @return 创建成功后的文章DTO + */ + public PostDto createPost(PostRequest postRequest){ + // 获取当前用户 + User user = authService.getCurrentUser(); + Post post = new Post(); + post.setUser(user); + // 设置附件价格,默认为0 + post.setAttachmentPrice(postRequest.getAttachmentPrice()!=null?postRequest.getAttachmentPrice():0); + // 设置文章可见性 + post.setVisibility(postRequest.getVisibility()); + // 文章内容 + List contents = new ArrayList<>(); + postRequest.getContents().forEach(contentReq -> { + PostContent content = new PostContent(); + content.setContent(contentReq.getContent()); // 设置内容 + content.setSort(contentReq.getSort()); // 设置排序 + content.setType(contentReq.getType()); // 设置类型 + content.setPost(post); // 关联文章 + content.setUser(user); // 关联用户 + contents.add(content); // 添加到列表 + }); + post.setContents(contents); + // 保存文章 + Post savedPost = postRepository.save(post); + + // 处理post中的标签 + handleTags(postRequest, user); + // 发送消息通知post中@的用户 + handleAtUser(postRequest, user); + + return postMapper.toDto(savedPost); + } + + private void handleTags(PostRequest postRequest, User currentUser){ + // 处理post中的标签 + postRequest.getTags().forEach((tag)->{ + Tag tagEntity = tagRepository.findByTag(tag).orElse(null); + if(tagEntity==null){ + // 如果标签不存在,则创建新标签并关联文章 + tagEntity = new Tag(); + tagEntity.setTag(tag); + tagEntity.setUser(currentUser); + tagEntity.setQuoteNum(1L); + tagRepository.save(tagEntity); + }else{ + // 如果标签已存在,则更新引用次数 + try { + tagEntity.setQuoteNum(tagEntity.getQuoteNum() + 1L); + tagRepository.save(tagEntity); // Spring Data JPA 自动处理乐观锁 + } catch (OptimisticLockingFailureException e) { + // 处理乐观锁失败的情况,如重新获取实体并重试或记录日志等 + log.error("Optimistic locking failed for tag: {}", tagEntity.getTag(), e); + // TODO: 可添加重试逻辑 + // 简单处理为继续抛出异常,让此次发帖失败 + throw e; + } + + } + }); + } + + private void handleAtUser(PostRequest postRequest, User currentUser){ + postRequest.getUsers().forEach((username)->{ + User toUser = userRepository.findByUsername(username).orElseThrow(()->new ResourceNotFoundException("User","username="+username)); + // TODO: 发送消息通知toUser + }); + } + + /** + * 获取用户推荐列表 + * @param keyword 关键字,用于筛选推荐用户 + * @return 符合条件的用户列表 + */ + public List getSuggestUsers(String keyword){ + // 如果关键字为空,则默认为空字符串 + keyword = keyword==null?"":keyword; + // 根据关键字查询并按用户名升序返回用户列表 + return userRepository.findByUsernameContainingOrderByUsernameAsc(keyword); + } + + /** + * 获取标签推荐列表 + * @param keyword 关键字,用于筛选推荐标签 + * @return 符合条件的标签列表 + */ + public List getSuggestTags(String keyword){ + keyword = keyword==null?"":keyword; + // 根据关键字查询并按标签名升序返回标签列表 + return tagRepository.findByTagContainingOrderByQuoteNumDesc(keyword); + } + + /** + * 封装帖子的分页数据。 + * + * @param posts 分页的帖子数据。 + * @return 返回封装好的帖子分页数据。 + */ + private Paged pageDataWrapper(Page posts){ + // 将帖子实体转换为DTO + List dtos = new ArrayList<>(); + posts.getContent().forEach((post)->{ + dtos.add(postMapper.toDto(post)); + }); + // 返回封装好的分页数据 + return new Paged<>(dtos,posts.getTotalElements(),posts.getNumber()+1,posts.getSize()); + } + + public boolean currentUserHasStarred(Long postId){ + User user = authService.getCurrentUser(); + return postStarRepository.findByUserIdAndPostId(user.getId(), postId).isPresent(); + } + + public boolean currentUserHasCollected(Long postId){ + User user = authService.getCurrentUser(); + return postCollectionRepository.findByUserIdAndPostId(user.getId(), postId).isPresent(); + } +}