369 lines
16 KiB
Java
369 lines
16 KiB
Java
package com.yupi.springbootinit.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.yupi.springbootinit.common.ErrorCode;
|
|
import com.yupi.springbootinit.constant.CommonConstant;
|
|
import com.yupi.springbootinit.exception.BusinessException;
|
|
import com.yupi.springbootinit.exception.ThrowUtils;
|
|
import com.yupi.springbootinit.mapper.PostFavourMapper;
|
|
import com.yupi.springbootinit.mapper.PostMapper;
|
|
import com.yupi.springbootinit.mapper.PostThumbMapper;
|
|
import com.yupi.springbootinit.model.dto.post.PostEsDTO;
|
|
import com.yupi.springbootinit.model.dto.post.PostQueryRequest;
|
|
import com.yupi.springbootinit.model.entity.Post;
|
|
import com.yupi.springbootinit.model.entity.PostFavour;
|
|
import com.yupi.springbootinit.model.entity.PostThumb;
|
|
import com.yupi.springbootinit.model.entity.User;
|
|
import com.yupi.springbootinit.model.vo.PostVO;
|
|
import com.yupi.springbootinit.model.vo.UserVO;
|
|
import com.yupi.springbootinit.service.PostService;
|
|
import com.yupi.springbootinit.service.UserService;
|
|
import com.yupi.springbootinit.utils.SqlUtils;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.stream.Collectors;
|
|
import javax.annotation.Resource;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import cn.hutool.core.collection.CollUtil;
|
|
import org.apache.commons.lang3.ObjectUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
|
import org.elasticsearch.index.query.QueryBuilders;
|
|
import org.elasticsearch.search.sort.SortBuilder;
|
|
import org.elasticsearch.search.sort.SortBuilders;
|
|
import org.elasticsearch.search.sort.SortOrder;
|
|
import org.springframework.data.domain.PageRequest;
|
|
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
|
import org.springframework.data.elasticsearch.core.SearchHit;
|
|
import org.springframework.data.elasticsearch.core.SearchHits;
|
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
|
|
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
/**
|
|
* 帖子服务实现
|
|
*
|
|
* @author <a href="https://github.com/liyupi">程序员鱼皮</a>
|
|
* @from <a href="https://yupi.icu">编程导航知识星球</a>
|
|
*/
|
|
@Service
|
|
@Slf4j
|
|
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
|
|
|
|
@Resource
|
|
private UserService userService;
|
|
|
|
@Resource
|
|
private PostThumbMapper postThumbMapper;
|
|
|
|
@Resource
|
|
private PostFavourMapper postFavourMapper;
|
|
|
|
@Resource
|
|
private ElasticsearchRestTemplate elasticsearchRestTemplate;
|
|
|
|
|
|
/**
|
|
* 获取帖子封装列表
|
|
*
|
|
* @param postList
|
|
* @param request
|
|
* @return
|
|
*/
|
|
@Override
|
|
public List<PostVO> getPostVOList(List<Post> postList, HttpServletRequest request) {
|
|
if (CollUtil.isEmpty(postList)) {
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
// 1. 关联查询用户信息
|
|
Set<Long> userIdSet = postList.stream().map(Post::getUserId).collect(Collectors.toSet());
|
|
Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
|
|
.collect(Collectors.groupingBy(User::getId));
|
|
|
|
// 2. 已登录,获取用户点赞、收藏状态
|
|
Map<Long, Boolean> postIdHasThumbMap = new HashMap<>();
|
|
Map<Long, Boolean> postIdHasFavourMap = new HashMap<>();
|
|
User loginUser = userService.getLoginUserPermitNull(request);
|
|
if (loginUser != null) {
|
|
Set<Long> postIdSet = postList.stream().map(Post::getId).collect(Collectors.toSet());
|
|
// 获取点赞
|
|
QueryWrapper<PostThumb> postThumbQueryWrapper = new QueryWrapper<>();
|
|
postThumbQueryWrapper.in("postId", postIdSet);
|
|
postThumbQueryWrapper.eq("userId", loginUser.getId());
|
|
List<PostThumb> postPostThumbList = postThumbMapper.selectList(postThumbQueryWrapper);
|
|
postPostThumbList.forEach(postPostThumb -> postIdHasThumbMap.put(postPostThumb.getPostId(), true));
|
|
|
|
// 获取收藏
|
|
QueryWrapper<PostFavour> postFavourQueryWrapper = new QueryWrapper<>();
|
|
postFavourQueryWrapper.in("postId", postIdSet);
|
|
postFavourQueryWrapper.eq("userId", loginUser.getId());
|
|
List<PostFavour> postFavourList = postFavourMapper.selectList(postFavourQueryWrapper);
|
|
postFavourList.forEach(postFavour -> postIdHasFavourMap.put(postFavour.getPostId(), true));
|
|
}
|
|
|
|
// 3. 填充信息
|
|
return postList.stream().map(post -> {
|
|
PostVO postVO = PostVO.objToVo(post);
|
|
Long userId = post.getUserId();
|
|
User user = null;
|
|
if (userIdUserListMap.containsKey(userId)) {
|
|
user = userIdUserListMap.get(userId).get(0);
|
|
}
|
|
postVO.setUser(userService.getUserVO(user));
|
|
postVO.setHasThumb(postIdHasThumbMap.getOrDefault(post.getId(), false));
|
|
postVO.setHasFavour(postIdHasFavourMap.getOrDefault(post.getId(), false));
|
|
return postVO;
|
|
}).collect(Collectors.toList());
|
|
}
|
|
|
|
|
|
@Override
|
|
public void validPost(Post post, boolean add) {
|
|
if (post == null) {
|
|
throw new BusinessException(ErrorCode.PARAMS_ERROR);
|
|
}
|
|
String title = post.getTitle();
|
|
String content = post.getContent();
|
|
String tags = post.getTags();
|
|
// 创建时,参数不能为空
|
|
if (add) {
|
|
ThrowUtils.throwIf(StringUtils.isAnyBlank(title, content, tags), ErrorCode.PARAMS_ERROR);
|
|
}
|
|
// 有参数则校验
|
|
if (StringUtils.isNotBlank(title) && title.length() > 80) {
|
|
throw new BusinessException(ErrorCode.PARAMS_ERROR, "标题过长");
|
|
}
|
|
if (StringUtils.isNotBlank(content) && content.length() > 8192) {
|
|
throw new BusinessException(ErrorCode.PARAMS_ERROR, "内容过长");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取查询包装类
|
|
*
|
|
* @param postQueryRequest
|
|
* @return
|
|
*/
|
|
@Override
|
|
public QueryWrapper<Post> getQueryWrapper(PostQueryRequest postQueryRequest) {
|
|
QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
|
|
if (postQueryRequest == null) {
|
|
return queryWrapper;
|
|
}
|
|
String searchText = postQueryRequest.getSearchText();
|
|
String sortField = postQueryRequest.getSortField();
|
|
String sortOrder = postQueryRequest.getSortOrder();
|
|
Long id = postQueryRequest.getId();
|
|
String title = postQueryRequest.getTitle();
|
|
String content = postQueryRequest.getContent();
|
|
List<String> tagList = postQueryRequest.getTags();
|
|
Long userId = postQueryRequest.getUserId();
|
|
Long notId = postQueryRequest.getNotId();
|
|
// 拼接查询条件
|
|
if (StringUtils.isNotBlank(searchText)) {
|
|
queryWrapper.and(qw -> qw.like("title", searchText).or().like("content", searchText));
|
|
}
|
|
queryWrapper.like(StringUtils.isNotBlank(title), "title", title);
|
|
queryWrapper.like(StringUtils.isNotBlank(content), "content", content);
|
|
if (CollUtil.isNotEmpty(tagList)) {
|
|
for (String tag : tagList) {
|
|
queryWrapper.like("tags", "\"" + tag + "\"");
|
|
}
|
|
}
|
|
queryWrapper.ne(ObjectUtils.isNotEmpty(notId), "id", notId);
|
|
queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
|
|
queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
|
|
queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
|
|
sortField);
|
|
return queryWrapper;
|
|
}
|
|
|
|
@Override
|
|
public Page<Post> searchFromEs(PostQueryRequest postQueryRequest) {
|
|
Long id = postQueryRequest.getId();
|
|
Long notId = postQueryRequest.getNotId();
|
|
String searchText = postQueryRequest.getSearchText();
|
|
String title = postQueryRequest.getTitle();
|
|
String content = postQueryRequest.getContent();
|
|
List<String> tagList = postQueryRequest.getTags();
|
|
List<String> orTagList = postQueryRequest.getOrTags();
|
|
Long userId = postQueryRequest.getUserId();
|
|
// es 起始页为 0
|
|
long current = postQueryRequest.getCurrent() - 1;
|
|
long pageSize = postQueryRequest.getPageSize();
|
|
String sortField = postQueryRequest.getSortField();
|
|
String sortOrder = postQueryRequest.getSortOrder();
|
|
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
|
// 过滤
|
|
boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete", 0));
|
|
if (id != null) {
|
|
boolQueryBuilder.filter(QueryBuilders.termQuery("id", id));
|
|
}
|
|
if (notId != null) {
|
|
boolQueryBuilder.mustNot(QueryBuilders.termQuery("id", notId));
|
|
}
|
|
if (userId != null) {
|
|
boolQueryBuilder.filter(QueryBuilders.termQuery("userId", userId));
|
|
}
|
|
// 必须包含所有标签
|
|
if (CollUtil.isNotEmpty(tagList)) {
|
|
for (String tag : tagList) {
|
|
boolQueryBuilder.filter(QueryBuilders.termQuery("tags", tag));
|
|
}
|
|
}
|
|
// 包含任何一个标签即可
|
|
if (CollUtil.isNotEmpty(orTagList)) {
|
|
BoolQueryBuilder orTagBoolQueryBuilder = QueryBuilders.boolQuery();
|
|
for (String tag : orTagList) {
|
|
orTagBoolQueryBuilder.should(QueryBuilders.termQuery("tags", tag));
|
|
}
|
|
orTagBoolQueryBuilder.minimumShouldMatch(1);
|
|
boolQueryBuilder.filter(orTagBoolQueryBuilder);
|
|
}
|
|
// 按关键词检索
|
|
if (StringUtils.isNotBlank(searchText)) {
|
|
boolQueryBuilder.should(QueryBuilders.matchQuery("title", searchText));
|
|
boolQueryBuilder.should(QueryBuilders.matchQuery("description", searchText));
|
|
boolQueryBuilder.should(QueryBuilders.matchQuery("content", searchText));
|
|
boolQueryBuilder.minimumShouldMatch(1);
|
|
}
|
|
// 按标题检索
|
|
if (StringUtils.isNotBlank(title)) {
|
|
boolQueryBuilder.should(QueryBuilders.matchQuery("title", title));
|
|
boolQueryBuilder.minimumShouldMatch(1);
|
|
}
|
|
// 按内容检索
|
|
if (StringUtils.isNotBlank(content)) {
|
|
boolQueryBuilder.should(QueryBuilders.matchQuery("content", content));
|
|
boolQueryBuilder.minimumShouldMatch(1);
|
|
}
|
|
// 排序
|
|
SortBuilder<?> sortBuilder = SortBuilders.scoreSort();
|
|
if (StringUtils.isNotBlank(sortField)) {
|
|
sortBuilder = SortBuilders.fieldSort(sortField);
|
|
sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC : SortOrder.DESC);
|
|
}
|
|
// 分页
|
|
PageRequest pageRequest = PageRequest.of((int) current, (int) pageSize);
|
|
// 构造查询
|
|
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
|
|
.withPageable(pageRequest).withSorts(sortBuilder).build();
|
|
SearchHits<PostEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);
|
|
Page<Post> page = new Page<>();
|
|
page.setTotal(searchHits.getTotalHits());
|
|
List<Post> resourceList = new ArrayList<>();
|
|
// 查出结果后,从 db 获取最新动态数据(比如点赞数)
|
|
if (searchHits.hasSearchHits()) {
|
|
List<SearchHit<PostEsDTO>> searchHitList = searchHits.getSearchHits();
|
|
List<Long> postIdList = searchHitList.stream().map(searchHit -> searchHit.getContent().getId())
|
|
.collect(Collectors.toList());
|
|
List<Post> postList = baseMapper.selectBatchIds(postIdList);
|
|
if (postList != null) {
|
|
Map<Long, List<Post>> idPostMap = postList.stream().collect(Collectors.groupingBy(Post::getId));
|
|
postIdList.forEach(postId -> {
|
|
if (idPostMap.containsKey(postId)) {
|
|
resourceList.add(idPostMap.get(postId).get(0));
|
|
} else {
|
|
// 从 es 清空 db 已物理删除的数据
|
|
String delete = elasticsearchRestTemplate.delete(String.valueOf(postId), PostEsDTO.class);
|
|
log.info("delete post {}", delete);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
page.setRecords(resourceList);
|
|
return page;
|
|
}
|
|
|
|
@Override
|
|
public PostVO getPostVO(Post post, HttpServletRequest request) {
|
|
PostVO postVO = PostVO.objToVo(post);
|
|
long postId = post.getId();
|
|
// 1. 关联查询用户信息
|
|
Long userId = post.getUserId();
|
|
User user = null;
|
|
if (userId != null && userId > 0) {
|
|
user = userService.getById(userId);
|
|
}
|
|
UserVO userVO = userService.getUserVO(user);
|
|
postVO.setUser(userVO);
|
|
// 2. 已登录,获取用户点赞、收藏状态
|
|
User loginUser = userService.getLoginUserPermitNull(request);
|
|
if (loginUser != null) {
|
|
// 获取点赞
|
|
QueryWrapper<PostThumb> postThumbQueryWrapper = new QueryWrapper<>();
|
|
postThumbQueryWrapper.in("postId", postId);
|
|
postThumbQueryWrapper.eq("userId", loginUser.getId());
|
|
PostThumb postThumb = postThumbMapper.selectOne(postThumbQueryWrapper);
|
|
postVO.setHasThumb(postThumb != null);
|
|
// 获取收藏
|
|
QueryWrapper<PostFavour> postFavourQueryWrapper = new QueryWrapper<>();
|
|
postFavourQueryWrapper.in("postId", postId);
|
|
postFavourQueryWrapper.eq("userId", loginUser.getId());
|
|
PostFavour postFavour = postFavourMapper.selectOne(postFavourQueryWrapper);
|
|
postVO.setHasFavour(postFavour != null);
|
|
}
|
|
return postVO;
|
|
}
|
|
|
|
@Override
|
|
public Page<PostVO> getPostVOPage(Page<Post> postPage, HttpServletRequest request) {
|
|
List<Post> postList = postPage.getRecords();
|
|
Page<PostVO> postVOPage = new Page<>(postPage.getCurrent(), postPage.getSize(), postPage.getTotal());
|
|
if (CollUtil.isEmpty(postList)) {
|
|
return postVOPage;
|
|
}
|
|
// 1. 关联查询用户信息
|
|
Set<Long> userIdSet = postList.stream().map(Post::getUserId).collect(Collectors.toSet());
|
|
Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
|
|
.collect(Collectors.groupingBy(User::getId));
|
|
// 2. 已登录,获取用户点赞、收藏状态
|
|
Map<Long, Boolean> postIdHasThumbMap = new HashMap<>();
|
|
Map<Long, Boolean> postIdHasFavourMap = new HashMap<>();
|
|
User loginUser = userService.getLoginUserPermitNull(request);
|
|
if (loginUser != null) {
|
|
Set<Long> postIdSet = postList.stream().map(Post::getId).collect(Collectors.toSet());
|
|
loginUser = userService.getLoginUser(request);
|
|
// 获取点赞
|
|
QueryWrapper<PostThumb> postThumbQueryWrapper = new QueryWrapper<>();
|
|
postThumbQueryWrapper.in("postId", postIdSet);
|
|
postThumbQueryWrapper.eq("userId", loginUser.getId());
|
|
List<PostThumb> postPostThumbList = postThumbMapper.selectList(postThumbQueryWrapper);
|
|
postPostThumbList.forEach(postPostThumb -> postIdHasThumbMap.put(postPostThumb.getPostId(), true));
|
|
// 获取收藏
|
|
QueryWrapper<PostFavour> postFavourQueryWrapper = new QueryWrapper<>();
|
|
postFavourQueryWrapper.in("postId", postIdSet);
|
|
postFavourQueryWrapper.eq("userId", loginUser.getId());
|
|
List<PostFavour> postFavourList = postFavourMapper.selectList(postFavourQueryWrapper);
|
|
postFavourList.forEach(postFavour -> postIdHasFavourMap.put(postFavour.getPostId(), true));
|
|
}
|
|
// 填充信息
|
|
List<PostVO> postVOList = postList.stream().map(post -> {
|
|
PostVO postVO = PostVO.objToVo(post);
|
|
Long userId = post.getUserId();
|
|
User user = null;
|
|
if (userIdUserListMap.containsKey(userId)) {
|
|
user = userIdUserListMap.get(userId).get(0);
|
|
}
|
|
postVO.setUser(userService.getUserVO(user));
|
|
postVO.setHasThumb(postIdHasThumbMap.getOrDefault(post.getId(), false));
|
|
postVO.setHasFavour(postIdHasFavourMap.getOrDefault(post.getId(), false));
|
|
return postVO;
|
|
}).collect(Collectors.toList());
|
|
postVOPage.setRecords(postVOList);
|
|
return postVOPage;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|