From 3689dc743073aa6c913afd3a29ae65b7144c108d Mon Sep 17 00:00:00 2001 From: robinjoon Date: Thu, 2 May 2024 11:47:30 +0900 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20=EC=9D=B8=EA=B8=B0=20=ED=85=8C?= =?UTF-8?q?=EB=A7=88=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7c7b3324bd..41fc748304 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ - [x] 예약이 있는 테마를 삭제 요청시 에러 - [ ] 사용자 예약 기능 추가 +- [ ] 인기 테마 기능 추가 # API 명세 From 0516901892ec253e933d2ae0763291991e7f86ee Mon Sep 17 00:00:00 2001 From: robinjoon Date: Thu, 2 May 2024 11:47:47 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EC=9D=B8=EA=B8=B0=20=ED=85=8C?= =?UTF-8?q?=EB=A7=88=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../controller/ThemeController.java | 9 +++ .../roomescape/controller/UserController.java | 5 ++ .../JdbcTemplateThemeRepository.java | 32 +++++---- .../repository/ThemeRepository.java | 3 + .../java/roomescape/service/ThemeService.java | 7 ++ src/main/resources/static/js/ranking.js | 72 +++++++++++-------- .../repository/CollectionThemeRepository.java | 6 ++ 8 files changed, 94 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 41fc748304..fd820a31e5 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ - [x] 예약이 있는 테마를 삭제 요청시 에러 - [ ] 사용자 예약 기능 추가 -- [ ] 인기 테마 기능 추가 +- [x] 인기 테마 기능 추가 # API 명세 diff --git a/src/main/java/roomescape/controller/ThemeController.java b/src/main/java/roomescape/controller/ThemeController.java index bc38a24576..dbb0cb2520 100644 --- a/src/main/java/roomescape/controller/ThemeController.java +++ b/src/main/java/roomescape/controller/ThemeController.java @@ -1,6 +1,7 @@ package roomescape.controller; import java.net.URI; +import java.time.LocalDate; import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import roomescape.dto.ThemeRequest; import roomescape.dto.ThemeResponse; @@ -29,6 +31,13 @@ public List findAll() { return themeService.findAll(); } + @GetMapping("/ranking") + public List findAndOrderByPopularity(@RequestParam LocalDate start, + @RequestParam LocalDate end, + @RequestParam int count) { + return themeService.findAndOrderByPopularity(start, end, count); + } + @PostMapping public ResponseEntity save(@RequestBody ThemeRequest themeRequest) { ThemeResponse saved = themeService.save(themeRequest); diff --git a/src/main/java/roomescape/controller/UserController.java b/src/main/java/roomescape/controller/UserController.java index 39d95139d3..86ecc0f8ce 100644 --- a/src/main/java/roomescape/controller/UserController.java +++ b/src/main/java/roomescape/controller/UserController.java @@ -9,4 +9,9 @@ public class UserController { public String reservationPage() { return "reservation"; } + + @GetMapping("/") + public String bestThemePage() { + return "index"; + } } diff --git a/src/main/java/roomescape/repository/JdbcTemplateThemeRepository.java b/src/main/java/roomescape/repository/JdbcTemplateThemeRepository.java index 7d44bd86be..497b82c526 100644 --- a/src/main/java/roomescape/repository/JdbcTemplateThemeRepository.java +++ b/src/main/java/roomescape/repository/JdbcTemplateThemeRepository.java @@ -1,9 +1,11 @@ package roomescape.repository; import java.sql.PreparedStatement; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; @@ -12,6 +14,14 @@ @Repository public class JdbcTemplateThemeRepository implements ThemeRepository { private final JdbcTemplate jdbcTemplate; + private RowMapper themeRowMapper = (rs, rowNum) -> { + long id = rs.getLong("id"); + String name = rs.getString("name"); + String description = rs.getString("description"); + String thumbnail = rs.getString("thumbnail"); + return new Theme(id, name, description, thumbnail); + }; + ; public JdbcTemplateThemeRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; @@ -19,24 +29,20 @@ public JdbcTemplateThemeRepository(JdbcTemplate jdbcTemplate) { @Override public List findAll() { - return jdbcTemplate.query("select ID, NAME, DESCRIPTION, THUMBNAIL from THEME", (rs, rowNum) -> { - long id = rs.getLong(1); - String name = rs.getString(2); - String description = rs.getString(3); - String thumbnail = rs.getString(4); - return new Theme(id, name, description, thumbnail); - }); + return jdbcTemplate.query("select ID, NAME, DESCRIPTION, THUMBNAIL from THEME", themeRowMapper); + } + + @Override + public List findAndOrderByPopularity(LocalDate start, LocalDate end, int count) { + return jdbcTemplate.query( + "select th.*, count(*) as count from theme th join reservation r on r.theme_id = th.id where PARSEDATETIME(r.date,'yyyy-MM-dd') >= PARSEDATETIME(?,'yyyy-MM-dd') and PARSEDATETIME(r.date,'yyyy-MM-dd') <= PARSEDATETIME(?,'yyyy-MM-dd') group by th.id order by count desc limit ?", + themeRowMapper, start, end, count); } @Override public Optional findById(long id) { List themes = jdbcTemplate.query("select id, name, description, thumbnail from theme where id = ?", - (rs, rowNum) -> { - String name = rs.getString("name"); - String description = rs.getString("description"); - String thumbnail = rs.getString("thumbnail"); - return new Theme(id, name, description, thumbnail); - }, id); + themeRowMapper, id); return themes.stream().findFirst(); } diff --git a/src/main/java/roomescape/repository/ThemeRepository.java b/src/main/java/roomescape/repository/ThemeRepository.java index a43cb24851..f9cdad4015 100644 --- a/src/main/java/roomescape/repository/ThemeRepository.java +++ b/src/main/java/roomescape/repository/ThemeRepository.java @@ -1,5 +1,6 @@ package roomescape.repository; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import roomescape.domain.Theme; @@ -7,6 +8,8 @@ public interface ThemeRepository { List findAll(); + List findAndOrderByPopularity(LocalDate start, LocalDate end, int count); + Optional findById(long id); Theme save(Theme theme); diff --git a/src/main/java/roomescape/service/ThemeService.java b/src/main/java/roomescape/service/ThemeService.java index 3fd8f6bab1..f417befdc9 100644 --- a/src/main/java/roomescape/service/ThemeService.java +++ b/src/main/java/roomescape/service/ThemeService.java @@ -1,5 +1,6 @@ package roomescape.service; +import java.time.LocalDate; import java.util.List; import java.util.Objects; import org.springframework.stereotype.Service; @@ -44,6 +45,12 @@ public List findAll() { .toList(); } + public List findAndOrderByPopularity(LocalDate start, LocalDate end, int count) { + return themeRepository.findAndOrderByPopularity(start, end, count).stream() + .map(this::toResponse) + .toList(); + } + public void delete(long id) { //todo : 변수명 고민 boolean invalidDelete = reservationRepository.findAll().stream() diff --git a/src/main/resources/static/js/ranking.js b/src/main/resources/static/js/ranking.js index dee05edf0b..c4b20948b1 100644 --- a/src/main/resources/static/js/ranking.js +++ b/src/main/resources/static/js/ranking.js @@ -1,25 +1,41 @@ document.addEventListener('DOMContentLoaded', () => { - /* - TODO: [3단계] 인기 테마 - 인기 테마 목록 조회 API 호출 - */ - requestRead('/') // 인기 테마 목록 조회 API endpoint - .then(render) - .catch(error => console.error('Error fetching times:', error)); + /* + TODO: [3단계] 인기 테마 - 인기 테마 목록 조회 API 호출 + */ + const today = new Date(); + let startDate = formatDate(minusDay(today, 7)); + let endDate = formatDate(minusDay(today, 1)); + const count = 10; + const endpoint = `/themes/ranking?start=${startDate}&end=${endDate}&count=${count}`; + requestRead(endpoint) // 인기 테마 목록 조회 API endpoint + .then(render) + .catch(error => console.error('Error fetching times:', error)); }); +function minusDay(date, minusValue) { + return new Date(new Date(date).setDate(date.getDate() - minusValue)); +} + +function formatDate(date) { + const year = date.getFullYear(); + const month = ('0' + (date.getMonth() + 1)).slice(-2); + const day = ('0' + date.getDate()).slice(-2); + return year + '-' + month + '-' + day; +} + function render(data) { - const container = document.getElementById('theme-ranking'); - - /* - TODO: [3단계] 인기 테마 - 인기 테마 목록 조회 API 호출 후 렌더링 - response 명세에 맞춰 name, thumbnail, description 값 설정 - */ - data.forEach(theme => { - const name = ''; - const thumbnail = ''; - const description = ''; - - const htmlContent = ` + const container = document.getElementById('theme-ranking'); + + /* + TODO: [3단계] 인기 테마 - 인기 테마 목록 조회 API 호출 후 렌더링 + response 명세에 맞춰 name, thumbnail, description 값 설정 + */ + data.forEach(theme => { + const name = theme.name; + const thumbnail = theme.thumbnail; + const description = theme.description; + + const htmlContent = ` ${name}
${name}
@@ -27,18 +43,18 @@ function render(data) {
`; - const div = document.createElement('li'); - div.className = 'media my-4'; - div.innerHTML = htmlContent; + const div = document.createElement('li'); + div.className = 'media my-4'; + div.innerHTML = htmlContent; - container.appendChild(div); - }) + container.appendChild(div); + }) } function requestRead(endpoint) { - return fetch(endpoint) - .then(response => { - if (response.status === 200) return response.json(); - throw new Error('Read failed'); - }); + return fetch(endpoint) + .then(response => { + if (response.status === 200) return response.json(); + throw new Error('Read failed'); + }); } diff --git a/src/test/java/roomescape/repository/CollectionThemeRepository.java b/src/test/java/roomescape/repository/CollectionThemeRepository.java index a851648ec3..5df15fb0c1 100644 --- a/src/test/java/roomescape/repository/CollectionThemeRepository.java +++ b/src/test/java/roomescape/repository/CollectionThemeRepository.java @@ -1,5 +1,6 @@ package roomescape.repository; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import roomescape.domain.Theme; @@ -10,6 +11,11 @@ public List findAll() { return null; } + @Override + public List findAndOrderByPopularity(LocalDate start, LocalDate end, int count) { + return null; + } + @Override public Optional findById(long id) { return Optional.of(new Theme(id, "이름", "설명", "썸네일"));