Skip to content

Commit db131cd

Browse files
authored
Merge pull request #83 from newsIntelligent/refactor/#82
refactor: 최신 수정 보도 조건 완화
2 parents a44633e + ab019b4 commit db131cd

File tree

5 files changed

+76
-80
lines changed

5 files changed

+76
-80
lines changed

src/main/java/UMC/news/newsIntelligent/domain/news/controller/NewsController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public CustomResponse<NewsResponseDTO.NewsResDTO> getRelatedNews(
4343
@RequestParam(defaultValue = "3") int size
4444
) {
4545
NewsResponseDTO.NewsResDTO response = newsQueryServiceImpl.getRelatedNews(topicId, lastId, size);
46-
return CustomResponse.onSuccess(SuccessCode.GET_TOPIC, response);
46+
return CustomResponse.onSuccess(SuccessCode.GET_NEWS, response);
4747
}
4848

4949
@Operation(summary = "최신 수정 보도 조회 API", description = "최신 수정된 기사 수가 3개 이상인 최신 토픽 하나를 반환합니다.")
@@ -53,7 +53,7 @@ public CustomResponse<NewsResponseDTO.NewsResDTO> getRelatedNews(
5353
@GetMapping("/latest")
5454
public CustomResponse<NewsResponseDTO.TopicQualifiedItemResDTO> getLatestTopic() {
5555
NewsResponseDTO.TopicQualifiedItemResDTO latestTopicNews = newsQueryServiceImpl.getLatestTopicNews();
56-
return CustomResponse.onSuccess(SuccessCode.GET_TOPIC, latestTopicNews);
56+
return CustomResponse.onSuccess(SuccessCode.GET_LATEST_TOPIC, latestTopicNews);
5757
}
5858

5959
}

src/main/java/UMC/news/newsIntelligent/domain/news/dto/NewsResponseDTO.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ public record NewsRelatedArticleDto (
4040
// “조건을 만족하는 토픽 묶음 중 최신 1개” 반환용 DTO
4141
public record TopicQualifiedItemResDTO(
4242
Long id,
43-
String title,
44-
String newsSummary,
43+
String topicName,
44+
String aiSummary,
4545
String imageUrl,
46-
LocalDateTime publishDate,
46+
LocalDateTime summaryTime,
4747
List<NewsRelatedArticleDto> relatedArticles
4848
) {}
4949
}
Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package UMC.news.newsIntelligent.domain.news.repository;
22

3+
import UMC.news.newsIntelligent.domain.news.dto.NewsResponseDTO;
34
import UMC.news.newsIntelligent.domain.news.entity.News;
45
import org.springframework.data.domain.Pageable;
56
import org.springframework.data.jpa.repository.JpaRepository;
@@ -24,37 +25,51 @@ List<News> findByTopicIdWithPaging(
2425

2526
int countByTopicId(Long topicId);
2627

27-
// @Query(value = """
28-
// SELECT *
29-
// FROM news n
30-
// WHERE n.is_new = 1
31-
// AND n.is_third = 0
32-
// AND n.topic_id IN (
33-
// SELECT topic_id
34-
// FROM news
35-
// WHERE is_new = 1 AND is_third = 0
36-
// GROUP BY topic_id
37-
// HAVING COUNT(*) >= 3
38-
// )
39-
// ORDER BY n.topic_id, n.publish_date
40-
// """, nativeQuery = true)
41-
// List<News> findLatestNews();
42-
28+
//토픽은 1개 (is_new true, is_third false)를 만족하는 뉴스가 단 하나라도 있다면 선택
4329
@Query(value = """
44-
SELECT n.*
45-
FROM news n
46-
JOIN (
47-
SELECT topic_id
48-
FROM news
49-
WHERE is_new = 1
50-
AND is_third = 0
51-
GROUP BY topic_id
52-
HAVING COUNT(*) >= 3
53-
ORDER BY COUNT(*) DESC, MAX(id) DESC -- 동률이면 id 큰 토픽 우선
30+
SELECT n.topic_id
31+
FROM news n
32+
WHERE n.is_new = 1
33+
AND n.is_third = 0
34+
GROUP BY n.topic_id
35+
ORDER BY COUNT(*) DESC, MAX(n.id) DESC
5436
LIMIT 1
55-
) t ON t.topic_id = n.topic_id
56-
WHERE n.is_new = 1
57-
AND n.is_third = 0
5837
""", nativeQuery = true)
59-
List<News> findArticlesOfTopTopicByCount();
38+
Long pickTopTopicIdByQualifiedNews();
39+
40+
/**
41+
* 토픽은 1개 (is_new true, is_third false)를 만족하는 뉴스가 단 하나라도 있다면 선택
42+
* 해당 토픽의 기사 3개를 반환하는데, 그중 하나는 (is_new true, is_third false)이 조건을 만족함
43+
* 나머지 2개는 조건 무관하게 최신순으로 리턴 기준 완화하려했으나,
44+
* sql구문이 매우 복잡해지고 잘못된 값을 불러서.. (is_new true, is_third false)를 만족하는 뉴스만큼 리턴함
45+
*/
46+
@Query(value = """
47+
SELECT n.*
48+
FROM news n
49+
WHERE n.topic_id = :topicId
50+
AND n.is_new = 1
51+
AND n.is_third = 0
52+
ORDER BY n.publish_date DESC, n.id DESC
53+
LIMIT 3
54+
""", nativeQuery = true)
55+
List<News> findTop3QualifiedNewsByTopicId(@Param("topicId") Long topicId);
56+
6057
}
58+
// @Query(value = """
59+
// SELECT n.*
60+
// FROM news n
61+
// JOIN (
62+
// SELECT topic_id
63+
// FROM news
64+
// WHERE is_new = 1
65+
// AND is_third = 0
66+
// GROUP BY topic_id
67+
// HAVING COUNT(*) >= 3
68+
// ORDER BY COUNT(*) DESC, MAX(id) DESC -- 동률이면 id 큰 토픽 우선
69+
// LIMIT 1
70+
// ) t ON t.topic_id = n.topic_id
71+
// WHERE n.is_new = 1
72+
// AND n.is_third = 0
73+
// """, nativeQuery = true)
74+
// List<News> findArticlesOfTopTopicByCount();
75+

