framework/src/main/java/cn/lili/elasticsearch/EsSuffix.java
@@ -14,6 +14,11 @@ public static final String GOODS_INDEX_NAME = "goods"; /** * 视频索引后缀 */ public static final String VIDEO_INDEX_NAME = "video"; /** * 日志索引后缀 */ public static final String LOGS_INDEX_NAME = "logs"; framework/src/main/java/cn/lili/modules/lmk/domain/es/VideoIndex.java
New file @@ -0,0 +1,94 @@ package cn.lili.modules.lmk.domain.es; import cn.lili.elasticsearch.EsSuffix; import cn.lili.modules.lmk.domain.vo.SimpleVideoTagVO; import cn.lili.modules.lmk.domain.vo.VideoGoodsDetailVO; import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import java.util.List; /** * es的视频document(存储单元) * * @author:xp * @date:2025/6/30 14:50 */ @Data @Document(indexName = "#{@elasticsearchProperties.indexPrefix}_" + EsSuffix.VIDEO_INDEX_NAME, createIndex = false) public class VideoIndex { /** 视频id */ @Id private String id; /** 视频标题 */ @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word") private String title; /** 作者id */ @Field(type = FieldType.Keyword) private String authorId; /** 作者名称 */ @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word") private String authorName; /** 作者头像 */ @Field(type = FieldType.Keyword) private String authorAvatar; /** 封面 */ @Field(type = FieldType.Keyword) private String coverFileKey; /** 视频地址 */ @Field(type = FieldType.Keyword) private String videoFileKey; /** * 视频内容类型:视频、图片 * @see cn.lili.modules.lmk.enums.general.VideoContentTypeEnum */ @Field(type = FieldType.Keyword) private String videoContentType; /** * 视频类型:视频、大健康、神厨 * @see cn.lili.modules.lmk.enums.general.VideoTypeEnum */ @Field(type = FieldType.Keyword) private String videoType; /** 图集-json数组 */ @Field(type = FieldType.Keyword) private String videoImgs; /** 视频标签 */ @Field(type = FieldType.Nested) private List<SimpleVideoTagVO> tagList; /** 视频时长:秒 */ @Field(type = FieldType.Keyword) private Long videoDuration; /** 视频填充模式 */ @Field(type = FieldType.Keyword) private String videoFit; /** 视频状态 */ @Field(type = FieldType.Keyword) private String status; /** 商品信息 */ @Field(type = FieldType.Nested) private List<VideoGoodsDetailVO> goodsList; /** 是否推荐视频 */ @Field(type = FieldType.Keyword) private boolean recommend = false; } framework/src/main/java/cn/lili/modules/lmk/domain/vo/SimpleVideoTagVO.java
@@ -6,6 +6,8 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.beans.BeanUtils; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.lang.NonNull; /** @@ -19,13 +21,16 @@ public class SimpleVideoTagVO { @ApiModelProperty("标签id") @Field(type = FieldType.Keyword) private String id; /** 标签名称 */ @ApiModelProperty("标签名称") @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word") private String tagName; @ApiModelProperty(hidden = true) @Field(type = FieldType.Keyword) private String videoId; framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoGoodsDetailVO.java
@@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; /** * @author:xp @@ -14,20 +16,26 @@ public class VideoGoodsDetailVO { @ApiModelProperty("商品id") @Field(type = FieldType.Keyword) private String goodsId; @ApiModelProperty("商品skuid") @Field(type = FieldType.Keyword) private String id; @ApiModelProperty("商品名称") @Field(type = FieldType.Text, searchAnalyzer = "ik_max_word") private String goodsName; @ApiModelProperty("价格") @Field(type = FieldType.Keyword) private String price; @ApiModelProperty("缩略图") @Field(type = FieldType.Keyword) private String thumbnail; @ApiModelProperty("商品数量") @Field(type = FieldType.Keyword) private Integer goodsNum; } framework/src/main/java/cn/lili/modules/lmk/mapper/VideoMapper.java
@@ -1,6 +1,7 @@ package cn.lili.modules.lmk.mapper; import cn.lili.modules.lmk.domain.entity.Video; import cn.lili.modules.lmk.domain.es.VideoIndex; import cn.lili.modules.lmk.domain.query.*; import cn.lili.modules.lmk.domain.vo.*; import com.baomidou.mybatisplus.core.mapper.BaseMapper; @@ -130,4 +131,13 @@ * @return */ List<VideoGoodsDetailVO> getVideoGoods(@Param("id") String videoId); /** * es同步查询视频数据 * * @param start 开始位置 * @param end 结束位置 * @return */ List<VideoIndex> getEsPage(@Param("start") int start, @Param("end") int end); } framework/src/main/java/cn/lili/modules/lmk/service/EsService.java
New file @@ -0,0 +1,70 @@ package cn.lili.modules.lmk.service; import java.util.Map; /** * es处理 * * @author:xp * @date:2025/6/30 14:47 */ public interface EsService { /** * 获取索引的完整名称 * * @param indexName * @return */ String getIndexFullName(String indexName); /** * 创建索引 * * @param indexName 索引名称 * @param mappingJsonPath json文件位置,相对于resource目录,例如:/es/video.json */ void createIndex(String indexName, String mappingJsonPath); /** * 重建索引,并重新添加索引数据 * * @param indexName 索引名称 * @param mappingJsonPath json文件位置,相对于resource目录,例如:/es/video.json */ void recreateIndex(String indexName, String mappingJsonPath); /** * 添加/修改 文档,如果是修改,则是整条数据更新 * * @param indexName 索引名称 * @param id es主键,可传业务主键 * @param data 数据对象 */ void addOrUpdateDocument(String indexName, String id, Object data); /** * 更新某些字段的值 * * @param indexName 索引名称 * @param id 数据id * @param updateList 更新哪些字段,key 字段 value要修改的值 */ void updateSomeField(String indexName, String id, Map<String, Object> updateList); /** * 删除文档 * @param indexName 索引名称 * @param id es主键,可传业务主键 */ void deleteDocument(String indexName, String id); /** * 索引是否存在 * * @param indexName * @return */ boolean indexExist(String indexName); } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoEsServiceImpl.java
New file @@ -0,0 +1,213 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.elasticsearch.BaseElasticsearchService; import cn.lili.elasticsearch.EsSuffix; import cn.lili.elasticsearch.config.ElasticsearchProperties; import cn.lili.modules.lmk.domain.entity.Video; import cn.lili.modules.lmk.domain.es.VideoIndex; import cn.lili.modules.lmk.enums.general.VideoStatusEnum; import cn.lili.modules.lmk.mapper.VideoMapper; import cn.lili.modules.lmk.service.EsService; import cn.lili.modules.search.repository.EsVideoIndexRepository; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import org.springframework.data.elasticsearch.core.document.Document; import org.springframework.data.elasticsearch.core.query.UpdateQuery; import org.springframework.stereotype.Service; import org.springframework.util.FileCopyUtils; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.concurrent.*; /** * 视频es * * @author:xp * @date:2025/6/30 15:54 */ @Slf4j @RequiredArgsConstructor @Service("videoEsServiceImpl") public class VideoEsServiceImpl extends BaseElasticsearchService implements EsService { private final ElasticsearchProperties elasticsearchProperties; private final VideoMapper videoMapper; private final EsVideoIndexRepository esVideoIndexRepository; @Override public String getIndexFullName(String indexName) { return elasticsearchProperties.getIndexPrefix() + "_" + indexName; } @Override public void createIndex(String indexName, String mappingJsonPath) { if (! indexName.startsWith(elasticsearchProperties.getIndexPrefix())) { indexName = this.getIndexFullName(indexName); } if (this.indexExist(indexName)) { throw new RuntimeException(String.format("索引:%s已经存在,无法创建", indexName)); } CreateIndexRequest request = new CreateIndexRequest(indexName); // 1. 配置索引 request.settings(Settings.builder() .put("index.number_of_shards", elasticsearchProperties.getIndex().getNumberOfShards()) .put("index.number_of_replicas", elasticsearchProperties.getIndex().getNumberOfReplicas()) .put("index.max_result_window", 100000) //最大查询结果数 .put("index.mapping.total_fields.limit", 2000)); // 2. 配置mapping String mapping; try (InputStream inputStream = this.getClass().getResourceAsStream(mappingJsonPath)) { byte[] bytes = FileCopyUtils.copyToByteArray(inputStream); mapping = new String(bytes, StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException(String.format("读取es映射json文件:%s异常", mappingJsonPath), e); } request.mapping(mapping, XContentType.JSON); // 3. 创建索引 try { CreateIndexResponse createIndexResponse = client.indices().create(request, COMMON_OPTIONS); } catch (IOException e) { throw new RuntimeException(String.format("es创建索引失败:%s", indexName), e); } } @Override public void recreateIndex(String indexName, String mappingJsonPath) { indexName = this.getIndexFullName(indexName); // 1. 如果索引存在,先删除索引,再创建索引 if (this.indexExist(indexName)) { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName); try { AcknowledgedResponse deleteRes = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); this.createIndex(indexName, mappingJsonPath); } catch (IOException e) { log.error("删除索引失败", e); throw new RuntimeException("删除索引失败"); } } else { this.createIndex(indexName, mappingJsonPath); } // 2. 多线程查询视频数据,构建文档对象 Long totalVideo = new LambdaQueryChainWrapper<>(videoMapper) .eq(Video::getStatus, VideoStatusEnum.PUBLISHED.getValue()) .count(); int totalThreads = (int) Math.ceil((double) totalVideo / 200); // 计算需要多少个线程 CountDownLatch latch = new CountDownLatch(totalThreads); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 4, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); BlockingQueue<VideoIndex> dataList = new LinkedBlockingQueue<>(); for (int page = 0; page < totalThreads; page++) { final int currentPage = page; threadPoolExecutor.execute(() -> { try { List<VideoIndex> pageData = videoMapper.getEsPage(currentPage * 200, 200); dataList.addAll(pageData); } catch (Exception e) { log.error("第{}页数据查询失败", currentPage, e); } finally { latch.countDown(); // 线程执行完成 -1 } }); } try { latch.await(); // 等待所有线程执行完成 // 3. 添加es数据 // BulkRequest bulkRequest = new BulkRequest(); // String finalIndexName = indexName; // dataList.forEach(data -> { // IndexRequest indexRequest = new IndexRequest(finalIndexName) // .id(data.getId()) // .source(data); // bulkRequest.add(indexRequest); // }); // client.bulk(bulkRequest, RequestOptions.DEFAULT); esVideoIndexRepository.saveAll(dataList); } catch (InterruptedException e) { log.error("多线程读取视频数据异常", e); } finally { threadPoolExecutor.shutdown(); } } @Override public void addOrUpdateDocument(String indexName, String id, Object data) { indexName = this.getIndexFullName(indexName); IndexRequest request = new IndexRequest(indexName); request.id(id).source(data); try { client.index(request, RequestOptions.DEFAULT); } catch (IOException e) { throw new RuntimeException("es文档添加/修改失败", e); } } @Override public void updateSomeField(String indexName, String id, Map<String, Object> updateList) { indexName = this.getIndexFullName(indexName); // 构建更新请求 UpdateRequest request = new UpdateRequest(indexName, id); try { // 构建更新内容 XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); for (Map.Entry<String, Object> entry : updateList.entrySet()) { builder.field(entry.getKey(), entry.getValue()); } builder.endObject(); request.doc(builder); // 设置部分更新内容 // 可选配置 request.retryOnConflict(2); // 冲突重试次数 // request.fetchSource(true); // 返回更新后的文档 client.update(request, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } } @Override public void deleteDocument(String indexName, String id) { indexName = this.getIndexFullName(indexName); DeleteRequest request = new DeleteRequest(indexName, id); try { client.delete(request, RequestOptions.DEFAULT); } catch (IOException e) { throw new RuntimeException("删除es文档失败:" + id, e); } } @Override public boolean indexExist(String indexName) { if (!indexName.startsWith(elasticsearchProperties.getIndexPrefix())) { indexName = this.getIndexFullName(indexName); } return super.indexExist(indexName); } } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java
@@ -3,8 +3,10 @@ import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.security.context.UserContext; import cn.lili.elasticsearch.EsSuffix; import cn.lili.modules.lmk.constant.RedisKeyExpireConstant; import cn.lili.modules.lmk.domain.entity.*; import cn.lili.modules.lmk.domain.es.VideoIndex; import cn.lili.modules.lmk.domain.form.*; import cn.lili.modules.lmk.domain.query.*; import cn.lili.modules.lmk.domain.vo.*; @@ -26,6 +28,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; @@ -61,6 +64,10 @@ private final VideoGoodsService videoGoodsService; private final KitchenTypeService kitchenTypeService; private final Cache cache; @Qualifier("videoEsServiceImpl") private final EsService videoEsService; /** * 添加 @@ -107,8 +114,16 @@ * @return */ @Override @Transactional(rollbackFor = Exception.class) public Result removeById(String id) { baseMapper.deleteById(id); new LambdaUpdateChainWrapper<>(videoGoodsService.getBaseMapper()) .eq(VideoGoods::getVideoId, id) .remove(); new LambdaUpdateChainWrapper<>(videoTagRefService.getBaseMapper()) .eq(VideoTagRef::getVideoId, id) .remove(); videoEsService.deleteDocument(EsSuffix.VIDEO_INDEX_NAME, id); return Result.ok("删除成功"); } @@ -175,6 +190,7 @@ } baseMapper.insert(video); // 2.处理标签 List<SimpleVideoTagVO> esTagList = new ArrayList<>(2); List<VideoTagRef> videoTagRefs = form.getTags().stream().map(tag -> { VideoTagRef videoTagRef = new VideoTagRef(); videoTagRef.setVideoId(video.getId()); @@ -194,14 +210,19 @@ } else { videoTagRef.setVideoTagId(tag.getId()); } SimpleVideoTagVO esTag = new SimpleVideoTagVO(); esTag.setVideoId(video.getId()); esTag.setTagName(tag.getTagName()); esTag.setId(tag.getId()); esTagList.add(esTag); return videoTagRef; }).collect(Collectors.toList()); videoTagRefService.saveBatch(videoTagRefs); // 3. 保存视频文件信息 lmkFileService.addByForm(form.getFileInfo()); // 4. 处理选择的商品 List<VideoGoods> videoGoods = new ArrayList<>(2); if (CollectionUtils.isNotEmpty(form.getGoodsList())) { List<VideoGoods> videoGoods = new ArrayList<>(2); for (int i = 0; i < form.getGoodsList().size(); i++) { VideoGoods e = new VideoGoods(); e.setVideoId(video.getId()); @@ -209,10 +230,22 @@ e.setGoodsSkuId(form.getGoodsList().get(i).getGoodsSkuId()); e.setGoodsNum(form.getGoodsList().get(i).getGoodsNum()); e.setOrderNum(i); videoGoods.add(e); videoGoodsService.save(e); } videoGoodsService.saveBatch(videoGoods); } // 5. 构建es中数据 VideoIndex videoIndex = new VideoIndex(); BeanUtils.copyProperties(video, videoIndex); videoIndex.setCoverFileKey(video.getCoverUrl()); List<VideoGoodsDetailVO> esGoodsList = videoGoods.stream().map(goods -> { VideoGoodsDetailVO vo = new VideoGoodsDetailVO(); BeanUtils.copyProperties(goods, vo); return vo; }).collect(Collectors.toList()); videoIndex.setGoodsList(esGoodsList); videoIndex.setTagList(esTagList); videoEsService.addOrUpdateDocument(EsSuffix.VIDEO_INDEX_NAME, video.getId(), videoIndex); return Result.ok("发布成功,视频审核中~"); } @@ -236,6 +269,7 @@ new LambdaUpdateChainWrapper<>(videoTagRefService.getBaseMapper()) .eq(VideoTagRef::getVideoId, video.getId()) .remove(); List<SimpleVideoTagVO> esTagList = new ArrayList<>(2); List<VideoTagRef> videoTagRefs = form.getTags().stream().map(tag -> { VideoTagRef videoTagRef = new VideoTagRef(); videoTagRef.setVideoId(video.getId()); @@ -255,6 +289,11 @@ } else { videoTagRef.setVideoTagId(tag.getId()); } SimpleVideoTagVO esTag = new SimpleVideoTagVO(); esTag.setVideoId(video.getId()); esTag.setTagName(tag.getTagName()); esTag.setId(tag.getId()); esTagList.add(esTag); return videoTagRef; }).collect(Collectors.toList()); videoTagRefService.saveBatch(videoTagRefs); @@ -264,8 +303,8 @@ new LambdaUpdateChainWrapper<>(videoGoodsService.getBaseMapper()) .eq(VideoGoods::getVideoId, video.getId()) .remove(); List<VideoGoods> videoGoods = new ArrayList<>(2); if (CollectionUtils.isNotEmpty(form.getGoodsList())) { List<VideoGoods> videoGoods = new ArrayList<>(2); for (int i = 0; i < form.getGoodsList().size(); i++) { VideoGoods e = new VideoGoods(); e.setVideoId(video.getId()); @@ -277,6 +316,18 @@ } videoGoodsService.saveBatch(videoGoods); } // 5. 更新es中的数据 VideoIndex videoIndex = new VideoIndex(); BeanUtils.copyProperties(video, videoIndex); videoIndex.setCoverFileKey(video.getCoverUrl()); List<VideoGoodsDetailVO> esGoodsList = videoGoods.stream().map(goods -> { VideoGoodsDetailVO vo = new VideoGoodsDetailVO(); BeanUtils.copyProperties(goods, vo); return vo; }).collect(Collectors.toList()); videoIndex.setGoodsList(esGoodsList); videoIndex.setTagList(esTagList); videoEsService.addOrUpdateDocument(EsSuffix.VIDEO_INDEX_NAME, video.getId(), videoIndex); return Result.ok("发布成功,视频审核中~"); } @@ -305,6 +356,9 @@ .eq(Video::getId, form.getId()) .set(Video::getRecommend, form.getRecommend()) .update(); Map<String, Object> fields = new HashMap<>(2); fields.put("recommend", form.getRecommend()); videoEsService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, form.getId(), fields); return Result.ok("设置成功"); } @@ -327,6 +381,10 @@ if (form.getResult()) { video.setStatus(VideoStatusEnum.PUBLISHED.getValue()); video.setAuditPassTime(new Date()); Map<String, Object> fields = new HashMap<>(2); fields.put("status", VideoStatusEnum.PUBLISHED.getValue()); videoEsService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, video.getId(), fields); } else { video.setStatus(VideoStatusEnum.REJECT.getValue()); } @@ -337,21 +395,32 @@ @Override public Result up(String id) { // 1. 更新数据库 new LambdaUpdateChainWrapper<>(baseMapper) .eq(Video::getId, id) .set(Video::getStatus, VideoStatusEnum.PUBLISHED.getValue()) .update(); // 2. 更新es Map<String, Object> fields = new HashMap<>(2); fields.put("status", VideoStatusEnum.PUBLISHED.getValue()); videoEsService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, id, fields); return Result.ok("上架成功"); } @Override public Result down(VideoDownForm form) { // 1. 更新数据库 new LambdaUpdateChainWrapper<>(baseMapper) .eq(Video::getId, form.getId()) .set(Video::getStatus, VideoStatusEnum.DISABLE.getValue()) .update(); // 2. 更新es Map<String, Object> fields = new HashMap<>(2); fields.put("status", VideoStatusEnum.DISABLE.getValue()); videoEsService.updateSomeField(EsSuffix.VIDEO_INDEX_NAME, form.getId(), fields); // TODO 将下架原因以通知的方式告知用户 return Result.ok("下架成功"); } framework/src/main/java/cn/lili/modules/search/repository/EsVideoIndexRepository.java
New file @@ -0,0 +1,15 @@ package cn.lili.modules.search.repository; import cn.lili.modules.lmk.domain.es.VideoIndex; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; /** * 视频索引 * * @author paulG * @since 2020/10/15 **/ public interface EsVideoIndexRepository extends ElasticsearchRepository<VideoIndex, String> { } framework/src/main/resources/es/video.json
New file @@ -0,0 +1,49 @@ { "properties": { "id": {"type": "keyword"}, "title": { "type": "text", "analyzer": "ik_max_word" }, "authorId": {"type": "keyword"}, "authorName": { "type": "text", "analyzer": "ik_max_word" }, "authorAvatar": {"type": "keyword"}, "recommend": {"type": "boolean"}, "coverFileKey": {"type": "keyword"}, "videoFileKey": {"type": "keyword"}, "videoContentType": {"type": "keyword"}, "videoType": {"type": "keyword"}, "videoImgs": {"type": "keyword"}, "tagList": { "type": "nested", "properties": { "id": {"type": "keyword"}, "videoId": {"type": "keyword"}, "tagName": { "type": "text", "analyzer": "ik_max_word" } } }, "videoDuration": {"type": "keyword"}, "videoFit": {"type": "keyword"}, "status": {"type": "keyword"}, "goodsList": { "type": "nested", "properties": { "id": {"type": "keyword"}, "goodsId": {"type": "keyword"}, "price": {"type": "keyword"}, "thumbnail": {"type": "keyword"}, "goodsNum": {"type": "keyword"}, "goodsName": { "type": "text", "analyzer": "ik_max_word" } } } } } framework/src/main/resources/mapper/lmk/VideoMapper.xml
@@ -545,4 +545,68 @@ <if test="query.authorId != null and query.authorId != ''">AND LV.author_id = #{query.authorId}</if> <if test="query.status != null and query.status != ''">AND LV.status = #{query.status}</if> </select> <resultMap id="EsResultMap" type="cn.lili.modules.lmk.domain.es.VideoIndex"> <id column="id" property="id"/> <result column="author_id" property="authorId" /> <result column="authorName" property="authorName" /> <result column="authorAvatar" property="authorAvatar" /> <result column="cover_url" property="coverFileKey" /> <result column="video_file_key" property="videoFileKey" /> <result column="video_fit" property="videoFit" /> <result column="video_duration" property="videoDuration" /> <result column="title" property="title" /> <result column="status" property="status" /> <result column="recommend" property="recommend" /> <result column="video_content_type" property="videoContentType" /> <result column="video_type" property="videoType" /> <result column="video_imgs" property="videoImgs" /> <collection property="goodsList" column="id" select="getVideoGoods" ofType="cn.lili.modules.lmk.domain.vo.VideoGoodsDetailVO"/> <collection property="tagList" column="id" select="getVideoTags" ofType="cn.lili.modules.lmk.domain.vo.SimpleVideoTagVO"/> </resultMap> <select id="getVideoTags" resultType="cn.lili.modules.lmk.domain.vo.SimpleVideoTagVO"> SELECT LVT.id, LVT.tag_name as tagName FROM lmk_video_tag_ref LVTR INNER JOIN lmk_video_tag LVT ON LVTR.video_tag_id = LVT.id AND LVT.delete_flag = 0 WHERE LVTR.video_id = #{id} </select> <select id="getEsPage" parameterType="int" resultMap="EsResultMap"> SELECT LV.author_id, LV.cover_url, LV.video_fit, LV.video_duration, LV.video_file_key, LV.title, LV.goods_view_num, LV.goods_order_num, LV.recommend, LV.status, LV.play_num, LV.comment_num, LV.collect_num, LV.weight, LV.audit_pass_time, LV.update_time, LV.create_time, LV.video_content_type, LV.video_type, LV.video_imgs, LV.id, LM.nick_name as authorName, LM.face as authorAvatar FROM lmk_video LV LEFT JOIN li_member LM ON LV.author_id = LM.id WHERE LV.delete_flag = 0 AND LV.status = '1' LIMIT #{start}, #{end} </select> </mapper> manager-api/src/main/java/cn/lili/controller/lmk/VideoController.java
@@ -1,5 +1,6 @@ package cn.lili.controller.lmk; import cn.lili.elasticsearch.EsSuffix; import cn.lili.group.Update; import cn.lili.group.Add; import cn.lili.modules.lmk.domain.form.VideoAuditingForm; @@ -7,6 +8,8 @@ import cn.lili.modules.lmk.domain.form.VideoRecommendForm; import cn.lili.modules.lmk.domain.form.WxVideoForm; import cn.lili.modules.lmk.domain.query.ManagerVideoQuery; import cn.lili.modules.lmk.service.EsService; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.validation.annotation.Validated; import lombok.RequiredArgsConstructor; import java.util.List; @@ -31,6 +34,9 @@ public class VideoController { private final VideoService videoService; @Qualifier("videoEsServiceImpl") private final EsService esService; @PostMapping @ApiOperation(value = "添加", notes = "添加") @@ -97,4 +103,11 @@ public Result down(@RequestBody @Validated VideoDownForm form) { return videoService.down(form); } @PostMapping("/recreate/es/index") @ApiOperation(value = "重建es索引", notes = "重建es索引") public Result recreateEsIndex() { esService.recreateIndex(EsSuffix.VIDEO_INDEX_NAME, "/es/video.json"); return Result.ok(); } }