Skip to content

Commit

Permalink
Merge pull request #41 from SJU-CapstoneDesign/feat/#40NewsCategorySe…
Browse files Browse the repository at this point in the history
…rvice

Feat/#40 news category service
  • Loading branch information
ms0828 authored Nov 28, 2023
2 parents e2884aa + 2214296 commit b19abc8
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 66 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.example.d3nserver.common.annotation.ApiDocumentResponse;
import com.example.d3nserver.common.annotation.ReqUser;
import com.example.d3nserver.common.dto.ResponseDto;
import com.example.d3nserver.news.domain.Field;
import com.example.d3nserver.news.dto.NewsResponseDto;
import com.example.d3nserver.news.dto.TodayHomeResponseDto;
import com.example.d3nserver.news.service.NewsService;
import com.example.d3nserver.user.domain.User;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -17,6 +19,9 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@Tag(name = "News v1.1 API", description = "News 관련 api")
@RestController
@RequiredArgsConstructor
Expand All @@ -25,10 +30,17 @@ public class NewsV2Controller {
private final NewsService newsService;

@ApiDocumentResponse
@Operation(summary = "News list", description = "Page index와 Page 크기를 받아 뉴스 페이지를 반환한다. (secondTime은 데이터가 없으면 0, selectedAnswer는 -1을 반환)")
@Operation(summary = "All News list", description = "Page index와 Page 크기를 받아 요청한 카테고리의 뉴스 페이지를 반환한다. (secondTime은 데이터가 없으면 0, selectedAnswer는 null을 반환)")
@GetMapping("/list")
public ResponseEntity<Page<NewsResponseDto>> getAllNews(@ReqUser User user, @RequestParam @Parameter(description="페이지 인덱스, 0부터 시작")int pageIndex, @RequestParam @Parameter(description="페이지 크기")int pageSize) {
return ResponseDto.ok(newsService.getAllNewsDtoPageList(user, pageIndex, pageSize));
public ResponseEntity<Page<NewsResponseDto>> getAllNews(@ReqUser User user, @RequestParam @Parameter(description="페이지 인덱스, 0부터 시작")int pageIndex, @RequestParam @Parameter(description="페이지 크기")int pageSize, @RequestParam(value = "field", defaultValue = "DEFAULT") @Parameter(description = "뉴스 필드(News의 Enum 타입 Field 기입)(미기입 시 DEFAULT)")Field field) {
return ResponseDto.ok(newsService.getAllNewsPageList(user, pageIndex, pageSize, field));
}

@ApiDocumentResponse
@Operation(summary = "Today News List", description = "type이 Recent일 경우 최신 뉴스만 반환, type이 My일 경우 맞춤형 뉴스만 반환, 지정 하지 않을 시 모두 반환")
@GetMapping("/today/list")
public ResponseEntity<List<TodayHomeResponseDto>> getTodayNews(@ReqUser User user, @RequestParam(value = "type", defaultValue = "All") String type) {
return ResponseDto.ok(newsService.getTodayNewsList(user,type));
}

}
2 changes: 2 additions & 0 deletions src/main/java/com/example/d3nserver/news/domain/Field.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.d3nserver.news.domain;

public enum Field {
DEFAULT,
POLITICS,
ECONOMY,
SOCIETY,
Expand All @@ -11,4 +12,5 @@ public enum Field {
IT,
SCIENCE,
ENTERTAINMENTS

}
2 changes: 2 additions & 0 deletions src/main/java/com/example/d3nserver/news/domain/News.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.d3nserver.news.domain;

import com.example.d3nserver.common.annotation.ValidEnum;
import com.example.d3nserver.common.base.BaseEntity;
import com.example.d3nserver.mediaCompany.domain.MediaCompany;
import com.example.d3nserver.quiz.domain.Quiz;
Expand All @@ -14,6 +15,7 @@
public class News extends BaseEntity {
@Id
private Long id;
@ValidEnum(enumClass = Field.class)
@Enumerated(EnumType.STRING)
private Field field;
@Enumerated(EnumType.STRING)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.example.d3nserver.news.dto;

import com.example.d3nserver.common.annotation.ValidEnum;
import com.example.d3nserver.news.domain.Field;
import com.example.d3nserver.news.domain.News;
import com.example.d3nserver.news.domain.NewsType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.example.d3nserver.news.dto;

import lombok.Data;

import java.util.List;

@Data
public class TodayHomeResponseDto {
private String type;
private String title;
private String subtitle;
private List<NewsResponseDto> newsList;

public TodayHomeResponseDto(String type, List<NewsResponseDto> newsList){

if(type.equals("Recent")){
this.type = type;
this.title = "최신 뉴스";
this.subtitle = "최신 뉴스를 가져왔어요";
}
else if(type.equals("My")){
this.type = type;
this.title = "맞춤 뉴스";
this.subtitle = "맞춤형 뉴스를 가져왔어요";
}
this.newsList = newsList;
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package com.example.d3nserver.news.repository;

import com.example.d3nserver.news.domain.Field;
import com.example.d3nserver.news.domain.News;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface NewsRepository extends JpaRepository<News, Integer> {
List<News> findTop10ByOrderByCreatedAtDesc();
public interface NewsRepository extends JpaRepository<News, Long> {

@Query("SELECT n FROM News n ORDER BY n.createdAt DESC LIMIT :n")
List<News> findTopNByOrderByCreatedAtDesc(@Param("n") int cnt);
@Query("SELECT n FROM News n WHERE n.field = :field ORDER BY n.createdAt DESC LIMIT :n")
List<News> findTopNByField(@Param("field") Field field, @Param("n") int n);
Page<News> findAllNewsByOrderByCreatedAtDesc(Pageable pageable);
Page<News> findAllByFieldOrderByCreatedAtDesc(Field field, Pageable pageable);
}
90 changes: 72 additions & 18 deletions src/main/java/com/example/d3nserver/news/service/NewsService.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package com.example.d3nserver.news.service;

import com.example.d3nserver.common.annotation.ReqUser;
import com.example.d3nserver.news.dto.NewsDTO;
import com.example.d3nserver.common.dto.ResponseDto;
import com.example.d3nserver.news.domain.Field;
import com.example.d3nserver.news.domain.News;
import com.example.d3nserver.news.dto.NewsResponseDto;
import com.example.d3nserver.news.dto.TodayHomeResponseDto;
import com.example.d3nserver.news.repository.NewsRepository;
import com.example.d3nserver.quiz.dto.response.QuizResponseDto;
import com.example.d3nserver.quiz.service.QuizService;
import com.example.d3nserver.time.domain.NewsReadingTime;
import com.example.d3nserver.time.repository.NewsReadingTimeRepository;
import com.example.d3nserver.time.service.NewsReadingTimeService;
import com.example.d3nserver.user.domain.User;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import java.util.*;
import java.util.stream.Collectors;


Expand All @@ -25,26 +26,79 @@
public class NewsService {
private final NewsRepository newsRepository;
private final NewsReadingTimeRepository newsReadingTimeRepository;
private final NewsReadingTimeService newsReadingTimeService;
private final QuizService quizService;

public List<NewsDTO> getTodayNewsDtoList(){
List<NewsDTO> todayNewsDtoList = new ArrayList<>();
List<News> recentTenNews = newsRepository.findTop10ByOrderByCreatedAtDesc();
for(News news : recentTenNews){
NewsDTO newsDTO = new NewsDTO(news);
todayNewsDtoList.add(newsDTO);
public Page<NewsResponseDto> getAllNewsPageList(User user, int pageIndex, int pageSize, Field field){
Page<News> newsPage;
if(field == Field.DEFAULT)
newsPage = newsRepository.findAllNewsByOrderByCreatedAtDesc(PageRequest.of(pageIndex, pageSize));
else
newsPage = newsRepository.findAllByFieldOrderByCreatedAtDesc(field, PageRequest.of(pageIndex, pageSize));

return newsPage.map(news -> getResponseDto(user, news));
}

public List<TodayHomeResponseDto> getTodayNewsList(User user, String type){
List<TodayHomeResponseDto> responseDtoList = new ArrayList<>();
if(type.equals("Recent")){
responseDtoList.add(new TodayHomeResponseDto("Recent", getRecentNewsList(user)));
}
else if(type.equals("My")){
responseDtoList.add(new TodayHomeResponseDto("My", getUserReferencedNewsList(user)));
}
return todayNewsDtoList;
else{
responseDtoList.add(new TodayHomeResponseDto("Recent", getRecentNewsList(user)));
responseDtoList.add(new TodayHomeResponseDto("My", getUserReferencedNewsList(user)));
}
return responseDtoList;
}

public Page<NewsResponseDto> getAllNewsDtoPageListV1(int pageIndex, int pageSize){
Page<News> newsPage = newsRepository.findAllNewsByOrderByCreatedAtDesc(PageRequest.of(pageIndex, pageSize));
return newsPage.map(NewsResponseDto::new);
public List<NewsResponseDto> getRecentNewsList(User user){
List<News> todayNewsList = newsRepository.findTopNByOrderByCreatedAtDesc(3);
return todayNewsList.stream().map((news -> getResponseDto(user, news))).collect(Collectors.toList());
}

public Page<NewsResponseDto> getAllNewsDtoPageList(User user, int pageIndex, int pageSize){
Page<News> newsPage = newsRepository.findAllNewsByOrderByCreatedAtDesc(PageRequest.of(pageIndex, pageSize));
return newsPage.map(news -> getResponseDto(user, news));
public List<NewsResponseDto> getUserReferencedNewsList(User user){
List<NewsResponseDto> userReferencedNewsDtoList = new ArrayList<>();
Field mostReadingTimeField = newsReadingTimeService.getCategoryOfMostReadingTime(user);
List<Field> userFieldList = user.getNewsFields();
Collections.shuffle(userFieldList);
List<Field> preferencedFiledList = userFieldList.subList(0, Math.min(3, userFieldList.size()));
if(preferencedFiledList.size() == 1){
if(mostReadingTimeField == Field.DEFAULT)
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(0),10).stream().map(news -> getResponseDto(user,news)).toList());
else{
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(mostReadingTimeField,5).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(0),5).stream().map(news -> getResponseDto(user,news)).toList());
}
}
else if(preferencedFiledList.size() == 2){
if(mostReadingTimeField == Field.DEFAULT){
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(0),5).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(1),5).stream().map(news -> getResponseDto(user,news)).toList());
}
else{
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(mostReadingTimeField,4).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(0),3).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(1),3).stream().map(news -> getResponseDto(user,news)).toList());
}
}
else{
if(mostReadingTimeField == Field.DEFAULT){
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(0),3).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(1),3).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(2),4).stream().map(news -> getResponseDto(user,news)).toList());
}
else{
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(mostReadingTimeField,4).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(0),2).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(1),2).stream().map(news -> getResponseDto(user,news)).toList());
userReferencedNewsDtoList.addAll(newsRepository.findTopNByField(preferencedFiledList.get(2),2).stream().map(news -> getResponseDto(user,news)).toList());
}
}
Collections.shuffle(userReferencedNewsDtoList);
return userReferencedNewsDtoList;
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.example.d3nserver.time.domain;

