Skip to content

Commit

Permalink
feat(#14) : mainpage api
Browse files Browse the repository at this point in the history
  • Loading branch information
eojinny committed Nov 16, 2023
1 parent 51efcf9 commit 0c1bb66
Show file tree
Hide file tree
Showing 16 changed files with 291 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gwangjang.server.domain.Issue.application.dto.res;

import lombok.*;

@Getter
@Builder
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class IssueRes {
private String issueTitle;
private String topicTitle;
private String imgUrl;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package gwangjang.server.domain.morpheme.domain.entity;
package gwangjang.server.domain.Issue.domain.entity;


import jakarta.persistence.*;
import lombok.AllArgsConstructor;
Expand All @@ -15,7 +16,11 @@ public class Issue {
@Column(name = "issue_id")
private Long id;
private String issueTitle;

private String imgUrl;
@ManyToOne
@JoinColumn(name = "topic_id")
private Topic topic;


}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gwangjang.server.domain.morpheme.domain.entity;
package gwangjang.server.domain.Issue.domain.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package gwangjang.server.domain.Issue.domain.repository;

import gwangjang.server.domain.Issue.application.dto.res.IssueRes;
import org.springframework.stereotype.Repository;

import java.util.Optional;
@Repository
public interface IssueCustomRepository {
Optional<IssueRes> findIssueAndTopicById(Long issueId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gwangjang.server.domain.Issue.domain.repository;

import gwangjang.server.domain.Issue.domain.entity.Issue;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface IssueRepository extends JpaRepository<Issue, Long>, IssueCustomRepository{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package gwangjang.server.domain.Issue.domain.repository;

import com.querydsl.core.Tuple;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;


import gwangjang.server.domain.Issue.application.dto.res.IssueRes;
import gwangjang.server.domain.Issue.domain.entity.Issue;
import gwangjang.server.domain.Issue.domain.entity.QIssue;

import gwangjang.server.domain.Issue.domain.entity.QTopic;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;

import java.util.Optional;

import static gwangjang.server.domain.Issue.domain.entity.QIssue.issue;
import static gwangjang.server.domain.Issue.domain.entity.QTopic.topic;

@Repository
public class IssueRepositoryImpl extends QuerydslRepositorySupport {

private final JPAQueryFactory jpaQueryFactory;

public IssueRepositoryImpl (JPAQueryFactory jpaQueryFactory){
super(Issue.class);
this.jpaQueryFactory = jpaQueryFactory;
}
public Optional<IssueRes> findIssueAndTopicById(Long issueId) {
// First query to get issueTitle and imgUrl
Tuple issueTuple = jpaQueryFactory
.select(
issue.issueTitle,
issue.imgUrl
)
.from(issue)
.where(issue.id.eq(issueId))
.fetchOne();

if (issueTuple != null) {
String issueTitle = issueTuple.get(issue.issueTitle);
String imgUrl = issueTuple.get(issue.imgUrl);

// Second query to get topicTitle based on topicId associated with the issue
String topicTitle = jpaQueryFactory
.select(topic.topicTitle)
.from(issue)
.leftJoin(issue.topic, topic)
.where(issue.id.eq(issueId))
.fetchOne();

return Optional.of(new IssueRes(issueTitle, topicTitle, imgUrl));
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package gwangjang.server.domain.Issue.domain.service;

import gwangjang.server.domain.Issue.application.dto.res.IssueRes;
import gwangjang.server.domain.Issue.domain.repository.IssueCustomRepository;
import gwangjang.server.domain.Issue.exception.NotFoundIssueException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class IssueService {
private final IssueCustomRepository issueQueryRepository;


public IssueRes findIssueAndTopicById(Long issueId) {
return issueQueryRepository.findIssueAndTopicById(issueId).orElseThrow(NotFoundIssueException::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package gwangjang.server.domain.Issue.exception;

import gwangjang.server.global.exception.ApplicationException;
import gwangjang.server.global.response.ErrorCode;
import org.springframework.http.HttpStatus;


public abstract class IssueException extends ApplicationException {

protected IssueException(ErrorCode errorCode, HttpStatus httpStatus) {
super(errorCode, httpStatus);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package gwangjang.server.domain.Issue.exception;

import gwangjang.server.global.response.ErrorCode;
import org.springframework.http.HttpStatus;

public class NotFoundIssueException extends IssueException{
public NotFoundIssueException() {
super(ErrorCode.NOT_FOUND_ISSUE_ERROR, HttpStatus.NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package gwangjang.server.domain.Issue.presentation;

import gwangjang.server.domain.Issue.application.dto.res.IssueRes;
import gwangjang.server.domain.Issue.domain.service.IssueService;
import gwangjang.server.domain.Issue.exception.NotFoundIssueException;
import gwangjang.server.domain.Issue.presentation.constant.IssueResponseMessage;
import gwangjang.server.global.response.SuccessResponse;
import lombok.AllArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@AllArgsConstructor
public class IssueController {
private final IssueService issueService;

@GetMapping("/issue/{issueId}")
public ResponseEntity<SuccessResponse<IssueRes>> getIssueById(@PathVariable Long issueId) {
return ResponseEntity.ok(SuccessResponse.create(IssueResponseMessage.GET_ISSUE_SUCCESS.getMessage(),this.issueService.findIssueAndTopicById(issueId) ));

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gwangjang.server.domain.Issue.presentation.constant;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum IssueResponseMessage {

GET_ISSUE_SUCCESS("이슈 조회 완료");

private final String message;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface MorphemeRepository extends JpaRepository<Morpheme,Long> {
Morpheme findByWordAndIssueId(String word, int issueId);
List<String> findTop5KeywordsExcluding(String word);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package gwangjang.server.domain.morpheme.domain.repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import gwangjang.server.domain.morpheme.domain.entity.Morpheme;
import gwangjang.server.domain.morpheme.domain.entity.QMorpheme;
import jakarta.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class MorphemeRepositoryImpl extends QuerydslRepositorySupport {

private final JPAQueryFactory jpaQueryFactory;

public MorphemeRepositoryImpl (JPAQueryFactory jpaQueryFactory){
super(Morpheme.class);
this.jpaQueryFactory = jpaQueryFactory;
}

public List<String> findTop5KeywordsExcluding(String excludedKeyword) {
return jpaQueryFactory
.select(QMorpheme.morpheme.word)
.from(QMorpheme.morpheme)
.where(QMorpheme.morpheme.word.ne(excludedKeyword))
.orderBy(QMorpheme.morpheme.count().desc())
.limit(5)
.fetch();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package gwangjang.server.domain.morpheme.domain.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.transaction.Transactional;
import kr.co.shineware.nlp.komoran.model.Token;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;

@Service
@Transactional
@RequiredArgsConstructor
public class AsyncService {
private final Logger logger = LoggerFactory.getLogger(AsyncService.class);
private final NewsAPIService newsAPIService;

private final MorphemeService morphemeService;
@Async
public CompletableFuture<Void> asyncMethodNews(String newsList1) throws JsonProcessingException {
logger.debug("ASYNC Start 1");
List<Token> newsAnalysis1 =newsAPIService.analysis(newsList1);
logger.debug("ASYNC Start");
morphemeService.saveOrUpdateWord(newsAnalysis1, 100 );
return null;
}
@Async
public CompletableFuture<Void> asyncMethodNews2(String newsList2) throws JsonProcessingException {
logger.debug("ASYNC Start 2");
List<Token> newsAnalysis2 =newsAPIService.analysis(newsList2);
logger.debug("ASYNC Start 3");
morphemeService.saveOrUpdateWord(newsAnalysis2, 200);
return null;
}
@Async
public CompletableFuture<Void> asyncMethodNews3(String newsList3) throws JsonProcessingException {
logger.debug("ASYNC Start 4 ");
List<Token> newsAnalysis3 =newsAPIService.analysis(newsList3);
logger.debug("ASYNC Start 5");
morphemeService.saveOrUpdateWord(newsAnalysis3, 300);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package gwangjang.server.domain.morpheme.presentation;

import com.fasterxml.jackson.core.JsonProcessingException;
import gwangjang.server.domain.morpheme.domain.service.AsyncService;
import gwangjang.server.domain.morpheme.domain.service.MorphemeService;
import gwangjang.server.domain.morpheme.domain.service.NewsAPIService;
import io.swagger.annotations.ApiOperation;
import kr.co.shineware.nlp.komoran.model.Token;
import lombok.RequiredArgsConstructor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;


@RestController
Expand All @@ -27,40 +27,34 @@ public class MorphemeController {
private final Logger logger = LoggerFactory.getLogger(MorphemeController.class);
private final NewsAPIService newsAPIService;
private final MorphemeService morphemeService;
//@GetMapping("/analysis/{msg}")
@Scheduled(fixedRate = 24 * 60 * 60 * 1000)
//@GetMapping("/test")
public String analysis() throws JsonProcessingException {
logger.debug("ASYNC Start");
String newsList1 = newsAPIService.naverAPI("주 69시간 근로시간 제도 개편");
String newsList2 = newsAPIService.naverAPI("이태원 참사");
String newsList3 = newsAPIService.naverAPI("국민연금 개혁");
private final AsyncService asyncSerivce;

asyncMethodNews(newsList1);
asyncMethodNews2(newsList2);
asyncMethodNews3(newsList3);
System.out.println("ASYNC END");
return "success";
}
@Async
public void asyncMethodNews(String newsList1) throws JsonProcessingException {
logger.debug("ASYNC Start 1");
List<Token> newsAnalysis1 =newsAPIService.analysis(newsList1);
//@Scheduled(fixedRate = 24 * 60 * 60 * 1000)
public String analysis(String msg) throws JsonProcessingException {
logger.debug("ASYNC Start");
morphemeService.saveOrUpdateWord(newsAnalysis1, 100 );
}
@Async
public void asyncMethodNews2(String newsList2) throws JsonProcessingException {
logger.debug("ASYNC Start 2");
List<Token> newsAnalysis2 =newsAPIService.analysis(newsList2);
logger.debug("ASYNC Start 3");
morphemeService.saveOrUpdateWord(newsAnalysis2, 200);
}
@Async
public void asyncMethodNews3(String newsList3) throws JsonProcessingException {
logger.debug("ASYNC Start 4 ");
List<Token> newsAnalysis3 =newsAPIService.analysis(newsList3);
logger.debug("ASYNC Start 5");
morphemeService.saveOrUpdateWord(newsAnalysis3, 300);
String newsList1 = newsAPIService.naverAPI(msg);
String newsList2 = newsAPIService.naverAPI(msg);


CompletableFuture<Void> future1 = asyncSerivce.asyncMethodNews(newsList1);
CompletableFuture<Void> future2 = asyncSerivce.asyncMethodNews2(newsList2);
//CompletableFuture<Void> future3 = asyncMethodNews3(newsList3);

CompletableFuture<Void> allOf = CompletableFuture.allOf(
asyncSerivce.asyncMethodNews(newsList1),
asyncSerivce.asyncMethodNews2(newsList2)
//asyncMethodNews3(newsList3)
);
// 모든 비동기 작업이 완료되기를 기다리고 "success" 반환
try {
allOf.get(); // 대기
logger.debug("비동기 종료");
return "success";
} catch (InterruptedException | ExecutionException e) {
logger.error("비동기 작업 중 오류 발생", e);
return "error";
}
}


}
Loading

0 comments on commit 0c1bb66

Please sign in to comment.