diff --git a/.gitignore b/.gitignore index 6d109ad..d618aaa 100644 --- a/.gitignore +++ b/.gitignore @@ -36,8 +36,9 @@ out/ ### VS Code ### .vscode/ +src/main/resources/application.properties +src/test/resources/application-test.properties + # Spring Boot *.yml *.yaml - -src/main/resources/application.properties \ No newline at end of file diff --git a/src/main/java/com/example/issueDive/config/QueryDslConfig.java b/src/main/java/com/example/issueDive/config/QueryDslConfig.java new file mode 100644 index 0000000..ed3677e --- /dev/null +++ b/src/main/java/com/example/issueDive/config/QueryDslConfig.java @@ -0,0 +1,18 @@ +package com.example.issueDive.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class QueryDslConfig { + @PersistenceContext + private EntityManager em; + + @Bean + public JPAQueryFactory queryFactory() { + return new JPAQueryFactory(em); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/issueDive/controller/IssueController.java b/src/main/java/com/example/issueDive/controller/IssueController.java index dc17b2a..3efb424 100644 --- a/src/main/java/com/example/issueDive/controller/IssueController.java +++ b/src/main/java/com/example/issueDive/controller/IssueController.java @@ -1,11 +1,10 @@ package com.example.issueDive.controller; -import com.example.issueDive.dto.CreateIssueRequest; -import com.example.issueDive.dto.IssueResponse; -import com.example.issueDive.dto.UpdateIssueRequest; +import com.example.issueDive.dto.*; import com.example.issueDive.service.IssueService; -import com.example.issueDive.dto.ApiResponse; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -32,7 +31,28 @@ public ResponseEntity> createIssue(@RequestBody Creat } /** - * Read + * Read: 다중 조회(필터링, 페이징) + * @param filter status, authorId, labelIds, page, size, sort, order + * @return 공통 응답 포맷 + 조회한 이슈 dto 리스트(페이지) + */ + @GetMapping + public ResponseEntity>> getIssues(@Valid IssueFilterRequest filter) { + Page issue = issueService.getFilteredIssues( + new IssueFilterRequest( + filter.status(), + filter.authorId(), + filter.assigneeId(), + filter.labelIds(), + filter.page() != null ? filter.page() : 0, + filter.size() != null ? filter.size() : 10, + filter.sort() != null ? filter.sort() : "createdAt", + filter.order() != null ? filter.order() : "desc" + )); + return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.ok(issue)); + } + + /** + * Read: 단건 조회 * @param id 조회할 이슈 * @return 공통 응답 포맷 + 해당 이슈 dto */ diff --git a/src/main/java/com/example/issueDive/dto/IssueFilterRequest.java b/src/main/java/com/example/issueDive/dto/IssueFilterRequest.java new file mode 100644 index 0000000..1a81ee9 --- /dev/null +++ b/src/main/java/com/example/issueDive/dto/IssueFilterRequest.java @@ -0,0 +1,17 @@ +package com.example.issueDive.dto; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Pattern; + +import java.util.List; + +public record IssueFilterRequest( + @Pattern(regexp = "open|closed|OPEN|CLOSED") String status, + Long authorId, + Long assigneeId, + List labelIds, + @Min(0) Integer page, + @Min(1) Integer size, + @Pattern(regexp = "createdAt|updatedAt") String sort, + @Pattern(regexp = "asc|desc|ASC|DESC") String order +) {} \ No newline at end of file diff --git a/src/main/java/com/example/issueDive/dto/IssueResponse.java b/src/main/java/com/example/issueDive/dto/IssueResponse.java index cbc5a15..c688c97 100644 --- a/src/main/java/com/example/issueDive/dto/IssueResponse.java +++ b/src/main/java/com/example/issueDive/dto/IssueResponse.java @@ -1,6 +1,7 @@ package com.example.issueDive.dto; import java.time.LocalDateTime; +import java.util.List; public record IssueResponse( Long id, @@ -9,6 +10,7 @@ public record IssueResponse( String status, Long authorId, Long assigneeId, + List labelIds, LocalDateTime createdAt, LocalDateTime updatedAt ) { diff --git a/src/main/java/com/example/issueDive/entity/Issue.java b/src/main/java/com/example/issueDive/entity/Issue.java index df0f558..09909b3 100644 --- a/src/main/java/com/example/issueDive/entity/Issue.java +++ b/src/main/java/com/example/issueDive/entity/Issue.java @@ -3,7 +3,10 @@ import jakarta.persistence.*; import lombok.*; +import java.awt.*; import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; @RequiredArgsConstructor @AllArgsConstructor @@ -45,4 +48,12 @@ public class Issue { columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private LocalDateTime updatedAt; + @Builder.Default + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "issue_label", + joinColumns = @JoinColumn(name = "issue_id"), + inverseJoinColumns = @JoinColumn(name = "label_id") + ) + private Set