diff --git a/music-houduan/src/main/java/com/test/musichouduan/service/impl/PlaylistServiceImpl.java b/music-houduan/src/main/java/com/test/musichouduan/service/impl/PlaylistServiceImpl.java index 820683f..5aded12 100644 --- a/music-houduan/src/main/java/com/test/musichouduan/service/impl/PlaylistServiceImpl.java +++ b/music-houduan/src/main/java/com/test/musichouduan/service/impl/PlaylistServiceImpl.java @@ -83,38 +83,54 @@ public class PlaylistServiceImpl implements PlaylistService { private FileService fileService; @Override + /** + * 根据歌单ID获取歌单信息 + * @param id 歌单的唯一标识符 + * @return PlaylistDTO 歌单的数据传输对象,包含歌单的详细信息 + * @throws BusinessException 当指定的歌单不存在时抛出业务异常 + */ public PlaylistDTO getPlaylistById(Long id) { + // 从数据库中查找指定ID的歌单,如果不存在则抛出业务异常 Playlist playlist = playlistRepository.findById(id) .orElseThrow(() -> new BusinessException("歌单不存在")); + // 将实体对象转换为DTO对象并返回 return convertToDTO(playlist); } @Override + /** + * 获取歌单列表 + * @param page 当前页码 + * @param size 每页大小 + * @param keyword 搜索关键词 + * @param typeId 歌单类型ID + * @return PageResult 歌单列表分页结果 + */ public PageResult getPlaylistList(Integer page, Integer size, String keyword, Long typeId) { // 构建查询条件 Specification spec = (root, query, cb) -> { List predicates = new ArrayList<>(); - query.distinct(true); // 添加 distinct 查询 + query.distinct(true); // 添加 distinct 查询,避免重复结果 // 关键字查询 if (StringUtils.hasText(keyword)) { // 搜索歌单名、描述、创建者用户名以及歌单内的音乐名 - Predicate p1 = cb.like(root.get("name"), "%" + keyword + "%"); - Predicate p2 = cb.like(root.get("description"), "%" + keyword + "%"); - Predicate p3 = cb.like(root.join("creator").get("username"), "%" + keyword + "%"); - Predicate p4 = cb.like(root.join("musics", jakarta.persistence.criteria.JoinType.LEFT).get("name"), "%" + keyword + "%"); - predicates.add(cb.or(p1, p2, p3, p4)); + Predicate p1 = cb.like(root.get("name"), "%" + keyword + "%"); // 匹配歌单名 + Predicate p2 = cb.like(root.get("description"), "%" + keyword + "%"); // 匹配歌单描述 + Predicate p3 = cb.like(root.join("creator").get("username"), "%" + keyword + "%"); // 匹配创建者用户名 + Predicate p4 = cb.like(root.join("musics", jakarta.persistence.criteria.JoinType.LEFT).get("name"), "%" + keyword + "%"); // 匹配歌单内的音乐名 + predicates.add(cb.or(p1, p2, p3, p4)); // 将多个查询条件组合为OR关系 } // 类型查询 if (typeId != null) { - predicates.add(cb.equal(root.get("type").get("id"), typeId)); + predicates.add(cb.equal(root.get("type").get("id"), typeId)); // 添加类型ID查询条件 } - return cb.and(predicates.toArray(new Predicate[0])); + return cb.and(predicates.toArray(new Predicate[0])); // 将所有查询条件组合为AND关系 }; - // 执行查询 + // 执行查询,按创建时间降序排列 Page playlistPage = playlistRepository.findAll( spec, PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime")) @@ -173,46 +189,80 @@ public class PlaylistServiceImpl implements PlaylistService { } } +/** + * 定时任务方法:用于更新热门歌单缓存 + * 使用@Scheduled注解配置定时任务,cron表达式设置为"0 0 * * * ?" + * 表示每小时整点执行一次任务(即每小时的0分0秒触发) + */ @Scheduled(cron = "0 0 * * * ?") public void scheduleUpdateHotPlaylist() { + // 打印任务开始日志 System.out.println("Scheduled task started: Updating hot playlist cache..."); + // 调用更新热门歌单缓存的方法 updateHotPlaylistCache(); } +/** + * 更新热门歌单缓存的方法 + * 使用异步方式和只读事务注解 + * @return 返回包含热门歌单DTO列表的CompletableFuture + */ @Async @Transactional(readOnly = true) public CompletableFuture> updateHotPlaylistCache() { + // 用于存储所有歌单的列表 List allPlaylists = new ArrayList<>(); + // 分页查询结果对象 Page playlistPage; + // 当前页码,从0开始 int pageNum = 0; + // 每页大小,设置为500 int pageSize = 500; + // 分页查询所有歌单,直到没有更多数据 do { + // 创建分页对象 Pageable pageable = PageRequest.of(pageNum, pageSize); + // 执行分页查询 playlistPage = playlistRepository.findAll(pageable); + // 将当前页的歌单添加到总列表中 allPlaylists.addAll(playlistPage.getContent()); + // 页码递增 pageNum++; } while (playlistPage.hasNext()); + // 使用并行流为每个歌单计算热门分数 allPlaylists.parallelStream().forEach(playlist -> { + // 计算热门歌单分数 double score = HotPlaylistScoreUtil.calculateHotScore(playlist); + // 设置歌单的热门分数 playlist.setHotScore(score); }); + // 将歌单按热门分数降序排序,并限制热门歌单数量 List sortedHotPlaylists = allPlaylists.stream() + // 按热门分数降序排序 .sorted(Comparator.comparing(Playlist::getHotScore).reversed()) + // 限制热门歌单数量 .limit(HOT_PLAYLIST_LIMIT) + // 将歌单实体转换为DTO对象 .map(this::convertToDTO) + // 收集为列表 .collect(Collectors.toList()); try { + // 将热门歌单列表转换为JSON字符串 String jsonToCache = objectMapper.writeValueAsString(sortedHotPlaylists); + // 将JSON字符串存入Redis缓存,设置过期时间 redisTemplate.opsForValue().set(HOT_PLAYLIST_CACHE_KEY, jsonToCache, CACHE_EXPIRATION_HOURS, TimeUnit.HOURS); + // 打印更新成功的日志 System.out.println("Hot playlist cache updated successfully with " + sortedHotPlaylists.size() + " items."); } catch (Exception e) { + // 打印更新失败的错误信息 System.err.println("Failed to cache hot playlist list to Redis: " + e.getMessage()); } + // 返回包含热门歌单DTO列表的CompletableFuture return CompletableFuture.completedFuture(sortedHotPlaylists); }