This commit is contained in:
many2many 2024-05-23 10:13:12 +08:00
parent 4fcf2042b2
commit d20e9ba3e2
6 changed files with 315 additions and 2 deletions

View File

@ -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<Paged<PostDto>> 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<PostDto> getPost(@PathParam("id") Long id) {
return ResultUtil.ok(postService.getPost(id));
}
@PostMapping("/post")
public DataResult<PostDto> createPost(@RequestBody PostRequest postRequest) {
return ResultUtil.ok(postService.createPost(postRequest));
}
@GetMapping("/post/comments")
public DataResult<Paged<CommentDto>> getPostComments(@PathParam("id") Long id, @PathParam("style") String style, @PathParam("page") Integer page, @PathParam("page_size") Integer pageSize) {
Paged<CommentDto> paged = new Paged<>(new ArrayList<>(),0L,1,10);
return ResultUtil.ok(paged);
}
@GetMapping("/post/star")
public DataResult<Map<String, Boolean>> currentHasStarred(@PathParam("id") Long postId) {
Map<String, Boolean> result = new HashMap<>();
result.put("status", postService.currentUserHasStarred(postId));
return ResultUtil.ok(result);
}
@GetMapping("/post/collection")
public DataResult<Map<String, Boolean>> currentHasCollected(@PathParam("id") Long postId) {
Map<String, Boolean> result = new HashMap<>();
result.put("status", postService.currentUserHasCollected(postId));
return ResultUtil.ok(result);
}
}

View File

@ -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<Map<String,List<String>>> suggestUsers(@RequestParam("k") String keyword){
List<String> names = postService.getSuggestUsers(keyword);
Map<String,List<String>> res = new HashMap<>();
res.put("suggest", names);
return ResultUtil.ok(res);
}
@GetMapping("/tags")
public DataResult<Map<String,List<String>>> suggestTags(@RequestParam("k") String keyword){
List<String> tags = postService.getSuggestTags(keyword);
Map<String,List<String>> res = new HashMap<>();
res.put("suggest", tags);
return ResultUtil.ok(res);
}
}

View File

@ -3,5 +3,8 @@ package com.lk.paopao.repository;
import com.lk.paopao.entity.PostCollection; import com.lk.paopao.entity.PostCollection;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface PostCollectionRepository extends JpaRepository<PostCollection, Long> { public interface PostCollectionRepository extends JpaRepository<PostCollection, Long> {
Optional<PostCollection> findByUserIdAndPostId(Long userId, Long postId);
} }

View File

@ -3,5 +3,8 @@ package com.lk.paopao.repository;
import com.lk.paopao.entity.PostStar; import com.lk.paopao.entity.PostStar;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface PostStarRepository extends JpaRepository<PostStar, Long> { public interface PostStarRepository extends JpaRepository<PostStar, Long> {
Optional<PostStar> findByUserIdAndPostId(Long postId, Long userId);
} }

View File

@ -10,8 +10,8 @@ import java.util.Optional;
public interface TagRepository extends JpaRepository<Tag, Long> { public interface TagRepository extends JpaRepository<Tag, Long> {
@Query("SELECT t.tag FROM Tag t WHERE t.tag LIKE CONCAT('%', :key, '%') ORDER BY t.tag ASC limit 20") @Query("SELECT t.tag FROM Tag t WHERE t.tag LIKE CONCAT('%', :key, '%') ORDER BY t.quoteNum DESC limit 20")
List<String> findByTagContainingOrderByTagAsc(@Param("key") String key); List<String> findByTagContainingOrderByQuoteNumDesc(@Param("key") String key);
Optional<Tag> findByTag(String tag); Optional<Tag> findByTag(String tag);

View File

@ -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<PostDto> 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<Post> posts = postRepository.findAll(pageable); // 执行分页查询
List<PostDto> 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<PostContent> 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<String> getSuggestUsers(String keyword){
// 如果关键字为空则默认为空字符串
keyword = keyword==null?"":keyword;
// 根据关键字查询并按用户名升序返回用户列表
return userRepository.findByUsernameContainingOrderByUsernameAsc(keyword);
}
/**
* 获取标签推荐列表
* @param keyword 关键字用于筛选推荐标签
* @return 符合条件的标签列表
*/
public List<String> getSuggestTags(String keyword){
keyword = keyword==null?"":keyword;
// 根据关键字查询并按标签名升序返回标签列表
return tagRepository.findByTagContainingOrderByQuoteNumDesc(keyword);
}
/**
* 封装帖子的分页数据
*
* @param posts 分页的帖子数据
* @return 返回封装好的帖子分页数据
*/
private Paged<PostDto> pageDataWrapper(Page<Post> posts){
// 将帖子实体转换为DTO
List<PostDto> 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();
}
}