ThemeManager.java 26.8 KB
Newer Older
刘基明's avatar
刘基明 committed
1 2
package com.tanpu.community.manager;

张辰's avatar
张辰 committed
3
import com.fasterxml.jackson.core.type.TypeReference;
刘基明's avatar
刘基明 committed
4
import com.google.common.collect.Sets;
张辰's avatar
张辰 committed
5 6 7
import com.tanpu.biz.common.enums.RelTypeEnum;
import com.tanpu.biz.common.enums.community.CollectionTypeEnum;
import com.tanpu.biz.common.enums.community.ReportTypeEnum;
刘基明's avatar
刘基明 committed
8
import com.tanpu.common.api.CommonResp;
刘基明's avatar
刘基明 committed
9
import com.tanpu.common.constant.ErrorCodeConstant;
刘基明's avatar
刘基明 committed
10
import com.tanpu.common.exception.BizException;
刘基明's avatar
刘基明 committed
11
import com.tanpu.common.util.JsonUtil;
12 13 14 15
import com.tanpu.community.api.beans.qo.ESThemeQo;
import com.tanpu.community.api.beans.qo.FormerThemeQo;
import com.tanpu.community.api.beans.qo.ThemeContentQo;
import com.tanpu.community.api.beans.qo.ThemeQo;
刘基明's avatar
刘基明 committed
16
import com.tanpu.community.api.beans.req.homepage.QueryRecordThemeReq;
刘基明's avatar
刘基明 committed
17
import com.tanpu.community.api.beans.req.theme.*;
刘基明's avatar
刘基明 committed
18
import com.tanpu.community.api.beans.resp.CreateThemeResp;
张辰's avatar
张辰 committed
19
import com.tanpu.community.api.beans.resp.ThemeFullSearchResp;
20
import com.tanpu.community.api.beans.resp.ThemeListResp;
21
import com.tanpu.community.api.beans.vo.feign.fatools.UserInfoResp;
刘基明's avatar
刘基明 committed
22 23 24 25
import com.tanpu.community.api.enums.BlockTypeEnum;
import com.tanpu.community.api.enums.OperationTypeEnum;
import com.tanpu.community.api.enums.ThemeListTypeEnum;
import com.tanpu.community.api.enums.ThemeTypeEnum;
张辰's avatar
张辰 committed
26
import com.tanpu.community.cache.RedisCache;
刘基明's avatar
刘基明 committed
27
import com.tanpu.community.dao.entity.community.*;
刘基明's avatar
刘基明 committed
28
import com.tanpu.community.feign.fatools.FeignClientForFatools;
刘基明's avatar
刘基明 committed
29
import com.tanpu.community.service.*;
张辰's avatar
张辰 committed
30
import com.tanpu.community.service.base.ESService;
张辰's avatar
张辰 committed
31
import com.tanpu.community.util.BizUtils;
32
import com.tanpu.community.util.ConvertUtil;
刘基明's avatar
刘基明 committed
33
import com.tanpu.community.util.RankUtils;
刘基明's avatar
刘基明 committed
34
import com.tanpu.community.util.TencentcloudUtils;
张辰's avatar
张辰 committed
35
import lombok.extern.slf4j.Slf4j;
刘基明's avatar
刘基明 committed
36
import org.apache.commons.collections4.CollectionUtils;
张辰's avatar
张辰 committed
37
import org.apache.commons.collections4.ListUtils;
刘基明's avatar
刘基明 committed
38
import org.apache.commons.lang3.StringUtils;
张辰's avatar
张辰 committed
39
import org.apache.commons.lang3.exception.ExceptionUtils;
刘基明's avatar
刘基明 committed
40
import org.springframework.beans.BeanUtils;
刘基明's avatar
刘基明 committed
41 42
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
刘基明's avatar
刘基明 committed
43
import org.springframework.transaction.annotation.Transactional;
刘基明's avatar
刘基明 committed
44

刘基明's avatar
刘基明 committed
45
import javax.annotation.Resource;
刘基明's avatar
刘基明 committed
46 47
import java.util.*;
import java.util.stream.Collectors;
刘基明's avatar
刘基明 committed
48

49
import static com.tanpu.community.api.constants.RedisKeyConstant.*;
张辰's avatar
张辰 committed
50

张辰's avatar
张辰 committed
51
@Slf4j
刘基明's avatar
刘基明 committed
52 53
@Service
public class ThemeManager {
刘基明's avatar
刘基明 committed
54
    @Resource
刘基明's avatar
刘基明 committed
55
    private ThemeService themeService;
刘基明's avatar
刘基明 committed
56 57 58 59 60 61 62 63

    @Autowired
    private CollectionService collectionService;

    @Autowired
    private CommentService commentService;

