package com.minzheng.blog.service.impl;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.minzheng.blog.dao.ArticleDao;
import com.minzheng.blog.dao.ArticleTagDao;
import com.minzheng.blog.dao.CategoryDao;
import com.minzheng.blog.dao.TagDao;
import com.minzheng.blog.dto.*;
import com.minzheng.blog.entity.Article;
import com.minzheng.blog.entity.ArticleTag;
import com.minzheng.blog.entity.Category;
import com.minzheng.blog.entity.Tag;
import com.minzheng.blog.enums.FileExtEnum;
import com.minzheng.blog.enums.FilePathEnum;
import com.minzheng.blog.exception.BizException;
import com.minzheng.blog.service.*;
import com.minzheng.blog.strategy.context.SearchStrategyContext;
import com.minzheng.blog.strategy.context.UploadStrategyContext;
import com.minzheng.blog.util.BeanCopyUtils;
import com.minzheng.blog.util.CommonUtils;
import com.minzheng.blog.util.PageUtils;
import com.minzheng.blog.util.UserUtils;
import com.minzheng.blog.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import static com.minzheng.blog.constant.CommonConst.ARTICLE_SET;
import static com.minzheng.blog.constant.CommonConst.FALSE;
import static com.minzheng.blog.constant.RedisPrefixConst.*;
import static com.minzheng.blog.enums.ArticleStatusEnum.DRAFT;
import static com.minzheng.blog.enums.ArticleStatusEnum.PUBLIC;
/**
* 文章服务
*
* @author yezhiqiu
* @date 2021/08/10
*/
@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleDao, Article> implements ArticleService {
@Autowired
private ArticleDao articleDao;
@Autowired
private CategoryDao categoryDao;
@Autowired
private TagDao tagDao;
@Autowired
private TagService tagService;
@Autowired
private ArticleTagDao articleTagDao;
@Autowired
private SearchStrategyContext searchStrategyContext;
@Autowired
private HttpSession session;
@Autowired
private RedisService redisService;
@Autowired
private ArticleTagService articleTagService;
@Autowired
private BlogInfoService blogInfoService;
@Autowired
private UploadStrategyContext uploadStrategyContext;
@Override
public PageResult<ArchiveDTO> listArchives() {
Page<Article> page = new Page<>(PageUtils.getCurrent(), PageUtils.getSize());
// 获取分页数据
Page<Article> articlePage = articleDao.selectPage(page, new LambdaQueryWrapper<Article>()
.select(Article::getId, Article::getArticleTitle, Article::getCreateTime).orderByDesc(Article::getCreateTime)
.eq(Article::getIsDelete, FALSE)
.eq(Article::getStatus, PUBLIC.getStatus()));
List<ArchiveDTO> archiveDTOList = BeanCopyUtils.copyList(articlePage.getRecords(), ArchiveDTO.class);
return new PageResult<>(archiveDTOList, (int) articlePage.getTotal());
}
@Override
public PageResult<ArticleBackDTO> listArticleBacks(ConditionVO condition) {
// 查询文章总量
Integer count = articleDao.countArticleBacks(condition);
if (count == 0) {
return new PageResult<>();
}
// 查询后台文章
List<ArticleBackDTO> articleBackDTOList = articleDao.listArticleBacks(PageUtils.getLimitCurrent(), PageUtils.getSize(), condition);
// 查询文章点赞量和浏览量
Map<Object, Double> viewsCountMap = redisService.zAllScore(ARTICLE_VIEWS_COUNT);
Map<String, Object> likeCountMap = redisService.hGetAll(ARTICLE_LIKE_COUNT);
// 封装点赞量和浏览量
articleBackDTOList.forEach(item -> {
Double viewsCount = viewsCountMap.get(item.getId());
if (Objects.nonNull(viewsCount)) {
item.setViewsCount(viewsCount.intValue());
}
item.setLikeCount((Integer) likeCountMap.get(item.getId().toString()));
});
return new PageResult<>(articleBackDTOList, count);
}
@Override
public List<ArticleHomeDTO> listArticles() {
return articleDao.listArticles(PageUtils.getLimitCurrent(), PageUtils.getSize());
}
@Override
public ArticlePreviewListDTO listArticlesByCondition(ConditionVO condition) {
// 查询文章
List<ArticlePreviewDTO> articlePreviewDTOList = articleDao.listArticlesByCondition(PageUtils.getLimitCurrent(), PageUtils.getSize(), condition);
// 搜索条件对应名(标签或分类名)
String name;
if (Objects.nonNull(condition.getCategoryId())) {
name = categoryDao.selectOne(new LambdaQueryWrapper<Category>().select(Category::getCategoryName)
.eq(Category::getId, condition.getCategoryId())).getCategoryName();
} else {
name = tagService.getOne(new LambdaQueryWrapper<Tag>()
.select(Tag::getTagName).eq(Tag::getId, condition.getTagId())).getTagName();
}
return ArticlePreviewListDTO.builder().articlePreviewDTOList(articlePreviewDTOList).name(name).build();
}
@Override
public ArticleDTO getArticleById(Integer articleId) {
// 查询推荐文章
CompletableFuture<List<ArticleRecommendDTO>> recommendArticleList = CompletableFuture.supplyAsync(() -> articleDao.listRecommendArticles(articleId));
// 查询最新文章
CompletableFuture<List<ArticleRecommendDTO>> newestArticleList = CompletableFuture.supplyAsync(() -> {
List<Article> articleList = articleDao.selectList(new LambdaQueryWrapper<Article>()
.select(Article::getId, Article::getArticleTitle, Article::getArticleCover, Article::getCreateTime).eq(Article::getIsDelete, FALSE)
.eq(Article::getStatus, PUBLIC.getStatus()).orderByDesc(Article::getId).last("limit 5"));
return BeanCopyUtils.copyList(articleList, ArticleRecommendDTO.class);
});
// 查询id对应文章
ArticleDTO article = articleDao.getArticleById(articleId);
if (Objects.isNull(article)) {
throw new BizException("文章不存在");
}
// 更新文章浏览量
updateArticleViewsCount(articleId);
// 查询上一篇下一篇文章
Article lastArticle = articleDao.selectOne(new LambdaQueryWrapper<Article>()
.select(Article::getId, Article::getArticleTitle, Article::getArticleCover).eq(Article::getIsDelete, FALSE)
.eq(Article::getStatus, PUBLIC.getStatus())
.lt(Article::getId, articleId)
.orderByDesc(Article::getId).last("limit 1"));
Article nextArticle = articleDao.selectOne(new LambdaQueryWrapper<Article>()
.select(Article::getId, Article::getArticleTitle, Article::getArticleCover).eq(Article::getIsDelete, FALSE)
.eq(Article::getStatus, PUBLIC.getStatus())
.gt(Article::getId, articleId).orderByAsc(Article::getId)
.last("limit 1"));
article.setLastArticle(BeanCopyUtils.copyObject(lastArticle, ArticlePaginationDTO.class));
article.setNextArticle(BeanCopyUtils.copyObject(nextArticle, ArticlePaginationDTO.class));
// 封装点赞量和浏览量
Double score = redisService.zScore(ARTICLE_VIEWS_COUNT, articleId);
if (Objects.nonNull(score)) {
article.setViewsCount(score.intValue());
}
arti