From 3b2835ebd97c42a5621529cfddcee53a7c1f8db3 Mon Sep 17 00:00:00 2001 From: Thuan ngo Date: Sun, 24 Aug 2025 23:36:13 +0700 Subject: [PATCH] add 10,000 records for course table. --- .gitignore | 1 + .../elearning/domain/course/Course.java | 3 +- .../domain/course/CourseController.java | 39 +++--- .../domain/course/CourseRepository.java | 122 ++++++++++++++---- .../domain/course/CourseService.java | 4 +- .../domain/course/CourseServiceImpl.java | 6 +- .../elearning/domain/review/Review.java | 2 +- .../backend/elearning/domain/topic/Topic.java | 2 +- src/main/resources/application-prod.yml | 2 +- 9 files changed, 123 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index 549e00a2..e3338e25 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ target/ .settings .springBeans .sts4-cache +.env ### IntelliJ IDEA ### .idea diff --git a/src/main/java/com/backend/elearning/domain/course/Course.java b/src/main/java/com/backend/elearning/domain/course/Course.java index f3145e83..d4852ffe 100644 --- a/src/main/java/com/backend/elearning/domain/course/Course.java +++ b/src/main/java/com/backend/elearning/domain/course/Course.java @@ -18,12 +18,12 @@ import java.util.Set; @Entity -@Table(name = "course") @AllArgsConstructor @NoArgsConstructor @Getter @Setter @Builder +@Table(name = "course") public class Course extends AbstractAuditEntity { @Id @@ -53,7 +53,6 @@ public class Course extends AbstractAuditEntity { private boolean free; - @Enumerated(EnumType.STRING) private CourseStatus status; diff --git a/src/main/java/com/backend/elearning/domain/course/CourseController.java b/src/main/java/com/backend/elearning/domain/course/CourseController.java index 828cba84..39ffcbb9 100644 --- a/src/main/java/com/backend/elearning/domain/course/CourseController.java +++ b/src/main/java/com/backend/elearning/domain/course/CourseController.java @@ -47,8 +47,23 @@ public ResponseEntity> getPageableCourse ( } + @GetMapping("/courses/search") + public ResponseEntity> getCoursesByMultiQueryWithPageable ( + @RequestParam(value = "pageNum", defaultValue = Constants.PageableConstant.DEFAULT_PAGE_NUMBER, required = false) int pageNum, + @RequestParam(value = "pageSize", defaultValue = Constants.PageableConstant.DEFAULT_PAGE_SIZE, required = false) int pageSize, + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam(value = "ratingStar", required = false) Float rating, + @RequestParam(value = "level", required = false) List level, + @RequestParam(value = "free", required = false) List free, + @RequestParam(value = "categoryName", required = false) String categoryName, + @RequestParam(value = "topicId", required = false) Integer topicId + ) { + PageableData pageableCourses = courseService.getCoursesByMultiQuery(pageNum, pageSize, keyword, rating, level, free, categoryName, topicId); + return ResponseEntity.ok().body(pageableCourses); + } + // @GetMapping("/courses/search") -// public ResponseEntity> getCoursesByMultiQueryWithPageable ( +// public ResponseEntity> getCoursesByMultiQuery ( // @RequestParam(value = "pageNum", defaultValue = Constants.PageableConstant.DEFAULT_PAGE_NUMBER, required = false) int pageNum, // @RequestParam(value = "pageSize", defaultValue = Constants.PageableConstant.DEFAULT_PAGE_SIZE, required = false) int pageSize, // @RequestParam(value = "keyword", required = false) String keyword, @@ -57,27 +72,11 @@ public ResponseEntity> getPageableCourse ( // @RequestParam(value = "free", required = false) Boolean[] free, // @RequestParam(value = "categoryName", required = false) String categoryName, // @RequestParam(value = "topicId", required = false) Integer topicId -// ) { -// PageableData pageableCourses = courseService.getCoursesByMultiQuery(pageNum, pageSize, keyword, rating, level, free, categoryName, topicId); -// return ResponseEntity.ok().body(pageableCourses); +// ) { +// List coursesByMultiQueryReturnList = courseService.getCoursesByMultiQueryReturnList(pageNum, pageSize, keyword, rating, level, free, categoryName, topicId); +// return ResponseEntity.ok().body(coursesByMultiQueryReturnList); // } - // this - @GetMapping("/courses/search") - public ResponseEntity> getCoursesByMultiQuery ( - @RequestParam(value = "pageNum", defaultValue = Constants.PageableConstant.DEFAULT_PAGE_NUMBER, required = false) int pageNum, - @RequestParam(value = "pageSize", defaultValue = Constants.PageableConstant.DEFAULT_PAGE_SIZE, required = false) int pageSize, - @RequestParam(value = "keyword", required = false) String keyword, - @RequestParam(value = "ratingStar", required = false) Float rating, - @RequestParam(value = "level", required = false) String[] level, - @RequestParam(value = "free", required = false) Boolean[] free, - @RequestParam(value = "categoryName", required = false) String categoryName, - @RequestParam(value = "topicId", required = false) Integer topicId - ) { - List coursesByMultiQueryReturnList = courseService.getCoursesByMultiQueryReturnList(pageNum, pageSize, keyword, rating, level, free, categoryName, topicId); - return ResponseEntity.ok().body(coursesByMultiQueryReturnList); - } - @PostMapping("/admin/courses") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = diff --git a/src/main/java/com/backend/elearning/domain/course/CourseRepository.java b/src/main/java/com/backend/elearning/domain/course/CourseRepository.java index 47982481..948677bf 100644 --- a/src/main/java/com/backend/elearning/domain/course/CourseRepository.java +++ b/src/main/java/com/backend/elearning/domain/course/CourseRepository.java @@ -3,12 +3,14 @@ import com.backend.elearning.domain.section.Section; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.Collection; import java.util.List; import java.util.Optional; @@ -222,37 +224,95 @@ List findByMultiQuery( @Param("categoryName") String categoryName, @Param("topicId") Integer topicId ); - @Query(value = """ - select c - from Course c - join fetch c.category cat - left join fetch cat.parent p - join fetch c.topic t - join fetch c.user u - left join fetch c.reviews - where LOWER(c.title) LIKE LOWER(CONCAT('%', :title, '%')) - and (:level IS NULL or c.level in :level) - and (:free IS NULL or c.free in :free) - and (:categoryName IS NULL or cat.name = :categoryName or p.name = :categoryName) - and (:topicId IS NULL or t.id = :topicId) - and (:ratingStar IS NULL or - (select avg(r.ratingStar) - from Review r - join r.course rc - where rc.id = c.id - group by rc.id) >= :ratingStar) - and c.status = 'PUBLISHED' - """) - Page findByMultiQueryWithKeyword(Pageable pageable, - @Param("title") String title, - @Param("ratingStar") Float ratingStar, - @Param("level") String[] level, - @Param("free") Boolean[] free, - @Param("categoryName") String categoryName, - @Param("topicId") Integer topicId + + +// @Query(value = """ +// select c +// from Course c +// join fetch c.category cat +// left join fetch cat.parent p +// join fetch c.topic t +// join fetch c.user u +// left join fetch c.reviews +// where LOWER(c.title) LIKE LOWER(CONCAT('%', :title, '%')) +// and (:level IS NULL or c.level in :level) +// and (:free IS NULL or c.free in :free) +// and (:categoryName IS NULL or cat.name = :categoryName or p.name = :categoryName) +// and (:topicId IS NULL or t.id = :topicId) +// and (:ratingStar IS NULL or +// (select avg(r.ratingStar) +// from Review r +// join r.course rc +// where rc.id = c.id +// group by rc.id) >= :ratingStar) +// and c.status = 'PUBLISHED' +// """) +// Page findByMultiQueryWithKeyword(Pageable pageable, +// @Param("title") String title, +// @Param("ratingStar") Float ratingStar, +// @Param("level") String[] level, +// @Param("free") Boolean[] free, +// @Param("categoryName") String categoryName, +// @Param("topicId") Integer topicId +// ); + + @EntityGraph(attributePaths = {"category","category.parent","topic","user"}) + @Query( + value = """ + SELECT c + FROM Course c + JOIN c.category cat + LEFT JOIN cat.parent p + JOIN c.topic t + JOIN c.user u + WHERE + (:title IS NULL OR :title = '' OR LOWER(c.title) LIKE LOWER(CONCAT('%', :title, '%'))) + AND (:levels IS NULL OR c.level IN :levels) + AND (:freeFlags IS NULL OR c.free IN :freeFlags) + AND (:categoryName IS NULL OR cat.name = :categoryName OR p.name = :categoryName) + AND (:topicId IS NULL OR t.id = :topicId) + AND c.status = 'PUBLISHED' + AND ( + :ratingStar IS NULL OR + (SELECT COALESCE(AVG(r.ratingStar), 0) + FROM Review r + WHERE r.course = c) >= :ratingStar + ) + ORDER BY c.createdAt DESC, c.id DESC + """, + countQuery = """ + SELECT COUNT(c) + FROM Course c + JOIN c.category cat + LEFT JOIN cat.parent p + JOIN c.topic t + WHERE + (:title IS NULL OR :title = '' OR LOWER(c.title) LIKE LOWER(CONCAT('%', :title, '%'))) + AND (:levels IS NULL OR c.level IN :levels) + AND (:freeFlags IS NULL OR c.free IN :freeFlags) + AND (:categoryName IS NULL OR cat.name = :categoryName OR p.name = :categoryName) + AND (:topicId IS NULL OR t.id = :topicId) + AND c.status = 'PUBLISHED' + AND ( + :ratingStar IS NULL OR + (SELECT COALESCE(AVG(r.ratingStar), 0) + FROM Review r + WHERE r.course = c) >= :ratingStar + ) + """ + ) + Page findByMultiQueryWithKeyword( + Pageable pageable, + @Param("title") String title, + @Param("ratingStar") Float ratingStar, + @Param("levels") Collection levels, + @Param("freeFlags") Collection freeFlags, + @Param("categoryName") String categoryName, + @Param("topicId") Integer topicId ); + @Query(value = """ select c from Course c @@ -296,4 +356,10 @@ WHERE c.id NOT IN ( """, nativeQuery = true) List findCoursesNotInPromotionToday(@Param("promotionId") Long promotionId); + + + Optional findByTitle(String title); + + + } diff --git a/src/main/java/com/backend/elearning/domain/course/CourseService.java b/src/main/java/com/backend/elearning/domain/course/CourseService.java index 7367d7ec..ac4302ae 100644 --- a/src/main/java/com/backend/elearning/domain/course/CourseService.java +++ b/src/main/java/com/backend/elearning/domain/course/CourseService.java @@ -22,8 +22,8 @@ PageableData getCoursesByMultiQuery(int pageNum, int pageSize, String title, Float rating, - String[] level, - Boolean[] free, + List level, + List free, String categoryName, Integer topicId ); diff --git a/src/main/java/com/backend/elearning/domain/course/CourseServiceImpl.java b/src/main/java/com/backend/elearning/domain/course/CourseServiceImpl.java index e7734364..bd2aaf32 100644 --- a/src/main/java/com/backend/elearning/domain/course/CourseServiceImpl.java +++ b/src/main/java/com/backend/elearning/domain/course/CourseServiceImpl.java @@ -346,15 +346,15 @@ public PageableData getCoursesByMultiQuery(int pageNum, int pageSize, String title, Float rating, - String[] level, - Boolean[] free, + List level, + List free, String categoryName, Integer topicId ) { log.info("received pageNum: {}, pageSize: {}, title: {}, rating: {}, level: {}, free: {}, categoryName: {}, " + "topicId: {}", pageNum, pageSize, title, rating, level, free, categoryName, topicId); Pageable pageable = PageRequest.of(pageNum, pageSize); - Page coursePage = courseRepositoryCustom.findByMultiFilter(title, rating, level, free, categoryName, topicId, pageable); + Page coursePage = courseRepository.findByMultiQueryWithKeyword(pageable, title, rating, level, free, categoryName, topicId) ; List courses = coursePage.getContent(); List courseListGetVMS = courses.stream().map(course -> { course = courseRepository.findByIdWithPromotions(course).orElseThrow(() -> new NotFoundException(Constants.ERROR_CODE.COURSE_NOT_FOUND)); diff --git a/src/main/java/com/backend/elearning/domain/review/Review.java b/src/main/java/com/backend/elearning/domain/review/Review.java index 22a90410..b81548e8 100644 --- a/src/main/java/com/backend/elearning/domain/review/Review.java +++ b/src/main/java/com/backend/elearning/domain/review/Review.java @@ -9,12 +9,12 @@ import java.time.LocalDateTime; @Entity -@Table(name = "review") @Setter @Getter @AllArgsConstructor @NoArgsConstructor @Builder +@Table(name = "review") public class Review extends AbstractAuditEntity { @Id diff --git a/src/main/java/com/backend/elearning/domain/topic/Topic.java b/src/main/java/com/backend/elearning/domain/topic/Topic.java index 354ec55d..9b50651a 100644 --- a/src/main/java/com/backend/elearning/domain/topic/Topic.java +++ b/src/main/java/com/backend/elearning/domain/topic/Topic.java @@ -10,12 +10,12 @@ import java.util.Set; @Entity -@Table(name = "topic") @AllArgsConstructor @NoArgsConstructor @Getter @Setter @Builder +@Table(name = "topic") public class Topic extends AbstractAuditEntity { @Id diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 1fad9102..1583797b 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -21,7 +21,7 @@ spring: format_sql: 'true' hibernate: ddl-auto: update - show-sql: 'true' + show-sql: true cloudinary: api: secret: u3aoCSJzt31lcqOJBsgykwTq81o