    @Autowired
刘基明's avatar
刘基明 committed
64
    private FollowRelService followRelService;
刘基明's avatar
刘基明 committed
65

刘基明's avatar
刘基明 committed
66 67 68
    @Autowired
    private BlackListService blackListService;

刘基明's avatar
刘基明 committed
69 70 71
    @Autowired
    private ThemeAttachmentService themeAttachmentService;

刘基明's avatar
刘基明 committed
72
    @Resource
刘基明's avatar
刘基明 committed
73
    private BatchFeignCallService batchFeignCallService;
刘基明's avatar
刘基明 committed
74

刘基明's avatar
刘基明 committed
75
    @Autowired
刘基明's avatar
刘基明 committed
76
    private VisitLogService visitLogService;
刘基明's avatar
刘基明 committed
77

78 79 80
    @Autowired
    private ReportLogService reportLogService;

刘基明's avatar
刘基明 committed
81 82 83
    @Autowired
    private RankService rankService;

张辰's avatar
张辰 committed
84 85 86
    @Autowired
    private ESService esService;

刘基明's avatar
刘基明 committed
87 88 89
    @Autowired
    private FeignClientForFatools feignClientForFatools;

张辰's avatar
张辰 committed
90 91 92
    @Autowired
    private RedisCache redisCache;

93 94 95
    @Autowired
    private RecommendService recommendService;

张辰's avatar
张辰 committed
96 97 98 99
    public ThemeFullSearchResp themeFullSearch(String keyword, Integer pageNo, Integer pageSize, String ident, String userId) {
        List<String> excludeIds;
        if (pageNo > 1) {
            String l = redisCache.get("themeFullSearch_" + ident);
张辰's avatar
张辰 committed
100 101
            excludeIds = StringUtils.isBlank(l) ? new ArrayList<>() : JsonUtil.toBean(l, new TypeReference<List<String>>() {
            });
张辰's avatar
张辰 committed
102 103 104 105
        } else {
            excludeIds = new ArrayList<>();
        }

张辰's avatar
张辰 committed
106
        Integer from = (pageNo - 1) * pageSize;
张辰's avatar
张辰 committed
107
        ThemeFullSearchResp resp = new ThemeFullSearchResp();
张辰's avatar
张辰 committed
108

109 110
        String[] keywords = StringUtils.split(keyword, " ");

张辰's avatar
张辰 committed
111
        // 按时间倒叙查询
112
        List<ESThemeQo> esIds = esService.queryThemeIdByContentAndTitle(keywords, from, pageSize * 5);
张辰's avatar
张辰 committed
113 114
        if (esIds.isEmpty()) {
            return resp;
张辰's avatar
张辰 committed
115 116
        }

张辰's avatar
张辰 committed
117 118 119 120 121 122
        // 排除已经展示过的id
        List<String> filterEsIds = esIds.stream().map(ESThemeQo::getThemeId).filter(tId -> {
            return !excludeIds.contains(tId);
        }).limit(pageSize).collect(Collectors.toList());

        resp.themes = convertEntityToQo(themeService.queryByThemeIds(filterEsIds), userId);
张辰's avatar
张辰 committed
123 124 125 126 127 128
        resp.themes.sort(new Comparator<ThemeQo>() {
            @Override
            public int compare(ThemeQo o1, ThemeQo o2) {
                return o2.createTime.compareTo(o1.createTime);
            }
        });
129 130
        // 截取关键词出现的那一部分段落
        for (ThemeQo theme : resp.themes) {
131
            theme.briefContent4FullSearch = BizUtils.getThemeContent(keywords, theme);
132
        }
张辰's avatar
张辰 committed
133 134

        excludeIds.addAll(resp.themes.stream().map(ThemeQo::getThemeId).collect(Collectors.toList()));
张辰's avatar
张辰 committed
135
        redisCache.put("themeFullSearch_" + ident, excludeIds, 60 * 60 * 6);
张辰's avatar
张辰 committed
136 137

        return resp;
张辰's avatar
张辰 committed
138
    }
刘基明's avatar
刘基明 committed
139

张辰's avatar
张辰 committed
140

刘基明's avatar
刘基明 committed
141
    /**
142
     * 发表主题(修改)
刘基明's avatar
刘基明 committed
143
     */
张辰's avatar
张辰 committed
144
    @Transactional
刘基明's avatar
刘基明 committed
145
    public CreateThemeResp publishTheme(CreateThemeReq req, String userId) {
刘基明's avatar
刘基明 committed
146
        // 保存主题表
刘基明's avatar
刘基明 committed
147
        ThemeEntity themeEntity = new ThemeEntity();
刘基明's avatar
刘基明 committed
148
        BeanUtils.copyProperties(req, themeEntity);
刘基明's avatar
刘基明 committed
149
        themeEntity.setAuthorId(userId);
刘基明's avatar
刘基明 committed
150
        // 腾讯云敏感词校验
刘基明's avatar
刘基明 committed
151 152
        checkContent(req);
        themeEntity.setContent(JsonUtil.toJson(req.getContent()));
刘基明's avatar
刘基明 committed
153

刘基明's avatar
刘基明 committed
154 155 156
        //附件校验
        checkAttachment(req.getContent());

刘基明's avatar
刘基明 committed
157
        if (StringUtils.isEmpty(req.getEditThemeId())) {
刘基明's avatar
刘基明 committed
158
            // 新建
刘基明's avatar
刘基明 committed
159
            themeService.insertTheme(themeEntity);
刘基明's avatar
刘基明 committed
160
        } else {
刘基明's avatar
刘基明 committed
161
            // 修改
刘基明's avatar
刘基明 committed
162
            themeService.update(themeEntity, req.getEditThemeId());
刘基明's avatar
刘基明 committed
163
            themeEntity.setThemeId(req.getEditThemeId());
刘基明's avatar
刘基明 committed
164
        }
刘基明's avatar
刘基明 committed
165
        // 保存附件表
刘基明's avatar
刘基明 committed
166
        List<ThemeAttachmentEntity> themeAttachments = ConvertUtil.themeReqToAttachmentList(req, themeEntity.getThemeId());
刘基明's avatar
刘基明 committed
167
        if (StringUtils.isNotEmpty(req.getEditThemeId())) {
刘基明's avatar
刘基明 committed
168
            // 修改需要刪除
刘基明's avatar
刘基明 committed
169
            themeAttachmentService.deleteByThemeId(req.getEditThemeId());
刘基明's avatar
刘基明 committed
170
        }
刘基明's avatar
刘基明 committed
171
        themeAttachmentService.insertList(themeAttachments);
刘基明's avatar
刘基明 committed
172

张辰's avatar
张辰 committed
173 174 175 176 177
        try {
            esService.insertOrUpdateTheme(ConvertUtil.convert(themeEntity));
        } catch (Exception e) {
            log.error("error in save theme to ES. themeId:{}, error:{}", themeEntity.getThemeId(), ExceptionUtils.getStackTrace(e));
        }
刘基明's avatar
刘基明 committed
178

张辰's avatar
张辰 committed
179 180
        redisCache.evict(StringUtils.joinWith("_", CACHE_THEME_ID, themeEntity.getThemeId()));

刘基明's avatar
刘基明 committed
181
        return CreateThemeResp.builder().themeId(themeEntity.getThemeId()).build();
刘基明's avatar
刘基明 committed
182
    }
刘基明's avatar
刘基明 committed
183

刘基明's avatar
刘基明 committed
184 185
    /**
     * 参数校验
刘基明's avatar
刘基明 committed
186
     *
刘基明's avatar
刘基明 committed
187 188
     * @param themeAttachments
     */
刘基明's avatar
刘基明 committed
189
    private void checkAttachment(List<ThemeContentReq> themeAttachments) {
刘基明's avatar
刘基明 committed
190
        for (ThemeContentReq content : themeAttachments) {
刘基明's avatar
刘基明 committed
191
            if (content.getType() == null) {
刘基明's avatar
刘基明 committed
192 193
                throw new IllegalArgumentException("主题内容ThemeContentReq缺少类型");
            }
刘基明's avatar
刘基明 committed
194 195
            if (content.getType().equals(RelTypeEnum.FUND.type)) {
                if (content.getProductType() == null) {
刘基明's avatar
刘基明 committed
196 197 198 199 200 201
                    throw new IllegalArgumentException("附件产品FUND缺少类型");
                }
            }
        }
    }

刘基明's avatar
刘基明 committed
202
    // 转发主题
刘基明's avatar
刘基明 committed
203 204 205 206 207 208 209 210 211
    public CreateThemeResp forward(ForwardThemeReq req, String userId) {
        ThemeEntity targetTheme = themeService.queryByThemeId(req.getFormerThemeId());
        ThemeEntity themeEntity = ThemeEntity.builder()
                .content(JsonUtil.toJson(req.getContent()))
                .topicId(req.getTopicId())
                .formerThemeId(req.getFormerThemeId())
                .authorId(userId)
                .themeType(ThemeTypeEnum.FORWARD.getCode())
                .build();
刘基明's avatar
刘基明 committed
212

张辰's avatar
张辰 committed
213
        if (StringUtils.isEmpty(req.getEditThemeId()) || req.getEditThemeId().equals(req.getFormerThemeId())) {
刘基明's avatar
刘基明 committed
214
            // 新建
刘基明's avatar
刘基明 committed
215 216
            themeService.insertTheme(themeEntity);
        } else {
刘基明's avatar
刘基明 committed
217
            // 修改
刘基明's avatar
刘基明 committed
218 219 220
            themeService.update(themeEntity, req.getEditThemeId());
            themeEntity.setThemeId(req.getEditThemeId());
        }
刘基明's avatar
刘基明 committed
221 222 223 224 225 226 227

        try {
            esService.insertOrUpdateTheme(ConvertUtil.convert(themeEntity));
        } catch (Exception e) {
            log.error("error in save theme to ES. themeId:{}, error:{}", themeEntity.getThemeId(), ExceptionUtils.getStackTrace(e));
        }

刘基明's avatar
刘基明 committed
228 229 230 231
        return CreateThemeResp.builder().themeId(themeEntity.getThemeId()).build();
    }


232 233 234
    /**
     * 推荐:由最热,最新和python推荐三个部分组成,比例为6,3,1
     */
刘基明's avatar
刘基明 committed
235
    // 查询主题列表:推荐/关注/热门/最新
刘基明's avatar
刘基明 committed
236
    public ThemeListResp queryList(ThemeListReq req, String userId) {
张辰's avatar
张辰 committed
237 238 239
        List<String> excludeIds;
        if (req.page.pageNumber > 1) {
            String l = redisCache.get("queryThemes_" + req.ident);
张辰's avatar
张辰 committed
240 241
            excludeIds = StringUtils.isBlank(l) ? new ArrayList<>() : JsonUtil.toBean(l, new TypeReference<List<String>>() {
            });
张辰's avatar
张辰 committed
242 243 244 245
        } else {
            excludeIds = new ArrayList<>();
        }

张辰's avatar
张辰 committed
246
        Integer pageStart = (req.page.pageNumber - 1) * req.page.pageSize;
刘基明's avatar
刘基明 committed
247
        Integer pageSize = req.page.pageSize;
248 249

        List<ThemeEntity> themes = new ArrayList<>();
张辰's avatar
张辰 committed
250

刘基明's avatar
刘基明 committed
251
        if (ThemeListTypeEnum.RECOMMEND.getCode().equals(req.getType())) {
刘基明's avatar
刘基明 committed
252
            // 推荐
张辰's avatar
张辰 committed
253
            // 需要筛掉用户访问过详情的 & 最近出现在列表页过的.
刘基明's avatar
刘基明 committed
254
            List<String> visitedIds = visitLogService.queryUserRecentVisited(userId);
张辰's avatar
张辰 committed
255
            List<String> excludes = ListUtils.union(excludeIds, visitedIds);
刘基明's avatar
刘基明 committed
256
            List<String> recmdIds = recommendService.getRecommendThemes(pageStart, pageSize, userId, excludes);
张辰's avatar
张辰 committed
257

258
            themes = themeService.queryByThemeIds(recmdIds);
刘基明's avatar
刘基明 committed
259 260 261
            themes = RankUtils.sortThemeEntityByIds(themes, recmdIds).stream().limit(pageSize).collect(Collectors.toList());


刘基明's avatar
刘基明 committed
262
        } else if (ThemeListTypeEnum.FOLLOW.getCode().equals(req.getType())) {
张辰's avatar
张辰 committed
263
            // 根据关注列表查询,按时间倒序
刘基明's avatar
刘基明 committed
264
            List<String> fansList = followRelService.queryIdolsByFollowerId(userId);
张辰's avatar
张辰 committed
265 266
            themes = themeService.queryByUserIdsCreateDesc(fansList, pageStart, pageSize);

张辰's avatar
张辰 committed
267 268 269 270 271 272 273
            if (CollectionUtils.isEmpty(excludeIds) && !themes.isEmpty()) {
                // 说明是从头开始刷,则直接把最新的lastId放到redis中,保留一个月
                Long lastId = themes.stream().map(ThemeEntity::getId).max(Long::compareTo).get();
                redisCache.put(CACHE_IDOL_THEME_LAST_ID + userId, lastId, 60 * 60 * 24 * 7 * 4);
//                visitLogService.addPageView(userId, userId, VisitTypeEnum.FOLLOW_THEME_VIEW);
            }

刘基明's avatar
刘基明 committed
274
        } else if (ThemeListTypeEnum.TOPIC_HOT.getCode().equals(req.getType())) {
张辰's avatar
张辰 committed
275
            // 根据话题查询热门
276 277 278
            if (StringUtils.isEmpty(req.getTopicId())) {
                throw new BizException("TopicId为空");
            }
279

张辰's avatar
张辰 committed
280
            List<String> rankThemeIds = rankService.getRankThemeListByTopic(req.getTopicId(), excludeIds);
张辰's avatar
张辰 committed
281
            rankThemeIds = BizUtils.subList(rankThemeIds, pageStart, pageSize);
282

283 284
            themes = themeService.queryByThemeIds(rankThemeIds);
            themes = RankUtils.sortThemeEntityByIds(themes, rankThemeIds);
张辰's avatar
张辰 committed
285

刘基明's avatar
刘基明 committed
286
        } else if (ThemeListTypeEnum.TOPIC_LATEST.getCode().equals(req.getType())) {
刘基明's avatar
刘基明 committed
287
            //根据话题查询最新
288 289 290
            if (StringUtils.isEmpty(req.getTopicId())) {
                throw new BizException("TopicId为空");
            }
刘基明's avatar
刘基明 committed
291
            themes = themeService.queryNewestByTopic(req.topicId, pageStart, pageSize, excludeIds);
刘基明's avatar
刘基明 committed
292
        }
293

294
        ThemeListResp resp = new ThemeListResp();
刘基明's avatar
刘基明 committed
295
        resp.themes = convertEntityToQo(themes, userId);
296

张辰's avatar
张辰 committed
297
        excludeIds.addAll(resp.themes.stream().map(ThemeQo::getThemeId).collect(Collectors.toList()));
张辰's avatar
张辰 committed
298
        redisCache.put("queryThemes_" + req.ident, excludeIds, 60 * 60 * 6);
张辰's avatar
张辰 committed
299

300
        //组装详情
301
        return resp;
刘基明's avatar
刘基明 committed
302 303
    }

刘基明's avatar
刘基明 committed
304
    // 主题Entity转QO,组装所有信息
305 306 307
    private List<ThemeQo> convertEntityToQo(List<ThemeEntity> themeEntities, String userId) {
        //Entity转Qo
        List<ThemeQo> themeQos = ConvertUtil.themeEntitiesToDTOs(themeEntities);
刘基明's avatar
刘基明 committed
308
        // 批量查询附件detail
309 310 311
        batchFeignCallService.getAttachDetailByBatch(themeQos);
        //其他信息
        for (ThemeQo themeQO : themeQos) {
刘基明's avatar
刘基明 committed
312
            // 通用信息
313
            buildThemeQoExtraInfo(themeQO);
刘基明's avatar
刘基明 committed
314

315
        }
刘基明's avatar
刘基明 committed
316
        // 和用户相关信息
刘基明's avatar
刘基明 committed
317
        buildThemeExtraInfoByUser(userId, themeQos);
刘基明's avatar
刘基明 committed
318

319 320 321
        return themeQos;
    }

刘基明's avatar
刘基明 committed
322
    // 转发对象、点赞、收藏、转发数
323 324
    private void buildThemeQoExtraInfo(ThemeQo themeQo) {
        String themeId = themeQo.getThemeId();
刘基明's avatar
刘基明 committed
325
        // 封装转发对象
326 327 328
        FormerThemeQo former = redisCache.getObject(StringUtils.joinWith("_", CACHE_FORMER_THEME_ID, themeId), 60,
                () -> this.getFormerTheme(themeQo.getFormerThemeId()), FormerThemeQo.class);
        themeQo.setFormerTheme(former);
刘基明's avatar
刘基明 committed
329
        // 点赞,收藏,转发
330 331 332 333 334 335
        Integer likeCount = collectionService.getCountByTypeAndId(themeId, CollectionTypeEnum.LIKE_THEME);
        Integer commentCount = commentService.getCommentCountByThemeId(themeId);
        Integer forwardCount = themeService.getForwardCountById(themeId);
        themeQo.setCommentCount(commentCount);
        themeQo.setLikeCount(likeCount);
        themeQo.setForwardCount(forwardCount);
刘基明's avatar
刘基明 committed
336 337
    }

刘基明's avatar
刘基明 committed
338
    // 组装和当前用户相关信息(单个查询)
339 340
    private void buildThemeExtraInfoByUser(String userId, ThemeQo themeQo) {
        String themeId = themeQo.getThemeId();
刘基明's avatar
刘基明 committed
341
        // 是否关注作者
刘基明's avatar
刘基明 committed
342
        themeQo.setFollow(followRelService.checkFollow(themeQo.getAuthorId(), userId));
刘基明's avatar
刘基明 committed
343
        // 是否点赞
刘基明's avatar
刘基明 committed
344
        CollectionEntity likeEntity = collectionService.getTarget(themeId, userId, CollectionTypeEnum.LIKE_THEME);
345
        themeQo.setHasLiked(likeEntity != null);
刘基明's avatar
刘基明 committed
346
        // 是否转发
刘基明's avatar
刘基明 committed
347
        themeQo.setHasForward(themeService.judgeForwardByUser(themeId, userId));
刘基明's avatar
刘基明 committed
348
        // 是否收藏
刘基明's avatar
刘基明 committed
349
        CollectionEntity collectionEntity = collectionService.getTarget(themeId, userId, CollectionTypeEnum.COLLECT_THEME);
350 351
        themeQo.setHasCollect(collectionEntity != null);
    }
刘基明's avatar
刘基明 committed
352

刘基明's avatar
刘基明 committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
    // 组装和当前用户相关信息(批量查询)
    private void buildThemeExtraInfoByUser(String userId, List<ThemeQo> themeQos) {
        // 批量查询
        List<String> themeIds = themeQos.stream().map(ThemeQo::getThemeId).collect(Collectors.toList());
        Set<String> idolSet = new HashSet<>(followRelService.queryIdolsByFollowerId(userId));
        Set<String> likeSet = collectionService.getTargets(themeIds, userId, CollectionTypeEnum.LIKE_THEME);
        Set<String> bookSet = collectionService.getTargets(themeIds, userId, CollectionTypeEnum.COLLECT_THEME);
        Set<String> forwardUsers = themeService.getForwardUsers(themeIds);
        // 从set中查找
        for (ThemeQo themeQo : themeQos) {
            themeQo.setFollow(idolSet.contains(themeQo.getAuthorId()));
            themeQo.setHasLiked(likeSet.contains(themeQo.getThemeId()));
            themeQo.setHasCollect(bookSet.contains(themeQo.getThemeId()));
            themeQo.setHasForward(forwardUsers.contains(userId));
        }
    }

刘基明's avatar
刘基明 committed
370
    // 返回用户发布、回复、点赞、收藏的主题列表
刘基明's avatar
刘基明 committed
371
    public List<ThemeQo> queryThemesByUser(QueryRecordThemeReq req, String userId) {
刘基明's avatar
刘基明 committed
372 373 374 375

        List<ThemeEntity> themeEntities = Collections.emptyList();
        switch (req.getRecordType()) {
            case 1://发布
刘基明's avatar
刘基明 committed
376
                themeEntities = themeService.queryThemesByUserId(req.getUserId(), req.getLastId(), req.getPageSize());
刘基明's avatar
刘基明 committed
377
                break;
刘基明's avatar
刘基明 committed
378
            case 2://回复
刘基明's avatar
刘基明 committed
379
                List<ThemeQo> commentThemeList = getCommentThemeQos(req, userId);
刘基明's avatar
刘基明 committed
380
                return commentThemeList;
刘基明's avatar
刘基明 committed
381
            case 3://点赞
382 383 384 385
                List<String> likeThemeIds = collectionService.getListByUser(req.getUserId(), CollectionTypeEnum.LIKE_THEME);
                themeEntities = themeService.queryByThemeIds(likeThemeIds, req.getLastId(), req.getPageSize());
                themeEntities = RankUtils.sortThemeEntityByIds(themeEntities, likeThemeIds);

刘基明's avatar
刘基明 committed
386
                break;
刘基明's avatar
刘基明 committed
387
            case 4://收藏
388 389 390
                List<String> collectThemeIds = collectionService.getListByUser(req.getUserId(), CollectionTypeEnum.COLLECT_THEME);
                themeEntities = themeService.queryByThemeIds(collectThemeIds, req.getLastId(), req.getPageSize());
                themeEntities = RankUtils.sortThemeEntityByIds(themeEntities, collectThemeIds);
刘基明's avatar
刘基明 committed
391 392 393
                break;
        }
        List<ThemeQo> themeQos = convertEntityToQo(themeEntities, userId);
刘基明's avatar
刘基明 committed
394 395 396 397 398 399 400 401 402 403 404 405

        if (userId.equals(req.getUserId())) {
            //如果用户是查询自己的帖子,需要实时查询用户自己的个人信息,防止数据不一致
            CommonResp<UserInfoResp> userInfoNewCommonResp = feignClientForFatools.queryUsersListNew(userId);
            if (userInfoNewCommonResp.isNotSuccess()) {
                throw new BizException("内部接口调用失败");
            }
            UserInfoResp user = userInfoNewCommonResp.getData();
            themeQos.stream().forEach(o->reBuildAuthorInfo(o,user));
            redisCache.put(StringUtils.joinWith("_", CACHE_FEIGN_USER_INFO, userId), user, 60);
        }

刘基明's avatar
刘基明 committed
406 407 408
        return themeQos;
    }

刘基明's avatar
刘基明 committed
409

刘基明's avatar
刘基明 committed
410
    // 查询正文
411
    public ThemeQo getThemeDetail(String themeId, String userId) {
刘基明's avatar
刘基明 committed
412
        // 查询详情
413
        ThemeQo themeQo = redisCache.getObject(StringUtils.joinWith("_", CACHE_THEME_ID, themeId), 60,
414
                () -> this.getDetailCommon(themeId), ThemeQo.class);
刘基明's avatar
刘基明 committed
415
        // 添加用户相关信息
416
        buildThemeExtraInfoByUser(userId, themeQo);
417 418 419
        return themeQo;
    }

刘基明's avatar
刘基明 committed
420
    // 正文通用信息,与用户无关,可使用缓存
421
    private ThemeQo getDetailCommon(String themeId) {
刘基明's avatar
刘基明 committed
422
        ThemeEntity themeEntity = themeService.queryByThemeId(themeId);
刘基明's avatar
刘基明 committed
423 424
        if (themeEntity == null) {
            throw new BizException("找不到帖子id:" + themeId);
刘基明's avatar
刘基明 committed
425
        }
刘基明's avatar
刘基明 committed
426
        ThemeQo themeQo = ConvertUtil.themeEntityToQo(themeEntity);
刘基明's avatar
刘基明 committed
427
        //附件
刘基明's avatar
刘基明 committed
428
        batchFeignCallService.getAttachDetail(themeQo);
刘基明's avatar
刘基明 committed
429 430

        //转发、收藏、点赞
431
        buildThemeQoExtraInfo(themeQo);
刘基明's avatar
刘基明 committed
432

刘基明's avatar
刘基明 committed
433
        return themeQo;
刘基明's avatar
刘基明 committed
434 435
    }

436

刘基明's avatar
刘基明 committed
437 438
    // 点赞/取消点赞
    public void like(LikeThemeReq req, String userId) {
刘基明's avatar
刘基明 committed
439
        if (OperationTypeEnum.CONFIRM.getCode().equals(req.getType())) {
刘基明's avatar
刘基明 committed
440
            collectionService.saveOrUpdate(req.getThemeId(), userId, CollectionTypeEnum.LIKE_THEME);
刘基明's avatar
刘基明 committed
441
        } else if (OperationTypeEnum.CANCEL.getCode().equals(req.getType())) {
刘基明's avatar
刘基明 committed
442 443 444
            collectionService.delete(req.getThemeId(), userId, CollectionTypeEnum.LIKE_THEME);
        }

刘基明's avatar
刘基明 committed
445 446
    }

刘基明's avatar
刘基明 committed
447 448
    //收藏/取消收藏
    public void collect(CollectThemeReq req, String userId) {
刘基明's avatar
刘基明 committed
449
        if (OperationTypeEnum.CONFIRM.getCode().equals(req.getType())) {
刘基明's avatar
刘基明 committed
450
            collectionService.saveOrUpdate(req.getThemeId(), userId, CollectionTypeEnum.COLLECT_THEME);
刘基明's avatar
刘基明 committed
451
        } else if (OperationTypeEnum.CANCEL.getCode().equals(req.getType())) {
刘基明's avatar
刘基明 committed
452 453
            collectionService.delete(req.getThemeId(), userId, CollectionTypeEnum.COLLECT_THEME);
        }
张辰's avatar
张辰 committed
454 455
    }

刘基明's avatar
刘基明 committed
456
    //举报主题
刘基明's avatar
刘基明 committed
457
    @Transactional
刘基明's avatar
刘基明 committed
458 459 460 461 462 463 464
    public void report(ReportThemeReq req, String userId) {
        //更改举报状态
        themeService.updateReportStatus(req.getThemeId());
        //写入举报记录表
        ThemeEntity themeEntity = themeService.queryByThemeId(req.getThemeId());
        reportLogService.insert(ReportTypeEnum.THEME, userId, req.getThemeId(), themeEntity.getAuthorId(), req.getReason());
    }
465

刘基明's avatar
刘基明 committed
466

刘基明's avatar
刘基明 committed
467 468
    //关注用户是否有更新
    public Integer getFollowUpdateCount(String userId) {
张辰's avatar
张辰 committed
469 470
        String lastIdStr = redisCache.get(CACHE_IDOL_THEME_LAST_ID + userId);
        Long lastId = StringUtils.isBlank(lastIdStr) ? 0L : Long.parseLong(lastIdStr);
刘基明's avatar
刘基明 committed
471
        List<String> fansList = followRelService.queryIdolsByFollowerId(userId);
张辰's avatar
张辰 committed
472
        return themeService.queryCountFromLastId(fansList, lastId);
刘基明's avatar
刘基明 committed
473 474
    }

刘基明's avatar
刘基明 committed
475 476 477 478 479 480
    //    屏蔽(用户)
    public void blockUser(String blockUser, String userId) {
        BlackListEntity selectOne = blackListService.selectOne(blockUser, userId, BlockTypeEnum.USER.getCode());
        if (selectOne == null) {
            blackListService.addBlock(blockUser, userId, BlockTypeEnum.USER);
        }
刘基明's avatar
刘基明 committed
481
    }
刘基明's avatar
刘基明 committed
482

刘基明's avatar
刘基明 committed
483

刘基明's avatar
刘基明 committed
484 485 486 487 488 489 490 491 492 493 494 495 496 497
    //返回被转发主题
    private FormerThemeQo getFormerTheme(String formerThemeId) {
        if (StringUtils.isNotEmpty(formerThemeId)) {
            ThemeQo formerTheme = ConvertUtil.themeEntityToQo(themeService.queryByThemeId(formerThemeId));
            if (formerTheme != null) {
                batchFeignCallService.getAttachDetail(formerTheme);
                FormerThemeQo f = ConvertUtil.themeQo2FormerThemeQo(formerTheme);
                return f;
            }

        }
        return null;
    }

刘基明's avatar
刘基明 committed
498

刘基明's avatar
刘基明 committed
499
    // 逻辑删除主题,校验用户
刘基明's avatar
刘基明 committed
500 501
    public void delete(String themeId, String userId) {
        themeService.deleteById(themeId, userId);
刘基明's avatar
刘基明 committed
502
    }
刘基明's avatar
刘基明 committed
503 504


刘基明's avatar
刘基明 committed
505 506
    /**
     * 腾讯云-内容检测
刘基明's avatar
刘基明 committed
507
     *
刘基明's avatar
刘基明 committed
508
     * @param req
刘基明's avatar
刘基明 committed
509
     */
刘基明's avatar
刘基明 committed
510
    private void checkContent(CreateThemeReq req) {
511

512
        if (ThemeTypeEnum.LONG_TEXT.getCode().equals(req.getThemeType()) && req.getTitle().length()>50){
513 514 515
            throw new IllegalArgumentException("长文标题不能超过50字");
        }

刘基明's avatar
刘基明 committed
516 517
        StringBuilder sb = new StringBuilder();
        for (ThemeContentReq themeContentReq : req.getContent()) {
刘基明's avatar
刘基明 committed
518
            if (RelTypeEnum.TEXT.type.equals(themeContentReq.getType())) {
刘基明's avatar
刘基明 committed
519 520 521 522
                sb.append(themeContentReq.getValue());
            }
        }
        String content = sb.toString();
刘基明's avatar
刘基明 committed
523
        // 腾讯云接口最多支持5000文字校验
刘基明's avatar
刘基明 committed
524
        // 检查内容是否涉黄违法
刘基明's avatar
刘基明 committed
525 526 527 528
        boolean b;
        while (content.length()>5000){
            b = TencentcloudUtils.textModeration(content.substring(0, 5000));
            if (!b) {
刘基明's avatar
刘基明 committed
529
                throw new BizException(ErrorCodeConstant.CONTENT_ILLEGAL);
刘基明's avatar
刘基明 committed
530
            }
刘基明's avatar
刘基明 committed
531 532 533 534 535
            content=content.substring(5000);
        }
        b = TencentcloudUtils.textModeration(content);
        if (!b) {
            throw new BizException(ErrorCodeConstant.CONTENT_ILLEGAL);
刘基明's avatar
刘基明 committed
536
        }
刘基明's avatar
刘基明 committed
537 538


刘基明's avatar
刘基明 committed
539 540
    }

刘基明's avatar
刘基明 committed
541 542 543

