diff --git a/src/main/java/gwangjang/server/domain/Issue/application/dto/res/SearchListRes.java b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/SearchListRes.java new file mode 100644 index 0000000..d84fded --- /dev/null +++ b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/SearchListRes.java @@ -0,0 +1,20 @@ +package gwangjang.server.domain.Issue.application.dto.res; + +import gwangjang.server.domain.Issue.domain.entity.Topic; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.*; + +@Getter +@Builder +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SearchListRes { + private Long issueId; + private String issueTitle; + private String issueDetail; + private String imgUrl; + private String topicTitle; + private String topicId; +} diff --git a/src/main/java/gwangjang/server/domain/Issue/application/dto/res/SearchRes.java b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/SearchRes.java new file mode 100644 index 0000000..e0fe14f --- /dev/null +++ b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/SearchRes.java @@ -0,0 +1,17 @@ +package gwangjang.server.domain.Issue.application.dto.res; + +import lombok.*; + +import java.util.List; +@Getter +@Builder +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class SearchRes { + + String searchKeyword; + String searchCount; + + List issueResList; +} diff --git a/src/main/java/gwangjang/server/domain/Issue/application/mapper/IssueMapper.java b/src/main/java/gwangjang/server/domain/Issue/application/mapper/IssueMapper.java new file mode 100644 index 0000000..5c495f5 --- /dev/null +++ b/src/main/java/gwangjang/server/domain/Issue/application/mapper/IssueMapper.java @@ -0,0 +1,24 @@ +package gwangjang.server.domain.Issue.application.mapper; + +import gwangjang.server.domain.Issue.application.dto.res.SearchListRes; +import gwangjang.server.domain.Issue.domain.entity.Issue; +import gwangjang.server.global.annotation.Mapper; + +@Mapper +public class IssueMapper { + public SearchListRes mapToSearchListRes(Issue issue) { + SearchListRes searchListRes = new SearchListRes(); + searchListRes.setIssueId(issue.getId()); + searchListRes.setIssueTitle(issue.getIssueTitle()); + searchListRes.setIssueDetail(issue.getIssueDetail()); + searchListRes.setImgUrl(issue.getImgUrl()); + + // Topic이 null이 아닌 경우에만 매핑 + if (issue.getTopic() != null) { + searchListRes.setTopicTitle(issue.getTopic().getTopicTitle()); + searchListRes.setTopicId(String.valueOf(issue.getTopic().getId())); + } + + return searchListRes; + } +} diff --git a/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueCustomRepository.java b/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueCustomRepository.java index 5e77e42..b5d4275 100644 --- a/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueCustomRepository.java +++ b/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueCustomRepository.java @@ -3,6 +3,7 @@ import gwangjang.server.domain.Issue.application.dto.res.IssueDetailTopicRes; import gwangjang.server.domain.Issue.application.dto.res.IssueRes; import gwangjang.server.domain.Issue.application.dto.res.KeywordRes; +import gwangjang.server.domain.Issue.domain.entity.Issue; import org.springframework.stereotype.Repository; import java.util.List; @@ -12,4 +13,5 @@ public interface IssueCustomRepository { Optional findIssueAndTopicById(Long issueId); Optional findKeywordsByIssueId(Long issueId); List getAllIssueDetailTopicRes(); + List search(String keyword); } diff --git a/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java b/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java index b8bee82..3cb3e3f 100644 --- a/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java +++ b/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java @@ -2,12 +2,16 @@ import com.querydsl.core.Tuple; import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.StringExpression; +import com.querydsl.core.types.dsl.StringPath; import com.querydsl.jpa.impl.JPAQueryFactory; import gwangjang.server.domain.Issue.application.dto.res.IssueDetailTopicRes; import gwangjang.server.domain.Issue.application.dto.res.IssueRes; import gwangjang.server.domain.Issue.application.dto.res.KeywordRes; import gwangjang.server.domain.Issue.domain.entity.Issue; import gwangjang.server.domain.Issue.domain.entity.Keyword; +import gwangjang.server.domain.Issue.domain.entity.QIssue; import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; import org.springframework.stereotype.Repository; @@ -106,5 +110,22 @@ public List getAllIssueDetailTopicRes() { )) .collect(Collectors.toList()); } + public List search(String keyword) { + QIssue issue = QIssue.issue; + + return jpaQueryFactory + .selectFrom(issue) + .leftJoin(issue.keywords).fetchJoin() + .where( + containsIgnoreCase(issue.issueTitle, keyword) + .or(containsIgnoreCase(issue.issueDetail, keyword)) + .or(containsIgnoreCase(issue.topic.topicTitle, keyword)) + ) + .fetch(); + } + + private BooleanExpression containsIgnoreCase(StringPath path, String keyword) { + return path.lower().contains(keyword.toLowerCase()); + } } diff --git a/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java b/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java index d99f19c..3e58c95 100644 --- a/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java +++ b/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java @@ -1,6 +1,7 @@ package gwangjang.server.domain.Issue.domain.service; import gwangjang.server.domain.Issue.application.dto.res.*; +import gwangjang.server.domain.Issue.application.mapper.IssueMapper; import gwangjang.server.domain.Issue.domain.entity.Issue; import gwangjang.server.domain.Issue.domain.entity.Keyword; import gwangjang.server.domain.Issue.domain.entity.Topic; @@ -10,6 +11,7 @@ import gwangjang.server.domain.Issue.domain.repository.TopicRepository; import gwangjang.server.domain.Issue.exception.NotFoundIssueException; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -25,6 +27,8 @@ public class IssueService { private final IssueRepository issueRepository; + private final IssueMapper issueMapper = new IssueMapper(); + public IssueRes findIssueAndTopicById(Long issueId) { return issueQueryRepository.findIssueAndTopicById(issueId).orElseThrow(NotFoundIssueException::new); @@ -116,5 +120,19 @@ public List getAllIssueDetailTopicRes(){ List list = issueRepository.getAllIssueDetailTopicRes(); return list; } + public SearchRes search(String keyword) { + List searchResults = issueRepository.search(keyword); + + List issueResList = searchResults.stream() + .map(issueMapper::mapToSearchListRes) + .collect(Collectors.toList()); + + SearchRes searchRes = new SearchRes(); + searchRes.setSearchKeyword(keyword); + searchRes.setSearchCount(String.valueOf(searchResults.size())); + searchRes.setIssueResList(issueResList); + + return searchRes; + } } diff --git a/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java b/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java index da3ba6d..31f28f9 100644 --- a/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java +++ b/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java @@ -44,5 +44,9 @@ public ResponseEntity>> getIssueDetailAll() public ResponseEntity>> getIssueDetailAndTopicAll() { return ResponseEntity.ok(SuccessResponse.create(IssueResponseMessage.GET_ISSUE_SUCCESS.getMessage(),this.issueService.getAllIssueDetailTopicRes())); } + @GetMapping("/search/{keyword}") + public ResponseEntity> search(@PathVariable String keyword) { + return ResponseEntity.ok(SuccessResponse.create(IssueResponseMessage.GET_ISSUE_SUCCESS.getMessage(),this.issueService.search(keyword))); + } }