Skip to content

Commit

Permalink
feat: 제출된 시험 목록들 페이지네이션
Browse files Browse the repository at this point in the history
  • Loading branch information
alstn113 committed Dec 24, 2024
1 parent d5579ee commit 059cd34
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 16 deletions.
12 changes: 10 additions & 2 deletions server/src/main/java/com/fluffy/exam/api/ExamController.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@
import com.fluffy.exam.api.request.UpdateExamDescriptionWebRequest;
import com.fluffy.exam.api.request.UpdateExamQuestionsWebRequest;
import com.fluffy.exam.api.request.UpdateExamTitleWebRequest;
import com.fluffy.global.response.PageResponse;
import com.fluffy.global.web.Accessor;
import com.fluffy.global.web.Auth;
import jakarta.validation.Valid;
import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
Expand All @@ -36,8 +40,12 @@ public class ExamController {
private final ExamQueryService examQueryService;

@GetMapping("/api/v1/exams")
public ResponseEntity<List<ExamSummaryDto>> getPublishedExamSummaries() {
List<ExamSummaryDto> response = examQueryService.getPublishedExamSummaries();
public ResponseEntity<PageResponse<ExamSummaryDto>> getPublishedExamSummaries(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size
) {
Pageable pageable = PageRequest.of(page, size);
PageResponse<ExamSummaryDto> response = examQueryService.getPublishedExamSummaries(pageable);

return ResponseEntity.ok(response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
import com.fluffy.exam.domain.ExamStatus;
import com.fluffy.exam.domain.dto.ExamSummaryDto;
import com.fluffy.global.exception.ForbiddenException;
import com.fluffy.global.response.PageResponse;
import com.fluffy.global.web.Accessor;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -21,8 +25,10 @@ public class ExamQueryService {
private final ExamMapper examMapper;

@Transactional(readOnly = true)
public List<ExamSummaryDto> getPublishedExamSummaries() {
return examRepository.findPublishedSummaries();
public PageResponse<ExamSummaryDto> getPublishedExamSummaries(Pageable pageable) {
Page<ExamSummaryDto> examSummaries = examRepository.findPublishedSummaries(pageable);

return PageResponse.of(examSummaries);
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.fluffy.exam.domain.dto.ExamSummaryDto;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface ExamRepositoryCustom {

List<ExamSummaryDto> findPublishedSummaries();
Page<ExamSummaryDto> findPublishedSummaries(Pageable pageable);

List<ExamSummaryDto> findMySummaries(ExamStatus status, Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
import com.fluffy.exam.domain.dto.QAuthorDto;
import com.fluffy.exam.domain.dto.QExamSummaryDto;
import com.querydsl.core.types.ConstructorExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;

@Repository
Expand All @@ -29,8 +33,8 @@ public class ExamRepositoryImpl implements ExamRepositoryCustom {
private final JPAQueryFactory queryFactory;

@Override
public List<ExamSummaryDto> findPublishedSummaries() {
return queryFactory
public Page<ExamSummaryDto> findPublishedSummaries(Pageable pageable) {
List<ExamSummaryDto> content = queryFactory
.selectDistinct(new QExamSummaryDto(
exam.id,
exam.title.value,
Expand All @@ -57,9 +61,17 @@ public List<ExamSummaryDto> findPublishedSummaries() {
exam.updatedAt
)
.orderBy(exam.updatedAt.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}

JPAQuery<Long> countQuery = queryFactory.select(exam.count())
.from(exam)
.where(exam.status.eq(ExamStatus.PUBLISHED));

return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchOne);
}

@Override
public List<ExamSummaryDto> findMySummaries(ExamStatus status, Long memberId) {
return queryFactory
Expand Down
10 changes: 10 additions & 0 deletions server/src/main/java/com/fluffy/global/response/PageInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.fluffy.global.response;

public record PageInfo(
int currentPage,
int totalPages,
long totalElements,
boolean hasNext,
boolean hasPrevious
) {
}
22 changes: 22 additions & 0 deletions server/src/main/java/com/fluffy/global/response/PageResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.fluffy.global.response;

import java.util.List;
import org.springframework.data.domain.Page;

public record PageResponse<T>(
PageInfo pageInfo,
List<T> content
) {
public static <T> PageResponse<T> of(Page<T> page) {
return new PageResponse<>(
new PageInfo(
page.getNumber(),
page.getTotalPages(),
page.getTotalElements(),
page.hasNext(),
page.hasPrevious()
),
page.getContent()
);
}
}
12 changes: 10 additions & 2 deletions web/src/api/examAPI.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { apiV1Client } from './apiClient';
import { QuestionBaseRequest, QuestionResponse, QuestionWithAnswersResponse } from './questionAPI';
import { PageResponse } from './response';

export const ExamAPI = {
getPublishedExamSummaries: async () => {
const { data } = await apiV1Client.get<ExamSummaryResponse[]>('/exams');
getPublishedExamSummaries: async ({ page, size }: ExamSummaryParams) => {
const { data } = await apiV1Client.get<PageResponse<ExamSummaryResponse>>('/exams', {
params: { page, size },
});
return data;
},

Expand Down Expand Up @@ -56,6 +59,11 @@ export const EXAM_STATUS = {
} as const;
export type ExamStatusType = (typeof EXAM_STATUS)[keyof typeof EXAM_STATUS];

export interface ExamSummaryParams {
page: number;
size: number;
}

export interface ExamSummaryResponse {
id: number;
title: string;
Expand Down
12 changes: 12 additions & 0 deletions web/src/api/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface PageInfo {
currentPage: number;
totalPages: number;
totalElements: number;
hasNext: boolean;
hasPrevious: boolean;
}

export interface PageResponse<T> {
pageInfo: PageInfo;
content: T[];
}
15 changes: 10 additions & 5 deletions web/src/hooks/api/exam/useGetExamSummaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@ import { useSuspenseQuery } from '@tanstack/react-query';
import { UseQueryOptionsOf } from '../types';
import { ExamAPI } from '@/api/examAPI.ts';

const useGetExamSummaries = (options: UseQueryOptionsOf<typeof ExamAPI.getPublishedExamSummaries> = {}) => {
const useGetExamSummaries = (
page: number = 0,
size: number = 10,
options: UseQueryOptionsOf<typeof ExamAPI.getPublishedExamSummaries> = {},
) => {
return useSuspenseQuery({
...options,
queryKey: getKey(),
queryFn: fetcher(),
queryKey: getKey(page, size),
queryFn: fetcher(page, size),
});
};

const getKey = () => ['exams'];
const fetcher = () => async () => await ExamAPI.getPublishedExamSummaries();
const getKey = (page: number, size: number) => ['examSummaries', { page, size }];
const fetcher = (page: number, size: number) => () =>
ExamAPI.getPublishedExamSummaries({ page, size });

useGetExamSummaries.getKey = getKey;
useGetExamSummaries.fetcher = fetcher;
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const ExamListContent = () => {

return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-5">
{data?.map((exam) => {
{data.content.map((exam) => {
return <ExamSummaryCard key={exam.id} exam={exam} />;
})}
</div>
Expand Down

0 comments on commit 059cd34

Please sign in to comment.