Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.back.web7_9_codecrete_be.domain.artists.controller;

import com.back.web7_9_codecrete_be.domain.artists.dto.request.CreateRequest;
import com.back.web7_9_codecrete_be.domain.artists.dto.request.UpdateRequest;
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistListResponse;
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistDetailResponse;
import com.back.web7_9_codecrete_be.domain.artists.service.ArtistService;
import com.back.web7_9_codecrete_be.domain.artists.service.ArtistEnrichService;
import com.back.web7_9_codecrete_be.global.rsData.RsData;
Expand All @@ -8,10 +12,12 @@
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/artists")
@RequiredArgsConstructor
@Tag(name = "Artists", description = "공연에 대한 정보를 제공하는 API 입니다.")
@Tag(name = "Artists", description = "아티스트에 대한 정보를 제공하는 API 입니다.")
public class ArtistsController {
private final ArtistService artistService;
private final ArtistEnrichService enrichService;
Expand All @@ -23,12 +29,54 @@ public RsData<Integer> saveArtist() {
return RsData.success("아티스트 저장에 성공하였습니다.", saved);
}

@Operation(summary = "아티스트 정보 보완", description = "아티스트 한국어 이름, 그룹 여부, 소속 그룹 정보 보완")
@Operation(summary = "아티스트 정보 보완", description = "아티스트 한국어 이름, 그룹 여부, 소속 그룹 정보를 보완합니다.")
@PostMapping("/enrich")
public RsData<Integer> enrich(
@RequestParam(required = false, defaultValue = "100") int limit
) {
int updated = enrichService.enrichArtist(limit);
return RsData.success("enrich 성공", updated);
}

@Operation(summary = "아티스트 생성", description = "아티스트를 등록합니다.")
@PostMapping()
public RsData<Void> create(
@RequestBody CreateRequest reqBody
) {
artistService.createArtist(reqBody.artistName(), reqBody.artistGroup(), reqBody.artistGroup(), reqBody.genreName());
return RsData.success("아티스트 생성이 완료되었습니다.", null);
}

@Operation(summary = "아티스트 목록 조회", description = "아티스트 전체 목록을 조회합니다.")
@GetMapping()
public RsData<List<ArtistListResponse>> list() {
return RsData.success("아티스트 전체 목록을 조회했습니다.", artistService.listArtist());
}

@Operation(summary = "아티스트 상세 조회", description = "아티스트의 상세 정보를 조회합니다.")
@GetMapping("/{id}")
public RsData<ArtistDetailResponse> artist(
@PathVariable Long id
) {
return RsData.success("아티스트 상세 조회를 성공했습니다.", artistService.getArtistDetail(id));
}

@Operation(summary = "아티스트 정보 수정", description = "아티스트 정보를 수정합니다.")
@PatchMapping("/{id}")
public RsData<Void> update(
@PathVariable Long id,
@RequestBody UpdateRequest reqBody
) {
artistService.updateArtist(id, reqBody);
return RsData.success("아티스트 정보 수정을 완료했습니다.", null);
}

@Operation(summary = "아티스트 정보 삭제", description = "아티스트 정보를 삭제합니다.")
@DeleteMapping("/{id}")
public RsData<Void> delete(
@PathVariable Long id
) {
artistService.delete(id);
return RsData.success("아티스트 정보를 삭제했습니다.", null);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.request;

import com.back.web7_9_codecrete_be.domain.artists.entity.Genre;


public record CreateRequest(
String artistName,
String artistGroup,
String artistType,
Genre genre
String genreName
) {
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.request;

import com.back.web7_9_codecrete_be.domain.artists.entity.Genre;


public record UpdateRequest(
String artistName,
String artistGroup,
String artistType,
Genre genre
String genreName
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.response;

public record AlbumResponse(
String albumName,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO에도 @Schema 통해서 설명 붙여주시면 좋을 것 같아요

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 수정하겠씁니다!

String releaseDate,
String albumType, // album / single / ep
String imageUrl,
String spotifyUrl
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.response;

import java.util.List;

public record ArtistDetailResponse(
String artistName,
String artistGroup,
String artistType,
String profileImageUrl,
long likeCount,
int totalAlbums,
double popularityRating,
String description,
List<AlbumResponse> albums,
List<TopTrackResponse> topTracks,
List<RelatedArtistResponse> relatedArtists
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.response;

import com.back.web7_9_codecrete_be.domain.artists.entity.Artist;

public record ArtistListResponse(
String artistName,
String artistGroup,
String genreName
) {
public static ArtistListResponse from(Artist artist) {
return new ArtistListResponse(
artist.getArtistName(),
artist.getArtistGroup(),
artist.getGenre().getGenreName()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.response;

public record RelatedArtistResponse(
String artistName,
String imageUrl,
String spotifyArtistId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.back.web7_9_codecrete_be.domain.artists.dto.response;

public record TopTrackResponse(
String trackName,
String spotifyUrl
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,34 @@ public Artist(String spotifyArtistId, String artistName, String artistGroup, Str
this.genre = genre;
}

public Artist(String artistName, String artistGroup, String artistType, Genre genre) {
this.artistName = artistName;
this.artistGroup = artistGroup;
this.artistType = artistType;
this.genre = genre;
}

public void updateProfile(String nameKo, String artistGroup, String artistType) {
this.nameKo = nameKo;
this.artistGroup = artistGroup; // nullable
this.artistType = artistType; // "SOLO" / "GROUP"
}

public void changeName(String name) {
this.artistName = name;
}

public void changeGroup(String group) {
this.artistGroup = group;
}

public void changeType(String type) {
this.artistType = type;
}

public void changeGenre(Genre genre) {
this.genre = genre;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@

@Repository
public interface ArtistLikeRepository extends JpaRepository<ArtistLike, Long> {
long countByArtistId(Long artistId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface ArtistRepository extends JpaRepository<Artist, Long> {
boolean existsBySpotifyArtistId(String spotifyArtistId);

@Query("SELECT a FROM Artist a WHERE a.nameKo IS NULL ORDER BY a.id ASC")
List<Artist> findByNameKoIsNullOrderByIdAsc(Pageable pageable);

boolean existsByArtistName(String artistName);
boolean existsByNameKo(String nameKo);

List<Artist> findTop5ByArtistGroupAndIdNot(String artistGroup, long excludeId);
List<Artist> findTop5ByGenreIdAndIdNot(Long genreId, long excludeId);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,111 @@
package com.back.web7_9_codecrete_be.domain.artists.service;

import com.back.web7_9_codecrete_be.domain.artists.dto.request.UpdateRequest;
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistListResponse;
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistDetailResponse;
import com.back.web7_9_codecrete_be.domain.artists.entity.Artist;
import com.back.web7_9_codecrete_be.domain.artists.entity.Genre;
import com.back.web7_9_codecrete_be.domain.artists.repository.ArtistRepository;
import com.back.web7_9_codecrete_be.domain.artists.repository.ArtistLikeRepository;
import com.back.web7_9_codecrete_be.global.error.code.ArtistErrorCode;
import com.back.web7_9_codecrete_be.global.error.exception.BusinessException;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ArtistService {

private final SpotifyService spotifyService;
private final ArtistRepository artistRepository;
private final GenreService genreService;
private final ArtistLikeRepository artistLikeRepository;

@Transactional
public int setArtist() {
return spotifyService.seedKoreanArtists300();
}

@Transactional
public Artist createArtist(String artistName, String artistGroup, String artistType, String genreName) {
Genre genre = genreService.findByGenreName(genreName);
if(artistRepository.existsByArtistName(artistName) || artistRepository.existsByNameKo(artistName)) {
throw new BusinessException(ArtistErrorCode.ARTIST_ALREADY_EXISTS);
}
Artist artist = new Artist(artistName, artistGroup, artistType, genre);
artistRepository.save(artist);
return artist;
}

@Transactional(readOnly = true)
public List<ArtistListResponse> listArtist() {
return artistRepository.findAll().stream()
.map(ArtistListResponse::from)
.toList();
}

@Transactional(readOnly = true)
public ArtistDetailResponse getArtistDetail(Long artistId) {
Artist artist = artistRepository.findById(artistId)
.orElseThrow(() -> new BusinessException(ArtistErrorCode.ARTIST_NOT_FOUND));

if (artist.getSpotifyArtistId() == null) {
throw new BusinessException(ArtistErrorCode.SPOTIFY_NOT_FOUND);
}

long likeCount = artistLikeRepository.countByArtistId(artistId);

return spotifyService.getArtistDetail(
artist.getSpotifyArtistId(),
artist.getArtistGroup(),
artist.getArtistType(),
likeCount,
artist.getId(),
artist.getGenre() != null ? artist.getGenre().getId() : null
);
}

@Transactional
public void updateArtist(Long id, UpdateRequest req) {
Artist artist = artistRepository.findById(id)
.orElseThrow(() -> new BusinessException(ArtistErrorCode.ARTIST_NOT_FOUND));

boolean changed = false;

if (req.artistName() != null && !req.artistName().isBlank()) {
artist.changeName(req.artistName().trim());
changed = true;
}

if (req.artistGroup() != null && !req.artistGroup().isBlank()) {
artist.changeGroup(req.artistGroup().trim());
changed = true;
}

if (req.artistType() != null && !req.artistType().isBlank()) {
artist.changeType(req.artistType().trim());
changed = true;
}

if (req.genreName() != null && !req.genreName().isBlank()) {
Genre genre = genreService.findByGenreName(req.genreName().trim());
artist.changeGenre(genre);
changed = true;
}

if (!changed) {
throw new BusinessException(ArtistErrorCode.INVALID_UPDATE_REQUEST); // "수정할 값이 없습니다"
}
}

@Transactional
public void delete(Long id) {
Artist artist = artistRepository.findById(id)
.orElseThrow(() -> new BusinessException(ArtistErrorCode.ARTIST_NOT_FOUND));
artistRepository.delete(artist);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.back.web7_9_codecrete_be.domain.artists.service;

import com.back.web7_9_codecrete_be.domain.artists.entity.Genre;
import com.back.web7_9_codecrete_be.domain.artists.repository.GenreRepository;
import com.back.web7_9_codecrete_be.global.error.code.GenreErrorCode;
import com.back.web7_9_codecrete_be.global.error.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class GenreService {

private final GenreRepository genreRepository;

public Genre findByGenreName(String genreName) {
String normalized = genreName.trim().toLowerCase();
Genre genre = genreRepository.findByGenreName(normalized)
.orElseThrow(() -> new BusinessException(GenreErrorCode.GENRE_NOT_FOUND));
return genre;
}
}
Loading