diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/controller/UnivAPI.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/controller/UnivAPI.java new file mode 100644 index 0000000..39e76c0 --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/controller/UnivAPI.java @@ -0,0 +1,26 @@ +package com.softeer5.uniro_backend.univ.controller; + +import com.softeer5.uniro_backend.univ.dto.SearchUnivResDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "대학교 관련 Api") +public interface UnivAPI { + + @Operation(summary = "대학 이름 검색") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "대학 이름 검색 성공"), + @ApiResponse(responseCode = "400", description = "EXCEPTION(임시)", content = @Content), + }) + ResponseEntity searchUniv( + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "cursor-id", required = false) Long cursorId, + @RequestParam(value = "page-size", required = false) Integer pageSize + ); + +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/controller/UnivController.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/controller/UnivController.java new file mode 100644 index 0000000..df57eda --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/controller/UnivController.java @@ -0,0 +1,25 @@ +package com.softeer5.uniro_backend.univ.controller; + +import com.softeer5.uniro_backend.univ.dto.SearchUnivResDTO; +import com.softeer5.uniro_backend.univ.service.UnivService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class UnivController implements UnivAPI{ + private final UnivService univService; + + @Override + @GetMapping("/univ/search") + public ResponseEntity searchUniv( + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "cursor-id", required = false) Long cursorId, + @RequestParam(value = "page-size", required = false, defaultValue = "6") Integer pageSize){ + SearchUnivResDTO searchResult = univService.searchUniv(name, cursorId, pageSize); + return ResponseEntity.ok().body(searchResult); + } +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/dto/SearchUnivResDTO.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/dto/SearchUnivResDTO.java new file mode 100644 index 0000000..226fd6c --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/dto/SearchUnivResDTO.java @@ -0,0 +1,27 @@ +package com.softeer5.uniro_backend.univ.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@Schema(name = "SearchUnivResDTO", description = "대학 검색 DTO") +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class SearchUnivResDTO { + + @Schema(description = "실제 data", example = "") + private final List data; + + @Schema(description = "다음 페이지 요청을 위한 커서 ID (마지막 데이터의 ID)", example = "103") + private final Long nextCursor; + + @Schema(description = "다음 페이지가 존재하는지 여부", example = "true") + private final boolean hasNext; + + public static SearchUnivResDTO of(List univInfos, Long nextCursor, boolean hasNext) { + return new SearchUnivResDTO(univInfos,nextCursor,hasNext); + } +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/dto/UnivInfo.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/dto/UnivInfo.java new file mode 100644 index 0000000..b390c46 --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/dto/UnivInfo.java @@ -0,0 +1,19 @@ +package com.softeer5.uniro_backend.univ.dto; + +import com.querydsl.core.annotations.QueryProjection; +import lombok.Getter; + +@Getter +public class UnivInfo { + private Long id; + private String name; + private String imageUrl; + + @QueryProjection + public UnivInfo(Long id, String name, String imageUrl) { + this.id = id; + this.name = name; + this.imageUrl = imageUrl; + } + +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/Univ.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/entity/Univ.java similarity index 91% rename from uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/Univ.java rename to uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/entity/Univ.java index 3cf2e39..629de9c 100644 --- a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/Univ.java +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/entity/Univ.java @@ -1,4 +1,4 @@ -package com.softeer5.uniro_backend.univ; +package com.softeer5.uniro_backend.univ.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivCustomRepository.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivCustomRepository.java new file mode 100644 index 0000000..5050893 --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivCustomRepository.java @@ -0,0 +1,10 @@ +package com.softeer5.uniro_backend.univ.repository; + +import com.softeer5.uniro_backend.common.CursorPage; +import com.softeer5.uniro_backend.univ.dto.UnivInfo; + +import java.util.List; + +public interface UnivCustomRepository { + CursorPage> searchUniv(String name, Long cursorId, Integer pageSize); +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivCustomRepositoryImpl.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivCustomRepositoryImpl.java new file mode 100644 index 0000000..857a5a5 --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivCustomRepositoryImpl.java @@ -0,0 +1,50 @@ +package com.softeer5.uniro_backend.univ.repository; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.softeer5.uniro_backend.common.CursorPage; +import com.softeer5.uniro_backend.univ.dto.QUnivInfo; +import com.softeer5.uniro_backend.univ.dto.UnivInfo; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +import static com.softeer5.uniro_backend.univ.entity.QUniv.univ; + +@Repository +@RequiredArgsConstructor +public class UnivCustomRepositoryImpl implements UnivCustomRepository { + private final JPAQueryFactory queryFactory; + + @Override + public CursorPage> searchUniv(String name, Long cursorId, Integer pageSize) { + + List universities = queryFactory + .select(new QUnivInfo(univ.id, univ.name, univ.imageUrl)) + .from(univ) + .where( + nameCondition(name), + cursorIdCondition(cursorId) + ) + .orderBy(univ.id.asc()) + .limit(pageSize + 1) + .fetch(); + + boolean hasNext = universities.size() > pageSize; + Long nextCursor = hasNext ? universities.get(pageSize).getId() : null; + + if (hasNext) { + universities.remove(universities.size() - 1); + } + + return new CursorPage<>(universities, nextCursor, hasNext); + } + + private BooleanExpression cursorIdCondition(Long cursorId) { + return cursorId == null ? null : univ.id.gt(cursorId); + } + private BooleanExpression nameCondition(String name) { + return name == null || name.isEmpty() ? null : univ.name.containsIgnoreCase(name); + } +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivRepository.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivRepository.java new file mode 100644 index 0000000..8ee7f3e --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/repository/UnivRepository.java @@ -0,0 +1,7 @@ +package com.softeer5.uniro_backend.univ.repository; + +import com.softeer5.uniro_backend.univ.entity.Univ; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UnivRepository extends JpaRepository, UnivCustomRepository { +} diff --git a/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/service/UnivService.java b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/service/UnivService.java new file mode 100644 index 0000000..e7973b7 --- /dev/null +++ b/uniro_backend/src/main/java/com/softeer5/uniro_backend/univ/service/UnivService.java @@ -0,0 +1,23 @@ +package com.softeer5.uniro_backend.univ.service; + +import com.softeer5.uniro_backend.common.CursorPage; +import com.softeer5.uniro_backend.univ.dto.SearchUnivResDTO; +import com.softeer5.uniro_backend.univ.dto.UnivInfo; +import com.softeer5.uniro_backend.univ.repository.UnivRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class UnivService { + private final UnivRepository univRepository; + + public SearchUnivResDTO searchUniv(String name, Long cursorId, Integer pageSize) { + CursorPage> universities = univRepository.searchUniv(name,cursorId,pageSize); + return SearchUnivResDTO.of(universities.getData(),universities.getNextCursor(), universities.isHasNext()); + } +}