-
Notifications
You must be signed in to change notification settings - Fork 4
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
상호 평가 반영 스케줄링 #602
상호 평가 반영 스케줄링 #602
Changes from all commits
7d52e17
d702770
27225ae
82fd135
f5d617c
c7cbc7e
99775b6
95bee2b
0b25861
d93a65e
d68496a
33552e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.ddang.ddang.configuration; | ||
|
||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.scheduling.annotation.EnableScheduling; | ||
|
||
@Configuration | ||
@EnableScheduling | ||
public class SchedulingConfiguration { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.ddang.ddang.review.domain; | ||
|
||
import com.ddang.ddang.user.domain.User; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.ToString; | ||
|
||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import static java.util.stream.Collectors.toSet; | ||
|
||
@RequiredArgsConstructor | ||
@Getter | ||
@ToString | ||
public class Reviews { | ||
|
||
private final List<Review> reviews; | ||
|
||
public double addAllReviewScore() { | ||
return reviews.stream() | ||
.mapToDouble(review -> review.getScore().getValue()) | ||
.sum(); | ||
} | ||
|
||
public int size() { | ||
return reviews.size(); | ||
} | ||
|
||
public boolean isEmpty() { | ||
return reviews.isEmpty(); | ||
} | ||
|
||
public Set<User> findReviewTargets() { | ||
return reviews.stream() | ||
.map(Review::getTarget) | ||
.collect(toSet()); | ||
} | ||
|
||
public List<Review> findReviewsByTarget(final User targetUser) { | ||
return reviews.stream() | ||
.filter(review -> review.getTarget().equals(targetUser)) | ||
.toList(); | ||
} | ||
|
||
public Long findLastReviewId() { | ||
final int lastIndex = reviews.size() - 1; | ||
|
||
return reviews.get(lastIndex) | ||
.getId(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,11 +12,15 @@ public interface JpaReviewRepository extends JpaRepository<Review, Long> { | |
boolean existsByAuctionIdAndWriterId(final Long auctionId, final Long writerId); | ||
|
||
@Query(""" | ||
SELECT r FROM Review r JOIN FETCH r.writer w JOIN FETCH r.target t | ||
SELECT r FROM Review r | ||
JOIN FETCH r.writer w | ||
JOIN FETCH r.target t | ||
WHERE t.id = :targetId | ||
ORDER BY r.id DESC | ||
""") | ||
List<Review> findAllByTargetId(final Long targetId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 선택? 필수?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아무 생각 없었어요 ㅠ 개행 추가했습니다. |
||
|
||
Optional<Review> findByAuctionIdAndWriterId(final Long auctionId, final Long writerId); | ||
|
||
List<Review> findAllByIdGreaterThan(final Long id); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package com.ddang.ddang.user.application.schedule; | ||
|
||
import com.ddang.ddang.review.domain.Review; | ||
import com.ddang.ddang.review.domain.Reviews; | ||
import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; | ||
import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; | ||
import com.ddang.ddang.user.domain.User; | ||
import com.ddang.ddang.user.domain.UserReliability; | ||
import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; | ||
import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.scheduling.annotation.Scheduled; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
import java.util.Set; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class ReliabilityUpdateSchedulingService { | ||
|
||
private final JpaReliabilityUpdateHistoryRepository updateHistoryRepository; | ||
private final JpaReviewRepository reviewRepository; | ||
private final JpaUserReliabilityRepository userReliabilityRepository; | ||
|
||
@Transactional | ||
@Scheduled(cron = "0 0 4 ? * MON") | ||
public void updateAllUserReliability() { | ||
final ReliabilityUpdateHistory updateHistory = updateHistoryRepository.findFirstByOrderByIdDesc() | ||
.orElse(new ReliabilityUpdateHistory()); | ||
final Long lastAppliedReviewId = updateHistory.getLastAppliedReviewId(); | ||
final List<Review> findNewReviews = reviewRepository.findAllByIdGreaterThan(lastAppliedReviewId); | ||
final Reviews newReviews = new Reviews(findNewReviews); | ||
|
||
if (newReviews.isEmpty()) { | ||
return; | ||
} | ||
|
||
update(newReviews); | ||
} | ||
|
||
private void update(final Reviews newReviews) { | ||
final Set<User> targetUsers = newReviews.findReviewTargets(); | ||
for (final User targetUser : targetUsers) { | ||
final UserReliability userReliability = userReliabilityRepository.findByUserId(targetUser.getId()) | ||
.orElseGet(() -> createUserReliability(targetUser)); | ||
|
||
final List<Review> targetReviews = newReviews.findReviewsByTarget(targetUser); | ||
|
||
userReliability.updateReliability(new Reviews(targetReviews)); | ||
} | ||
|
||
final ReliabilityUpdateHistory newHistory = new ReliabilityUpdateHistory(newReviews.findLastReviewId()); | ||
|
||
updateHistoryRepository.save(newHistory); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 선택개행..? |
||
} | ||
|
||
private UserReliability createUserReliability(final User user) { | ||
final UserReliability userReliability = new UserReliability(user); | ||
|
||
return userReliabilityRepository.save(userReliability); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,29 @@ | ||
package com.ddang.ddang.user.domain; | ||
|
||
import com.ddang.ddang.review.domain.Review; | ||
import jakarta.persistence.Embeddable; | ||
import lombok.AccessLevel; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
import java.util.List; | ||
|
||
@Embeddable | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
@EqualsAndHashCode | ||
@ToString | ||
public class Reliability { | ||
|
||
public static final Reliability INITIAL_RELIABILITY = new Reliability(null); | ||
private static final double INITIAL_RELIABILITY_VALUE = Double.MIN_VALUE; | ||
public static final Reliability INITIAL_RELIABILITY = new Reliability(INITIAL_RELIABILITY_VALUE); | ||
|
||
private Double value; | ||
private double value; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 칭찬원시타입으로 바꿔주셔서 마음이 굉장히 편안해졌어요 감사합니다@@ |
||
|
||
public Reliability(final Double value) { | ||
public Reliability(final double value) { | ||
this.value = value; | ||
} | ||
|
||
public void updateReliability(final List<Review> reviews) { | ||
if (reviews.isEmpty()) { | ||
this.value = null; | ||
|
||
return; | ||
} | ||
|
||
this.value = reviews.stream() | ||
.mapToDouble(review -> review.getScore().getValue()) | ||
.average() | ||
.orElseGet(null); | ||
public double calculateReviewScoreSum(final int appliedReviewCount) { | ||
return value * appliedReviewCount; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.ddang.ddang.user.domain; | ||
|
||
import com.ddang.ddang.common.entity.BaseCreateTimeEntity; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
@Entity | ||
@NoArgsConstructor | ||
@Getter | ||
@EqualsAndHashCode(of = "id", callSuper = false) | ||
@ToString(of = {"id", "lastAppliedReviewId"}) | ||
public class ReliabilityUpdateHistory extends BaseCreateTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
private Long lastAppliedReviewId = 0L; | ||
|
||
public ReliabilityUpdateHistory(final Long lastAppliedReviewId) { | ||
this.lastAppliedReviewId = lastAppliedReviewId; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.ddang.ddang.user.domain; | ||
|
||
import com.ddang.ddang.review.domain.Reviews; | ||
import jakarta.persistence.AttributeOverride; | ||
import jakarta.persistence.CascadeType; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embedded; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.ForeignKey; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.OneToOne; | ||
import lombok.AccessLevel; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
@EqualsAndHashCode(of = "id", callSuper = false) | ||
@ToString(of = {"id", "reliability", "appliedReviewCount"}) | ||
public class UserReliability { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) | ||
@JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_user_reliability_user"), nullable = false) | ||
private User user; | ||
|
||
@Embedded | ||
@AttributeOverride(name = "value", column = @Column(name = "reliability")) | ||
private Reliability reliability; | ||
|
||
private int appliedReviewCount = 0; | ||
|
||
public UserReliability(final User user) { | ||
this.user = user; | ||
this.reliability = user.getReliability(); | ||
} | ||
|
||
public void updateReliability(final Reviews newReviews) { | ||
if (newReviews.isEmpty()) { | ||
return; | ||
} | ||
final Reliability newReliability = calculateNewReliability(newReviews); | ||
|
||
this.reliability = newReliability; | ||
addAppliedReviewCount(newReviews.size()); | ||
user.updateReliability(newReliability); | ||
} | ||
|
||
private Reliability calculateNewReliability(final Reviews newReviews) { | ||
final double currentReviewScoreSum = reliability.calculateReviewScoreSum(appliedReviewCount); | ||
final double newReviewScoreSum = newReviews.addAllReviewScore(); | ||
final int allReviewCount = appliedReviewCount + newReviews.size(); | ||
|
||
final double newReliabilityValue = (currentReviewScoreSum + newReviewScoreSum) / allReviewCount; | ||
|
||
return new Reliability(newReliabilityValue); | ||
} | ||
|
||
private void addAppliedReviewCount(final int newReviewCount) { | ||
this.appliedReviewCount += newReviewCount; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.ddang.ddang.user.infrastructure.persistence; | ||
|
||
import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface JpaReliabilityUpdateHistoryRepository extends JpaRepository<ReliabilityUpdateHistory, Long> { | ||
|
||
Optional<ReliabilityUpdateHistory> findFirstByOrderByIdDesc(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.ddang.ddang.user.infrastructure.persistence; | ||
|
||
import com.ddang.ddang.user.domain.UserReliability; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface JpaUserReliabilityRepository extends JpaRepository<UserReliability, Long> { | ||
|
||
Optional<UserReliability> findByUserId(final Long userId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
create table reliability_update_history | ||
( | ||
id bigint not null auto_increment, | ||
created_time datetime(6) not null, | ||
last_applied_review_id bigint, | ||
primary key (id) | ||
); | ||
|
||
create table user_reliability | ||
( | ||
id bigint not null auto_increment, | ||
applied_review_count integer not null, | ||
reliability float(53), | ||
user_id bigint not null, | ||
primary key (id) | ||
); | ||
|
||
alter table user_reliability add constraint fk_user_reliability_user foreign key (user_id) references users (id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
칭찬
칭찬해요!!!!!!!!!!!!!!!!!!!!!!!!!!
테스트 시 설정 파일을 exclude하는 것만으로도 깔끔하게 분리할 수 있겠네요