2311061111-lyt/src/main/java/com/vibevault/service/PlaylistServiceImpl.java
liyitian bfd351e365
Some checks failed
autograde-final-vibevault / check-trigger (push) Successful in 12s
autograde-final-vibevault / grade (push) Failing after 58s
完成作业
2025-12-14 16:13:55 +08:00

199 lines
6.9 KiB
Java

package com.vibevault.service;
import com.vibevault.dto.PlaylistDTO;
import com.vibevault.dto.SongCreateDTO;
import com.vibevault.dto.SongDTO;
import com.vibevault.exception.ResourceNotFoundException;
import com.vibevault.exception.UnauthorizedException;
import com.vibevault.model.Playlist;
import com.vibevault.model.Song;
import com.vibevault.model.User;
import com.vibevault.repository.PlaylistRepository;
import com.vibevault.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 歌单服务实现
*
* 需要实现:
* - 所有 PlaylistService 接口中定义的方法
* - 将实体转换为 DTO 返回给调用者
* - 资源不存在时抛出 ResourceNotFoundException
* - [Challenge] 检查用户是否有权限操作歌单(所有权检查)
*/
@Service
public class PlaylistServiceImpl implements PlaylistService {
private final PlaylistRepository playlistRepository;
private final UserRepository userRepository;
public PlaylistServiceImpl(PlaylistRepository playlistRepository, UserRepository userRepository) {
this.playlistRepository = playlistRepository;
this.userRepository = userRepository;
}
@Override
public List<PlaylistDTO> getAllPlaylists() {
return playlistRepository.findAll()
.stream()
.map(this::toDTO)
.toList();
}
@Override
public PlaylistDTO getPlaylistById(Long id) {
Playlist playlist = playlistRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Playlist not found with id: " + id));
return toDTO(playlist);
}
@Override
@Transactional
public PlaylistDTO createPlaylist(String name, String ownerUsername) {
User owner = userRepository.findByUsername(ownerUsername)
.orElseThrow(() -> new ResourceNotFoundException("User not found: " + ownerUsername));
Playlist playlist = new Playlist(name, owner);
Playlist savedPlaylist = playlistRepository.save(playlist);
return toDTO(savedPlaylist);
}
@Override
@Transactional
public PlaylistDTO addSongToPlaylist(Long playlistId, SongCreateDTO song, String username) {
Playlist playlist = playlistRepository.findById(playlistId)
.orElseThrow(() -> new ResourceNotFoundException("Playlist not found with id: " + playlistId));
// [Challenge] 检查用户是否有权限操作此歌单
checkPermission(playlist, username);
Song newSong = new Song(song.title(), song.artist(), song.durationInSeconds());
playlist.addSong(newSong);
Playlist updatedPlaylist = playlistRepository.save(playlist);
return toDTO(updatedPlaylist);
}
@Override
@Transactional
public void removeSongFromPlaylist(Long playlistId, Long songId, String username) {
Playlist playlist = playlistRepository.findById(playlistId)
.orElseThrow(() -> new ResourceNotFoundException("Playlist not found with id: " + playlistId));
// [Challenge] 检查用户是否有权限操作此歌单
checkPermission(playlist, username);
Song song = playlist.getSongs().stream()
.filter(s -> s.getId().equals(songId))
.findFirst()
.orElseThrow(() -> new ResourceNotFoundException("Song not found with id: " + songId));
playlist.removeSong(song);
playlistRepository.save(playlist);
}
@Override
@Transactional
public void deletePlaylist(Long playlistId, String username) {
Playlist playlist = playlistRepository.findById(playlistId)
.orElseThrow(() -> new ResourceNotFoundException("Playlist not found with id: " + playlistId));
// [Challenge] 检查用户是否有权限操作此歌单
checkPermission(playlist, username);
playlistRepository.delete(playlist);
}
// ========== Advanced 方法 ==========
@Override
@Transactional(readOnly = true)
public List<PlaylistDTO> searchPlaylists(String keyword) {
return playlistRepository.findByNameContainingIgnoreCase(keyword)
.stream()
.map(this::toDTO)
.toList();
}
@Override
@Transactional
public PlaylistDTO copyPlaylist(Long playlistId, String newName, String username) {
// 获取要复制的歌单
Playlist originalPlaylist = playlistRepository.findById(playlistId)
.orElseThrow(() -> new ResourceNotFoundException("Playlist not found with id: " + playlistId));
// 获取当前用户(新歌单的所有者)
User currentUser = userRepository.findByUsername(username)
.orElseThrow(() -> new ResourceNotFoundException("User not found: " + username));
// 创建新歌单
Playlist copiedPlaylist = new Playlist(newName, currentUser);
// 复制原歌单中的所有歌曲
originalPlaylist.getSongs().forEach(originalSong -> {
Song copiedSong = new Song(
originalSong.getTitle(),
originalSong.getArtist(),
originalSong.getDurationInSeconds()
);
copiedPlaylist.addSong(copiedSong);
});
// 保存新歌单
Playlist savedPlaylist = playlistRepository.save(copiedPlaylist);
return toDTO(savedPlaylist);
}
// ========== 辅助方法 ==========
/**
* 将 Playlist 实体转换为 DTO
*/
private PlaylistDTO toDTO(Playlist playlist) {
List<SongDTO> songDTOs = playlist.getSongs()
.stream()
.map(this::toSongDTO)
.toList();
return new PlaylistDTO(
playlist.getId(),
playlist.getName(),
playlist.getOwner().getUsername(),
songDTOs
);
}
/**
* 将 Song 实体转换为 DTO
*/
private SongDTO toSongDTO(Song song) {
return new SongDTO(
song.getId(),
song.getTitle(),
song.getArtist(),
song.getDurationInSeconds()
);
}
/**
* [Challenge] 检查用户是否有权限操作指定歌单
* 规则:歌单所有者或管理员可以操作
*/
private void checkPermission(Playlist playlist, String username) {
User currentUser = userRepository.findByUsername(username)
.orElseThrow(() -> new ResourceNotFoundException("User not found: " + username));
// 检查是否是歌单所有者或管理员
if (!playlist.getOwner().getUsername().equals(username) && !currentUser.getRole().equals("ROLE_ADMIN")) {
throw new UnauthorizedException("You don't have permission to modify this playlist");
}
}
}