src/main/java/UMC/news/newsIntelligent/domain/news/service/NewsQueryServiceImpl.java

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import UMC.news.newsIntelligent.domain.news.converter.NewsConverter;
44
import UMC.news.newsIntelligent.domain.news.dto.NewsResponseDTO;
5+
//import UMC.news.newsIntelligent.domain.news.entity.News;
56
import UMC.news.newsIntelligent.domain.news.entity.News;
67
import UMC.news.newsIntelligent.domain.news.entity.PressLogo;
78
import UMC.news.newsIntelligent.domain.news.repository.NewsRepository;
89
import UMC.news.newsIntelligent.domain.news.repository.PressLogoRepository;
10+
import UMC.news.newsIntelligent.domain.topic.entity.Topic;
11+
import UMC.news.newsIntelligent.domain.topic.repository.TopicRepository;
912
import UMC.news.newsIntelligent.global.apiPayload.code.error.ErrorCode;
1013
import UMC.news.newsIntelligent.global.apiPayload.exception.CustomException;
1114
import lombok.RequiredArgsConstructor;
@@ -25,6 +28,7 @@ public class NewsQueryServiceImpl implements NewsQueryService{
2528
private static final int MAX_PAGE_SIZE = 20;
2629
private static final String DEFAULT_LOGO = null; // 기본 로고
2730

31+
private final TopicRepository topicRepository;
2832
private final NewsRepository newsRepository;
2933
private final PressLogoRepository pressLogoRepository;
3034

@@ -51,55 +55,32 @@ public NewsResponseDTO.NewsResDTO getRelatedNews(Long topicId, Long lastId, int
5155
return new NewsResponseDTO.NewsResDTO(content, totalCount, newLastId, pageSize, hasNext);
5256
}
5357

54-
// 최신 수정 보도 (조건 만족 + 같은 topic_id로 3개 이상 중 '기사 수가 가장많은' 토픽 1개)
58+
// 최신 수정 보도 (조건 만족 + 같은 topic_id로 1개 이상인 토픽 1개)
5559
@Override
5660
public NewsResponseDTO.TopicQualifiedItemResDTO getLatestTopicNews() throws CustomException {
57-
List<News> latestNews = newsRepository.findArticlesOfTopTopicByCount();
58-
59-
if (latestNews.isEmpty()) {
60-
throw new CustomException(ErrorCode.LATEST_NEWS_NOT_FOUND);
61+
Long qualifiedTopic = newsRepository.pickTopTopicIdByQualifiedNews();
62+
if (qualifiedTopic == null) {
63+
throw new CustomException(ErrorCode.TOPIC_NOT_FOUND);
6164
}
6265

63-
// 최신순 정렬
64-
latestNews.sort(
65-
Comparator.comparing(News::getPublishDate)
66-
.thenComparing(News::getId)
67-
.reversed()
68-
);
69-
70-
Long topicId = latestNews.get(0).getTopic().getId();
71-
72-
// 대표 기사: 정렬 결과의 첫 번째(= 가장 최신 기사)
73-
News main = latestNews.get(0);
66+
Topic topic = topicRepository.findById(qualifiedTopic)
67+
.orElseThrow(() -> new CustomException(ErrorCode.TOPIC_NOT_FOUND));
7468

75-
List<NewsResponseDTO.NewsRelatedArticleDto> related = NewsConverter.toRelatedDtos(latestNews);
69+
List<News> relatedNewsEntity = newsRepository.findTop3QualifiedNewsByTopicId(qualifiedTopic);
70+
if (relatedNewsEntity.isEmpty()) {
71+
throw new CustomException(ErrorCode.LATEST_NEWS_NOT_FOUND);
72+
}
73+
List<NewsResponseDTO.NewsRelatedArticleDto> relatedNews =
74+
NewsConverter.toRelatedDtos(relatedNewsEntity);
7675

7776
return new NewsResponseDTO.TopicQualifiedItemResDTO(
78-
topicId,
79-
main.getTitle(),
80-
main.getNewsSummary(),
81-
main.getTopic().getImageUrl(),
82-
main.getPublishDate(),
83-
related
77+
topic.getId(),
78+
topic.getTopicName(),
79+
topic.getAiSummary(),
80+
topic.getImageUrl(),
81+
topic.getSummaryTime(),
82+
relatedNews
8483
);
85-
86-
// // topic_id 단위로 그룹핑
87-
// Map<Long, List<News>> byTopic = latestNews.stream()
88-
// .collect(Collectors.groupingBy(n -> n.getTopic().getId(), LinkedHashMap::new, Collectors.toList()));
89-
//
90-
// // 개수가 가장 많은 토픽 그룹 선택 (동률이면 첫 그룹)
91-
// Map.Entry<Long, List<News>> mostCountGroup = byTopic.entrySet().stream()
92-
// .max(Comparator.comparingInt(e -> e.getValue().size()))
93-
// .orElseThrow(() -> new CustomException(GeneralErrorCode.LATEST_NEWS_NOT_FOUND));
94-
//
95-
// Long topicId = mostCountGroup.getKey();
96-
// List<News> items = mostCountGroup.getValue();
97-
//
98-
// // 대표 기사: id가 가장 큰 기사
99-
// News main = items.stream()
100-
// .max(Comparator.comparing(News::getId))
101-
// .orElse(items.get(0));
102-
10384
}
10485

10586
private static int normalizeSize(int size) {
@@ -135,4 +116,4 @@ private static String normPress(String s) {
135116
if (t.isEmpty()) return null;
136117
return Normalizer.normalize(t, Normalizer.Form.NFC);
137118
}
138-
}
119+
}

src/main/java/UMC/news/newsIntelligent/global/apiPayload/code/success/SuccessCode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ public enum SuccessCode implements BaseSuccessCode{
2626

2727

2828
// 토픽
29-
GET_TOPIC(HttpStatus.OK, "TOPIC200", "토픽 상세 페이지 조회가 완료되었습니다."),
30-
GET_NEWS(HttpStatus.OK, "NEWS200", "토픽 출처 기사 목록 조회가 완료되었습니다."),
31-
GET_LATEST_TOPIC(HttpStatus.OK, "TOPIC200", "최신 수정 보도 조회가 완료되었습니다."),
29+
GET_TOPIC(HttpStatus.OK, "TOPIC_PAGE200", "토픽 상세 페이지 조회가 완료되었습니다."),
30+
GET_NEWS(HttpStatus.OK, "TOPIC_NEWS200", "토픽 출처 기사 목록 조회가 완료되었습니다."),
31+
GET_LATEST_TOPIC(HttpStatus.OK, "LATEST_TOPIC200", "최신 수정 보도 조회가 완료되었습니다."),
3232

3333
// 피드백
3434
FEEDBACK_CREATED(HttpStatus.CREATED, "FEEDBACK2001", "성공적으로 피드백이 생성했습니다.");

0 commit comments

Comments
 (0)