Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] issue129: 원하는 갯수만큼 작성된 후기 조회 #136

Merged
merged 4 commits into from
Jul 29, 2022
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,15 +1,19 @@
package com.woowacourse.moamoa.common.advice;

import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;

import com.woowacourse.moamoa.common.advice.response.ErrorResponse;
import com.woowacourse.moamoa.common.exception.InvalidFormatException;
import com.woowacourse.moamoa.common.exception.UnauthorizedException;
import com.woowacourse.moamoa.study.domain.exception.InvalidPeriodException;
import com.woowacourse.moamoa.study.service.exception.FailureParticipationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

@RestControllerAdvice
public class CommonControllerAdvice {
Expand All @@ -23,8 +27,22 @@ public ResponseEntity<ErrorResponse> handleBadRequest(final Exception e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}

@ExceptionHandler({
MethodArgumentTypeMismatchException.class,
HttpMessageNotReadableException.class
})
public ResponseEntity<ErrorResponse> handleBadRequest() {
return ResponseEntity.badRequest().body(new ErrorResponse("잘못된 요청 형식입니다."));
}

@ExceptionHandler
public ResponseEntity<Void> handleUnauthorized(final UnauthorizedException e) {
return ResponseEntity.status(UNAUTHORIZED).build();
}

@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleInternalServerError(RuntimeException e) {
e.printStackTrace();
return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(new ErrorResponse("요청을 처리할 수 없습니다."));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.woowacourse.moamoa.review.controller;

import com.woowacourse.moamoa.review.service.ReviewService;
import com.woowacourse.moamoa.review.service.request.SizeRequest;
import com.woowacourse.moamoa.review.service.response.ReviewsResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand All @@ -20,10 +21,9 @@ public class ReviewController {
@GetMapping("/{study-id}/reviews")
public ResponseEntity<ReviewsResponse> getReviews(
@PathVariable(name = "study-id") Long studyId,
@RequestParam(required = false) Integer size
@RequestParam(name = "size", required = false, defaultValue = "") SizeRequest sizeRequest
Comment on lines -23 to +24
Copy link
Collaborator

Choose a reason for hiding this comment

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

SizeRequest 라는 DTO로 감싸주었군요..!!
기존의 @RequestParam(required = false) Integer size 와는 어떤 차이가 있는지 궁금합니다!!

) {
final ReviewsResponse reviewsResponse = reviewService.getReviewsByStudy(studyId, size);

final ReviewsResponse reviewsResponse = reviewService.getReviewsByStudy(studyId, sizeRequest);
return ResponseEntity.ok(reviewsResponse);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.woowacourse.moamoa.review.controller.converter;

import com.woowacourse.moamoa.review.service.request.SizeRequest;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class SizeRequestConverter implements Converter<String, SizeRequest> {

@Override
public SizeRequest convert(final String source) {
return source.isBlank() ? SizeRequest.empty() : new SizeRequest(Integer.parseInt(source));
}
Comment on lines +10 to +13
Copy link
Collaborator

Choose a reason for hiding this comment

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

음..빈 값을 포함한 요청일 때마다 Converter 가 추가된다면 관리가 힘들지 않을까하는 생각이 들어요..ㅠ.ㅠ🥲

Copy link
Collaborator

Choose a reason for hiding this comment

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

아래에도 CategoryIdConverter가 있던데 비슷한 처리를 할 때마다 Converter를 만드는 방법 이외에 더 좋은 방법은 없을까요?? 아니면 혹시 Converter가 꼭 필요한 이유가 있을까요?

}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.woowacourse.moamoa.review.query;

import com.woowacourse.moamoa.member.query.data.MemberData;
import com.woowacourse.moamoa.review.query.data.ReviewData;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class ReviewDao {

private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public List<ReviewData> findAllByStudyId(final Long studyId) {
String sql = "SELECT review.id, review.content, review.created_date, review.last_modified_date, "
+ "member.github_id, member.username, member.image_url, member.profile_url "
+ "FROM review JOIN member ON review.member_id = member.id "
+ "WHERE review.study_id = :studyId";

return namedParameterJdbcTemplate.query(sql, Map.of("studyId", studyId), rowMapper());
}

private RowMapper<ReviewData> rowMapper() {
return (rs, rn) -> {
final Long reviewId = rs.getLong("id");
final String content = rs.getString("content");
final LocalDate createdDate = rs.getObject("created_date", LocalDate.class);
final LocalDate lastModifiedDate = rs.getObject("last_modified_date", LocalDate.class);
final Long githubId = rs.getLong("github_id");
final String username = rs.getString("username");
final String imageUrl = rs.getString("image_url");
final String profileUrl = rs.getString("profile_url");
return new ReviewData(reviewId, new MemberData(githubId, username, imageUrl, profileUrl),
createdDate, lastModifiedDate, content);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.woowacourse.moamoa.review.query.data;

import com.woowacourse.moamoa.member.query.data.MemberData;
import java.time.LocalDate;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode
public class ReviewData {

private Long id;
private MemberData member;
private LocalDate createdDate;
private LocalDate lastModifiedDate;
private String content;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package com.woowacourse.moamoa.review.service;

import static java.util.stream.Collectors.toList;

import com.woowacourse.moamoa.review.domain.AssociatedStudy;
import com.woowacourse.moamoa.review.domain.Review;
import com.woowacourse.moamoa.review.domain.repository.ReviewRepository;
import com.woowacourse.moamoa.review.service.response.ReviewResponse;
import com.woowacourse.moamoa.review.query.ReviewDao;
import com.woowacourse.moamoa.review.query.data.ReviewData;
import com.woowacourse.moamoa.review.service.request.SizeRequest;
import com.woowacourse.moamoa.review.service.response.ReviewsResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand All @@ -17,25 +14,16 @@
@RequiredArgsConstructor
public class ReviewService {

private final ReviewRepository reviewRepository;

public ReviewsResponse getReviewsByStudy(Long studyId, Integer size) {
final AssociatedStudy associatedStudy = new AssociatedStudy(studyId);
private final ReviewDao reviewDao;

final List<Review> reviews = reviewRepository.findAllByAssociatedStudy(associatedStudy);
public ReviewsResponse getReviewsByStudy(Long studyId, SizeRequest sizeRequest) {
final List<ReviewData> allReviews = reviewDao.findAllByStudyId(studyId);

if (size != null) {
return makeReviewsResponse(reviews.subList(0, size), reviews.size());
if (sizeRequest.isEmpty() || sizeRequest.isMoreThan(allReviews.size())) {
return new ReviewsResponse(allReviews);
Comment on lines +22 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

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

단순 Integer가 아닌 DTO로 관리하니 isMoreThan 과 같은 메소드 호라용이 가능하군요..!!

}

return makeReviewsResponse(reviews, reviews.size());
return new ReviewsResponse(allReviews.subList(0, sizeRequest.getValue()), allReviews.size());
}

private ReviewsResponse makeReviewsResponse(final List<Review> reviews, final int totalCount) {
final List<ReviewResponse> reviewResponses = reviews.stream()
.map(ReviewResponse::new)
.collect(toList());

return new ReviewsResponse(reviewResponses, totalCount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.woowacourse.moamoa.review.service.request;

public class SizeRequest {

private final Integer value;

private SizeRequest() {
value = null;
}

public SizeRequest(final int value) {
this.value = value;
}

public Integer getValue() {
return value;
}

public boolean isEmpty() {
return value == null;
}

public boolean isMoreThan(int value) {
if (isEmpty()) {
throw new IllegalStateException("SizeRequest에 value가 null 입니다.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

BadRequestException을 상속하는 예외 클래스를 만들어도 좋을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

500 응답을 던지도록 ControllerAdvice 수정

}
return getValue() > value;
}

public static SizeRequest empty() {
return new SizeRequest();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,30 @@

import com.woowacourse.moamoa.member.query.data.MemberData;
import com.woowacourse.moamoa.review.domain.Review;
import com.woowacourse.moamoa.review.query.data.ReviewData;
import java.time.LocalDate;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode
@ToString
public class ReviewResponse {

private Long id;
private MemberData member;
private String createdDate;
private String lastModifiedDate;
private WriterResponse member;
private LocalDate createdDate;
private LocalDate lastModifiedDate;
private String content;

public ReviewResponse(Review review) {
this.id = review.getId();
this.member = new MemberData(review.getMember().getGithubId(), review.getMember().getUsername(),
review.getMember().getImageUrl(), review.getMember().getProfileUrl());
this.createdDate = review.getCreatedDate().toLocalDate().toString();
this.lastModifiedDate = review.getLastModifiedDate().toLocalDate().toString();
this.content = review.getContent();
public ReviewResponse(final ReviewData reviewData) {
this(reviewData.getId(), new WriterResponse(reviewData.getMember()), reviewData.getCreatedDate(),
reviewData.getLastModifiedDate(), reviewData.getContent());
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
package com.woowacourse.moamoa.review.service.response;

import com.woowacourse.moamoa.review.query.data.ReviewData;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ReviewsResponse {

private List<ReviewResponse> reviews;
private Integer totalResults;

public ReviewsResponse(final List<ReviewData> reviews, final Integer totalResults) {
this.reviews = reviews.stream()
.map(ReviewResponse::new)
.collect(Collectors.toList());
this.totalResults = totalResults;
}

public ReviewsResponse(final List<ReviewData> reviews) {
this.reviews = reviews.stream()
.map(ReviewResponse::new)
.collect(Collectors.toList());
totalResults = reviews.size();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.woowacourse.moamoa.review.service.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.woowacourse.moamoa.member.query.data.MemberData;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor
@EqualsAndHashCode
public class WriterResponse {

@JsonProperty("id")
private Long githubId;

private String username;

private String imageUrl;

private String profileUrl;

public WriterResponse(MemberData memberData) {
this(memberData.getGithubId(), memberData.getUsername(), memberData.getImageUrl(), memberData.getProfileUrl());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.woowacourse.moamoa.tag.controller;

import com.woowacourse.moamoa.tag.query.request.CategoryIdRequest;
import com.woowacourse.moamoa.tag.service.SearchingTagService;
import com.woowacourse.moamoa.tag.service.response.TagsResponse;
import java.util.Optional;
Expand All @@ -18,8 +19,8 @@ public class SearchingTagController {
@GetMapping("/api/tags")
public ResponseEntity<TagsResponse> searchTags(
@RequestParam(value = "name", required = false, defaultValue = "") final String tagShortName,
@RequestParam(value = "category", required = false, defaultValue = "") final Optional<Long> categoryId) {
final TagsResponse tagsResponse = searchingTagService.getBy(tagShortName, categoryId);
@RequestParam(value = "category", required = false, defaultValue = "") final CategoryIdRequest categoryIdRequest) {
final TagsResponse tagsResponse = searchingTagService.getBy(tagShortName, categoryIdRequest);
return ResponseEntity.ok().body(tagsResponse);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.woowacourse.moamoa.tag.controller.converter;

import com.woowacourse.moamoa.tag.query.request.CategoryIdRequest;
import java.util.Optional;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class CategoryIdConverter implements Converter<String, Optional<Long>> {
public class CategoryIdConverter implements Converter<String, CategoryIdRequest> {

@Override
public Optional<Long> convert(final String source) {
return source.isBlank() ? Optional.empty() : Optional.of(Long.valueOf(source));
public CategoryIdRequest convert(final String source) {
return source.isBlank() ? CategoryIdRequest.empty() : new CategoryIdRequest(Long.parseLong(source));
}
}
Loading