pricelees 5fb5d2650b [#7] API 응답 형식 재정의 및 Swagger-UI 관련 코드 패키지 분리 (#8)
<!-- 제목 양식 -->
<!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) -->

## 📝 관련 이슈 및 PR

**PR과 관련된 이슈 번호**
- #7

##  작업 내용
<!-- 어떤 작업을 했는지 알려주세요! -->
1. 808c6675 에서 작업했던 정상 / 오류를 통합하는 객체를 사용하려 했으나, Swagger-UI상에서 응답 형식에 null 필드가 포함되는 문제로 다시 정상 / 오류 별도로 분리
2. Swagger-UI(문서화, 명세) 관련 코드는 인지하기 쉽도록 ../web -> ../docs 패키지로 이전
3. 현재까지 코틀린으로 마이그레이션 된 서비스를 대상으로, 응답에 ResponseEntity를 적용하고 \@ResponseStatus 제거

## 🧪 테스트
<!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! -->
예정으로는 Issue에 작성했던 테스트까지 처리하려고 했으나, 테스트는 바로 다음에 진행 예정

## 📚 참고 자료 및 기타
<!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! -->

Reviewed-on: #8
Co-authored-by: pricelees <priceelees@gmail.com>
Co-committed-by: pricelees <priceelees@gmail.com>
2025-07-15 05:37:41 +00:00

83 lines
2.5 KiB
Java

package roomescape.theme.service;
import java.time.LocalDate;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import roomescape.common.exception.ErrorType;
import roomescape.common.exception.RoomescapeException;
import roomescape.reservation.domain.repository.ReservationRepository;
import roomescape.theme.domain.Theme;
import roomescape.theme.domain.repository.ThemeRepository;
import roomescape.theme.dto.ThemeRequest;
import roomescape.theme.dto.ThemeResponse;
import roomescape.theme.dto.ThemesResponse;
@Service
@Transactional
public class ThemeService {
private final ThemeRepository themeRepository;
public ThemeService(ThemeRepository themeRepository) {
this.themeRepository = themeRepository;
}
@Transactional(readOnly = true)
public Theme findThemeById(Long id) {
return themeRepository.findById(id)
.orElseThrow(() -> new RoomescapeException(ErrorType.THEME_NOT_FOUND,
String.format("[themeId: %d]", id), HttpStatus.BAD_REQUEST));
}
@Transactional(readOnly = true)
public ThemesResponse findAllThemes() {
List<ThemeResponse> response = themeRepository.findAll()
.stream()
.map(ThemeResponse::from)
.toList();
return new ThemesResponse(response);
}
@Transactional(readOnly = true)
public ThemesResponse getMostReservedThemesByCount(int count) {
LocalDate today = LocalDate.now();
LocalDate startDate = today.minusDays(7);
LocalDate endDate = today.minusDays(1);
List<ThemeResponse> response = themeRepository.findTopNThemeBetweenStartDateAndEndDate(startDate, endDate,
count)
.stream()
.map(ThemeResponse::from)
.toList();
return new ThemesResponse(response);
}
public ThemeResponse addTheme(ThemeRequest request) {
validateIsSameThemeNameExist(request.name());
Theme theme = themeRepository.save(new Theme(request.name(), request.description(), request.thumbnail()));
return ThemeResponse.from(theme);
}
private void validateIsSameThemeNameExist(String name) {
if (themeRepository.existsByName(name)) {
throw new RoomescapeException(ErrorType.THEME_DUPLICATED,
String.format("[name: %s]", name), HttpStatus.CONFLICT);
}
}
public void removeThemeById(Long id) {
if (themeRepository.isReservedTheme(id)) {
throw new RoomescapeException(ErrorType.THEME_IS_USED_CONFLICT,
String.format("[themeId: %d]", id), HttpStatus.CONFLICT);
}
themeRepository.deleteById(id);
}
}