Skip to content

Commit

Permalink
Merge pull request #11 from sopt-makers/feat/#10-review-api
Browse files Browse the repository at this point in the history
[Feat]:Review 조회 기능 v2 API 마이그레이션 작업
  • Loading branch information
softmoca authored Dec 16, 2024
2 parents e929e76 + f6c405b commit 8947860
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 9 deletions.
18 changes: 18 additions & 0 deletions src/main/java/sopt/org/homepage/common/mapper/ResponseMapper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sopt.org.homepage.common.mapper;

import org.springframework.stereotype.Component;
import sopt.org.homepage.review.entity.ReviewEntity;
import sopt.org.homepage.internal.crew.dto.CrewMeetingVo;
import sopt.org.homepage.internal.crew.dto.StudyResponse;
import sopt.org.homepage.internal.playground.dto.PlaygroundProjectDetailResponse;
Expand All @@ -12,6 +13,7 @@
import sopt.org.homepage.project.dto.response.ProjectDetailResponseDto;
import sopt.org.homepage.project.dto.response.ProjectsResponseDto;
import sopt.org.homepage.project.dto.type.LinkType;
import sopt.org.homepage.review.dto.response.ReviewsResponseDto;
import sopt.org.homepage.semester.dto.SemesterDao;
import sopt.org.homepage.semester.dto.SemestersListResponse;

Expand Down Expand Up @@ -98,4 +100,20 @@ public ProjectDetailResponseDto toProjectDetailResponse(PlaygroundProjectDetailR
.members(members)
.build();
}

public ReviewsResponseDto toReviewResponseDto(ReviewEntity entity) {
return ReviewsResponseDto.builder()
.id(entity.getId())
.title(entity.getTitle())
.author(entity.getAuthor())
.authorProfileImageUrl(entity.getAuthorProfileImageUrl())
.generation(entity.getGeneration())
.description(entity.getDescription())
.part(entity.getPart())
.subject(entity.getSubject())
.thumbnailUrl(entity.getThumbnailUrl())
.platform(entity.getPlatform())
.url(entity.getUrl())
.build();
}
}
38 changes: 38 additions & 0 deletions src/main/java/sopt/org/homepage/common/type/Part.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package sopt.org.homepage.common.type;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;