    /**
     * 直播类型做转播检查
刘基明's avatar
刘基明 committed
544
     *
刘基明's avatar
刘基明 committed
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
     * @param userId
     * @param contents
     */
    private void liveRelayCheck(String userId, List<ThemeContentReq> contents) {
        for (ThemeContentReq content : contents) {
            if (content != null && content.getType().equals(RelTypeEnum.LIVE.type)) {
                CommonResp<Set<String>> notRelayResp = feignClientForFatools.getNotRelaySet(userId, Sets.newHashSet(content.getValue()));
                if (!notRelayResp.isSuccess()) {
                    throw new BizException("转播失败");
                }
                if (CollectionUtils.isEmpty(notRelayResp.getData())) {
                    throw new BizException("9999", "很抱歉!您需要购买或报名成功后才可以添加这个直播哦~");
                }
            }
        }
    }

刘基明's avatar
刘基明 committed
562

刘基明's avatar
刘基明 committed
563 564 565 566 567 568 569 570 571 572
    /**
     * 查询用户评论过的主题,并封装成转发主题结构
     *
     * @param req
     * @param userId 当前用户
     * @return
     */
    private List<ThemeQo> getCommentThemeQos(QueryRecordThemeReq req, String userId) {
        List<ThemeQo> commentThemeList = new ArrayList<>();
        List<ThemeEntity> themeEntities;
刘基明's avatar
刘基明 committed
573
        // 评论列表
刘基明's avatar
刘基明 committed
574
        List<CommentEntity> commentEntities = commentService.queryCommentsByUserId(req.getUserId(), req.getLastId(), req.getPageSize());
刘基明's avatar
刘基明 committed
575
        // 当前用户信息
576 577
        UserInfoResp userInfo = redisCache.getObject(StringUtils.joinWith("_", CACHE_FEIGN_USER_INFO, req.getUserId()),
                60, () -> this.getUserInfo(req.getUserId()), UserInfoResp.class);
刘基明's avatar
刘基明 committed
578 579 580 581 582 583
        Set<String> replyThemeIds = commentEntities.stream().map(CommentEntity::getThemeId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(replyThemeIds)) {
            return commentThemeList;
        }
        themeEntities = themeService.queryByThemeIds(new ArrayList<>(replyThemeIds));
        List<ThemeQo> themeQos = convertEntityToQo(themeEntities, userId);
刘基明's avatar
刘基明 committed
584
        // 组装附件
刘基明's avatar
刘基明 committed
585
        batchFeignCallService.getAttachDetailByBatch(themeQos);
刘基明's avatar
刘基明 committed
586
        // 主题列表
刘基明's avatar
刘基明 committed
587 588
        Map<String, ThemeQo> themeMap = themeQos.stream()
                .collect(Collectors.toMap(ThemeQo::getThemeId, o -> o));
刘基明's avatar
刘基明 committed
589
        // 主题+评论封装转发对象
刘基明's avatar
刘基明 committed
590 591 592 593 594 595 596
        for (CommentEntity commentEntity : commentEntities) {
            String themeId = commentEntity.getThemeId();
            //评论内容包装到ThemeContentQo里
            ThemeContentQo commentContent = ThemeContentQo.builder()
                    .type(RelTypeEnum.TEXT.type)
                    .value(commentEntity.getContent())
                    .build();
刘基明's avatar
刘基明 committed
597

刘基明's avatar
刘基明 committed
598

刘基明's avatar
刘基明 committed
599
            ThemeQo commentThemeQo = ThemeQo.builder()
600 601 602 603 604 605 606 607
                    .authorId(userInfo.getUserId())
                    .nickName(userInfo.getNickName())
                    .userImg(userInfo.getHeadImageUrl())
                    .userType(userInfo.getUserType())
                    .levelGrade(userInfo.getLevelGrade())
                    .userInvestorType(userInfo.getUserInvestorType())
                    .belongUserOrgId(userInfo.getBelongUserOrgId())
                    .belongUserOrgName(userInfo.getBelongUserOrgName())
刘基明's avatar
刘基明 committed
608
                    .content(Collections.singletonList(commentContent))
刘基明's avatar
刘基明 committed
609 610
                    .commentId(commentEntity.getCommentId())
                    .themeType(ThemeTypeEnum.RES_COMMENT.getCode())
刘基明's avatar
刘基明 committed
611
                    .follow(followRelService.checkFollow(userId, userId))
刘基明's avatar
刘基明 committed
612
                    .build();
刘基明's avatar
刘基明 committed
613 614 615

            //原主题包装到formerThemeQo中
            ThemeQo themeQo = themeMap.get(themeId);
刘基明's avatar
刘基明 committed
616
            if (themeQo != null) {
刘基明's avatar
刘基明 committed
617
                FormerThemeQo f = ConvertUtil.themeQo2FormerThemeQo(themeQo);
刘基明's avatar
刘基明 committed
618
                commentThemeQo.setFormerTheme(f);
刘基明's avatar
刘基明 committed
619
            }
刘基明's avatar
刘基明 committed
620 621
            commentThemeList.add(commentThemeQo);
        }
刘基明's avatar
刘基明 committed
622
        return commentThemeList;
刘基明's avatar
刘基明 committed
623 624
    }

625

626 627
    private UserInfoResp getUserInfo(String authorId) {
        CommonResp<UserInfoResp> userInfoNewCommonResp = feignClientForFatools.queryUsersListNew(authorId);
628 629 630 631 632 633
        if (userInfoNewCommonResp.isNotSuccess()) {
            throw new BizException("内部接口调用失败");
        }
        return userInfoNewCommonResp.getData();
    }

刘基明's avatar
刘基明 committed
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
    private void reBuildAuthorInfo(ThemeQo themeQo,UserInfoResp userInfo){
        themeQo.setNickName(userInfo.getNickName());
        themeQo.setUserImg(userInfo.getHeadImageUrl());
        themeQo.setUserIntroduction(userInfo.getIntroduction());
        //认证标签相关
        themeQo.setUserType(userInfo.getUserType());
        themeQo.setLevelGrade(userInfo.getLevelGrade());
        themeQo.setUserInvestorType(userInfo.getUserInvestorType());
        themeQo.setBelongUserOrgId(userInfo.getBelongUserOrgId());
        themeQo.setBelongUserOrgName(userInfo.getBelongUserOrgName());
        //工作室相关
        themeQo.setWorkshopName(userInfo.getWorkshopName());
        themeQo.setWorkshopStatus(userInfo.getWorkshopStatus());
        themeQo.setWorkshopIntroduction(userInfo.getWorkshopIntroduction());
    }

刘基明's avatar
刘基明 committed
650
}