Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.assu.server.domain.map.dto.*;
import com.assu.server.domain.map.service.MapService;
import com.assu.server.domain.map.service.PlaceSearchService;
import com.assu.server.domain.store.entity.enums.StoreCategory;
import com.assu.server.global.apiPayload.BaseResponse;
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
import com.assu.server.global.apiPayload.code.status.SuccessStatus;
Expand All @@ -29,10 +30,13 @@ public class MapController {

@Operation(
summary = "현재 위치 기반 주변 장소 조회 API",
description = "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/2441197c19ed80bcb55fcad675dd9837?source=copy_link)\n" +
description = "# [v1.4 (2025-01-04)](https://clumsy-seeder-416.notion.site/2441197c19ed80bcb55fcad675dd9837?source=copy_link)\n" +
"- 로그인한 유저의 역할에 따라 Map 객체를 반환합니다.\n" +
"- 경도, 위도 순서로 입력한 Viewport 객체 입력.\n" +
"- 성공 시 200(OK)과 Map 객체 반환.\n"+
"\n**Request Params (STUDENT 전용):**\n" +
" - `storeCategory` (StoreCategory, optional): 카테고리 필터\n" +
" - `adminId` (Long, optional): 특정 학생회 필터\n" +
"\n**Request Body:**\n" +
" - `viewport` 객체 (JSON, required): 공간인덱싱을 위한 경도, 위도 객체\n" +
" - `lng1` (double): 좌 상단 경도\n" +
Expand Down Expand Up @@ -86,13 +90,15 @@ public class MapController {
@GetMapping("/nearby")
public BaseResponse<?> getLocations(
@ModelAttribute MapRequestDTO viewport,
@RequestParam(required = false) StoreCategory storeCategory,
@RequestParam(required = false) Long adminId,
@AuthenticationPrincipal PrincipalDetails pd
) {
Long memberId = pd.getMember().getId();
UserRole role = pd.getMember().getRole();

return switch (role) {
case STUDENT -> BaseResponse.onSuccess(SuccessStatus._OK, mapService.getStores(viewport, memberId));
case STUDENT -> BaseResponse.onSuccess(SuccessStatus._OK, mapService.getStores(viewport, memberId, storeCategory, adminId));
case ADMIN -> BaseResponse.onSuccess(SuccessStatus._OK, mapService.getPartners(viewport, memberId));
case PARTNER -> BaseResponse.onSuccess(SuccessStatus._OK, mapService.getAdmins(viewport, memberId));
default -> BaseResponse.onFailure(ErrorStatus._BAD_REQUEST, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import com.assu.server.domain.map.dto.MapRequestDTO;
import com.assu.server.domain.map.dto.PartnerMapResponseDTO;
import com.assu.server.domain.map.dto.StoreMapResponseDTO;
import com.assu.server.domain.store.entity.enums.StoreCategory;

import java.util.List;

public interface MapService {
List<AdminMapResponseDTO> getAdmins(MapRequestDTO viewport, Long memberId);
List<PartnerMapResponseDTO> getPartners(MapRequestDTO viewport, Long memberId);
List<StoreMapResponseDTO> getStores(MapRequestDTO viewport, Long memberId);
List<StoreMapResponseDTO> getStores(MapRequestDTO viewport, Long memberId, StoreCategory storeCategory, Long adminId);

List<StoreMapResponseDTO> searchStores(String keyword, Long memberId);
List<PartnerMapResponseDTO> searchPartner(String keyword, Long memberId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.assu.server.domain.partnership.repository.PaperContentRepository;
import com.assu.server.domain.partnership.repository.PaperRepository;
import com.assu.server.domain.store.entity.Store;
import com.assu.server.domain.store.entity.enums.StoreCategory;
import com.assu.server.domain.store.repository.StoreRepository;
import com.assu.server.domain.student.entity.UserPaper;
import com.assu.server.domain.student.repository.UserPaperRepository;
Expand Down Expand Up @@ -90,7 +91,7 @@ public List<AdminMapResponseDTO> getAdmins(MapRequestDTO viewport, Long memberId
* papercontent의 note가 있으면 benefit 대신 note를 사용.
*/
@Override
public List<StoreMapResponseDTO> getStores(MapRequestDTO viewport, Long memberId) {
public List<StoreMapResponseDTO> getStores(MapRequestDTO viewport, Long memberId, StoreCategory storeCategory, Long adminId) {
final String wkt = toWKT(viewport);

// 1) 뷰포트 내 매장 조회 (Partner, Member fetch join)
Expand All @@ -100,7 +101,7 @@ public List<StoreMapResponseDTO> getStores(MapRequestDTO viewport, Long memberId
}

// 2) 해당 학생의 활성 UserPaper 조회 (paper, store, admin fetch join 포함)
final List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId);
final List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId, storeCategory, adminId);
if (userPapers.isEmpty()) {
return List.of(); // active 제휴가 없으면 빈 리스트 반환
}
Expand Down Expand Up @@ -170,14 +171,14 @@ public List<StoreMapResponseDTO> getStores(MapRequestDTO viewport, Long memberId

List<StoreMapResponseDTO.PartnershipInfo> partnerships = benefitsByAdmin.entrySet().stream()
.map(entry -> {
Long adminId = entry.getKey();
Long paperAdminId = entry.getKey();
List<String> benefits = entry.getValue();
String adminName = sPapers.stream()
.filter(p -> p.getAdmin().getId().equals(adminId))
.filter(p -> p.getAdmin().getId().equals(paperAdminId))
.findFirst()
.map(p -> p.getAdmin().getName())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부에서 먼저 admin name 으로 map을 시킨 후에 안에서 필터링을 하는게 탐색 시간에 대해 좋아보여요!!

        .filter(p -> p.getAdmin() != null)
        .collect(Collectors.toMap(
                p -> p.getAdmin().getId(),
                p -> p.getAdmin().getName(),
                (existing, replacement) -> existing // 중복 id 방어
        ));

String adminName = adminNameMap.get(paperAdminId);

이런식으로요!!

.orElse(null);
return new StoreMapResponseDTO.PartnershipInfo(adminId, adminName, benefits);
return new StoreMapResponseDTO.PartnershipInfo(paperAdminId, adminName, benefits);
})
.filter(p -> p.adminId() != null && !p.benefits().isEmpty())
.toList();
Expand Down Expand Up @@ -231,7 +232,7 @@ private String generateBenefitText(PaperContent content) {
public List<StoreMapResponseDTO> searchStores(String keyword, Long memberId) {
String normalizedKeyword = (keyword == null) ? "" : keyword.replace(" ", "").toLowerCase();

List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId);
List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId, null, null);

if (userPapers.isEmpty()) {
return List.of();
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/assu/server/domain/store/entity/Store.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import com.assu.server.domain.common.entity.BaseEntity;
import com.assu.server.domain.common.enums.ActivationStatus;
import com.assu.server.domain.partner.entity.Partner;
import com.assu.server.domain.store.entity.enums.StoreCategory;

import jakarta.persistence.*;
import lombok.*;
Expand Down Expand Up @@ -44,6 +45,9 @@ public class Store extends BaseEntity {
private double latitude;
private double longitude;

@Enumerated(EnumType.STRING)
private StoreCategory storeCategory;

public void linkPartner(Partner partner) {
this.partner = partner;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.assu.server.domain.store.entity.enums;

public enum StoreCategory {
RESTAURANT, CAFE, BAR, BEAUTY, ENTERTAINMENT, SPORTS, LIVING, HOSPITAL, EDUCATION, OTHERS
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.assu.server.domain.store.repository;
import java.util.Optional;

import com.assu.server.domain.store.entity.enums.StoreCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import com.assu.server.domain.store.entity.Store;
import com.assu.server.domain.partner.entity.Partner;
Expand Down Expand Up @@ -113,7 +115,9 @@ Optional<Store> findBySameAddress(
WHERE s.point IS NOT NULL
AND function('ST_Contains', function('ST_GeomFromText', :wkt, 4326), s.point) = true
""")
List<Store> findAllWithinViewportWithPartner(@Param("wkt") String wkt);
List<Store> findAllWithinViewportWithPartner(
@Param("wkt") String wkt
);

@Query("""
SELECT DISTINCT s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import com.assu.server.domain.store.entity.enums.StoreCategory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -114,7 +115,8 @@ public BaseResponse<String> earnStamp(
"**Request Parameters:**\n" +
"- `all` (Boolean, optional): 전체 조회 여부 - 기본값: false\n" +
" - true: 모든 이용 가능한 제휴 조회\n" +
" - false: 최대 2개만 조회\n\n" +
" - false: 최대 2개만 조회\n" +
"- `storeCategory` (StoreCategory, optional): 카테고리 필터 - 미입력 시 전체 조회\n\n" +
"**Response:**\n" +
"- 성공 시 200(OK)와 이용 가능한 제휴 목록 반환\n" +
"- 401(UNAUTHORIZED): 인증되지 않은 사용자\n" +
Expand All @@ -123,9 +125,11 @@ public BaseResponse<String> earnStamp(
@GetMapping("/usable")
public BaseResponse<List<StudentResponseDTO.UsablePartnershipDTO>> getUsablePartnership(
@AuthenticationPrincipal PrincipalDetails pd,
@RequestParam(name = "all", defaultValue = "false") boolean all
) {
return BaseResponse.onSuccess(SuccessStatus._OK, studentService.getUsablePartnership(pd.getId(), all));
@RequestParam(name = "all", defaultValue = "false") boolean all,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5
all 파라미터 이름이 약간 모호한 것 같아요
요약 조회 목적이라면 previewOnly / isSummary 등으로 필드명을 좀더 구체적으로 바꾸는 것도 좋아보입니다.

@RequestParam(required = false) StoreCategory storeCategory,
@RequestParam(required = false) Long adminId
) {
return BaseResponse.onSuccess(SuccessStatus._OK, studentService.getUsablePartnership(pd.getId(), all, storeCategory, adminId));
}

@Operation(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.assu.server.domain.student.repository;

import com.assu.server.domain.store.entity.enums.StoreCategory;
import com.assu.server.domain.student.entity.UserPaper;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.LocalDate;
import java.util.List;

public interface UserPaperRepository extends JpaRepository<UserPaper, Long> {
Expand All @@ -17,13 +16,15 @@ public interface UserPaperRepository extends JpaRepository<UserPaper, Long> {
LEFT JOIN FETCH p.admin a
WHERE up.student.id = :studentId
AND p.isActivated = com.assu.server.domain.common.enums.ActivationStatus.ACTIVE
AND (:storeCategory IS NULL OR s.storeCategory = :storeCategory)
AND (:adminId IS NULL OR a.id = :adminId)
ORDER BY p.id DESC
""")
List<UserPaper> findActivePartnershipsByStudentId(@Param("studentId") Long studentId);

boolean existsByStudentIdAndPaperId(Long studentId, Long paperId);

boolean existsByStudentIdAndPaperIdAndPaperContentId(Long studentId, Long paperId, Long paperContentId);
List<UserPaper> findActivePartnershipsByStudentId(
@Param("studentId") Long studentId,
@Param("storeCategory") StoreCategory storeCategory,
@Param("adminId") Long adminId
);

@Query("""
SELECT up FROM UserPaper up
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import com.assu.server.domain.store.entity.enums.StoreCategory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

Expand All @@ -12,7 +13,7 @@ public interface StudentService {
StudentResponseDTO.MyPartnership getMyPartnership(Long studentId, int year, int month);
StudentResponseDTO.CheckStampResponseDTO getStamp(Long memberId);//조회
Page<StudentResponseDTO.UsageDetail> getUnreviewedUsage(Long memberId, Pageable pageable);
List<StudentResponseDTO.UsablePartnershipDTO> getUsablePartnership(Long memberId, Boolean all);
List<StudentResponseDTO.UsablePartnershipDTO> getUsablePartnership(Long memberId, Boolean all, StoreCategory storeCategory, Long adminId);
void syncUserPapersForAllStudents();
StudentResponseDTO.CheckStampResponseDTO addStamp(Long id);
StudentProfileResponseDTO getStudentProfile(Long memberId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.stream.Collectors;

import com.assu.server.domain.notification.service.NotificationCommandService;
import com.assu.server.domain.store.entity.enums.StoreCategory;
import com.assu.server.domain.student.entity.StampEventApplicant;
import com.assu.server.domain.student.repository.StampEventApplicantRepository;
import org.springframework.data.domain.Page;
Expand Down Expand Up @@ -141,8 +142,8 @@ public Page<StudentResponseDTO.UsageDetail> getUnreviewedUsage(Long memberId, Pa
}

@Override
public List<StudentResponseDTO.UsablePartnershipDTO> getUsablePartnership(Long memberId, Boolean all) {
List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId);
public List<StudentResponseDTO.UsablePartnershipDTO> getUsablePartnership(Long memberId, Boolean all, StoreCategory storeCategory, Long adminId) {
List<UserPaper> userPapers = userPaperRepository.findActivePartnershipsByStudentId(memberId, storeCategory, adminId);

// Goods 일괄 조회 (N+1 방지)
List<Long> contentIds = userPapers.stream()
Expand Down
Loading
Loading