import com.example.d3nserver.common.base.BaseEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import com.example.d3nserver.news.domain.News;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -14,12 +13,14 @@ public class NewsReadingTime extends BaseEntity {
@Id
@GeneratedValue
private Long id;
private Long newsId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "news_id")
private News news;
private String userId;
private Integer secondTime;

public NewsReadingTime(String userId, Long newsId){
this.newsId = newsId;
public NewsReadingTime(String userId, News news){
this.news = news;
this.userId = userId;
this.secondTime = 0;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package com.example.d3nserver.time.repository;

import com.example.d3nserver.news.domain.Field;
import com.example.d3nserver.time.domain.NewsReadingTime;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;


import java.util.List;
import java.util.Optional;

public interface NewsReadingTimeRepository extends JpaRepository<NewsReadingTime, Long> {
public Optional<NewsReadingTime> findByUserIdAndNewsId(String userId, Long newsId);
@Query("SELECT nrt FROM NewsReadingTime nrt JOIN FETCH nrt.news WHERE nrt.userId = :userId ORDER BY nrt.createdAt DESC")
List<NewsReadingTime> findTop10ByUserIdOrderByCreatedAtDesc(@Param("userId") String userId);

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,56 @@
package com.example.d3nserver.time.service;

import com.example.d3nserver.news.domain.Field;
import com.example.d3nserver.news.domain.News;
import com.example.d3nserver.news.repository.NewsRepository;
import com.example.d3nserver.time.domain.NewsReadingTime;
import com.example.d3nserver.time.repository.NewsReadingTimeRepository;
import com.example.d3nserver.user.domain.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;


@Service
@RequiredArgsConstructor
public class NewsReadingTimeService {
private final NewsReadingTimeRepository newsReadingTimeRepository;
private final NewsRepository newsRepository;

public void updateNewsReadingTime(User user, Long newsId, int secondTime){
NewsReadingTime readingTime = newsReadingTimeRepository.findByUserIdAndNewsId(user.getId(), newsId).orElseGet(
()-> new NewsReadingTime(user.getId(), newsId)
()-> {
Optional<News> news = newsRepository.findById(newsId);
return news.map(value -> new NewsReadingTime(user.getId(), value)).orElse(null);
}
);
if(readingTime == null)
return;
readingTime.updateReadingTime(secondTime);
newsReadingTimeRepository.save(readingTime);
}

public Field getCategoryOfMostReadingTime(User user){
Map<Field, Integer> categoryTimeMap = new HashMap<Field, Integer>();
List<NewsReadingTime> newsReadingTimeList = newsReadingTimeRepository.findTop10ByUserIdOrderByCreatedAtDesc(user.getId());
if(newsReadingTimeList.isEmpty())
return Field.DEFAULT;
int mostReadingTime = 0;
Field mostReadingTimeField = Field.DEFAULT;
for(NewsReadingTime readingTime : newsReadingTimeList) {
Field field = readingTime.getNews().getField();
if(categoryTimeMap.containsKey(field))
categoryTimeMap.put(field, categoryTimeMap.get(field) + readingTime.getSecondTime());
else
categoryTimeMap.put(field, readingTime.getSecondTime());
if (categoryTimeMap.get(field) > mostReadingTime) {
mostReadingTime = categoryTimeMap.get(field);
mostReadingTimeField = field;
}
}
return mostReadingTimeField;
}
}
Loading

0 comments on commit b19abc8

Please sign in to comment.