@Getter
public enum Part {
iOS("iOS"),
PLAN("PLAN"),
DESIGN("DESIGN"),
SERVER("SERVER"),
ANDROID("ANDROID"),
WEB("WEB");

private final String value;

Part(String value) {
this.value = value;
}

@JsonValue
public String getValue() {
return value;
}
public static Part fromValue(String value) {
for (Part part : values()) {
if (part.getValue().equalsIgnoreCase(value)) {
return part;
}
}
throw new IllegalArgumentException("Unknown Part value: " + value);
}

@Override
public String toString() {
return this.value;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package sopt.org.homepage.project.dto.request;

import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import org.springframework.validation.annotation.Validated;
import sopt.org.homepage.common.dto.PaginateRequest;
import sopt.org.homepage.project.dto.type.ProjectType;
import sopt.org.homepage.project.dto.type.ServiceType;


@Schema(description = "리뷰 응답")
@Validated
@Getter
public class GetProjectsRequestDto extends PaginateRequest {
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/sopt/org/homepage/review/ReviewController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package sopt.org.homepage.review;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sopt.org.homepage.common.dto.PaginateResponseDto;
import sopt.org.homepage.review.dto.request.ReviewsRequestDto;
import sopt.org.homepage.review.dto.response.ReviewsResponseDto;

@Tag(name = "Reviews")
@RestController
@RequestMapping("reviews")
@RequiredArgsConstructor
public class ReviewController {

private final ReviewService reviewService;

@Operation(summary = "활동 후기 가져오기")
@GetMapping
public ResponseEntity<PaginateResponseDto<ReviewsResponseDto>> getReviews(
@ParameterObject @ModelAttribute ReviewsRequestDto reviewsRequestDto
) {
return ResponseEntity.ok(reviewService.getReviews(reviewsRequestDto));
}

@GetMapping("/random")
@Operation(summary = "랜덤 활동 후기 파트별로 하나씩 가져오기",
description = "만약 특정 파트에 리뷰가 없다면 그 파트의 데이터는 나오지 않습니다.")
public ResponseEntity<List<ReviewsResponseDto>> getRandomReviewByPart() {
return ResponseEntity.ok(reviewService.getRandomReviewByPart());
}
}
56 changes: 56 additions & 0 deletions src/main/java/sopt/org/homepage/review/ReviewService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package sopt.org.homepage.review;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sopt.org.homepage.common.dto.PaginateResponseDto;
import sopt.org.homepage.common.mapper.ResponseMapper;
import sopt.org.homepage.common.type.Part;
import sopt.org.homepage.review.dto.request.ReviewsRequestDto;
import sopt.org.homepage.review.dto.response.ReviewsResponseDto;
import sopt.org.homepage.review.repository.ReviewQueryRepository;
import sopt.org.homepage.review.repository.ReviewRepository;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ReviewService {

private final ReviewQueryRepository reviewQueryRepository;
private final ReviewRepository reviewRepository;

private final ResponseMapper responseMapper;

public PaginateResponseDto<ReviewsResponseDto> getReviews(ReviewsRequestDto requestDto) {
long totalCount = reviewQueryRepository.countWithFilters(requestDto);

var reviews = reviewQueryRepository.findAllWithFilters(
requestDto,
requestDto.getOffset(),
requestDto.getLimit()
);

var reviewDtos = reviews.stream()
.map(responseMapper::toReviewResponseDto)
.toList();

return new PaginateResponseDto<>(
reviewDtos,
(int) totalCount,
requestDto.getLimit(),
requestDto.getPageNo()
);
}

public List<ReviewsResponseDto> getRandomReviewByPart() {
return Arrays.stream(Part.values())
.map(reviewQueryRepository::findRandomReviewByPart)
.filter(Objects::nonNull)
.map(responseMapper::toReviewResponseDto)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package sopt.org.homepage.review.dto.request;

import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import org.springframework.validation.annotation.Validated;
import sopt.org.homepage.common.dto.PaginateRequest;
import sopt.org.homepage.common.type.Part;

@Validated
@Getter
@Schema(description = "리뷰 조회 요청")
public class ReviewsRequestDto extends PaginateRequest {
@Parameter(description = "Part, 전체를 불러올땐 아무값도 안넣으면 됩니다.")
private final Part part;

@Parameter(description = "활동기수로 필터링 합니다, 값을 넣지 않을 경우 전체 조회합니다.")
private final Integer generation;

public ReviewsRequestDto(Integer pageNo, Integer limit, Part part, Integer generation) {
super(pageNo, limit);
this.part = part;
this.generation = generation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package sopt.org.homepage.review.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
import sopt.org.homepage.common.type.Part;

@Schema(description = "리뷰 응답")
@Getter
public class ReviewsResponseDto {

@Schema(description = "리뷰 ID(item의 기본 키)")
private final Long id;

@Schema(description = "활동 리뷰 타이틀")
private final String title;

@Schema(description = "작성자")
private final String author;

@Schema(description = "작성자 프로필 이미지")
private final String authorProfileImageUrl;

@Schema(description = "활동 기수")
private final Integer generation;

@Schema(description = "활동후기 설명")
private final String description;

@Schema(description = "파트(활동 기수)")
private final Part part;

@Schema(description = "주제")
private final String subject;

@Schema(description = "썸네일 URL(활동후기 타이틀)")
private final String thumbnailUrl;

@Schema(description = "후기 작성 플랫폼")
private final String platform;

@Schema(description = "Redirect Link")
private final String url;

@Builder
private ReviewsResponseDto(Long id, String title, String author, String authorProfileImageUrl,
Integer generation, String description, Part part, String subject,
String thumbnailUrl, String platform, String url) {
this.id = id;
this.title = title;
this.author = author;
this.authorProfileImageUrl = authorProfileImageUrl;
this.generation = generation;
this.description = description;
this.part = part;
this.subject = subject;
this.thumbnailUrl = thumbnailUrl;
this.platform = platform;
this.url = url;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package sopt.org.homepage.entity;
package sopt.org.homepage.review.entity;

import jakarta.persistence.*;

import java.util.Objects;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import sopt.org.homepage.common.type.Part;
@Entity
@Getter
@Table(name = "\"Review\"")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ReviewEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "\"id\"", nullable = false)
private int id;
private Long id;
@Basic
@Column(name = "\"title\"", nullable = false, length = 200)
private String title;
Expand All @@ -20,9 +24,9 @@ public class ReviewEntity {
@Basic
@Column(name = "\"generation\"", nullable = false)
private int generation;
@Basic
@Enumerated(EnumType.STRING)
@Column(name = "\"part\"", nullable = false, length = 10)
private String part;
private Part part;
@Basic
@Column(name = "\"subject\"", nullable = false, length = 20)
private String subject;
Expand All @@ -41,5 +45,4 @@ public class ReviewEntity {
@Basic
@Column(name = "\"authorProfileImageUrl\"", nullable = true, length = 500)
private String authorProfileImageUrl;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package sopt.org.homepage.review.repository;

import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;


import sopt.org.homepage.common.type.Part;
import sopt.org.homepage.review.entity.QReviewEntity;
import sopt.org.homepage.review.entity.ReviewEntity;
import sopt.org.homepage.review.dto.request.ReviewsRequestDto;


@Repository
@RequiredArgsConstructor
public class ReviewQueryRepository {

private final JPAQueryFactory queryFactory;
private final QReviewEntity review = QReviewEntity.reviewEntity;

public List<ReviewEntity> findAllWithFilters(ReviewsRequestDto requestDto, long offset, int limit) {
var query = queryFactory
.selectFrom(review);

if (requestDto.getPart() != null) {
query.where(review.part.eq(requestDto.getPart()));
}

if (requestDto.getGeneration() != null) {
query.where(review.generation.eq(requestDto.getGeneration()));
}

return query
.orderBy(review.generation.desc())
.orderBy(review.author.asc())
.orderBy(review.id.asc())
.offset(offset)
.limit(limit)
.fetch();
}

public long countWithFilters(ReviewsRequestDto requestDto) {
var query = queryFactory
.select(review.count())
.from(review);

if (requestDto.getPart() != null) {
query.where(review.part.eq(requestDto.getPart()));
}

if (requestDto.getGeneration() != null) {
query.where(review.generation.eq(requestDto.getGeneration()));
}

return query.fetchOne();
}

public ReviewEntity findRandomReviewByPart(Part part) {
return queryFactory
.selectFrom(review)
.where(review.part.eq(part))
.orderBy(Expressions.numberTemplate(Double.class, "RANDOM()").asc())
.limit(1)
.fetchFirst();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package sopt.org.homepage.review.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import sopt.org.homepage.review.entity.ReviewEntity;

public interface ReviewRepository extends JpaRepository<ReviewEntity, Long> {
}

0 comments on commit 8947860

Please sign in to comment.