From a2ff37a1f8ebdc57ca0767ecba0048c3779fe2f0 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 09:26:45 +0900 Subject: [PATCH 01/64] =?UTF-8?q?[feat]=20#15=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/domain/Meeting.java | 4 ++++ .../domain/meeting/domain/MeetingStatus.java | 17 +++++++++++++++++ .../domain/meeting/service/MeetingService.java | 7 +++++++ 3 files changed, 28 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/MeetingStatus.java diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java index 5b941e85..3cacacce 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java @@ -50,6 +50,10 @@ public abstract class Meeting { @Embedded private ParticipantLimit participantLimit; + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private MeetingStatus meetingStatus; + @CreatedDate @Column(updatable = false) private LocalDateTime createdAt; diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/MeetingStatus.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/MeetingStatus.java new file mode 100644 index 00000000..995e947f --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/MeetingStatus.java @@ -0,0 +1,17 @@ +package com.example.eatmate.app.domain.meeting.domain; + +import lombok.Getter; + +@Getter +public enum MeetingStatus { + ACTIVE("활성화"), + INACTIVE("비활성화"), + ; + + private final String text; + + MeetingStatus(String text) { + this.text = text; + } + +} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index f47e8498..fd6c8fa4 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -16,6 +16,7 @@ import com.example.eatmate.app.domain.meeting.domain.GenderRestriction; import com.example.eatmate.app.domain.meeting.domain.Meeting; import com.example.eatmate.app.domain.meeting.domain.MeetingParticipant; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.OfflineMeeting; import com.example.eatmate.app.domain.meeting.domain.OfflineMeetingCategory; import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; @@ -82,6 +83,7 @@ public CreateDeliveryMeetingResponseDto createDeliveryMeeting( .isLimited(createDeliveryMeetingRequestDto.getIsLimited()) .maxParticipants(createDeliveryMeetingRequestDto.getMaxParticipants()) .build()) + .meetingStatus(MeetingStatus.ACTIVE) .foodCategory(createDeliveryMeetingRequestDto.getFoodCategory()) .storeName(createDeliveryMeetingRequestDto.getStoreName()) .pickupLocation(createDeliveryMeetingRequestDto.getPickupLocation()) @@ -118,6 +120,7 @@ public CreateOfflineMeetingResponseDto createOfflineMeeting( .isLimited(createOfflineMeetingRequestDto.getIsLimited()) .maxParticipants(createOfflineMeetingRequestDto.getMaxParticipants()) .build()) + .meetingStatus(MeetingStatus.ACTIVE) .meetingPlace(createOfflineMeetingRequestDto.getMeetingPlace()) .meetingDate(createOfflineMeetingRequestDto.getMeetingDate()) .offlineMeetingCategory(createOfflineMeetingRequestDto.getOfflineMeetingCategory()) @@ -143,6 +146,10 @@ private void joinMeeting(Long meetingId, UserDetails userDetails, boolean isDeli .orElseThrow(() -> new CommonException(ErrorCode.MEETING_NOT_FOUND)); } + if (meeting.getMeetingStatus() == MeetingStatus.INACTIVE) { + throw new CommonException(ErrorCode.MEETING_NOT_FOUND); + } + validateParticipantLimit(meeting); validateGenderRestriction(meeting, member); validateDuplicateParticipant(meeting, member); From 74ef6b0f2a8b74f5591db5b3e16b4634004df7d4 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 09:31:57 +0900 Subject: [PATCH 02/64] =?UTF-8?q?[feat]=20#15=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=8B=9C=20=EC=83=81=ED=83=9C=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/DeliveryMeetingRepository.java | 4 +++- .../repository/OfflineMeetingRepository.java | 4 +++- .../domain/meeting/service/MeetingService.java | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java index 7fccbd7e..694aabd8 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java @@ -6,8 +6,10 @@ import com.example.eatmate.app.domain.meeting.domain.DeliveryMeeting; import com.example.eatmate.app.domain.meeting.domain.FoodCategory; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; public interface DeliveryMeetingRepository extends JpaRepository { - List findAllByFoodCategory(FoodCategory foodCategory); + List findAllByFoodCategoryAndMeetingStatus(FoodCategory foodCategory, + MeetingStatus meetingStatus); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java index 4136fc7a..4006596f 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java @@ -4,9 +4,11 @@ import org.springframework.data.jpa.repository.JpaRepository; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.OfflineMeeting; import com.example.eatmate.app.domain.meeting.domain.OfflineMeetingCategory; public interface OfflineMeetingRepository extends JpaRepository { - List findAllByOfflineMeetingCategory(OfflineMeetingCategory offlineMeetingCategory); + List findAllByOfflineMeetingCategoryAndMeetingStatus(OfflineMeetingCategory offlineMeetingCategory, + MeetingStatus meetingStatus); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index fd6c8fa4..b2b67c89 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -172,8 +172,8 @@ public void joinOfflineMeeting(Long meetingId, UserDetails userDetails) { // 밥, 술 모임 목록 조회 메소드 @Transactional(readOnly = true) public List getOfflineMeetingList(OfflineMeetingCategory offlineMeetingCategory) { - List meetings = offlineMeetingRepository.findAllByOfflineMeetingCategory( - offlineMeetingCategory); + List meetings = offlineMeetingRepository.findAllByOfflineMeetingCategoryAndMeetingStatus( + offlineMeetingCategory, MeetingStatus.ACTIVE); return meetings.stream() .map(meeting -> { @@ -186,7 +186,8 @@ public List getOfflineMeetingList(OfflineMeetingC // 배달 모임 목록 조회 메소드 @Transactional(readOnly = true) public List getDeliveryMeetingList(FoodCategory foodCategory) { - List meetings = deliveryMeetingRepository.findAllByFoodCategory(foodCategory); + List meetings = deliveryMeetingRepository.findAllByFoodCategoryAndMeetingStatus(foodCategory, + MeetingStatus.ACTIVE); return meetings.stream() .map(meeting -> { @@ -203,6 +204,10 @@ public OfflineMeetingDetailResponseDto getOfflineMeetingDetail(Long meetingId) { OfflineMeeting offlinemeeting = offlineMeetingRepository.findById(meetingId) .orElseThrow(() -> new CommonException(ErrorCode.MEETING_NOT_FOUND)); + if (offlinemeeting.getMeetingStatus() == MeetingStatus.INACTIVE) { + throw new CommonException(ErrorCode.MEETING_NOT_FOUND); + } + MeetingParticipant meetingParticipant = meetingParticipantRepository.findByMeetingAndRole(offlinemeeting, HOST) .orElseThrow(() -> new CommonException(ErrorCode.MEETING_NOT_FOUND)); // 모임 주인 컬럼 확인 @@ -222,6 +227,10 @@ public DeliveryMeetingDetailResponseDto getDeliveryMeetingDetail(Long meetingId) DeliveryMeeting deliveryMeeting = deliveryMeetingRepository.findById(meetingId) .orElseThrow(() -> new CommonException(ErrorCode.MEETING_NOT_FOUND)); + if (deliveryMeeting.getMeetingStatus() == MeetingStatus.INACTIVE) { + throw new CommonException(ErrorCode.MEETING_NOT_FOUND); + } + MeetingParticipant meetingParticipant = meetingParticipantRepository.findByMeetingAndRole(deliveryMeeting, HOST) .orElseThrow(() -> new CommonException(ErrorCode.MEETING_NOT_FOUND)); // 모임 주인 컬럼 확인 From 73f510ac732f7ce9fe043b650c37e965ea323b4d Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 11:44:41 +0900 Subject: [PATCH 03/64] =?UTF-8?q?[feat]=20#15=20QueryDSL=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 9 +- .../repository/MeetingCustomRepository.java | 9 ++ .../MeetingCustomRepositoryImpl.java | 91 +++++++++++++++++++ .../domain/repository/MeetingRepository.java | 6 +- .../eatmate/global/config/QueryDslConfig.java | 21 +++++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java create mode 100644 src/main/java/com/example/eatmate/global/config/QueryDslConfig.java diff --git a/build.gradle b/build.gradle index aadd3b33..4f0095a9 100644 --- a/build.gradle +++ b/build.gradle @@ -27,14 +27,16 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + + // 로그인 implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'com.auth0:java-jwt:4.2.1' implementation 'org.hibernate.validator:hibernate-validator:8.0.0.Final' implementation 'jakarta.validation:jakarta.validation-api:3.0.2' - runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' @@ -42,6 +44,11 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' + + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java new file mode 100644 index 00000000..f3eb83c9 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -0,0 +1,9 @@ +package com.example.eatmate.app.domain.meeting.domain.repository; + +import java.util.List; + +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; + +public interface MeetingCustomRepository { + List findAllHostMeetings(Long memberId); +} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java new file mode 100644 index 00000000..1467ce3d --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -0,0 +1,91 @@ +package com.example.eatmate.app.domain.meeting.domain.repository; + +import static com.example.eatmate.app.domain.meeting.domain.QDeliveryMeeting.*; +import static com.example.eatmate.app.domain.meeting.domain.QMeeting.*; +import static com.example.eatmate.app.domain.meeting.domain.QMeetingParticipant.*; +import static com.example.eatmate.app.domain.meeting.domain.QOfflineMeeting.*; + +import java.util.List; + +import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; +import com.querydsl.core.types.ExpressionUtils; +import com.querydsl.core.types.Order; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { + private final JPAQueryFactory queryFactory; + + @Override + public List findAllHostMeetings(Long memberId) { + BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); + + return queryFactory + .select(Projections.constructor(CreatedMeetingListResponseDto.class, + meeting.type, + meeting.id, + meeting.meetingName, + meeting.meetingStatus, + ExpressionUtils.as( + JPAExpressions + .select(deliveryMeeting.storeName) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id)), + "storeName"), + ExpressionUtils.as( + JPAExpressions + .select(offlineMeeting.meetingPlace) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id)), + "meetingPlace"), + ExpressionUtils.as( + JPAExpressions + .select(deliveryMeeting.orderDeadline) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id)), + "orderDeadline"), + ExpressionUtils.as( + JPAExpressions + .select(offlineMeeting.meetingDate) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id)), + "meetingDate"), + ExpressionUtils.as( + JPAExpressions + .select(meetingParticipant.count()) + .from(meetingParticipant) + .where(meetingParticipant.meeting.id.eq(meeting.id)), + "participantCount") + )) + .from(meeting) + .join(meetingParticipant).on( + meetingParticipant.meeting.id.eq(meeting.id), + meetingParticipant.member.memberId.eq(memberId), + meetingParticipant.role.eq(ParticipantRole.HOST) + ) + .orderBy( + meeting.meetingStatus.asc(), + new OrderSpecifier<>(Order.ASC, + new CaseBuilder() + .when(isDelivery) + .then(JPAExpressions + .select(deliveryMeeting.orderDeadline) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id))) + .otherwise(JPAExpressions + .select(offlineMeeting.meetingDate) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id))) + ) + ) + .fetch(); + } +} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java index b95264c7..42bb2687 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java @@ -1,8 +1,12 @@ package com.example.eatmate.app.domain.meeting.domain.repository; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.Meeting; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; -public interface MeetingRepository extends JpaRepository { +public interface MeetingRepository extends JpaRepository, MeetingCustomRepository { + List findAllHostMeetings(Long memberId); } diff --git a/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java b/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java new file mode 100644 index 00000000..ff66596f --- /dev/null +++ b/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java @@ -0,0 +1,21 @@ +package com.example.eatmate.global.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.querydsl.jpa.impl.JPAQueryFactory; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +@Configuration +public class QueryDslConfig { + + @PersistenceContext + private EntityManager em; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(em); + } +} From 355b6b9519051d630719a56362a18756a7e38589 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 11:44:52 +0900 Subject: [PATCH 04/64] =?UTF-8?q?[feat]=20#15=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/eatmate/app/domain/meeting/domain/Meeting.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java index 3cacacce..edcf5a00 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java @@ -36,6 +36,9 @@ public abstract class Meeting { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "meeting_type", insertable = false, updatable = false) + private String type; // discriminator 값을 조회하기 위한 필드 + @Column(length = 30, nullable = false) private String meetingName; From 663fc796667d1e11cf645b322c1a819bb313f33b Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 11:45:05 +0900 Subject: [PATCH 05/64] =?UTF-8?q?[feat]=20#15=20=EB=82=B4=EA=B0=80=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=9C=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meeting/controller/MeetingController.java | 10 +++++ .../dto/CreatedMeetingListResponseDto.java | 43 +++++++++++++++++++ .../meeting/service/MeetingService.java | 11 +++++ 3 files changed, 64 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 9a381df7..dc004413 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -20,6 +20,7 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; @@ -114,4 +115,13 @@ public ResponseEntity> getDe .body(GlobalResponseDto.success( meetingService.getDeliveryMeetingDetail(meetingId))); } + + @GetMapping("/my/created") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록을 조회합니다.") + public ResponseEntity>> getMyCreatedMeetingList( + @AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getMyCreatedMeetingList(userDetails))); + } } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java new file mode 100644 index 00000000..dd836996 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java @@ -0,0 +1,43 @@ +package com.example.eatmate.app.domain.meeting.dto; + +import java.time.LocalDateTime; + +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; + +import lombok.Getter; + +@Getter +public class CreatedMeetingListResponseDto { + private String meetingType; + private Long id; + private String meetingName; + private MeetingStatus meetingStatus; + private Long participantCount; + private String storeName; // DeliveryMeeting인 경우 + private String meetingPlace; // OfflineMeeting인 경우 + private LocalDateTime orderDeadline; // DeliveryMeeting인 경우 + private LocalDateTime meetingDate; // OfflineMeeting인 경우 + + public CreatedMeetingListResponseDto( + String type, + Long id, + String meetingName, + MeetingStatus meetingStatus, + String storeName, + String meetingPlace, + LocalDateTime orderDeadline, + LocalDateTime meetingDate, + Long participantCount + ) { + this.meetingType = type; + this.id = id; + this.meetingName = meetingName; + this.meetingStatus = meetingStatus; + this.storeName = storeName; + this.meetingPlace = meetingPlace; + this.orderDeadline = orderDeadline; + this.meetingDate = meetingDate; + this.participantCount = participantCount; + } +} + diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index b2b67c89..fd89fe15 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -22,11 +22,13 @@ import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; import com.example.eatmate.app.domain.meeting.domain.repository.DeliveryMeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingParticipantRepository; +import com.example.eatmate.app.domain.meeting.domain.repository.MeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.OfflineMeetingRepository; import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; @@ -46,6 +48,7 @@ public class MeetingService { private final MemberRepository memberRepository; private final OfflineMeetingRepository offlineMeetingRepository; private final MeetingParticipantRepository meetingParticipantRepository; + private final MeetingRepository meetingRepository; // 참여자와 모임 성별제한 일치 여부 확인 메소드 private static void validateGenderRestriction(CreateOfflineMeetingRequestDto requestDto, Member member) { @@ -285,11 +288,19 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } } + // 내가 생성한 모임 조회 + @Transactional + public List getMyCreatedMeetingList(UserDetails userDetails) { + Member member = getMember(userDetails); + return meetingRepository.findAllHostMeetings(member.getMemberId()); + } + // 회원 정보 조회 메소드 private Member getMember(UserDetails userDetails) { return memberRepository.findByEmail(userDetails.getUsername()) .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); } + } From 27222cd4a20d4b95f6eecbec4693b90308d9a6c7 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 12:00:45 +0900 Subject: [PATCH 06/64] =?UTF-8?q?[feat]=20#15=20=EB=82=B4=EA=B0=80=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=ED=95=9C=20=EB=AA=A8=EC=9E=84=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meeting/controller/MeetingController.java | 16 ++++++++++++++-- .../repository/MeetingCustomRepository.java | 3 ++- .../repository/MeetingCustomRepositoryImpl.java | 4 ++-- .../domain/repository/MeetingRepository.java | 4 ---- .../domain/meeting/service/MeetingService.java | 7 ++++--- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index dc004413..a52ca7e0 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -1,5 +1,7 @@ package com.example.eatmate.app.domain.meeting.controller; +import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; + import java.util.List; import org.springframework.http.HttpStatus; @@ -117,11 +119,21 @@ public ResponseEntity> getDe } @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록을 조회합니다.") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyCreatedMeetingList(userDetails))); + meetingService.getMyMeetingList(userDetails, HOST))); } + + @GetMapping("/my/participated") + @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") + public ResponseEntity>> getMyParticipatedMeetingList( + @AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getMyMeetingList(userDetails, PARTICIPANT))); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index f3eb83c9..9d09e92c 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -2,8 +2,9 @@ import java.util.List; +import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingCustomRepository { - List findAllHostMeetings(Long memberId); + List findAllMeetings(Long memberId, ParticipantRole role); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index 1467ce3d..a9d0dd46 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -25,7 +25,7 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllHostMeetings(Long memberId) { + public List findAllMeetings(Long memberId, ParticipantRole role) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); return queryFactory @@ -69,7 +69,7 @@ public List findAllHostMeetings(Long memberId) { .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId), - meetingParticipant.role.eq(ParticipantRole.HOST) + meetingParticipant.role.eq(role) ) .orderBy( meeting.meetingStatus.asc(), diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java index 42bb2687..6acc1e0d 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java @@ -1,12 +1,8 @@ package com.example.eatmate.app.domain.meeting.domain.repository; -import java.util.List; - import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.Meeting; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingRepository extends JpaRepository, MeetingCustomRepository { - List findAllHostMeetings(Long memberId); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index fd89fe15..21847df9 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -20,6 +20,7 @@ import com.example.eatmate.app.domain.meeting.domain.OfflineMeeting; import com.example.eatmate.app.domain.meeting.domain.OfflineMeetingCategory; import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; +import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.domain.repository.DeliveryMeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingParticipantRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingRepository; @@ -288,11 +289,11 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } } - // 내가 생성한 모임 조회 + // 내가 생성, 참여한 모임 조회 @Transactional - public List getMyCreatedMeetingList(UserDetails userDetails) { + public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); - return meetingRepository.findAllHostMeetings(member.getMemberId()); + return meetingRepository.findAllMeetings(member.getMemberId(), role); } // 회원 정보 조회 메소드 From c69ebea041c7998a87be2545acdd39ad88e21b33 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 12:10:47 +0900 Subject: [PATCH 07/64] =?UTF-8?q?[rename]=20#15=20DTO=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/controller/MeetingController.java | 6 +++--- .../meeting/domain/repository/MeetingCustomRepository.java | 4 ++-- .../domain/repository/MeetingCustomRepositoryImpl.java | 6 +++--- ...tingListResponseDto.java => MeetingListResponseDto.java} | 4 ++-- .../eatmate/app/domain/meeting/service/MeetingService.java | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/main/java/com/example/eatmate/app/domain/meeting/dto/{CreatedMeetingListResponseDto.java => MeetingListResponseDto.java} (92%) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index a52ca7e0..eeb150f0 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -22,9 +22,9 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.service.MeetingService; @@ -120,7 +120,7 @@ public ResponseEntity> getDe @GetMapping("/my/created") @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyCreatedMeetingList( + public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -129,7 +129,7 @@ public ResponseEntity>> ge @GetMapping("/my/participated") @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyParticipatedMeetingList( + public ResponseEntity>> getMyParticipatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index 9d09e92c..b22bd155 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -3,8 +3,8 @@ import java.util.List; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role); + List findAllMeetings(Long memberId, ParticipantRole role); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index a9d0dd46..d6c7a92f 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -8,7 +8,7 @@ import java.util.List; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.querydsl.core.types.ExpressionUtils; import com.querydsl.core.types.Order; import com.querydsl.core.types.OrderSpecifier; @@ -25,11 +25,11 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role) { + public List findAllMeetings(Long memberId, ParticipantRole role) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); return queryFactory - .select(Projections.constructor(CreatedMeetingListResponseDto.class, + .select(Projections.constructor(MeetingListResponseDto.class, meeting.type, meeting.id, meeting.meetingName, diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java similarity index 92% rename from src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java rename to src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java index dd836996..1fcbe088 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java @@ -7,7 +7,7 @@ import lombok.Getter; @Getter -public class CreatedMeetingListResponseDto { +public class MeetingListResponseDto { private String meetingType; private Long id; private String meetingName; @@ -18,7 +18,7 @@ public class CreatedMeetingListResponseDto { private LocalDateTime orderDeadline; // DeliveryMeeting인 경우 private LocalDateTime meetingDate; // OfflineMeeting인 경우 - public CreatedMeetingListResponseDto( + public MeetingListResponseDto( String type, Long id, String meetingName, diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 21847df9..26547742 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -29,9 +29,9 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.member.domain.Member; @@ -291,7 +291,7 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { // 내가 생성, 참여한 모임 조회 @Transactional - public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { + public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); return meetingRepository.findAllMeetings(member.getMemberId(), role); } From 018dfb5e69cf6e48ebb498208f8bb3b167a486c2 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 16:30:46 +0900 Subject: [PATCH 08/64] =?UTF-8?q?[feat]=20#15=20=EC=B0=B8=EC=97=AC=20?= =?UTF-8?q?=EC=A4=91=EC=9D=B8=20=EB=AA=A8=EC=9E=84=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meeting/controller/MeetingController.java | 13 +++++++++++-- .../repository/MeetingCustomRepository.java | 3 ++- .../MeetingCustomRepositoryImpl.java | 14 ++++++++++++-- .../domain/meeting/service/MeetingService.java | 18 +++++++++++++----- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index eeb150f0..a77a959e 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -119,7 +119,7 @@ public ResponseEntity> getDe } @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "마이페이지에서 내가 생성한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) @@ -128,7 +128,7 @@ public ResponseEntity>> getMyCrea } @GetMapping("/my/participated") - @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 참여한 모임 목록 조회", description = "마이페이지에서 내가 참여한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyParticipatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) @@ -136,4 +136,13 @@ public ResponseEntity>> getMyPart meetingService.getMyMeetingList(userDetails, PARTICIPANT))); } + @GetMapping("my/active") + @Operation(summary = "내가 참여 중인 모임 목록 조회", description = "내가 참여중인 활성화된 모임 목록을 조회합니다.") + public ResponseEntity>> + getMyActiveMeetingList(@AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getMyActiveMeetingList(userDetails, null))); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index b22bd155..a5c5f823 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -2,9 +2,10 @@ import java.util.List; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role); + List findAllMeetings(Long memberId, ParticipantRole role, MeetingStatus meetingStatus); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index d6c7a92f..58d1613b 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -7,6 +7,7 @@ import java.util.List; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.querydsl.core.types.ExpressionUtils; @@ -25,9 +26,16 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role) { + public List findAllMeetings(Long memberId, ParticipantRole role, + MeetingStatus meetingStatus) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); + BooleanExpression statusCondition = meetingStatus != null ? + meeting.meetingStatus.eq(meetingStatus) : null; + + BooleanExpression roleCondition = role != null ? + meetingParticipant.role.eq(role) : null; + return queryFactory .select(Projections.constructor(MeetingListResponseDto.class, meeting.type, @@ -69,8 +77,9 @@ public List findAllMeetings(Long memberId, ParticipantRo .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId), - meetingParticipant.role.eq(role) + roleCondition ) + .where(statusCondition) .orderBy( meeting.meetingStatus.asc(), new OrderSpecifier<>(Order.ASC, @@ -88,4 +97,5 @@ public List findAllMeetings(Long memberId, ParticipantRo ) .fetch(); } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 26547742..f206e28a 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -1,6 +1,7 @@ package com.example.eatmate.app.domain.meeting.service; import static com.example.eatmate.app.domain.meeting.domain.GenderRestriction.*; +import static com.example.eatmate.app.domain.meeting.domain.MeetingStatus.*; import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; import java.time.LocalDateTime; @@ -87,7 +88,7 @@ public CreateDeliveryMeetingResponseDto createDeliveryMeeting( .isLimited(createDeliveryMeetingRequestDto.getIsLimited()) .maxParticipants(createDeliveryMeetingRequestDto.getMaxParticipants()) .build()) - .meetingStatus(MeetingStatus.ACTIVE) + .meetingStatus(ACTIVE) .foodCategory(createDeliveryMeetingRequestDto.getFoodCategory()) .storeName(createDeliveryMeetingRequestDto.getStoreName()) .pickupLocation(createDeliveryMeetingRequestDto.getPickupLocation()) @@ -124,7 +125,7 @@ public CreateOfflineMeetingResponseDto createOfflineMeeting( .isLimited(createOfflineMeetingRequestDto.getIsLimited()) .maxParticipants(createOfflineMeetingRequestDto.getMaxParticipants()) .build()) - .meetingStatus(MeetingStatus.ACTIVE) + .meetingStatus(ACTIVE) .meetingPlace(createOfflineMeetingRequestDto.getMeetingPlace()) .meetingDate(createOfflineMeetingRequestDto.getMeetingDate()) .offlineMeetingCategory(createOfflineMeetingRequestDto.getOfflineMeetingCategory()) @@ -177,7 +178,7 @@ public void joinOfflineMeeting(Long meetingId, UserDetails userDetails) { @Transactional(readOnly = true) public List getOfflineMeetingList(OfflineMeetingCategory offlineMeetingCategory) { List meetings = offlineMeetingRepository.findAllByOfflineMeetingCategoryAndMeetingStatus( - offlineMeetingCategory, MeetingStatus.ACTIVE); + offlineMeetingCategory, ACTIVE); return meetings.stream() .map(meeting -> { @@ -191,7 +192,7 @@ public List getOfflineMeetingList(OfflineMeetingC @Transactional(readOnly = true) public List getDeliveryMeetingList(FoodCategory foodCategory) { List meetings = deliveryMeetingRepository.findAllByFoodCategoryAndMeetingStatus(foodCategory, - MeetingStatus.ACTIVE); + ACTIVE); return meetings.stream() .map(meeting -> { @@ -293,7 +294,14 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { @Transactional public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), role); + return meetingRepository.findAllMeetings(member.getMemberId(), role, null); + } + + // 내가 참여 중인 활성화된 모임 조회 + @Transactional + public List getMyActiveMeetingList(UserDetails userDetails, ParticipantRole role) { + Member member = getMember(userDetails); + return meetingRepository.findAllMeetings(member.getMemberId(), null, ACTIVE); } // 회원 정보 조회 메소드 From 1db32ff90f17164e00993067a923d3863f492ae8 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:32:41 +0900 Subject: [PATCH 09/64] =?UTF-8?q?Revert=20"[feat]=20#15=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=A4=91=EC=9D=B8=20=EB=AA=A8=EC=9E=84=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 018dfb5e69cf6e48ebb498208f8bb3b167a486c2. --- .../meeting/controller/MeetingController.java | 13 ++----------- .../repository/MeetingCustomRepository.java | 3 +-- .../MeetingCustomRepositoryImpl.java | 14 ++------------ .../domain/meeting/service/MeetingService.java | 18 +++++------------- 4 files changed, 10 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index a77a959e..eeb150f0 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -119,7 +119,7 @@ public ResponseEntity> getDe } @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "마이페이지에서 내가 생성한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) @@ -128,7 +128,7 @@ public ResponseEntity>> getMyCrea } @GetMapping("/my/participated") - @Operation(summary = "내가 참여한 모임 목록 조회", description = "마이페이지에서 내가 참여한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyParticipatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) @@ -136,13 +136,4 @@ public ResponseEntity>> getMyPart meetingService.getMyMeetingList(userDetails, PARTICIPANT))); } - @GetMapping("my/active") - @Operation(summary = "내가 참여 중인 모임 목록 조회", description = "내가 참여중인 활성화된 모임 목록을 조회합니다.") - public ResponseEntity>> - getMyActiveMeetingList(@AuthenticationPrincipal UserDetails userDetails) { - return ResponseEntity.status(HttpStatus.OK) - .body(GlobalResponseDto.success( - meetingService.getMyActiveMeetingList(userDetails, null))); - } - } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index a5c5f823..b22bd155 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -2,10 +2,9 @@ import java.util.List; -import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role, MeetingStatus meetingStatus); + List findAllMeetings(Long memberId, ParticipantRole role); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index 58d1613b..d6c7a92f 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -7,7 +7,6 @@ import java.util.List; -import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.querydsl.core.types.ExpressionUtils; @@ -26,16 +25,9 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role, - MeetingStatus meetingStatus) { + public List findAllMeetings(Long memberId, ParticipantRole role) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); - BooleanExpression statusCondition = meetingStatus != null ? - meeting.meetingStatus.eq(meetingStatus) : null; - - BooleanExpression roleCondition = role != null ? - meetingParticipant.role.eq(role) : null; - return queryFactory .select(Projections.constructor(MeetingListResponseDto.class, meeting.type, @@ -77,9 +69,8 @@ public List findAllMeetings(Long memberId, ParticipantRo .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId), - roleCondition + meetingParticipant.role.eq(role) ) - .where(statusCondition) .orderBy( meeting.meetingStatus.asc(), new OrderSpecifier<>(Order.ASC, @@ -97,5 +88,4 @@ public List findAllMeetings(Long memberId, ParticipantRo ) .fetch(); } - } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index f206e28a..26547742 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -1,7 +1,6 @@ package com.example.eatmate.app.domain.meeting.service; import static com.example.eatmate.app.domain.meeting.domain.GenderRestriction.*; -import static com.example.eatmate.app.domain.meeting.domain.MeetingStatus.*; import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; import java.time.LocalDateTime; @@ -88,7 +87,7 @@ public CreateDeliveryMeetingResponseDto createDeliveryMeeting( .isLimited(createDeliveryMeetingRequestDto.getIsLimited()) .maxParticipants(createDeliveryMeetingRequestDto.getMaxParticipants()) .build()) - .meetingStatus(ACTIVE) + .meetingStatus(MeetingStatus.ACTIVE) .foodCategory(createDeliveryMeetingRequestDto.getFoodCategory()) .storeName(createDeliveryMeetingRequestDto.getStoreName()) .pickupLocation(createDeliveryMeetingRequestDto.getPickupLocation()) @@ -125,7 +124,7 @@ public CreateOfflineMeetingResponseDto createOfflineMeeting( .isLimited(createOfflineMeetingRequestDto.getIsLimited()) .maxParticipants(createOfflineMeetingRequestDto.getMaxParticipants()) .build()) - .meetingStatus(ACTIVE) + .meetingStatus(MeetingStatus.ACTIVE) .meetingPlace(createOfflineMeetingRequestDto.getMeetingPlace()) .meetingDate(createOfflineMeetingRequestDto.getMeetingDate()) .offlineMeetingCategory(createOfflineMeetingRequestDto.getOfflineMeetingCategory()) @@ -178,7 +177,7 @@ public void joinOfflineMeeting(Long meetingId, UserDetails userDetails) { @Transactional(readOnly = true) public List getOfflineMeetingList(OfflineMeetingCategory offlineMeetingCategory) { List meetings = offlineMeetingRepository.findAllByOfflineMeetingCategoryAndMeetingStatus( - offlineMeetingCategory, ACTIVE); + offlineMeetingCategory, MeetingStatus.ACTIVE); return meetings.stream() .map(meeting -> { @@ -192,7 +191,7 @@ public List getOfflineMeetingList(OfflineMeetingC @Transactional(readOnly = true) public List getDeliveryMeetingList(FoodCategory foodCategory) { List meetings = deliveryMeetingRepository.findAllByFoodCategoryAndMeetingStatus(foodCategory, - ACTIVE); + MeetingStatus.ACTIVE); return meetings.stream() .map(meeting -> { @@ -294,14 +293,7 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { @Transactional public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), role, null); - } - - // 내가 참여 중인 활성화된 모임 조회 - @Transactional - public List getMyActiveMeetingList(UserDetails userDetails, ParticipantRole role) { - Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), null, ACTIVE); + return meetingRepository.findAllMeetings(member.getMemberId(), role); } // 회원 정보 조회 메소드 From b6bdaab917deac0adbf1d1880fe493e720155ee4 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:32:49 +0900 Subject: [PATCH 10/64] =?UTF-8?q?Revert=20"[rename]=20#15=20DTO=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EC=88=98=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c69ebea041c7998a87be2545acdd39ad88e21b33. --- .../app/domain/meeting/controller/MeetingController.java | 6 +++--- .../meeting/domain/repository/MeetingCustomRepository.java | 4 ++-- .../domain/repository/MeetingCustomRepositoryImpl.java | 6 +++--- ...tResponseDto.java => CreatedMeetingListResponseDto.java} | 4 ++-- .../eatmate/app/domain/meeting/service/MeetingService.java | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/main/java/com/example/eatmate/app/domain/meeting/dto/{MeetingListResponseDto.java => CreatedMeetingListResponseDto.java} (92%) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index eeb150f0..a52ca7e0 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -22,9 +22,9 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; -import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.service.MeetingService; @@ -120,7 +120,7 @@ public ResponseEntity> getDe @GetMapping("/my/created") @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyCreatedMeetingList( + public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -129,7 +129,7 @@ public ResponseEntity>> getMyCrea @GetMapping("/my/participated") @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyParticipatedMeetingList( + public ResponseEntity>> getMyParticipatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index b22bd155..9d09e92c 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -3,8 +3,8 @@ import java.util.List; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role); + List findAllMeetings(Long memberId, ParticipantRole role); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index d6c7a92f..a9d0dd46 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -8,7 +8,7 @@ import java.util.List; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.querydsl.core.types.ExpressionUtils; import com.querydsl.core.types.Order; import com.querydsl.core.types.OrderSpecifier; @@ -25,11 +25,11 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role) { + public List findAllMeetings(Long memberId, ParticipantRole role) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); return queryFactory - .select(Projections.constructor(MeetingListResponseDto.class, + .select(Projections.constructor(CreatedMeetingListResponseDto.class, meeting.type, meeting.id, meeting.meetingName, diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java similarity index 92% rename from src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java rename to src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java index 1fcbe088..dd836996 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java @@ -7,7 +7,7 @@ import lombok.Getter; @Getter -public class MeetingListResponseDto { +public class CreatedMeetingListResponseDto { private String meetingType; private Long id; private String meetingName; @@ -18,7 +18,7 @@ public class MeetingListResponseDto { private LocalDateTime orderDeadline; // DeliveryMeeting인 경우 private LocalDateTime meetingDate; // OfflineMeeting인 경우 - public MeetingListResponseDto( + public CreatedMeetingListResponseDto( String type, Long id, String meetingName, diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 26547742..21847df9 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -29,9 +29,9 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; -import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.member.domain.Member; @@ -291,7 +291,7 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { // 내가 생성, 참여한 모임 조회 @Transactional - public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { + public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); return meetingRepository.findAllMeetings(member.getMemberId(), role); } From a0249ad78cf36fcfcfe21d0fbfc307dba977832d Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:32:50 +0900 Subject: [PATCH 11/64] =?UTF-8?q?Revert=20"[feat]=20#15=20=EB=82=B4?= =?UTF-8?q?=EA=B0=80=20=EC=B0=B8=EC=97=AC=ED=95=9C=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 27222cd4a20d4b95f6eecbec4693b90308d9a6c7. --- .../meeting/controller/MeetingController.java | 16 ++-------------- .../repository/MeetingCustomRepository.java | 3 +-- .../repository/MeetingCustomRepositoryImpl.java | 4 ++-- .../domain/repository/MeetingRepository.java | 4 ++++ .../domain/meeting/service/MeetingService.java | 7 +++---- 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index a52ca7e0..dc004413 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -1,7 +1,5 @@ package com.example.eatmate.app.domain.meeting.controller; -import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; - import java.util.List; import org.springframework.http.HttpStatus; @@ -119,21 +117,11 @@ public ResponseEntity> getDe } @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록을 조회합니다.") public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyMeetingList(userDetails, HOST))); + meetingService.getMyCreatedMeetingList(userDetails))); } - - @GetMapping("/my/participated") - @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyParticipatedMeetingList( - @AuthenticationPrincipal UserDetails userDetails) { - return ResponseEntity.status(HttpStatus.OK) - .body(GlobalResponseDto.success( - meetingService.getMyMeetingList(userDetails, PARTICIPANT))); - } - } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index 9d09e92c..f3eb83c9 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -2,9 +2,8 @@ import java.util.List; -import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role); + List findAllHostMeetings(Long memberId); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index a9d0dd46..1467ce3d 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -25,7 +25,7 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role) { + public List findAllHostMeetings(Long memberId) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); return queryFactory @@ -69,7 +69,7 @@ public List findAllMeetings(Long memberId, Partic .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId), - meetingParticipant.role.eq(role) + meetingParticipant.role.eq(ParticipantRole.HOST) ) .orderBy( meeting.meetingStatus.asc(), diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java index 6acc1e0d..42bb2687 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java @@ -1,8 +1,12 @@ package com.example.eatmate.app.domain.meeting.domain.repository; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.Meeting; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingRepository extends JpaRepository, MeetingCustomRepository { + List findAllHostMeetings(Long memberId); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 21847df9..fd89fe15 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -20,7 +20,6 @@ import com.example.eatmate.app.domain.meeting.domain.OfflineMeeting; import com.example.eatmate.app.domain.meeting.domain.OfflineMeetingCategory; import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; -import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.domain.repository.DeliveryMeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingParticipantRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingRepository; @@ -289,11 +288,11 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } } - // 내가 생성, 참여한 모임 조회 + // 내가 생성한 모임 조회 @Transactional - public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { + public List getMyCreatedMeetingList(UserDetails userDetails) { Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), role); + return meetingRepository.findAllHostMeetings(member.getMemberId()); } // 회원 정보 조회 메소드 From 02e934e200a6da9f55a48a347cc3bcbf0fb81636 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:32:51 +0900 Subject: [PATCH 12/64] =?UTF-8?q?Revert=20"[feat]=20#15=20=EB=82=B4?= =?UTF-8?q?=EA=B0=80=20=EC=83=9D=EC=84=B1=ED=95=9C=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 663fc796667d1e11cf645b322c1a819bb313f33b. --- .../meeting/controller/MeetingController.java | 10 ----- .../dto/CreatedMeetingListResponseDto.java | 43 ------------------- .../meeting/service/MeetingService.java | 11 ----- 3 files changed, 64 deletions(-) delete mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index dc004413..9a381df7 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -20,7 +20,6 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; @@ -115,13 +114,4 @@ public ResponseEntity> getDe .body(GlobalResponseDto.success( meetingService.getDeliveryMeetingDetail(meetingId))); } - - @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록을 조회합니다.") - public ResponseEntity>> getMyCreatedMeetingList( - @AuthenticationPrincipal UserDetails userDetails) { - return ResponseEntity.status(HttpStatus.OK) - .body(GlobalResponseDto.success( - meetingService.getMyCreatedMeetingList(userDetails))); - } } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java deleted file mode 100644 index dd836996..00000000 --- a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.eatmate.app.domain.meeting.dto; - -import java.time.LocalDateTime; - -import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; - -import lombok.Getter; - -@Getter -public class CreatedMeetingListResponseDto { - private String meetingType; - private Long id; - private String meetingName; - private MeetingStatus meetingStatus; - private Long participantCount; - private String storeName; // DeliveryMeeting인 경우 - private String meetingPlace; // OfflineMeeting인 경우 - private LocalDateTime orderDeadline; // DeliveryMeeting인 경우 - private LocalDateTime meetingDate; // OfflineMeeting인 경우 - - public CreatedMeetingListResponseDto( - String type, - Long id, - String meetingName, - MeetingStatus meetingStatus, - String storeName, - String meetingPlace, - LocalDateTime orderDeadline, - LocalDateTime meetingDate, - Long participantCount - ) { - this.meetingType = type; - this.id = id; - this.meetingName = meetingName; - this.meetingStatus = meetingStatus; - this.storeName = storeName; - this.meetingPlace = meetingPlace; - this.orderDeadline = orderDeadline; - this.meetingDate = meetingDate; - this.participantCount = participantCount; - } -} - diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index fd89fe15..b2b67c89 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -22,13 +22,11 @@ import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; import com.example.eatmate.app.domain.meeting.domain.repository.DeliveryMeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingParticipantRepository; -import com.example.eatmate.app.domain.meeting.domain.repository.MeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.OfflineMeetingRepository; import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; @@ -48,7 +46,6 @@ public class MeetingService { private final MemberRepository memberRepository; private final OfflineMeetingRepository offlineMeetingRepository; private final MeetingParticipantRepository meetingParticipantRepository; - private final MeetingRepository meetingRepository; // 참여자와 모임 성별제한 일치 여부 확인 메소드 private static void validateGenderRestriction(CreateOfflineMeetingRequestDto requestDto, Member member) { @@ -288,19 +285,11 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } } - // 내가 생성한 모임 조회 - @Transactional - public List getMyCreatedMeetingList(UserDetails userDetails) { - Member member = getMember(userDetails); - return meetingRepository.findAllHostMeetings(member.getMemberId()); - } - // 회원 정보 조회 메소드 private Member getMember(UserDetails userDetails) { return memberRepository.findByEmail(userDetails.getUsername()) .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); } - } From 084cc914ca3561ca8c02f4e37de4eb0b5fe17e0b Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:32:52 +0900 Subject: [PATCH 13/64] =?UTF-8?q?Revert=20"[feat]=20#15=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EA=B5=AC=EB=B6=84=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 355b6b9519051d630719a56362a18756a7e38589. --- .../com/example/eatmate/app/domain/meeting/domain/Meeting.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java index edcf5a00..3cacacce 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java @@ -36,9 +36,6 @@ public abstract class Meeting { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "meeting_type", insertable = false, updatable = false) - private String type; // discriminator 값을 조회하기 위한 필드 - @Column(length = 30, nullable = false) private String meetingName; From d8d65fbeeb2160176b739477060d0bc4e1072ed8 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:32:52 +0900 Subject: [PATCH 14/64] =?UTF-8?q?Revert=20"[feat]=20#15=20QueryDSL=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 73f510ac732f7ce9fe043b650c37e965ea323b4d. --- build.gradle | 9 +- .../repository/MeetingCustomRepository.java | 9 -- .../MeetingCustomRepositoryImpl.java | 91 ------------------- .../domain/repository/MeetingRepository.java | 6 +- .../eatmate/global/config/QueryDslConfig.java | 21 ----- 5 files changed, 2 insertions(+), 134 deletions(-) delete mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java delete mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java delete mode 100644 src/main/java/com/example/eatmate/global/config/QueryDslConfig.java diff --git a/build.gradle b/build.gradle index 4f0095a9..aadd3b33 100644 --- a/build.gradle +++ b/build.gradle @@ -27,16 +27,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' - - // 로그인 implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'com.auth0:java-jwt:4.2.1' implementation 'org.hibernate.validator:hibernate-validator:8.0.0.Final' implementation 'jakarta.validation:jakarta.validation-api:3.0.2' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' - compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' @@ -44,11 +42,6 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' - - implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' - annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" - annotationProcessor "jakarta.annotation:jakarta.annotation-api" - annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java deleted file mode 100644 index f3eb83c9..00000000 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.eatmate.app.domain.meeting.domain.repository; - -import java.util.List; - -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; - -public interface MeetingCustomRepository { - List findAllHostMeetings(Long memberId); -} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java deleted file mode 100644 index 1467ce3d..00000000 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.example.eatmate.app.domain.meeting.domain.repository; - -import static com.example.eatmate.app.domain.meeting.domain.QDeliveryMeeting.*; -import static com.example.eatmate.app.domain.meeting.domain.QMeeting.*; -import static com.example.eatmate.app.domain.meeting.domain.QMeetingParticipant.*; -import static com.example.eatmate.app.domain.meeting.domain.QOfflineMeeting.*; - -import java.util.List; - -import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; -import com.querydsl.core.types.ExpressionUtils; -import com.querydsl.core.types.Order; -import com.querydsl.core.types.OrderSpecifier; -import com.querydsl.core.types.Projections; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.core.types.dsl.CaseBuilder; -import com.querydsl.jpa.JPAExpressions; -import com.querydsl.jpa.impl.JPAQueryFactory; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { - private final JPAQueryFactory queryFactory; - - @Override - public List findAllHostMeetings(Long memberId) { - BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); - - return queryFactory - .select(Projections.constructor(CreatedMeetingListResponseDto.class, - meeting.type, - meeting.id, - meeting.meetingName, - meeting.meetingStatus, - ExpressionUtils.as( - JPAExpressions - .select(deliveryMeeting.storeName) - .from(deliveryMeeting) - .where(deliveryMeeting.id.eq(meeting.id)), - "storeName"), - ExpressionUtils.as( - JPAExpressions - .select(offlineMeeting.meetingPlace) - .from(offlineMeeting) - .where(offlineMeeting.id.eq(meeting.id)), - "meetingPlace"), - ExpressionUtils.as( - JPAExpressions - .select(deliveryMeeting.orderDeadline) - .from(deliveryMeeting) - .where(deliveryMeeting.id.eq(meeting.id)), - "orderDeadline"), - ExpressionUtils.as( - JPAExpressions - .select(offlineMeeting.meetingDate) - .from(offlineMeeting) - .where(offlineMeeting.id.eq(meeting.id)), - "meetingDate"), - ExpressionUtils.as( - JPAExpressions - .select(meetingParticipant.count()) - .from(meetingParticipant) - .where(meetingParticipant.meeting.id.eq(meeting.id)), - "participantCount") - )) - .from(meeting) - .join(meetingParticipant).on( - meetingParticipant.meeting.id.eq(meeting.id), - meetingParticipant.member.memberId.eq(memberId), - meetingParticipant.role.eq(ParticipantRole.HOST) - ) - .orderBy( - meeting.meetingStatus.asc(), - new OrderSpecifier<>(Order.ASC, - new CaseBuilder() - .when(isDelivery) - .then(JPAExpressions - .select(deliveryMeeting.orderDeadline) - .from(deliveryMeeting) - .where(deliveryMeeting.id.eq(meeting.id))) - .otherwise(JPAExpressions - .select(offlineMeeting.meetingDate) - .from(offlineMeeting) - .where(offlineMeeting.id.eq(meeting.id))) - ) - ) - .fetch(); - } -} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java index 42bb2687..b95264c7 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java @@ -1,12 +1,8 @@ package com.example.eatmate.app.domain.meeting.domain.repository; -import java.util.List; - import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.Meeting; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; -public interface MeetingRepository extends JpaRepository, MeetingCustomRepository { - List findAllHostMeetings(Long memberId); +public interface MeetingRepository extends JpaRepository { } diff --git a/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java b/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java deleted file mode 100644 index ff66596f..00000000 --- a/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.example.eatmate.global.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import com.querydsl.jpa.impl.JPAQueryFactory; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; - -@Configuration -public class QueryDslConfig { - - @PersistenceContext - private EntityManager em; - - @Bean - public JPAQueryFactory jpaQueryFactory() { - return new JPAQueryFactory(em); - } -} From f18e61e7b82b1a271c21568770d8b372abd09e8a Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:52:26 +0900 Subject: [PATCH 15/64] =?UTF-8?q?Reapply=20"[feat]=20#15=20QueryDSL=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit d8d65fbeeb2160176b739477060d0bc4e1072ed8. --- build.gradle | 9 +- .../repository/MeetingCustomRepository.java | 9 ++ .../MeetingCustomRepositoryImpl.java | 91 +++++++++++++++++++ .../domain/repository/MeetingRepository.java | 6 +- .../eatmate/global/config/QueryDslConfig.java | 21 +++++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java create mode 100644 src/main/java/com/example/eatmate/global/config/QueryDslConfig.java diff --git a/build.gradle b/build.gradle index aadd3b33..4f0095a9 100644 --- a/build.gradle +++ b/build.gradle @@ -27,14 +27,16 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + + // 로그인 implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'com.auth0:java-jwt:4.2.1' implementation 'org.hibernate.validator:hibernate-validator:8.0.0.Final' implementation 'jakarta.validation:jakarta.validation-api:3.0.2' - runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' @@ -42,6 +44,11 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' + + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java new file mode 100644 index 00000000..f3eb83c9 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -0,0 +1,9 @@ +package com.example.eatmate.app.domain.meeting.domain.repository; + +import java.util.List; + +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; + +public interface MeetingCustomRepository { + List findAllHostMeetings(Long memberId); +} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java new file mode 100644 index 00000000..1467ce3d --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -0,0 +1,91 @@ +package com.example.eatmate.app.domain.meeting.domain.repository; + +import static com.example.eatmate.app.domain.meeting.domain.QDeliveryMeeting.*; +import static com.example.eatmate.app.domain.meeting.domain.QMeeting.*; +import static com.example.eatmate.app.domain.meeting.domain.QMeetingParticipant.*; +import static com.example.eatmate.app.domain.meeting.domain.QOfflineMeeting.*; + +import java.util.List; + +import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; +import com.querydsl.core.types.ExpressionUtils; +import com.querydsl.core.types.Order; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { + private final JPAQueryFactory queryFactory; + + @Override + public List findAllHostMeetings(Long memberId) { + BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); + + return queryFactory + .select(Projections.constructor(CreatedMeetingListResponseDto.class, + meeting.type, + meeting.id, + meeting.meetingName, + meeting.meetingStatus, + ExpressionUtils.as( + JPAExpressions + .select(deliveryMeeting.storeName) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id)), + "storeName"), + ExpressionUtils.as( + JPAExpressions + .select(offlineMeeting.meetingPlace) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id)), + "meetingPlace"), + ExpressionUtils.as( + JPAExpressions + .select(deliveryMeeting.orderDeadline) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id)), + "orderDeadline"), + ExpressionUtils.as( + JPAExpressions + .select(offlineMeeting.meetingDate) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id)), + "meetingDate"), + ExpressionUtils.as( + JPAExpressions + .select(meetingParticipant.count()) + .from(meetingParticipant) + .where(meetingParticipant.meeting.id.eq(meeting.id)), + "participantCount") + )) + .from(meeting) + .join(meetingParticipant).on( + meetingParticipant.meeting.id.eq(meeting.id), + meetingParticipant.member.memberId.eq(memberId), + meetingParticipant.role.eq(ParticipantRole.HOST) + ) + .orderBy( + meeting.meetingStatus.asc(), + new OrderSpecifier<>(Order.ASC, + new CaseBuilder() + .when(isDelivery) + .then(JPAExpressions + .select(deliveryMeeting.orderDeadline) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id))) + .otherwise(JPAExpressions + .select(offlineMeeting.meetingDate) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id))) + ) + ) + .fetch(); + } +} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java index b95264c7..42bb2687 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java @@ -1,8 +1,12 @@ package com.example.eatmate.app.domain.meeting.domain.repository; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.Meeting; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; -public interface MeetingRepository extends JpaRepository { +public interface MeetingRepository extends JpaRepository, MeetingCustomRepository { + List findAllHostMeetings(Long memberId); } diff --git a/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java b/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java new file mode 100644 index 00000000..ff66596f --- /dev/null +++ b/src/main/java/com/example/eatmate/global/config/QueryDslConfig.java @@ -0,0 +1,21 @@ +package com.example.eatmate.global.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.querydsl.jpa.impl.JPAQueryFactory; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +@Configuration +public class QueryDslConfig { + + @PersistenceContext + private EntityManager em; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(em); + } +} From 12843d0e4005999948767615a623752eac5e73cb Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:52:26 +0900 Subject: [PATCH 16/64] =?UTF-8?q?Reapply=20"[feat]=20#15=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EA=B5=AC=EB=B6=84=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 084cc914ca3561ca8c02f4e37de4eb0b5fe17e0b. --- .../com/example/eatmate/app/domain/meeting/domain/Meeting.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java index 3cacacce..edcf5a00 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/Meeting.java @@ -36,6 +36,9 @@ public abstract class Meeting { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "meeting_type", insertable = false, updatable = false) + private String type; // discriminator 값을 조회하기 위한 필드 + @Column(length = 30, nullable = false) private String meetingName; From 54e09b772402c4bd435a2f3527ec58866781e438 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:52:27 +0900 Subject: [PATCH 17/64] =?UTF-8?q?Reapply=20"[feat]=20#15=20=EB=82=B4?= =?UTF-8?q?=EA=B0=80=20=EC=83=9D=EC=84=B1=ED=95=9C=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 02e934e200a6da9f55a48a347cc3bcbf0fb81636. --- .../meeting/controller/MeetingController.java | 10 +++++ .../dto/CreatedMeetingListResponseDto.java | 43 +++++++++++++++++++ .../meeting/service/MeetingService.java | 11 +++++ 3 files changed, 64 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 9a381df7..dc004413 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -20,6 +20,7 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; @@ -114,4 +115,13 @@ public ResponseEntity> getDe .body(GlobalResponseDto.success( meetingService.getDeliveryMeetingDetail(meetingId))); } + + @GetMapping("/my/created") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록을 조회합니다.") + public ResponseEntity>> getMyCreatedMeetingList( + @AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getMyCreatedMeetingList(userDetails))); + } } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java new file mode 100644 index 00000000..dd836996 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java @@ -0,0 +1,43 @@ +package com.example.eatmate.app.domain.meeting.dto; + +import java.time.LocalDateTime; + +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; + +import lombok.Getter; + +@Getter +public class CreatedMeetingListResponseDto { + private String meetingType; + private Long id; + private String meetingName; + private MeetingStatus meetingStatus; + private Long participantCount; + private String storeName; // DeliveryMeeting인 경우 + private String meetingPlace; // OfflineMeeting인 경우 + private LocalDateTime orderDeadline; // DeliveryMeeting인 경우 + private LocalDateTime meetingDate; // OfflineMeeting인 경우 + + public CreatedMeetingListResponseDto( + String type, + Long id, + String meetingName, + MeetingStatus meetingStatus, + String storeName, + String meetingPlace, + LocalDateTime orderDeadline, + LocalDateTime meetingDate, + Long participantCount + ) { + this.meetingType = type; + this.id = id; + this.meetingName = meetingName; + this.meetingStatus = meetingStatus; + this.storeName = storeName; + this.meetingPlace = meetingPlace; + this.orderDeadline = orderDeadline; + this.meetingDate = meetingDate; + this.participantCount = participantCount; + } +} + diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index b2b67c89..fd89fe15 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -22,11 +22,13 @@ import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; import com.example.eatmate.app.domain.meeting.domain.repository.DeliveryMeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingParticipantRepository; +import com.example.eatmate.app.domain.meeting.domain.repository.MeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.OfflineMeetingRepository; import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; +import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; @@ -46,6 +48,7 @@ public class MeetingService { private final MemberRepository memberRepository; private final OfflineMeetingRepository offlineMeetingRepository; private final MeetingParticipantRepository meetingParticipantRepository; + private final MeetingRepository meetingRepository; // 참여자와 모임 성별제한 일치 여부 확인 메소드 private static void validateGenderRestriction(CreateOfflineMeetingRequestDto requestDto, Member member) { @@ -285,11 +288,19 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } } + // 내가 생성한 모임 조회 + @Transactional + public List getMyCreatedMeetingList(UserDetails userDetails) { + Member member = getMember(userDetails); + return meetingRepository.findAllHostMeetings(member.getMemberId()); + } + // 회원 정보 조회 메소드 private Member getMember(UserDetails userDetails) { return memberRepository.findByEmail(userDetails.getUsername()) .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); } + } From 9238ed5c63738b92b67ee38e6fbab640bf63d55b Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:52:27 +0900 Subject: [PATCH 18/64] =?UTF-8?q?Reapply=20"[feat]=20#15=20=EB=82=B4?= =?UTF-8?q?=EA=B0=80=20=EC=B0=B8=EC=97=AC=ED=95=9C=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a0249ad78cf36fcfcfe21d0fbfc307dba977832d. --- .../meeting/controller/MeetingController.java | 16 ++++++++++++++-- .../repository/MeetingCustomRepository.java | 3 ++- .../repository/MeetingCustomRepositoryImpl.java | 4 ++-- .../domain/repository/MeetingRepository.java | 4 ---- .../domain/meeting/service/MeetingService.java | 7 ++++--- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index dc004413..a52ca7e0 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -1,5 +1,7 @@ package com.example.eatmate.app.domain.meeting.controller; +import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; + import java.util.List; import org.springframework.http.HttpStatus; @@ -117,11 +119,21 @@ public ResponseEntity> getDe } @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록을 조회합니다.") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyCreatedMeetingList(userDetails))); + meetingService.getMyMeetingList(userDetails, HOST))); } + + @GetMapping("/my/participated") + @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") + public ResponseEntity>> getMyParticipatedMeetingList( + @AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getMyMeetingList(userDetails, PARTICIPANT))); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index f3eb83c9..9d09e92c 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -2,8 +2,9 @@ import java.util.List; +import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingCustomRepository { - List findAllHostMeetings(Long memberId); + List findAllMeetings(Long memberId, ParticipantRole role); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index 1467ce3d..a9d0dd46 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -25,7 +25,7 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllHostMeetings(Long memberId) { + public List findAllMeetings(Long memberId, ParticipantRole role) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); return queryFactory @@ -69,7 +69,7 @@ public List findAllHostMeetings(Long memberId) { .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId), - meetingParticipant.role.eq(ParticipantRole.HOST) + meetingParticipant.role.eq(role) ) .orderBy( meeting.meetingStatus.asc(), diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java index 42bb2687..6acc1e0d 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingRepository.java @@ -1,12 +1,8 @@ package com.example.eatmate.app.domain.meeting.domain.repository; -import java.util.List; - import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.Meeting; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; public interface MeetingRepository extends JpaRepository, MeetingCustomRepository { - List findAllHostMeetings(Long memberId); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index fd89fe15..21847df9 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -20,6 +20,7 @@ import com.example.eatmate.app.domain.meeting.domain.OfflineMeeting; import com.example.eatmate.app.domain.meeting.domain.OfflineMeetingCategory; import com.example.eatmate.app.domain.meeting.domain.ParticipantLimit; +import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.domain.repository.DeliveryMeetingRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingParticipantRepository; import com.example.eatmate.app.domain.meeting.domain.repository.MeetingRepository; @@ -288,11 +289,11 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } } - // 내가 생성한 모임 조회 + // 내가 생성, 참여한 모임 조회 @Transactional - public List getMyCreatedMeetingList(UserDetails userDetails) { + public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); - return meetingRepository.findAllHostMeetings(member.getMemberId()); + return meetingRepository.findAllMeetings(member.getMemberId(), role); } // 회원 정보 조회 메소드 From 1b510466eb679a4b1e12b1b4e4e7064669a76c2f Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:52:28 +0900 Subject: [PATCH 19/64] =?UTF-8?q?Reapply=20"[rename]=20#15=20DTO=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EC=88=98=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b6bdaab917deac0adbf1d1880fe493e720155ee4. --- .../app/domain/meeting/controller/MeetingController.java | 6 +++--- .../meeting/domain/repository/MeetingCustomRepository.java | 4 ++-- .../domain/repository/MeetingCustomRepositoryImpl.java | 6 +++--- ...tingListResponseDto.java => MeetingListResponseDto.java} | 4 ++-- .../eatmate/app/domain/meeting/service/MeetingService.java | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/main/java/com/example/eatmate/app/domain/meeting/dto/{CreatedMeetingListResponseDto.java => MeetingListResponseDto.java} (92%) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index a52ca7e0..eeb150f0 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -22,9 +22,9 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.service.MeetingService; @@ -120,7 +120,7 @@ public ResponseEntity> getDe @GetMapping("/my/created") @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyCreatedMeetingList( + public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -129,7 +129,7 @@ public ResponseEntity>> ge @GetMapping("/my/participated") @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyParticipatedMeetingList( + public ResponseEntity>> getMyParticipatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index 9d09e92c..b22bd155 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -3,8 +3,8 @@ import java.util.List; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role); + List findAllMeetings(Long memberId, ParticipantRole role); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index a9d0dd46..d6c7a92f 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -8,7 +8,7 @@ import java.util.List; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.querydsl.core.types.ExpressionUtils; import com.querydsl.core.types.Order; import com.querydsl.core.types.OrderSpecifier; @@ -25,11 +25,11 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role) { + public List findAllMeetings(Long memberId, ParticipantRole role) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); return queryFactory - .select(Projections.constructor(CreatedMeetingListResponseDto.class, + .select(Projections.constructor(MeetingListResponseDto.class, meeting.type, meeting.id, meeting.meetingName, diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java similarity index 92% rename from src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java rename to src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java index dd836996..1fcbe088 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/dto/CreatedMeetingListResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java @@ -7,7 +7,7 @@ import lombok.Getter; @Getter -public class CreatedMeetingListResponseDto { +public class MeetingListResponseDto { private String meetingType; private Long id; private String meetingName; @@ -18,7 +18,7 @@ public class CreatedMeetingListResponseDto { private LocalDateTime orderDeadline; // DeliveryMeeting인 경우 private LocalDateTime meetingDate; // OfflineMeeting인 경우 - public CreatedMeetingListResponseDto( + public MeetingListResponseDto( String type, Long id, String meetingName, diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 21847df9..26547742 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -29,9 +29,9 @@ import com.example.eatmate.app.domain.meeting.dto.CreateDeliveryMeetingResponseDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingRequestDto; import com.example.eatmate.app.domain.meeting.dto.CreateOfflineMeetingResponseDto; -import com.example.eatmate.app.domain.meeting.dto.CreatedMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.DeliveryMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.member.domain.Member; @@ -291,7 +291,7 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { // 내가 생성, 참여한 모임 조회 @Transactional - public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { + public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); return meetingRepository.findAllMeetings(member.getMemberId(), role); } From 986a7e1b94adb655c30c21c5ad53e3acae0dc2b2 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:52:29 +0900 Subject: [PATCH 20/64] =?UTF-8?q?Reapply=20"[feat]=20#15=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=A4=91=EC=9D=B8=20=EB=AA=A8=EC=9E=84=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1db32ff90f17164e00993067a923d3863f492ae8. --- .../meeting/controller/MeetingController.java | 13 +++++++++++-- .../repository/MeetingCustomRepository.java | 3 ++- .../MeetingCustomRepositoryImpl.java | 14 ++++++++++++-- .../domain/meeting/service/MeetingService.java | 18 +++++++++++++----- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index eeb150f0..a77a959e 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -119,7 +119,7 @@ public ResponseEntity> getDe } @GetMapping("/my/created") - @Operation(summary = "내가 생성한 모임 목록 조회", description = "내가 생성한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 생성한 모임 목록 조회", description = "마이페이지에서 내가 생성한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyCreatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) @@ -128,7 +128,7 @@ public ResponseEntity>> getMyCrea } @GetMapping("/my/participated") - @Operation(summary = "내가 참여한 모임 목록 조회", description = "내가 참여한 모임 목록(과거 포함)을 조회합니다.") + @Operation(summary = "내가 참여한 모임 목록 조회", description = "마이페이지에서 내가 참여한 모임 목록(과거 포함)을 조회합니다.") public ResponseEntity>> getMyParticipatedMeetingList( @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) @@ -136,4 +136,13 @@ public ResponseEntity>> getMyPart meetingService.getMyMeetingList(userDetails, PARTICIPANT))); } + @GetMapping("my/active") + @Operation(summary = "내가 참여 중인 모임 목록 조회", description = "내가 참여중인 활성화된 모임 목록을 조회합니다.") + public ResponseEntity>> + getMyActiveMeetingList(@AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getMyActiveMeetingList(userDetails, null))); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index b22bd155..a5c5f823 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -2,9 +2,10 @@ import java.util.List; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role); + List findAllMeetings(Long memberId, ParticipantRole role, MeetingStatus meetingStatus); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index d6c7a92f..58d1613b 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -7,6 +7,7 @@ import java.util.List; +import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.querydsl.core.types.ExpressionUtils; @@ -25,9 +26,16 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findAllMeetings(Long memberId, ParticipantRole role) { + public List findAllMeetings(Long memberId, ParticipantRole role, + MeetingStatus meetingStatus) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); + BooleanExpression statusCondition = meetingStatus != null ? + meeting.meetingStatus.eq(meetingStatus) : null; + + BooleanExpression roleCondition = role != null ? + meetingParticipant.role.eq(role) : null; + return queryFactory .select(Projections.constructor(MeetingListResponseDto.class, meeting.type, @@ -69,8 +77,9 @@ public List findAllMeetings(Long memberId, ParticipantRo .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId), - meetingParticipant.role.eq(role) + roleCondition ) + .where(statusCondition) .orderBy( meeting.meetingStatus.asc(), new OrderSpecifier<>(Order.ASC, @@ -88,4 +97,5 @@ public List findAllMeetings(Long memberId, ParticipantRo ) .fetch(); } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 26547742..f206e28a 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -1,6 +1,7 @@ package com.example.eatmate.app.domain.meeting.service; import static com.example.eatmate.app.domain.meeting.domain.GenderRestriction.*; +import static com.example.eatmate.app.domain.meeting.domain.MeetingStatus.*; import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; import java.time.LocalDateTime; @@ -87,7 +88,7 @@ public CreateDeliveryMeetingResponseDto createDeliveryMeeting( .isLimited(createDeliveryMeetingRequestDto.getIsLimited()) .maxParticipants(createDeliveryMeetingRequestDto.getMaxParticipants()) .build()) - .meetingStatus(MeetingStatus.ACTIVE) + .meetingStatus(ACTIVE) .foodCategory(createDeliveryMeetingRequestDto.getFoodCategory()) .storeName(createDeliveryMeetingRequestDto.getStoreName()) .pickupLocation(createDeliveryMeetingRequestDto.getPickupLocation()) @@ -124,7 +125,7 @@ public CreateOfflineMeetingResponseDto createOfflineMeeting( .isLimited(createOfflineMeetingRequestDto.getIsLimited()) .maxParticipants(createOfflineMeetingRequestDto.getMaxParticipants()) .build()) - .meetingStatus(MeetingStatus.ACTIVE) + .meetingStatus(ACTIVE) .meetingPlace(createOfflineMeetingRequestDto.getMeetingPlace()) .meetingDate(createOfflineMeetingRequestDto.getMeetingDate()) .offlineMeetingCategory(createOfflineMeetingRequestDto.getOfflineMeetingCategory()) @@ -177,7 +178,7 @@ public void joinOfflineMeeting(Long meetingId, UserDetails userDetails) { @Transactional(readOnly = true) public List getOfflineMeetingList(OfflineMeetingCategory offlineMeetingCategory) { List meetings = offlineMeetingRepository.findAllByOfflineMeetingCategoryAndMeetingStatus( - offlineMeetingCategory, MeetingStatus.ACTIVE); + offlineMeetingCategory, ACTIVE); return meetings.stream() .map(meeting -> { @@ -191,7 +192,7 @@ public List getOfflineMeetingList(OfflineMeetingC @Transactional(readOnly = true) public List getDeliveryMeetingList(FoodCategory foodCategory) { List meetings = deliveryMeetingRepository.findAllByFoodCategoryAndMeetingStatus(foodCategory, - MeetingStatus.ACTIVE); + ACTIVE); return meetings.stream() .map(meeting -> { @@ -293,7 +294,14 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { @Transactional public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), role); + return meetingRepository.findAllMeetings(member.getMemberId(), role, null); + } + + // 내가 참여 중인 활성화된 모임 조회 + @Transactional + public List getMyActiveMeetingList(UserDetails userDetails, ParticipantRole role) { + Member member = getMember(userDetails); + return meetingRepository.findAllMeetings(member.getMemberId(), null, ACTIVE); } // 회원 정보 조회 메소드 From d79bfe2aadaf838155e90fe3eb59d161263a5fe8 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 7 Jan 2025 21:55:42 +0900 Subject: [PATCH 21/64] =?UTF-8?q?[mod]=20#15=20URI=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/controller/MeetingController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index a77a959e..6c29601a 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -136,7 +136,7 @@ public ResponseEntity>> getMyPart meetingService.getMyMeetingList(userDetails, PARTICIPANT))); } - @GetMapping("my/active") + @GetMapping("my/participating") @Operation(summary = "내가 참여 중인 모임 목록 조회", description = "내가 참여중인 활성화된 모임 목록을 조회합니다.") public ResponseEntity>> getMyActiveMeetingList(@AuthenticationPrincipal UserDetails userDetails) { From 6e173181ec7326e2fdc83e7203fda747684975f9 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:20:10 +0900 Subject: [PATCH 22/64] =?UTF-8?q?[feat]=20#17=20Notice=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=EC=99=80=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/notice/domain/Notice.java | 41 +++++++++++++++++++ .../domain/repository/NoticeRepository.java | 8 ++++ .../notice/dto/NoticeAdminRequestDto.java | 15 +++++++ 3 files changed, 64 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeAdminRequestDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java new file mode 100644 index 00000000..5639709c --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java @@ -0,0 +1,41 @@ +package com.example.eatmate.app.domain.notice.domain; + +import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +@Getter +public class Notice { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + + @Column(columnDefinition = "TEXT") + private String content; + + @Builder + private Notice(NoticeAdminRequestDto noticeAdminRequestDto) { + this.title = noticeAdminRequestDto.getTitle(); + this.content = noticeAdminRequestDto.getContent(); + } + + public static Notice createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { + return Notice.builder() + .noticeAdminRequestDto(noticeAdminRequestDto) + .build(); + } + +} diff --git a/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java b/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java new file mode 100644 index 00000000..84810332 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java @@ -0,0 +1,8 @@ +package com.example.eatmate.app.domain.notice.domain.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.example.eatmate.app.domain.notice.domain.Notice; + +public interface NoticeRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeAdminRequestDto.java b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeAdminRequestDto.java new file mode 100644 index 00000000..acc678dc --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeAdminRequestDto.java @@ -0,0 +1,15 @@ +package com.example.eatmate.app.domain.notice.dto; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; + +@Getter +public class NoticeAdminRequestDto { + + @NotBlank + private String title; + + @NotBlank + private String content; + +} From bf92220ffa7f9c5490ec5df7551ea6791d66a55f Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:20:47 +0900 Subject: [PATCH 23/64] =?UTF-8?q?[feat]=20#17=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=20=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/NoticeAdminController.java | 35 +++++++++++++++++++ .../domain/notice/service/NoticeService.java | 21 +++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java new file mode 100644 index 00000000..25832af4 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java @@ -0,0 +1,35 @@ +package com.example.eatmate.app.domain.notice.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; +import com.example.eatmate.app.domain.notice.service.NoticeService; +import com.example.eatmate.global.response.GlobalResponseDto; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/api/admin/notices") +@RequiredArgsConstructor +public class NoticeAdminController { + + private final NoticeService noticeService; + + @PostMapping + public ResponseEntity> save( + @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { + + noticeService.createNotice(noticeAdminRequestDto); + + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success()); + + } + +} diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java new file mode 100644 index 00000000..6abdcc30 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -0,0 +1,21 @@ +package com.example.eatmate.app.domain.notice.service; + +import org.springframework.stereotype.Service; + +import com.example.eatmate.app.domain.notice.domain.Notice; +import com.example.eatmate.app.domain.notice.domain.repository.NoticeRepository; +import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class NoticeService { + + private final NoticeRepository noticeRepository; + + public void createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { + Notice notice = Notice.createNotice(noticeAdminRequestDto); + noticeRepository.save(notice); + } +} From 30afa2b7259bc312bbb0184e2cb5be7afa9c9b04 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:23:53 +0900 Subject: [PATCH 24/64] =?UTF-8?q?[feat]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=9E=91=EC=84=B1=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/notice/controller/NoticeAdminController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java index 25832af4..9fcaef57 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java @@ -11,6 +11,7 @@ import com.example.eatmate.app.domain.notice.service.NoticeService; import com.example.eatmate.global.response.GlobalResponseDto; +import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -22,6 +23,7 @@ public class NoticeAdminController { private final NoticeService noticeService; @PostMapping + @Operation(summary = "관리자 공지사항 작성", description = "관리자가 공지사항을 작성합니다.") public ResponseEntity> save( @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { From 37e5019b0a55ca8724b37ac1a5294b8826e3522b Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:37:49 +0900 Subject: [PATCH 25/64] =?UTF-8?q?[feat]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=EC=9D=84=20=EC=B0=BE=EC=9D=84=20=EC=88=98=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/eatmate/global/config/error/ErrorCode.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java index cfe6425d..b1903791 100644 --- a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java +++ b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java @@ -34,7 +34,10 @@ public enum ErrorCode { // 신고 SELF_REPORT_NOT_ALLOWED(400, "SELF_REPORT_NOT_ALLOWED", "자기 자신을 신고할 수 없습니다."), INVALID_REPORT_TYPE_LIST(400, "INVALID_REPORT_TYPE_LIST", "올바르지 않은 신고 사유 리스트입니다."), - DUPLICATE_REPORT_NOT_ALLOWED(400, "DUPLICATE_REPORT_NOT_ALLOWED", "같은 유저를 연속적으로 신고할 수 없습니다."); + DUPLICATE_REPORT_NOT_ALLOWED(400, "DUPLICATE_REPORT_NOT_ALLOWED", "같은 유저를 연속적으로 신고할 수 없습니다."), + + // 공지사항 + NOTICE_NOT_FOUND(404, "NOTICE_NOT_FOUND", "해당 공지사항을 찾을 수 없습니다."); private final int status; private final String code; From 91deb29b490f81bddde465b95c5420538ba77742 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:38:11 +0900 Subject: [PATCH 26/64] =?UTF-8?q?[feat]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20responseDto=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notice/dto/NoticeResponseDto.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java new file mode 100644 index 00000000..99b4dec5 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java @@ -0,0 +1,26 @@ +package com.example.eatmate.app.domain.notice.dto; + +import com.example.eatmate.app.domain.notice.domain.Notice; + +import lombok.Builder; +import lombok.Getter; + +@Getter +public class NoticeResponseDto { + Long noticeId; + String title; + String content; + + @Builder + private NoticeResponseDto(Notice notice) { + this.noticeId = notice.getId(); + this.title = notice.getTitle(); + this.content = notice.getContent(); + } + + public static NoticeResponseDto createNoticeResponseDto(Notice notice) { + return NoticeResponseDto.builder() + .notice(notice) + .build(); + } +} From 02dad572207748717b73f85e1a7cc7f5744e5bcd Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:38:24 +0900 Subject: [PATCH 27/64] =?UTF-8?q?[feat]=20#17=20=EB=8B=A8=EC=9D=BC=20?= =?UTF-8?q?=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notice/controller/NoticeController.java | 31 +++++++++++++++++++ .../domain/notice/service/NoticeService.java | 10 ++++++ 2 files changed, 41 insertions(+) create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java new file mode 100644 index 00000000..923eb1c7 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java @@ -0,0 +1,31 @@ +package com.example.eatmate.app.domain.notice.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.example.eatmate.app.domain.notice.dto.NoticeResponseDto; +import com.example.eatmate.app.domain.notice.service.NoticeService; +import com.example.eatmate.global.response.GlobalResponseDto; + +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/api/notices") +@RequiredArgsConstructor +public class NoticeController { + + private final NoticeService noticeService; + + @GetMapping("/{noticeId}") + @Operation(summary = "단일 공지사항 조회", description = "단일 공지사항을 조회합니다.") + public ResponseEntity> getNotice(@PathVariable Long noticeId) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success(noticeService.findNotice(noticeId))); + } + +} diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 6abdcc30..491d67b2 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -5,6 +5,9 @@ import com.example.eatmate.app.domain.notice.domain.Notice; import com.example.eatmate.app.domain.notice.domain.repository.NoticeRepository; import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; +import com.example.eatmate.app.domain.notice.dto.NoticeResponseDto; +import com.example.eatmate.global.config.error.ErrorCode; +import com.example.eatmate.global.config.error.exception.CommonException; import lombok.RequiredArgsConstructor; @@ -18,4 +21,11 @@ public void createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { Notice notice = Notice.createNotice(noticeAdminRequestDto); noticeRepository.save(notice); } + + public NoticeResponseDto findNotice(Long noticeId) { + Notice notice = noticeRepository.findById(noticeId) + .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); + + return NoticeResponseDto.createNoticeResponseDto(notice); + } } From 56353240e5a9fb371255839454d0818e2fdd5bd8 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 00:52:35 +0900 Subject: [PATCH 28/64] =?UTF-8?q?[feat]=20#17=20Notice=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=EA=B0=80=20BaseTimeEntity=EC=9D=84=20?= =?UTF-8?q?=EC=83=81=EC=86=8D,=20DTO=EC=97=90=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9D=BC=EA=B3=BC=20=EC=88=98=EC=A0=95=EC=9D=BC=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/eatmate/app/domain/notice/domain/Notice.java | 3 ++- .../eatmate/app/domain/notice/dto/NoticeResponseDto.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java index 5639709c..197f4d96 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java @@ -1,6 +1,7 @@ package com.example.eatmate.app.domain.notice.domain; import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; +import com.example.eatmate.global.common.BaseTimeEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -15,7 +16,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity @Getter -public class Notice { +public class Notice extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java index 99b4dec5..3650f255 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java @@ -1,5 +1,7 @@ package com.example.eatmate.app.domain.notice.dto; +import java.time.LocalDateTime; + import com.example.eatmate.app.domain.notice.domain.Notice; import lombok.Builder; @@ -10,12 +12,16 @@ public class NoticeResponseDto { Long noticeId; String title; String content; + LocalDateTime createdAt; + LocalDateTime updatedAt; @Builder private NoticeResponseDto(Notice notice) { this.noticeId = notice.getId(); this.title = notice.getTitle(); this.content = notice.getContent(); + this.createdAt = notice.getCreatedAt(); + this.updatedAt = notice.getUpdatedAt(); } public static NoticeResponseDto createNoticeResponseDto(Notice notice) { From 90639b4d274169457b4b551ae979f8fe67c38503 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 01:13:31 +0900 Subject: [PATCH 29/64] =?UTF-8?q?[feat]=20#17=20=EC=98=AC=EB=B0=94?= =?UTF-8?q?=EB=A5=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B0=92=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EA=B2=BD=EC=9A=B0=EC=9D=98=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/eatmate/global/config/error/ErrorCode.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java index b1903791..6c02c923 100644 --- a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java +++ b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java @@ -37,7 +37,9 @@ public enum ErrorCode { DUPLICATE_REPORT_NOT_ALLOWED(400, "DUPLICATE_REPORT_NOT_ALLOWED", "같은 유저를 연속적으로 신고할 수 없습니다."), // 공지사항 - NOTICE_NOT_FOUND(404, "NOTICE_NOT_FOUND", "해당 공지사항을 찾을 수 없습니다."); + NOTICE_NOT_FOUND(404, "NOTICE_NOT_FOUND", "해당 공지사항을 찾을 수 없습니다."), + INVALID_PAGE_NUMBER(400, "INVALID_PAGE_NUMBER ", "올바르지 않은 페이지 넘버입니다."), + INVALID_PAGE_SIZE(400, "INVALID_PAGE_SIZE", "올바르지 않은 페이지 크기입니다"); private final int status; private final String code; From 8b42024273b36be23fcdff03211dbf1a9f059f6c Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 01:13:57 +0900 Subject: [PATCH 30/64] =?UTF-8?q?[feat]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=AC=B4=ED=95=9C=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=ED=98=95=ED=83=9C=EB=A1=9C=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notice/controller/NoticeController.java | 12 ++++++++++++ .../domain/repository/NoticeRepository.java | 3 +++ .../domain/notice/service/NoticeService.java | 17 +++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java index 923eb1c7..9e56fac4 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java @@ -1,10 +1,12 @@ package com.example.eatmate.app.domain.notice.controller; +import org.springframework.data.domain.Slice; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.example.eatmate.app.domain.notice.dto.NoticeResponseDto; @@ -28,4 +30,14 @@ public ResponseEntity> getNotice(@PathVaria .body(GlobalResponseDto.success(noticeService.findNotice(noticeId))); } + @GetMapping + @Operation(summary = "공지사항 목록 조회", description = "공지사항을 조회합니다.") + public ResponseEntity>> getNotices( + @RequestParam int pageNumber, + @RequestParam int pageSize) { + + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success(noticeService.findNotices(pageNumber, pageSize))); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java b/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java index 84810332..10fa4e67 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/domain/repository/NoticeRepository.java @@ -1,8 +1,11 @@ package com.example.eatmate.app.domain.notice.domain.repository; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.notice.domain.Notice; public interface NoticeRepository extends JpaRepository { + Slice findPageBy(Pageable pageable); } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 491d67b2..09e2365d 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -1,5 +1,9 @@ package com.example.eatmate.app.domain.notice.service; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import com.example.eatmate.app.domain.notice.domain.Notice; @@ -28,4 +32,17 @@ public NoticeResponseDto findNotice(Long noticeId) { return NoticeResponseDto.createNoticeResponseDto(notice); } + + public Slice findNotices(int pageNumber, int pageSize) { + if (pageNumber < 0) { + throw new CommonException(ErrorCode.INVALID_PAGE_NUMBER); + } + if (pageSize < 0) { + throw new CommonException(ErrorCode.INVALID_PAGE_SIZE); + } + Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")); + Slice notices = noticeRepository.findPageBy(pageable); + + return notices.map(NoticeResponseDto::createNoticeResponseDto); + } } From 002cd53476594c7eebdb7ada9702df9058333dd8 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 01:24:45 +0900 Subject: [PATCH 31/64] =?UTF-8?q?[feat]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notice/controller/NoticeAdminController.java | 13 +++++++++++++ .../eatmate/app/domain/notice/domain/Notice.java | 5 +++++ .../app/domain/notice/service/NoticeService.java | 10 ++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java index 9fcaef57..652934a3 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java @@ -2,6 +2,8 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -34,4 +36,15 @@ public ResponseEntity> save( } + @PatchMapping("/{noticeId}") + @Operation(summary = "관리자 공지사항 수정", description = "관리자가 공지사항을 수정합니다.") + public ResponseEntity> update(@PathVariable Long noticeId, + @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { + + noticeService.updateNotice(noticeId, noticeAdminRequestDto); + + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success()); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java index 197f4d96..1f743add 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java @@ -39,4 +39,9 @@ public static Notice createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { .build(); } + public void update(NoticeAdminRequestDto noticeAdminRequestDto) { + this.title = noticeAdminRequestDto.getTitle(); + this.content = noticeAdminRequestDto.getContent(); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 09e2365d..6ee20712 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -45,4 +45,14 @@ public Slice findNotices(int pageNumber, int pageSize) { return notices.map(NoticeResponseDto::createNoticeResponseDto); } + + public void updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequestDto) { + + Notice notice = noticeRepository.findById(noticeId) + .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); + + notice.update(noticeAdminRequestDto); + + noticeRepository.save(notice); + } } From 073e3cbded5a63de3724781c23bd974ebd251108 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 01:27:40 +0900 Subject: [PATCH 32/64] =?UTF-8?q?[feat]=20#17=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=20=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notice/controller/NoticeAdminController.java | 10 ++++++++++ .../app/domain/notice/service/NoticeService.java | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java index 652934a3..06481140 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java @@ -2,6 +2,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -47,4 +48,13 @@ public ResponseEntity> update(@PathVariable Long noticeI .body(GlobalResponseDto.success()); } + @DeleteMapping("/{noticeId}") + @Operation(summary = "관리자 공지사항 삭제", description = "관리자가 공지사항을 삭제합니다.") + public ResponseEntity> delete(@PathVariable Long noticeId) { + noticeService.deleteNotice(noticeId); + + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success()); + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 6ee20712..40b1146d 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -55,4 +55,12 @@ public void updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequest noticeRepository.save(notice); } + + public void deleteNotice(Long noticeId) { + + Notice notice = noticeRepository.findById(noticeId) + .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); + + noticeRepository.delete(notice); + } } From fd890a244ca9483846dcb4da2778c479e4141169 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 8 Jan 2025 01:30:27 +0900 Subject: [PATCH 33/64] =?UTF-8?q?[refactor]=20#17=20=EC=97=AC=EB=9F=AC=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=93=A4=20=EC=A4=84=EB=B0=94=EA=BF=88=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/notice/controller/NoticeAdminController.java | 5 ----- .../app/domain/notice/controller/NoticeController.java | 1 - .../eatmate/app/domain/notice/dto/NoticeResponseDto.java | 5 +++++ .../eatmate/app/domain/notice/service/NoticeService.java | 4 ++++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java index 06481140..80d56948 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java @@ -29,9 +29,7 @@ public class NoticeAdminController { @Operation(summary = "관리자 공지사항 작성", description = "관리자가 공지사항을 작성합니다.") public ResponseEntity> save( @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { - noticeService.createNotice(noticeAdminRequestDto); - return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success()); @@ -41,9 +39,7 @@ public ResponseEntity> save( @Operation(summary = "관리자 공지사항 수정", description = "관리자가 공지사항을 수정합니다.") public ResponseEntity> update(@PathVariable Long noticeId, @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { - noticeService.updateNotice(noticeId, noticeAdminRequestDto); - return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success()); } @@ -52,7 +48,6 @@ public ResponseEntity> update(@PathVariable Long noticeI @Operation(summary = "관리자 공지사항 삭제", description = "관리자가 공지사항을 삭제합니다.") public ResponseEntity> delete(@PathVariable Long noticeId) { noticeService.deleteNotice(noticeId); - return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success()); } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java index 9e56fac4..a16d744e 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java @@ -35,7 +35,6 @@ public ResponseEntity> getNotice(@PathVaria public ResponseEntity>> getNotices( @RequestParam int pageNumber, @RequestParam int pageSize) { - return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success(noticeService.findNotices(pageNumber, pageSize))); } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java index 3650f255..9d210096 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java @@ -9,10 +9,15 @@ @Getter public class NoticeResponseDto { + Long noticeId; + String title; + String content; + LocalDateTime createdAt; + LocalDateTime updatedAt; @Builder diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 40b1146d..1f421ae8 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -22,11 +22,13 @@ public class NoticeService { private final NoticeRepository noticeRepository; public void createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { + Notice notice = Notice.createNotice(noticeAdminRequestDto); noticeRepository.save(notice); } public NoticeResponseDto findNotice(Long noticeId) { + Notice notice = noticeRepository.findById(noticeId) .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); @@ -34,12 +36,14 @@ public NoticeResponseDto findNotice(Long noticeId) { } public Slice findNotices(int pageNumber, int pageSize) { + if (pageNumber < 0) { throw new CommonException(ErrorCode.INVALID_PAGE_NUMBER); } if (pageSize < 0) { throw new CommonException(ErrorCode.INVALID_PAGE_SIZE); } + Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")); Slice notices = noticeRepository.findPageBy(pageable); From 373b7980d1afff760847ce6eaa36a80bb157969b Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Wed, 8 Jan 2025 19:50:40 +0900 Subject: [PATCH 34/64] =?UTF-8?q?[feat]=20#15=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EB=AA=85=20=ED=99=95=EC=9D=B8=20=EB=A1=9C=EA=B7=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalExceptionHandler.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java b/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java index 268f2b47..99e21d27 100644 --- a/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java @@ -34,8 +34,9 @@ public ResponseEntity handleGenericException(Exception ex) { ErrorCode errorCode = ErrorCode.INTERNAL_SERVER_ERROR; ErrorResponse errorResponse = new ErrorResponse(errorCode); log.error(ex.getMessage()); + log.error(ex.getClass().getSimpleName()); return ResponseEntity.status(HttpStatus.valueOf(errorCode.getStatus())) - .body(GlobalResponseDto.fail(errorCode, errorResponse.getMessage())); + .body(GlobalResponseDto.fail(errorCode, errorResponse.getMessage())); } @ExceptionHandler(CommonException.class) // Custom Exception을 포괄적으로 처리 @@ -44,23 +45,23 @@ public ResponseEntity> handleCommonException(CommonExc ErrorResponse errorResponse = new ErrorResponse(errorCode); showErrorLog(errorCode); return ResponseEntity.status(HttpStatus.valueOf(errorCode.getStatus())) - .body(GlobalResponseDto.fail(errorCode, errorResponse.getMessage())); + .body(GlobalResponseDto.fail(errorCode, errorResponse.getMessage())); } @ExceptionHandler(MethodArgumentNotValidException.class) // Valid 검증 실패시 예외처리 public ResponseEntity> handleValidationExceptions( - MethodArgumentNotValidException ex) { + MethodArgumentNotValidException ex) { ErrorCode errorCode = ErrorCode.VALIDATION_FAILED; // 모든 검증 오류를 하나의 문자열로 결합 String errorMessage = ex.getBindingResult() - .getAllErrors() - .stream() - .map(error -> error.getDefaultMessage()) - .collect(Collectors.joining(", ")); + .getAllErrors() + .stream() + .map(error -> error.getDefaultMessage()) + .collect(Collectors.joining(", ")); return ResponseEntity.status(HttpStatus.valueOf(errorCode.getStatus())) - .body(GlobalResponseDto.fail(errorCode, errorMessage)); + .body(GlobalResponseDto.fail(errorCode, errorMessage)); } -} \ No newline at end of file +} From 7064daf16157415face349aacd501864a4b74bf4 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Wed, 8 Jan 2025 20:47:34 +0900 Subject: [PATCH 35/64] =?UTF-8?q?[feat]=20#15=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/eatmate/global/config/error/ErrorCode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java index cabf50bd..fe6437c3 100644 --- a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java +++ b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java @@ -22,6 +22,7 @@ public enum ErrorCode { INVALID_MBTI(404, "INVALID_MBTI", "유효하지 않은 MBTI입니다."), INVALID_GENDER(400, "INVALID_GENDER", "성별 선택은 필수입니다."), INVALID_PHONE_NUMBER(400, "INVALID_PHONE_NUMBER", "유효하지 않은 전화번호입니다."), + INVALID_LOGIN_INFO(401, "INVALID_LOGIN_INFO", "로그인 정보가 올바르지 않습니다."), // 모임 INVALID_PARTICIPANT_LIMIT(400, "INVALID_PARTICIPANT_LIMIT", "올바른 참가자 수를 입력해주세요."), From 2f83d0b4e73a85517f6db44766f3a62b3df7bf01 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Wed, 8 Jan 2025 20:47:53 +0900 Subject: [PATCH 36/64] =?UTF-8?q?[feat]=20#15=20=EC=9E=84=EB=B0=95?= =?UTF-8?q?=ED=95=9C=20=EB=AA=A8=EC=9E=84=20=ED=99=95=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meeting/controller/MeetingController.java | 12 +++- .../repository/MeetingCustomRepository.java | 3 + .../MeetingCustomRepositoryImpl.java | 60 ++++++++++++++++++- .../dto/UpcomingMeetingResponseDto.java | 18 ++++++ .../meeting/service/MeetingService.java | 26 +++++++- 5 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/example/eatmate/app/domain/meeting/dto/UpcomingMeetingResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 6c29601a..349a8360 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -27,6 +27,7 @@ import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.UpcomingMeetingResponseDto; import com.example.eatmate.app.domain.meeting.service.MeetingService; import com.example.eatmate.global.response.GlobalResponseDto; @@ -142,7 +143,16 @@ public ResponseEntity>> getMyPart getMyActiveMeetingList(@AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyActiveMeetingList(userDetails, null))); + meetingService.getMyActiveMeetingList(userDetails))); + } + + @GetMapping("my/upcoming") + @Operation(summary = "가장 임박한 모임 조회", description = "내가 참여중인 활성화된 모임 중 가장 임박한 모임을 조회합니다.") + public ResponseEntity> getUpcomingMeeting( + @AuthenticationPrincipal UserDetails userDetails) { + return ResponseEntity.status(HttpStatus.OK) + .body(GlobalResponseDto.success( + meetingService.getUpcomingMeeting(userDetails))); } } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index a5c5f823..14b1fc05 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -5,7 +5,10 @@ import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.UpcomingMeetingResponseDto; public interface MeetingCustomRepository { List findAllMeetings(Long memberId, ParticipantRole role, MeetingStatus meetingStatus); + + UpcomingMeetingResponseDto findUpcomingMeeting(Long memberId); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index 58d1613b..3b220e19 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -10,6 +10,7 @@ import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; import com.example.eatmate.app.domain.meeting.domain.ParticipantRole; import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.UpcomingMeetingResponseDto; import com.querydsl.core.types.ExpressionUtils; import com.querydsl.core.types.Order; import com.querydsl.core.types.OrderSpecifier; @@ -76,10 +77,9 @@ public List findAllMeetings(Long memberId, ParticipantRo .from(meeting) .join(meetingParticipant).on( meetingParticipant.meeting.id.eq(meeting.id), - meetingParticipant.member.memberId.eq(memberId), - roleCondition + meetingParticipant.member.memberId.eq(memberId) ) - .where(statusCondition) + .where(statusCondition, roleCondition) .orderBy( meeting.meetingStatus.asc(), new OrderSpecifier<>(Order.ASC, @@ -98,4 +98,58 @@ public List findAllMeetings(Long memberId, ParticipantRo .fetch(); } + @Override + public UpcomingMeetingResponseDto findUpcomingMeeting(Long memberId) { + BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); + + return queryFactory + .select(Projections.constructor(UpcomingMeetingResponseDto.class, + meetingParticipant.member.nickname, + ExpressionUtils.as( + new CaseBuilder() + .when(isDelivery) + .then(JPAExpressions + .select(deliveryMeeting.orderDeadline) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id))) + .otherwise(JPAExpressions + .select(offlineMeeting.meetingDate) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id))), + "meetingTime"), + ExpressionUtils.as( + new CaseBuilder() + .when(isDelivery) + .then(JPAExpressions + .select(deliveryMeeting.storeName) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id))) + .otherwise(JPAExpressions + .select(offlineMeeting.meetingPlace) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id))), + "meetingLocation") + )) + .from(meeting) + .join(meetingParticipant).on( + meetingParticipant.meeting.id.eq(meeting.id), + meetingParticipant.member.memberId.eq(memberId) + ) + .where(meeting.meetingStatus.eq(MeetingStatus.ACTIVE)) + .orderBy( + new OrderSpecifier<>(Order.ASC, + new CaseBuilder() + .when(isDelivery) + .then(JPAExpressions + .select(deliveryMeeting.orderDeadline) + .from(deliveryMeeting) + .where(deliveryMeeting.id.eq(meeting.id))) + .otherwise(JPAExpressions + .select(offlineMeeting.meetingDate) + .from(offlineMeeting) + .where(offlineMeeting.id.eq(meeting.id))) + ) + ) + .fetchFirst(); + } } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/UpcomingMeetingResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/UpcomingMeetingResponseDto.java new file mode 100644 index 00000000..87d0ef23 --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/UpcomingMeetingResponseDto.java @@ -0,0 +1,18 @@ +package com.example.eatmate.app.domain.meeting.dto; + +import java.time.LocalDateTime; + +import lombok.Getter; + +@Getter +public class UpcomingMeetingResponseDto { + private String nickname; + private LocalDateTime meetingTime; + private String meetingLocation; + + public UpcomingMeetingResponseDto(String nickname, LocalDateTime meetingTime, String meetingLocation) { + this.nickname = nickname; + this.meetingTime = meetingTime; + this.meetingLocation = meetingLocation; + } +} diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index f206e28a..45d91171 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -35,6 +35,7 @@ import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingDetailResponseDto; import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; +import com.example.eatmate.app.domain.meeting.dto.UpcomingMeetingResponseDto; import com.example.eatmate.app.domain.member.domain.Member; import com.example.eatmate.app.domain.member.domain.repository.MemberRepository; import com.example.eatmate.global.config.error.ErrorCode; @@ -291,21 +292,40 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { } // 내가 생성, 참여한 모임 조회 - @Transactional + @Transactional(readOnly = true) public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { Member member = getMember(userDetails); return meetingRepository.findAllMeetings(member.getMemberId(), role, null); } // 내가 참여 중인 활성화된 모임 조회 - @Transactional - public List getMyActiveMeetingList(UserDetails userDetails, ParticipantRole role) { + @Transactional(readOnly = true) + public List getMyActiveMeetingList(UserDetails userDetails) { Member member = getMember(userDetails); return meetingRepository.findAllMeetings(member.getMemberId(), null, ACTIVE); } + // 가장 최근 미팅 조회 + @Transactional(readOnly = true) + public UpcomingMeetingResponseDto getUpcomingMeeting(UserDetails userDetails) { + Member member = getMember(userDetails); + + // 임박한 미팅 조회 + UpcomingMeetingResponseDto upcomingMeeting = meetingRepository.findUpcomingMeeting(member.getMemberId()); + + // 진행중인 미팅이 없는 경우 + if (upcomingMeeting == null) { + throw new CommonException(ErrorCode.MEETING_NOT_FOUND); + } + + return upcomingMeeting; + } + // 회원 정보 조회 메소드 private Member getMember(UserDetails userDetails) { + if (userDetails == null) { + throw new CommonException(ErrorCode.INVALID_LOGIN_INFO); + } return memberRepository.findByEmail(userDetails.getUsername()) .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); } From 2cde72a86ac9b8aeb0f0f410026bfb86671714ad Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 02:46:42 +0900 Subject: [PATCH 37/64] =?UTF-8?q?=20[feat]=20#23=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=9D=91=EB=8B=B5Dto=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/login/dto/UserLoginResponseDto.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/example/eatmate/global/auth/login/dto/UserLoginResponseDto.java diff --git a/src/main/java/com/example/eatmate/global/auth/login/dto/UserLoginResponseDto.java b/src/main/java/com/example/eatmate/global/auth/login/dto/UserLoginResponseDto.java new file mode 100644 index 00000000..16c785b6 --- /dev/null +++ b/src/main/java/com/example/eatmate/global/auth/login/dto/UserLoginResponseDto.java @@ -0,0 +1,15 @@ +package com.example.eatmate.global.auth.login.dto; + +import com.example.eatmate.app.domain.member.domain.Role; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class UserLoginResponseDto { + + private String email; + private Role role; +} From 1fff507739bf430e6d753d56d638444757608d29 Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 02:48:02 +0900 Subject: [PATCH 38/64] =?UTF-8?q?=20[add]=20#23=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/eatmate/global/config/error/ErrorCode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java index cfe6425d..ca5213f3 100644 --- a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java +++ b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java @@ -13,6 +13,7 @@ public enum ErrorCode { //회원 USER_NOT_FOUND(404, "USER_NOT_FOUND", "유저를 찾을 수 없습니다."), + TOKEN_NOT_FOUND(404, "TOKEN_NOT_FOUND", "토큰를 찾을 수 없습니다."), MEMBER_ALREADY_EXISTS(409, "MEMBER_ALREADY_EXISTS", "이미 가입된 이메일입니다."), DUPLICATE_PHONE_NUMBER(409, "DUPLICATE_PHONE_NUMBER", "이미 사용 중인 전화번호입니다."), DUPLICATE_STUDENT_NUMBER(409, "DUPLICATE_STUDENT_NUMBER", "이미 사용 중인 학번입니다."), From 2469fbfdc89c3bcf411d587cab8f48e44b2298cf Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 02:49:30 +0900 Subject: [PATCH 39/64] =?UTF-8?q?=20[add]=20#23=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C(=ED=86=A0?= =?UTF-8?q?=ED=81=B0=EC=97=90=EC=84=9C=20=EC=B6=94=EC=B6=9C)=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/login/controller/AuthController.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/controller/AuthController.java b/src/main/java/com/example/eatmate/global/auth/login/controller/AuthController.java index 1b2cb932..f5103c79 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/controller/AuthController.java +++ b/src/main/java/com/example/eatmate/global/auth/login/controller/AuthController.java @@ -1,13 +1,15 @@ package com.example.eatmate.global.auth.login.controller; +import com.example.eatmate.global.auth.jwt.JwtService; +import com.example.eatmate.global.auth.login.dto.UserLoginResponseDto; +import com.example.eatmate.global.auth.login.service.LoginService; +import com.example.eatmate.global.config.error.exception.CommonException; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import com.example.eatmate.app.domain.member.dto.MemberSignUpRequestDto; import com.example.eatmate.app.domain.member.service.MemberService; @@ -23,6 +25,8 @@ public class AuthController { private final MemberService memberService; + private final JwtService jwtService; + private final LoginService loginService; //회원가입 @PostMapping("/signup") //매핑 경로 수정 @@ -36,5 +40,16 @@ public ResponseEntity> register( HttpStatus.CREATED.value())); } - //로그아웃 + //로그인 시, 사용자 정보 조회 + @GetMapping("/info") + @Operation(summary = "사용자 정보 조회", description = "로그인 기반으로 사용자 정보를 조회합니다.") + public ResponseEntity> getUserInfo(HttpServletRequest request) { + + UserLoginResponseDto userInfo = loginService.getUserInfoFromRequest(request); + + return ResponseEntity.ok(GlobalResponseDto.success(userInfo, HttpStatus.OK.value())); + } + + + } From c7ca6ad89f403528791a4574c0b1e7288e273817 Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 02:49:48 +0900 Subject: [PATCH 40/64] =?UTF-8?q?=20[add]=20#23=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C(=ED=86=A0?= =?UTF-8?q?=ED=81=B0=EC=97=90=EC=84=9C=20=EC=B6=94=EC=B6=9C)=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/login/service/LoginService.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/main/java/com/example/eatmate/global/auth/login/service/LoginService.java b/src/main/java/com/example/eatmate/global/auth/login/service/LoginService.java index 69076c99..bf476439 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/service/LoginService.java +++ b/src/main/java/com/example/eatmate/global/auth/login/service/LoginService.java @@ -3,8 +3,15 @@ import static org.springframework.security.core.userdetails.User.*; import com.example.eatmate.app.domain.member.domain.Member; +import com.example.eatmate.app.domain.member.domain.Role; import com.example.eatmate.app.domain.member.domain.repository.MemberRepository; +import com.example.eatmate.global.auth.jwt.JwtService; +import com.example.eatmate.global.auth.login.dto.UserLoginResponseDto; +import com.example.eatmate.global.config.error.ErrorCode; +import com.example.eatmate.global.config.error.exception.CommonException; +import com.example.eatmate.global.config.error.exception.custom.InvalidTokenException; import com.example.eatmate.global.config.error.exception.custom.UserNotFoundException; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -17,6 +24,7 @@ public class LoginService implements UserDetailsService { private final MemberRepository memberRepository; + private final JwtService jwtService; @Override public UserDetails loadUserByUsername(String email) throws UserNotFoundException { @@ -28,4 +36,31 @@ public UserDetails loadUserByUsername(String email) throws UserNotFoundException .username(member.getEmail()) .build(); } + + public UserLoginResponseDto getUserInfoFromRequest(HttpServletRequest request) { + // 쿠키에서 AccessToken 추출 + String accessToken = jwtService.extractAccessTokenFromCookie(request) + .orElseThrow(() -> new CommonException(ErrorCode.TOKEN_NOT_FOUND)); + + // AccessToken 유효성 검증 및 사용자 정보 조회 + return getUserInfo(accessToken); + } + + public UserLoginResponseDto getUserInfo(String accessToken) { + // AccessToken 유효성 검증 + if (!jwtService.isTokenValid(accessToken)) { + throw new CommonException(ErrorCode.INVALID_TOKEN); + } + // AccessToken에서 이메일과 역할(Role) 추출 + String email = jwtService.extractEmail(accessToken) + .orElseThrow(() -> new CommonException(ErrorCode.INVALID_TOKEN)); + String role = jwtService.extractRole(accessToken) + .orElseThrow(() -> new CommonException(ErrorCode.INVALID_TOKEN)); + + // 사용자 정보 반환 + return new UserLoginResponseDto(email, Role.valueOf(role)); + } + + + } From 4b3fef6f3f05640b9edd194d592111b92694adea Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 02:50:53 +0900 Subject: [PATCH 41/64] =?UTF-8?q?=20[mod]=20#23=20=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=ED=99=98=EA=B2=BD=20=EC=A0=84=EC=9A=A9=20SECURE=20=3D=20TRUE?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/auth/login/oauth/OAuthLoginSuccessHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java index c0a0c311..bb1f89fd 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java +++ b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java @@ -22,7 +22,7 @@ public class OAuthLoginSuccessHandler implements AuthenticationSuccessHandler { private final JwtService jwtService; private static final boolean COOKIE_HTTP_ONLY = true; - private static final boolean COOKIE_SECURE = false; + private static final boolean COOKIE_SECURE = true; //https 환경에서는 true private static final String COOKIE_PATH = "/"; private static final int ACCESS_TOKEN_MAX_AGE = 60 * 60; // 1시간 private static final int REFRESH_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7일 From fa5c210929066e45f8974fdde3b058a8bc9a61ef Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Thu, 9 Jan 2025 11:09:42 +0900 Subject: [PATCH 42/64] =?UTF-8?q?[feat]=20#15=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 내가 생성한 모임 목록 조회, 내가 참여한 모임 목록 조회, 내가 참여 중인 모임 목록 조회에만 적용 --- .../meeting/controller/MeetingController.java | 45 +++++++++++++++---- .../repository/MeetingCustomRepository.java | 4 +- .../MeetingCustomRepositoryImpl.java | 42 +++++++++++++++-- .../meeting/dto/MeetingListResponseDto.java | 5 +++ .../meeting/service/MeetingService.java | 38 ++++++++++++++-- .../global/response/CursorResponseDto.java | 44 ++++++++++++++++++ 6 files changed, 161 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/example/eatmate/global/response/CursorResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 349a8360..3755ded4 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -2,8 +2,10 @@ import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; +import java.time.LocalDateTime; import java.util.List; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -29,10 +31,14 @@ import com.example.eatmate.app.domain.meeting.dto.OfflineMeetingListResponseDto; import com.example.eatmate.app.domain.meeting.dto.UpcomingMeetingResponseDto; import com.example.eatmate.app.domain.meeting.service.MeetingService; +import com.example.eatmate.global.response.CursorResponseDto; import com.example.eatmate.global.response.GlobalResponseDto; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Positive; import lombok.RequiredArgsConstructor; @RestController @@ -121,29 +127,50 @@ public ResponseEntity> getDe @GetMapping("/my/created") @Operation(summary = "내가 생성한 모임 목록 조회", description = "마이페이지에서 내가 생성한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyCreatedMeetingList( - @AuthenticationPrincipal UserDetails userDetails) { + @Parameter(name = "lastMeetingId", description = "마지막으로 조회한 모임 ID", required = false) + @Parameter(name = "lastDateTime", description = "마지막으로 조회한 모임의 날짜시간(ISO 형식: yyyy-MM-dd'T'HH:mm:ss)", required = false) + @Parameter(name = "pageSize", description = "페이지당 조회할 항목 수 (기본값: 20, 최대: 100)", required = false) + public ResponseEntity>> getMyCreatedMeetingList( + @AuthenticationPrincipal UserDetails userDetails, + @RequestParam(required = false) Long lastMeetingId, + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastDateTime, + @RequestParam(defaultValue = "20") @Positive @Max(100) int pageSize + ) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyMeetingList(userDetails, HOST))); + meetingService.getMyMeetingList(userDetails, HOST, lastMeetingId, lastDateTime, pageSize))); } @GetMapping("/my/participated") @Operation(summary = "내가 참여한 모임 목록 조회", description = "마이페이지에서 내가 참여한 모임 목록(과거 포함)을 조회합니다.") - public ResponseEntity>> getMyParticipatedMeetingList( - @AuthenticationPrincipal UserDetails userDetails) { + @Parameter(name = "lastMeetingId", description = "마지막으로 조회한 모임 ID", required = false) + @Parameter(name = "lastDateTime", description = "마지막으로 조회한 모임의 날짜시간(ISO 형식: yyyy-MM-dd'T'HH:mm:ss)", required = false) + @Parameter(name = "pageSize", description = "페이지당 조회할 항목 수 (기본값: 20, 최대: 100)", required = false) + public ResponseEntity>> getMyParticipatedMeetingList( + @AuthenticationPrincipal UserDetails userDetails, + @RequestParam(required = false) Long lastMeetingId, + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastDateTime, + @RequestParam(defaultValue = "20") @Positive @Max(100) int pageSize + ) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyMeetingList(userDetails, PARTICIPANT))); + meetingService.getMyMeetingList(userDetails, PARTICIPANT, lastMeetingId, lastDateTime, pageSize))); } @GetMapping("my/participating") @Operation(summary = "내가 참여 중인 모임 목록 조회", description = "내가 참여중인 활성화된 모임 목록을 조회합니다.") - public ResponseEntity>> - getMyActiveMeetingList(@AuthenticationPrincipal UserDetails userDetails) { + @Parameter(name = "lastMeetingId", description = "마지막으로 조회한 모임 ID", required = false) + @Parameter(name = "lastDateTime", description = "마지막으로 조회한 모임의 날짜시간(ISO 형식: yyyy-MM-dd'T'HH:mm:ss)", required = false) + @Parameter(name = "pageSize", description = "페이지당 조회할 항목 수 (기본값: 20, 최대: 100)", required = false) + public ResponseEntity>> getMyActiveMeetingList( + @AuthenticationPrincipal UserDetails userDetails, + @RequestParam(required = false) Long lastMeetingId, + @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastDateTime, + @RequestParam(defaultValue = "20") @Positive @Max(100) int pageSize + ) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getMyActiveMeetingList(userDetails))); + meetingService.getMyActiveMeetingList(userDetails, lastMeetingId, lastDateTime, pageSize))); } @GetMapping("my/upcoming") diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java index 14b1fc05..1783c27a 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepository.java @@ -1,5 +1,6 @@ package com.example.eatmate.app.domain.meeting.domain.repository; +import java.time.LocalDateTime; import java.util.List; import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; @@ -8,7 +9,8 @@ import com.example.eatmate.app.domain.meeting.dto.UpcomingMeetingResponseDto; public interface MeetingCustomRepository { - List findAllMeetings(Long memberId, ParticipantRole role, MeetingStatus meetingStatus); + List findAllMeetings(Long memberId, ParticipantRole role, MeetingStatus meetingStatus, + Long lastMeetingId, LocalDateTime lastDateTime, int pageSize); UpcomingMeetingResponseDto findUpcomingMeeting(Long memberId); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java index 3b220e19..137499d9 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/MeetingCustomRepositoryImpl.java @@ -5,6 +5,7 @@ import static com.example.eatmate.app.domain.meeting.domain.QMeetingParticipant.*; import static com.example.eatmate.app.domain.meeting.domain.QOfflineMeeting.*; +import java.time.LocalDateTime; import java.util.List; import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; @@ -28,15 +29,20 @@ public class MeetingCustomRepositoryImpl implements MeetingCustomRepository { @Override public List findAllMeetings(Long memberId, ParticipantRole role, - MeetingStatus meetingStatus) { + MeetingStatus meetingStatus, Long lastMeetingId, LocalDateTime lastDateTime, int pageSize) { + BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); + // 상태와 역할에 대한 조건 BooleanExpression statusCondition = meetingStatus != null ? meeting.meetingStatus.eq(meetingStatus) : null; BooleanExpression roleCondition = role != null ? meetingParticipant.role.eq(role) : null; + // No-Offset 페이징을 위한 동적 조건 + BooleanExpression cursorCondition = getCursorCondition(lastMeetingId, lastDateTime); + return queryFactory .select(Projections.constructor(MeetingListResponseDto.class, meeting.type, @@ -79,7 +85,7 @@ public List findAllMeetings(Long memberId, ParticipantRo meetingParticipant.meeting.id.eq(meeting.id), meetingParticipant.member.memberId.eq(memberId) ) - .where(statusCondition, roleCondition) + .where(statusCondition, roleCondition, cursorCondition) .orderBy( meeting.meetingStatus.asc(), new OrderSpecifier<>(Order.ASC, @@ -93,11 +99,41 @@ public List findAllMeetings(Long memberId, ParticipantRo .select(offlineMeeting.meetingDate) .from(offlineMeeting) .where(offlineMeeting.id.eq(meeting.id))) - ) + ), + meeting.id.desc() ) + .limit(pageSize) .fetch(); } + private BooleanExpression getCursorCondition(Long lastMeetingId, LocalDateTime lastDateTime) { + if (lastMeetingId == null || lastDateTime == null) { + return null; + } + + return new CaseBuilder() + .when(meeting.meetingStatus.ne(MeetingStatus.INACTIVE)) + .then(1) + .otherwise(0) + .eq(new CaseBuilder() + .when(meeting.meetingStatus.ne(MeetingStatus.INACTIVE)) + .then(1) + .otherwise(0)) + .and(new CaseBuilder() + .when(meeting.type.eq("DELIVERY")) + .then(deliveryMeeting.orderDeadline) + .otherwise(offlineMeeting.meetingDate) + .gt(lastDateTime) + .or(new CaseBuilder() + .when(meeting.type.eq("DELIVERY")) + .then(deliveryMeeting.orderDeadline) + .otherwise(offlineMeeting.meetingDate) + .eq(lastDateTime) + .and(meeting.id.lt(lastMeetingId)) + ) + ); + } + @Override public UpcomingMeetingResponseDto findUpcomingMeeting(Long memberId) { BooleanExpression isDelivery = meeting.type.eq("DELIVERY"); diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java index 1fcbe088..e7987f37 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java @@ -39,5 +39,10 @@ public MeetingListResponseDto( this.meetingDate = meetingDate; this.participantCount = participantCount; } + + public LocalDateTime getDateTime() { + return "DELIVERY".equals(meetingType) ? orderDeadline : meetingDate; + } + } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index 45d91171..cb1d4568 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -40,7 +40,10 @@ import com.example.eatmate.app.domain.member.domain.repository.MemberRepository; import com.example.eatmate.global.config.error.ErrorCode; import com.example.eatmate.global.config.error.exception.CommonException; +import com.example.eatmate.global.response.CursorResponseDto; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Positive; import lombok.RequiredArgsConstructor; @Service @@ -293,16 +296,43 @@ private void validateDuplicateParticipant(Meeting meeting, Member member) { // 내가 생성, 참여한 모임 조회 @Transactional(readOnly = true) - public List getMyMeetingList(UserDetails userDetails, ParticipantRole role) { + public CursorResponseDto getMyMeetingList( + UserDetails userDetails, + ParticipantRole role, + Long lastMeetingId, + LocalDateTime lastDateTime, + @Positive @Max(value = 100) int pageSize + ) { Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), role, null); + List meetings = meetingRepository.findAllMeetings( + member.getMemberId(), + role, + null, + lastMeetingId, + lastDateTime, + pageSize + ); + return CursorResponseDto.of(meetings, pageSize); } // 내가 참여 중인 활성화된 모임 조회 @Transactional(readOnly = true) - public List getMyActiveMeetingList(UserDetails userDetails) { + public CursorResponseDto getMyActiveMeetingList( + UserDetails userDetails, + Long lastMeetingId, + LocalDateTime lastDateTime, + @Positive @Max(value = 100) int pageSize + ) { Member member = getMember(userDetails); - return meetingRepository.findAllMeetings(member.getMemberId(), null, ACTIVE); + List meetings = meetingRepository.findAllMeetings( + member.getMemberId(), + null, + ACTIVE, + lastMeetingId, + lastDateTime, + pageSize + ); + return CursorResponseDto.of(meetings, pageSize); } // 가장 최근 미팅 조회 diff --git a/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java b/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java new file mode 100644 index 00000000..d0528d9f --- /dev/null +++ b/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java @@ -0,0 +1,44 @@ +package com.example.eatmate.global.response; + +import java.time.LocalDateTime; +import java.util.List; + +import com.example.eatmate.app.domain.meeting.dto.MeetingListResponseDto; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class CursorResponseDto { + private List content; + private boolean hasNext; + private Long lastId; + private LocalDateTime lastDateTime; + + public CursorResponseDto(List content, boolean hasNext, Long lastId, LocalDateTime lastDateTime) { + this.content = content; + this.hasNext = hasNext; + this.lastId = lastId; + this.lastDateTime = lastDateTime; + } + + public static CursorResponseDto of(List content, int pageSize) { + boolean hasNext = content.size() > pageSize; + // 실제 요청한 크기보다 1개 더 조회했으므로, 마지막 데이터는 제거 + List result = hasNext ? content.subList(0, content.size() - 1) : content; + + if (result.isEmpty()) { + return new CursorResponseDto<>(result, false, null, null); + } + + MeetingListResponseDto lastItem = (MeetingListResponseDto)result.get(result.size() - 1); + + return new CursorResponseDto<>( + result, + hasNext, + lastItem.getId(), + lastItem.getDateTime() // orderDeadline 또는 meetingDate + ); + } +} From 9fe3de9fd5eaf129a2cd723539bf3e286ae84700 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Thu, 9 Jan 2025 11:16:54 +0900 Subject: [PATCH 43/64] =?UTF-8?q?[refactor]=20#15=20=EB=82=A0=EC=A7=9C=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=EA=B8=B0=EB=8A=A5=20=EC=B1=85=EC=9E=84=20?= =?UTF-8?q?=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/dto/MeetingListResponseDto.java | 4 ---- .../example/eatmate/global/response/CursorResponseDto.java | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java index e7987f37..0be89690 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/dto/MeetingListResponseDto.java @@ -40,9 +40,5 @@ public MeetingListResponseDto( this.participantCount = participantCount; } - public LocalDateTime getDateTime() { - return "DELIVERY".equals(meetingType) ? orderDeadline : meetingDate; - } - } diff --git a/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java b/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java index d0528d9f..9c53902b 100644 --- a/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java +++ b/src/main/java/com/example/eatmate/global/response/CursorResponseDto.java @@ -33,12 +33,13 @@ public static CursorResponseDto of(List content, int pageSize) { } MeetingListResponseDto lastItem = (MeetingListResponseDto)result.get(result.size() - 1); - + LocalDateTime lastDateTime = + "DELIVERY".equals(lastItem.getMeetingType()) ? lastItem.getOrderDeadline() : lastItem.getMeetingDate(); return new CursorResponseDto<>( result, hasNext, lastItem.getId(), - lastItem.getDateTime() // orderDeadline 또는 meetingDate + lastDateTime // orderDeadline 또는 meetingDate ); } } From b2c20ae0e0ae66cbf290974b5192b4c89acf27e6 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Thu, 9 Jan 2025 12:31:08 +0900 Subject: [PATCH 44/64] =?UTF-8?q?[feat]=20#15=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 배달 모임 목록, 오프라인 모임 목록 --- .../meeting/controller/MeetingController.java | 22 ++++++---- .../repository/DeliveryMeetingRepository.java | 8 ++-- .../repository/OfflineMeetingRepository.java | 8 ++-- .../meeting/service/MeetingService.java | 40 +++++++++---------- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 3755ded4..61b7c876 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -3,8 +3,10 @@ import static com.example.eatmate.app.domain.meeting.domain.ParticipantRole.*; import java.time.LocalDateTime; -import java.util.List; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -91,20 +93,26 @@ public ResponseEntity> joinOfflineMeeting( @GetMapping("/offline") @Operation(summary = "오프라인 모임 목록 조회", description = "오프라인 모임 목록을 조회합니다.") - public ResponseEntity>> getOfflineMeetingList( - @RequestParam(required = true) OfflineMeetingCategory category) { + public ResponseEntity>> getOfflineMeetingList( + @RequestParam(required = true) OfflineMeetingCategory category, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getOfflineMeetingList(category))); + meetingService.getOfflineMeetingList(category, pageRequest))); } @GetMapping("/delivery") @Operation(summary = "배달 모임 목록 조회", description = "배달 모임 목록을 조회합니다.") - public ResponseEntity>> getDeliveryMeetingList( - @RequestParam(required = true) FoodCategory foodCategory) { + public ResponseEntity>> getDeliveryMeetingList( + @RequestParam(required = true) FoodCategory foodCategory, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( - meetingService.getDeliveryMeetingList(foodCategory))); + meetingService.getDeliveryMeetingList(foodCategory, pageRequest))); } @GetMapping("/offline/{meetingId}") diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java index 694aabd8..92b8f733 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/DeliveryMeetingRepository.java @@ -1,7 +1,7 @@ package com.example.eatmate.app.domain.meeting.domain.repository; -import java.util.List; - +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.DeliveryMeeting; @@ -9,7 +9,7 @@ import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; public interface DeliveryMeetingRepository extends JpaRepository { - List findAllByFoodCategoryAndMeetingStatus(FoodCategory foodCategory, - MeetingStatus meetingStatus); + Slice findAllByFoodCategoryAndMeetingStatus(FoodCategory foodCategory, + MeetingStatus meetingStatus, Pageable pageable); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java index 4006596f..e5f37e5f 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/domain/repository/OfflineMeetingRepository.java @@ -1,7 +1,7 @@ package com.example.eatmate.app.domain.meeting.domain.repository; -import java.util.List; - +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import com.example.eatmate.app.domain.meeting.domain.MeetingStatus; @@ -9,6 +9,6 @@ import com.example.eatmate.app.domain.meeting.domain.OfflineMeetingCategory; public interface OfflineMeetingRepository extends JpaRepository { - List findAllByOfflineMeetingCategoryAndMeetingStatus(OfflineMeetingCategory offlineMeetingCategory, - MeetingStatus meetingStatus); + Slice findAllByOfflineMeetingCategoryAndMeetingStatus(OfflineMeetingCategory offlineMeetingCategory, + MeetingStatus meetingStatus, Pageable pageable); } diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index cb1d4568..f04492bd 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -6,8 +6,9 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.stream.Collectors; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -180,30 +181,27 @@ public void joinOfflineMeeting(Long meetingId, UserDetails userDetails) { // 밥, 술 모임 목록 조회 메소드 @Transactional(readOnly = true) - public List getOfflineMeetingList(OfflineMeetingCategory offlineMeetingCategory) { - List meetings = offlineMeetingRepository.findAllByOfflineMeetingCategoryAndMeetingStatus( - offlineMeetingCategory, ACTIVE); - - return meetings.stream() - .map(meeting -> { - Long participantCount = meetingParticipantRepository.countByMeeting_Id(meeting.getId()); - return OfflineMeetingListResponseDto.of(meeting, participantCount); - }) - .collect(Collectors.toList()); + public Slice getOfflineMeetingList(OfflineMeetingCategory offlineMeetingCategory, + Pageable pageable) { + Slice meetings = offlineMeetingRepository.findAllByOfflineMeetingCategoryAndMeetingStatus( + offlineMeetingCategory, ACTIVE, pageable); + + return meetings.map(meeting -> { + Long participantCount = meetingParticipantRepository.countByMeeting_Id(meeting.getId()); + return OfflineMeetingListResponseDto.of(meeting, participantCount); + }); } // 배달 모임 목록 조회 메소드 @Transactional(readOnly = true) - public List getDeliveryMeetingList(FoodCategory foodCategory) { - List meetings = deliveryMeetingRepository.findAllByFoodCategoryAndMeetingStatus(foodCategory, - ACTIVE); - - return meetings.stream() - .map(meeting -> { - Long participantCount = meetingParticipantRepository.countByMeeting_Id(meeting.getId()); - return DeliveryMeetingListResponseDto.of(meeting, participantCount); - }) - .collect(Collectors.toList()); + public Slice getDeliveryMeetingList(FoodCategory foodCategory, Pageable pageable) { + Slice meetings = deliveryMeetingRepository.findAllByFoodCategoryAndMeetingStatus(foodCategory, + ACTIVE, pageable); + + return meetings.map(meeting -> { + Long participantCount = meetingParticipantRepository.countByMeeting_Id(meeting.getId()); + return DeliveryMeetingListResponseDto.of(meeting, participantCount); + }); } // 오프라인 모임 상세 조회 메소드 From 2703d7598ed04d4bde4607731b6a761a612ecafd Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Thu, 9 Jan 2025 18:07:21 +0900 Subject: [PATCH 45/64] =?UTF-8?q?[refactor]=20#15=20URI=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/controller/MeetingController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 61b7c876..62d922ad 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -165,7 +165,7 @@ public ResponseEntity> getUpcomingMeeting( @AuthenticationPrincipal UserDetails userDetails) { From 69fabe9102f12ecd7b0f65d07d50287412096f5f Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 23:33:49 +0900 Subject: [PATCH 46/64] =?UTF-8?q?=20[mod]=20#23=20save->saveAndFlush?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/eatmate/global/auth/jwt/JwtService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/global/auth/jwt/JwtService.java b/src/main/java/com/example/eatmate/global/auth/jwt/JwtService.java index ed570ffe..db982c49 100644 --- a/src/main/java/com/example/eatmate/global/auth/jwt/JwtService.java +++ b/src/main/java/com/example/eatmate/global/auth/jwt/JwtService.java @@ -152,7 +152,7 @@ public void updateRefreshToken(String email, String refreshToken) { memberRepository.findByEmail(email).ifPresentOrElse( member -> { member.updateRefreshToken(refreshToken); - memberRepository.save(member); + memberRepository.saveAndFlush(member); }, () -> { throw new UserNotFoundException(); From ec553e0082f84df05fd083ddbc5fcab86053f454 Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Thu, 9 Jan 2025 23:35:31 +0900 Subject: [PATCH 47/64] =?UTF-8?q?=20[mod]=20#23=20=EC=BB=A4=EB=B0=8B=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/login/oauth/OAuthLoginSuccessHandler.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java index bb1f89fd..de72c293 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java +++ b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java @@ -30,26 +30,20 @@ public class OAuthLoginSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { log.info("OAuth2 Login 성공"); - try { CustomOAuth2User oAuth2User = (CustomOAuth2User) authentication.getPrincipal(); - // 사용자 Role 확인 Role userRole = oAuth2User.getRole(); - //토큰 생성 String accessToken = jwtService.createAccessToken(oAuth2User.getEmail(), oAuth2User.getRole().name() ); String refreshToken = null; - if (userRole == Role.USER) { refreshToken = jwtService.createRefreshToken(); jwtService.updateRefreshToken(oAuth2User.getEmail(), refreshToken); } logTokens(accessToken, refreshToken); - setTokensInCookie(response,accessToken, refreshToken); - - response.sendRedirect("http://localhost:3000/oauth2/callback"); + response.sendRedirect("http://localhost:3000/oauth2/callback"); } catch (Exception e) { log.error("OAuth2 로그인 처리 중 오류 발생: {} " , e.getMessage()); throw e; @@ -58,6 +52,9 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo // 쿠키 설정 메소드 생성 private void setTokensInCookie(HttpServletResponse response, String accessToken, String refreshToken) { + + + // Access Token 쿠키 설정 Cookie accessTokenCookie = new Cookie("AccessToken", accessToken); accessTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); From 97bf5b0d29a0a83640d3e2eb7808a42cacca5b4a Mon Sep 17 00:00:00 2001 From: jj Date: Sun, 12 Jan 2025 23:34:30 +0900 Subject: [PATCH 48/64] =?UTF-8?q?[refactor]=20#17=20pageNumber=EC=99=80=20?= =?UTF-8?q?pageSize=20=EA=B0=92=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notice/controller/NoticeController.java | 12 +++++++++--- .../app/domain/notice/service/NoticeService.java | 7 ------- .../eatmate/global/config/error/ErrorCode.java | 4 +--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java index a16d744e..dbfae9f1 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeController.java @@ -14,6 +14,10 @@ import com.example.eatmate.global.response.GlobalResponseDto; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; @RestController @@ -31,10 +35,12 @@ public ResponseEntity> getNotice(@PathVaria } @GetMapping - @Operation(summary = "공지사항 목록 조회", description = "공지사항을 조회합니다.") + @Operation(summary = "공지사항 목록 조회", description = "공지사항 목록을 페이지별로 조회합니다..") + @Parameter(name = "pageNumber", description = "조회할 페이지 번호 (0부터 시작, 기본값: 0)", required = false) + @Parameter(name = "pageSize", description = "페이지당 조회할 공지사항 수 (기본값: 20, 최대: 100)", required = false) public ResponseEntity>> getNotices( - @RequestParam int pageNumber, - @RequestParam int pageSize) { + @RequestParam(defaultValue = "0") @PositiveOrZero int pageNumber, + @RequestParam(defaultValue = "20") @Positive @Max(100) int pageSize) { return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success(noticeService.findNotices(pageNumber, pageSize))); } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 1f421ae8..bd140537 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -37,13 +37,6 @@ public NoticeResponseDto findNotice(Long noticeId) { public Slice findNotices(int pageNumber, int pageSize) { - if (pageNumber < 0) { - throw new CommonException(ErrorCode.INVALID_PAGE_NUMBER); - } - if (pageSize < 0) { - throw new CommonException(ErrorCode.INVALID_PAGE_SIZE); - } - Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")); Slice notices = noticeRepository.findPageBy(pageable); diff --git a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java index 6c02c923..b1903791 100644 --- a/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java +++ b/src/main/java/com/example/eatmate/global/config/error/ErrorCode.java @@ -37,9 +37,7 @@ public enum ErrorCode { DUPLICATE_REPORT_NOT_ALLOWED(400, "DUPLICATE_REPORT_NOT_ALLOWED", "같은 유저를 연속적으로 신고할 수 없습니다."), // 공지사항 - NOTICE_NOT_FOUND(404, "NOTICE_NOT_FOUND", "해당 공지사항을 찾을 수 없습니다."), - INVALID_PAGE_NUMBER(400, "INVALID_PAGE_NUMBER ", "올바르지 않은 페이지 넘버입니다."), - INVALID_PAGE_SIZE(400, "INVALID_PAGE_SIZE", "올바르지 않은 페이지 크기입니다"); + NOTICE_NOT_FOUND(404, "NOTICE_NOT_FOUND", "해당 공지사항을 찾을 수 없습니다."); private final int status; private final String code; From 437e6fe1c6244a66f761354f13657e8990d9d8ee Mon Sep 17 00:00:00 2001 From: jj Date: Sun, 12 Jan 2025 23:48:55 +0900 Subject: [PATCH 49/64] =?UTF-8?q?[refactor]=20#17=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B3=84=EC=B8=B5=EC=9D=98=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EA=B0=80=20DTO=EB=A5=BC=20=EC=A7=81=EC=A0=91=20?= =?UTF-8?q?=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/notice/domain/Notice.java | 18 +++++++++--------- .../domain/notice/service/NoticeService.java | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java index 1f743add..9f9de803 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/domain/Notice.java @@ -1,6 +1,5 @@ package com.example.eatmate.app.domain.notice.domain; -import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; import com.example.eatmate.global.common.BaseTimeEntity; import jakarta.persistence.Column; @@ -28,20 +27,21 @@ public class Notice extends BaseTimeEntity { private String content; @Builder - private Notice(NoticeAdminRequestDto noticeAdminRequestDto) { - this.title = noticeAdminRequestDto.getTitle(); - this.content = noticeAdminRequestDto.getContent(); + private Notice(String title, String content) { + this.title = title; + this.content = content; } - public static Notice createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { + public static Notice createNotice(String title, String content) { return Notice.builder() - .noticeAdminRequestDto(noticeAdminRequestDto) + .title(title) + .content(content) .build(); } - public void update(NoticeAdminRequestDto noticeAdminRequestDto) { - this.title = noticeAdminRequestDto.getTitle(); - this.content = noticeAdminRequestDto.getContent(); + public void update(String title, String content) { + this.title = title; + this.content = content; } } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index bd140537..0b8af757 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -23,7 +23,7 @@ public class NoticeService { public void createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { - Notice notice = Notice.createNotice(noticeAdminRequestDto); + Notice notice = Notice.createNotice(noticeAdminRequestDto.getTitle(), noticeAdminRequestDto.getContent()); noticeRepository.save(notice); } @@ -48,7 +48,7 @@ public void updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequest Notice notice = noticeRepository.findById(noticeId) .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); - notice.update(noticeAdminRequestDto); + notice.update(noticeAdminRequestDto.getTitle(), noticeAdminRequestDto.getContent()); noticeRepository.save(notice); } From a1a1edb32e7687d4a1562823d9771763390d5070 Mon Sep 17 00:00:00 2001 From: jj Date: Sun, 12 Jan 2025 23:56:29 +0900 Subject: [PATCH 50/64] =?UTF-8?q?[refactor]=20#17=20createNoticeResponseDt?= =?UTF-8?q?o=EC=9D=84=20from=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notice/dto/NoticeResponseDto.java | 31 +++++++++++-------- .../domain/notice/service/NoticeService.java | 5 +-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java index 9d210096..e408cb6a 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeResponseDto.java @@ -10,28 +10,33 @@ @Getter public class NoticeResponseDto { - Long noticeId; + private final Long noticeId; - String title; + private final String title; - String content; + private final String content; - LocalDateTime createdAt; + private final LocalDateTime createdAt; - LocalDateTime updatedAt; + private final LocalDateTime updatedAt; @Builder - private NoticeResponseDto(Notice notice) { - this.noticeId = notice.getId(); - this.title = notice.getTitle(); - this.content = notice.getContent(); - this.createdAt = notice.getCreatedAt(); - this.updatedAt = notice.getUpdatedAt(); + private NoticeResponseDto(Long noticeId, String title, String content, + LocalDateTime createdAt, LocalDateTime updatedAt) { + this.noticeId = noticeId; + this.title = title; + this.content = content; + this.createdAt = createdAt; + this.updatedAt = updatedAt; } - public static NoticeResponseDto createNoticeResponseDto(Notice notice) { + public static NoticeResponseDto from(Notice notice) { return NoticeResponseDto.builder() - .notice(notice) + .noticeId(notice.getId()) + .title(notice.getTitle()) + .content(notice.getContent()) + .createdAt(notice.getCreatedAt()) + .updatedAt(notice.getUpdatedAt()) .build(); } } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 0b8af757..d082e9b8 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -8,6 +8,7 @@ import com.example.eatmate.app.domain.notice.domain.Notice; import com.example.eatmate.app.domain.notice.domain.repository.NoticeRepository; +import com.example.eatmate.app.domain.notice.dto.CreateNoticeResponseDto; import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; import com.example.eatmate.app.domain.notice.dto.NoticeResponseDto; import com.example.eatmate.global.config.error.ErrorCode; @@ -40,10 +41,10 @@ public Slice findNotices(int pageNumber, int pageSize) { Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")); Slice notices = noticeRepository.findPageBy(pageable); - return notices.map(NoticeResponseDto::createNoticeResponseDto); + return notices.map(NoticeResponseDto::from); } - public void updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequestDto) { + public CreateNoticeResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequestDto) { Notice notice = noticeRepository.findById(noticeId) .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); From d6e97268d9a29096f93f3b414ebff92f90538698 Mon Sep 17 00:00:00 2001 From: jj Date: Mon, 13 Jan 2025 00:08:52 +0900 Subject: [PATCH 51/64] =?UTF-8?q?[refactor]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=83=9D=EC=84=B1/=EC=88=98=EC=A0=95/?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=9C=20=EB=92=A4=20noticeId=EB=A5=BC=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=ED=95=9C=20NoticeIdResponseDto=EB=A5=BC=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/NoticeAdminController.java | 16 +++++++-------- .../notice/dto/NoticeIdResponseDto.java | 20 +++++++++++++++++++ .../domain/notice/service/NoticeService.java | 16 ++++++++++----- 3 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeIdResponseDto.java diff --git a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java index 80d56948..35fa24fd 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/controller/NoticeAdminController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController; import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; +import com.example.eatmate.app.domain.notice.dto.NoticeIdResponseDto; import com.example.eatmate.app.domain.notice.service.NoticeService; import com.example.eatmate.global.response.GlobalResponseDto; @@ -27,29 +28,26 @@ public class NoticeAdminController { @PostMapping @Operation(summary = "관리자 공지사항 작성", description = "관리자가 공지사항을 작성합니다.") - public ResponseEntity> save( + public ResponseEntity> save( @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { - noticeService.createNotice(noticeAdminRequestDto); return ResponseEntity.status(HttpStatus.OK) - .body(GlobalResponseDto.success()); + .body(GlobalResponseDto.success(noticeService.createNotice(noticeAdminRequestDto))); } @PatchMapping("/{noticeId}") @Operation(summary = "관리자 공지사항 수정", description = "관리자가 공지사항을 수정합니다.") - public ResponseEntity> update(@PathVariable Long noticeId, + public ResponseEntity> update(@PathVariable Long noticeId, @RequestBody @Valid NoticeAdminRequestDto noticeAdminRequestDto) { - noticeService.updateNotice(noticeId, noticeAdminRequestDto); return ResponseEntity.status(HttpStatus.OK) - .body(GlobalResponseDto.success()); + .body(GlobalResponseDto.success(noticeService.updateNotice(noticeId, noticeAdminRequestDto))); } @DeleteMapping("/{noticeId}") @Operation(summary = "관리자 공지사항 삭제", description = "관리자가 공지사항을 삭제합니다.") - public ResponseEntity> delete(@PathVariable Long noticeId) { - noticeService.deleteNotice(noticeId); + public ResponseEntity> delete(@PathVariable Long noticeId) { return ResponseEntity.status(HttpStatus.OK) - .body(GlobalResponseDto.success()); + .body(GlobalResponseDto.success(noticeService.deleteNotice(noticeId))); } } diff --git a/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeIdResponseDto.java b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeIdResponseDto.java new file mode 100644 index 00000000..c6b8696c --- /dev/null +++ b/src/main/java/com/example/eatmate/app/domain/notice/dto/NoticeIdResponseDto.java @@ -0,0 +1,20 @@ +package com.example.eatmate.app.domain.notice.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +public class NoticeIdResponseDto { + private final Long noticeId; + + @Builder + NoticeIdResponseDto(Long noticeId) { + this.noticeId = noticeId; + } + + public static NoticeIdResponseDto from(Long noticeId) { + return NoticeIdResponseDto.builder() + .noticeId(noticeId) + .build(); + } +} diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index d082e9b8..4e16ecfe 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -8,8 +8,8 @@ import com.example.eatmate.app.domain.notice.domain.Notice; import com.example.eatmate.app.domain.notice.domain.repository.NoticeRepository; -import com.example.eatmate.app.domain.notice.dto.CreateNoticeResponseDto; import com.example.eatmate.app.domain.notice.dto.NoticeAdminRequestDto; +import com.example.eatmate.app.domain.notice.dto.NoticeIdResponseDto; import com.example.eatmate.app.domain.notice.dto.NoticeResponseDto; import com.example.eatmate.global.config.error.ErrorCode; import com.example.eatmate.global.config.error.exception.CommonException; @@ -22,10 +22,12 @@ public class NoticeService { private final NoticeRepository noticeRepository; - public void createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { + public NoticeIdResponseDto createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { Notice notice = Notice.createNotice(noticeAdminRequestDto.getTitle(), noticeAdminRequestDto.getContent()); noticeRepository.save(notice); + + return NoticeIdResponseDto.from(notice.getId()); } public NoticeResponseDto findNotice(Long noticeId) { @@ -33,7 +35,7 @@ public NoticeResponseDto findNotice(Long noticeId) { Notice notice = noticeRepository.findById(noticeId) .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); - return NoticeResponseDto.createNoticeResponseDto(notice); + return NoticeResponseDto.from(notice); } public Slice findNotices(int pageNumber, int pageSize) { @@ -44,7 +46,7 @@ public Slice findNotices(int pageNumber, int pageSize) { return notices.map(NoticeResponseDto::from); } - public CreateNoticeResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequestDto) { + public NoticeIdResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequestDto) { Notice notice = noticeRepository.findById(noticeId) .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); @@ -52,13 +54,17 @@ public CreateNoticeResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto notice.update(noticeAdminRequestDto.getTitle(), noticeAdminRequestDto.getContent()); noticeRepository.save(notice); + + return NoticeIdResponseDto.from(noticeId); } - public void deleteNotice(Long noticeId) { + public NoticeIdResponseDto deleteNotice(Long noticeId) { Notice notice = noticeRepository.findById(noticeId) .orElseThrow(() -> new CommonException(ErrorCode.NOTICE_NOT_FOUND)); noticeRepository.delete(notice); + + return NoticeIdResponseDto.from(noticeId); } } From 63be49fec52112a049d284162dd4ee76e917f103 Mon Sep 17 00:00:00 2001 From: jj Date: Mon, 13 Jan 2025 00:10:34 +0900 Subject: [PATCH 52/64] =?UTF-8?q?[refactor]=20#17=20@Transactional=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eatmate/app/domain/notice/service/NoticeService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 4e16ecfe..00d95d35 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -5,6 +5,7 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import com.example.eatmate.app.domain.notice.domain.Notice; import com.example.eatmate.app.domain.notice.domain.repository.NoticeRepository; @@ -22,6 +23,7 @@ public class NoticeService { private final NoticeRepository noticeRepository; + @Transactional public NoticeIdResponseDto createNotice(NoticeAdminRequestDto noticeAdminRequestDto) { Notice notice = Notice.createNotice(noticeAdminRequestDto.getTitle(), noticeAdminRequestDto.getContent()); @@ -30,6 +32,7 @@ public NoticeIdResponseDto createNotice(NoticeAdminRequestDto noticeAdminRequest return NoticeIdResponseDto.from(notice.getId()); } + @Transactional(readOnly = true) public NoticeResponseDto findNotice(Long noticeId) { Notice notice = noticeRepository.findById(noticeId) @@ -38,6 +41,7 @@ public NoticeResponseDto findNotice(Long noticeId) { return NoticeResponseDto.from(notice); } + @Transactional(readOnly = true) public Slice findNotices(int pageNumber, int pageSize) { Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id")); @@ -46,6 +50,7 @@ public Slice findNotices(int pageNumber, int pageSize) { return notices.map(NoticeResponseDto::from); } + @Transactional public NoticeIdResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto noticeAdminRequestDto) { Notice notice = noticeRepository.findById(noticeId) @@ -58,6 +63,7 @@ public NoticeIdResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto not return NoticeIdResponseDto.from(noticeId); } + @Transactional public NoticeIdResponseDto deleteNotice(Long noticeId) { Notice notice = noticeRepository.findById(noticeId) From 46caf6419bfdd232172de98260be770a93bbc616 Mon Sep 17 00:00:00 2001 From: jj Date: Mon, 13 Jan 2025 00:11:58 +0900 Subject: [PATCH 53/64] =?UTF-8?q?[refactor]=20#17=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95=EC=97=90=EC=84=9C=20.sa?= =?UTF-8?q?ve=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eatmate/app/domain/notice/service/NoticeService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java index 00d95d35..b718ca18 100644 --- a/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java +++ b/src/main/java/com/example/eatmate/app/domain/notice/service/NoticeService.java @@ -58,8 +58,6 @@ public NoticeIdResponseDto updateNotice(Long noticeId, NoticeAdminRequestDto not notice.update(noticeAdminRequestDto.getTitle(), noticeAdminRequestDto.getContent()); - noticeRepository.save(notice); - return NoticeIdResponseDto.from(noticeId); } From aeaf856ebb566430df78a647ce62b37f05dc91dc Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 08:56:14 +0900 Subject: [PATCH 54/64] =?UTF-8?q?[feat]=20#22=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=A0=9C=EC=95=BD?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/controller/MeetingController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 62d922ad..97bd4a67 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -96,7 +96,7 @@ public ResponseEntity> joinOfflineMeeting( public ResponseEntity>> getOfflineMeetingList( @RequestParam(required = true) OfflineMeetingCategory category, @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { + @RequestParam(defaultValue = "20") @Positive @Max(100) int size) { PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -108,7 +108,7 @@ public ResponseEntity>> g public ResponseEntity>> getDeliveryMeetingList( @RequestParam(required = true) FoodCategory foodCategory, @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { + @RequestParam(defaultValue = "20") @Positive @Max(100) int size) { PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( From 5316e7d35a5d210b9afedc055fab790bc1975007 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 08:56:14 +0900 Subject: [PATCH 55/64] =?UTF-8?q?[feat]=20#15=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=A0=9C=EC=95=BD?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/controller/MeetingController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 62d922ad..97bd4a67 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -96,7 +96,7 @@ public ResponseEntity> joinOfflineMeeting( public ResponseEntity>> getOfflineMeetingList( @RequestParam(required = true) OfflineMeetingCategory category, @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { + @RequestParam(defaultValue = "20") @Positive @Max(100) int size) { PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -108,7 +108,7 @@ public ResponseEntity>> g public ResponseEntity>> getDeliveryMeetingList( @RequestParam(required = true) FoodCategory foodCategory, @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") int size) { + @RequestParam(defaultValue = "20") @Positive @Max(100) int size) { PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( From 409a2080554eb52d9cb6c795493842f450fc563f Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 11:05:05 +0900 Subject: [PATCH 56/64] =?UTF-8?q?[refactor]=20#15=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eatmate/app/domain/meeting/service/MeetingService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java index f04492bd..83d196cc 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/service/MeetingService.java @@ -43,8 +43,6 @@ import com.example.eatmate.global.config.error.exception.CommonException; import com.example.eatmate.global.response.CursorResponseDto; -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.Positive; import lombok.RequiredArgsConstructor; @Service @@ -299,7 +297,7 @@ public CursorResponseDto getMyMeetingList( ParticipantRole role, Long lastMeetingId, LocalDateTime lastDateTime, - @Positive @Max(value = 100) int pageSize + int pageSize ) { Member member = getMember(userDetails); List meetings = meetingRepository.findAllMeetings( @@ -319,7 +317,7 @@ public CursorResponseDto getMyActiveMeetingList( UserDetails userDetails, Long lastMeetingId, LocalDateTime lastDateTime, - @Positive @Max(value = 100) int pageSize + int pageSize ) { Member member = getMember(userDetails); List meetings = meetingRepository.findAllMeetings( From 9b61f480cdd3b9238bca0a7d048fd54a20e4809f Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 11:05:28 +0900 Subject: [PATCH 57/64] =?UTF-8?q?[refactor]=20#15=20=EC=A0=9C=EC=95=BD?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=97=90=EB=9F=AC=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meeting/controller/MeetingController.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 97bd4a67..2a7ebacf 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -96,7 +96,9 @@ public ResponseEntity> joinOfflineMeeting( public ResponseEntity>> getOfflineMeetingList( @RequestParam(required = true) OfflineMeetingCategory category, @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") @Positive @Max(100) int size) { + @RequestParam(defaultValue = "20") + @Positive(message = "페이지 크기는 양수여야 합니다") + @Max(value = 100, message = "페이지 크기는 최대 100을 초과할 수 없습니다") int size) { PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -108,7 +110,9 @@ public ResponseEntity>> g public ResponseEntity>> getDeliveryMeetingList( @RequestParam(required = true) FoodCategory foodCategory, @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "20") @Positive @Max(100) int size) { + @RequestParam(defaultValue = "20") + @Positive(message = "페이지 크기는 양수여야 합니다") + @Max(value = 100, message = "페이지 크기는 최대 100을 초과할 수 없습니다") int size) { PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending()); return ResponseEntity.status(HttpStatus.OK) .body(GlobalResponseDto.success( @@ -142,7 +146,9 @@ public ResponseEntity Date: Mon, 13 Jan 2025 11:20:49 +0900 Subject: [PATCH 58/64] =?UTF-8?q?[refactor]=20#15=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=A0=9C=EC=95=BD=EC=A1=B0=EA=B1=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/domain/meeting/controller/MeetingController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java index 2a7ebacf..e0c9a70c 100644 --- a/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java +++ b/src/main/java/com/example/eatmate/app/domain/meeting/controller/MeetingController.java @@ -41,6 +41,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import lombok.RequiredArgsConstructor; @RestController @@ -95,7 +96,8 @@ public ResponseEntity> joinOfflineMeeting( @Operation(summary = "오프라인 모임 목록 조회", description = "오프라인 모임 목록을 조회합니다.") public ResponseEntity>> getOfflineMeetingList( @RequestParam(required = true) OfflineMeetingCategory category, - @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "0") + @PositiveOrZero(message = "페이지 번호는 0 이상이어야 합니다") int page, @RequestParam(defaultValue = "20") @Positive(message = "페이지 크기는 양수여야 합니다") @Max(value = 100, message = "페이지 크기는 최대 100을 초과할 수 없습니다") int size) { @@ -109,7 +111,8 @@ public ResponseEntity>> g @Operation(summary = "배달 모임 목록 조회", description = "배달 모임 목록을 조회합니다.") public ResponseEntity>> getDeliveryMeetingList( @RequestParam(required = true) FoodCategory foodCategory, - @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "0") + @PositiveOrZero(message = "페이지 번호는 0 이상이어야 합니다") int page, @RequestParam(defaultValue = "20") @Positive(message = "페이지 크기는 양수여야 합니다") @Max(value = 100, message = "페이지 크기는 최대 100을 초과할 수 없습니다") int size) { From 5410bc244277ec99952f22fe571e653f80d3e957 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 11:28:36 +0900 Subject: [PATCH 59/64] =?UTF-8?q?[refactor]=20#15=20GlobalExceptionHandler?= =?UTF-8?q?=EC=97=90=20ConstraintViolationException=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../error/exception/GlobalExceptionHandler.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java b/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java index 99e21d27..d4b0e53a 100644 --- a/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/eatmate/global/config/error/exception/GlobalExceptionHandler.java @@ -13,6 +13,7 @@ import com.example.eatmate.global.config.error.ErrorResponse; import com.example.eatmate.global.response.GlobalResponseDto; +import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -64,4 +65,17 @@ public ResponseEntity> handleValidationExceptions( .body(GlobalResponseDto.fail(errorCode, errorMessage)); } + @ExceptionHandler(ConstraintViolationException.class) // 파라미터 검증 실패 + public ResponseEntity> handleConstraintViolationException( + ConstraintViolationException ex) { + ErrorCode errorCode = ErrorCode.VALIDATION_FAILED; + + String errorMessage = ex.getConstraintViolations() + .stream() + .map(violation -> violation.getMessage()) + .collect(Collectors.joining(", ")); + + return ResponseEntity.status(HttpStatus.valueOf(errorCode.getStatus())) + .body(GlobalResponseDto.fail(errorCode, errorMessage)); + } } From d452a57f08a3989ba438f192b012b70b093d02b4 Mon Sep 17 00:00:00 2001 From: seokjun01 Date: Mon, 13 Jan 2025 14:59:57 +0900 Subject: [PATCH 60/64] =?UTF-8?q?=20[HOTFIX]=20SECURE=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C=ED=99=98=EA=B2=BD(false)=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EC=9E=84=EC=8B=9C=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/auth/login/oauth/OAuthLoginSuccessHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java index de72c293..cd12aa28 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java +++ b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java @@ -22,7 +22,7 @@ public class OAuthLoginSuccessHandler implements AuthenticationSuccessHandler { private final JwtService jwtService; private static final boolean COOKIE_HTTP_ONLY = true; - private static final boolean COOKIE_SECURE = true; //https 환경에서는 true + private static final boolean COOKIE_SECURE = false; //https 환경에서는 true private static final String COOKIE_PATH = "/"; private static final int ACCESS_TOKEN_MAX_AGE = 60 * 60; // 1시간 private static final int REFRESH_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7일 From 0a4689ccddcbb3ea8068f03d199414a19e4d53a6 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 21:55:43 +0900 Subject: [PATCH 61/64] =?UTF-8?q?[fix]=20secure=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/oauth/OAuthLoginSuccessHandler.java | 165 +++++++++--------- 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java index cd12aa28..c60982e0 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java +++ b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java @@ -1,100 +1,101 @@ package com.example.eatmate.global.auth.login.oauth; +import java.io.IOException; + +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + import com.example.eatmate.app.domain.member.domain.Role; import com.example.eatmate.global.auth.jwt.JwtService; + import jakarta.servlet.ServletException; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; -import org.springframework.stereotype.Component; - -import java.io.IOException; @Slf4j @Component @RequiredArgsConstructor public class OAuthLoginSuccessHandler implements AuthenticationSuccessHandler { - private final JwtService jwtService; - - private static final boolean COOKIE_HTTP_ONLY = true; - private static final boolean COOKIE_SECURE = false; //https 환경에서는 true - private static final String COOKIE_PATH = "/"; - private static final int ACCESS_TOKEN_MAX_AGE = 60 * 60; // 1시간 - private static final int REFRESH_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7일 - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { - log.info("OAuth2 Login 성공"); - try { - CustomOAuth2User oAuth2User = (CustomOAuth2User) authentication.getPrincipal(); - // 사용자 Role 확인 - Role userRole = oAuth2User.getRole(); - //토큰 생성 - String accessToken = jwtService.createAccessToken(oAuth2User.getEmail(), oAuth2User.getRole().name() ); - String refreshToken = null; - if (userRole == Role.USER) { - refreshToken = jwtService.createRefreshToken(); - jwtService.updateRefreshToken(oAuth2User.getEmail(), refreshToken); - } - logTokens(accessToken, refreshToken); - setTokensInCookie(response,accessToken, refreshToken); - response.sendRedirect("http://localhost:3000/oauth2/callback"); - } catch (Exception e) { - log.error("OAuth2 로그인 처리 중 오류 발생: {} " , e.getMessage()); - throw e; - } - } - -// 쿠키 설정 메소드 생성 - private void setTokensInCookie(HttpServletResponse response, String accessToken, String refreshToken) { - - - - // Access Token 쿠키 설정 - Cookie accessTokenCookie = new Cookie("AccessToken", accessToken); - accessTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); - accessTokenCookie.setSecure(COOKIE_SECURE); - accessTokenCookie.setPath(COOKIE_PATH); - accessTokenCookie.setMaxAge(ACCESS_TOKEN_MAX_AGE); - - // Refresh Token 쿠키 설정 (필요 시) - Cookie refreshTokenCookie = null; - if (refreshToken != null) { - refreshTokenCookie = new Cookie("RefreshToken", refreshToken); - refreshTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); - refreshTokenCookie.setSecure(COOKIE_SECURE); - refreshTokenCookie.setPath(COOKIE_PATH); - refreshTokenCookie.setMaxAge(REFRESH_TOKEN_MAX_AGE); - } - - // SameSite 설정 - response.addHeader("Set-Cookie", "AccessToken=" + accessToken + - "; HttpOnly; Secure=" + COOKIE_SECURE + "; SameSite=None; Path=" + COOKIE_PATH + "; Max-Age=" + ACCESS_TOKEN_MAX_AGE); - - if (refreshToken != null) { - response.addHeader("Set-Cookie", "RefreshToken=" + refreshToken + - "; HttpOnly; Secure=" + COOKIE_SECURE + "; SameSite=None; Path=" + COOKIE_PATH + "; Max-Age=" + REFRESH_TOKEN_MAX_AGE); - } - // 응답에 쿠키 추가 - response.addCookie(accessTokenCookie); - if (refreshTokenCookie != null) { - response.addCookie(refreshTokenCookie); - } - - } - - - // 로그용 (삭제해도 ok) - private void logTokens(String accessToken, String refreshToken) { - log.info("AccessToken: {}", accessToken); - if (refreshToken != null) { - log.info("RefreshToken: {}", refreshToken); - } - } + private static final boolean COOKIE_HTTP_ONLY = true; + private static final boolean COOKIE_SECURE = true; //https 환경에서는 true + private static final String COOKIE_PATH = "/"; + private static final int ACCESS_TOKEN_MAX_AGE = 60 * 60; // 1시간 + private static final int REFRESH_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7일 + private final JwtService jwtService; + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { + log.info("OAuth2 Login 성공"); + try { + CustomOAuth2User oAuth2User = (CustomOAuth2User)authentication.getPrincipal(); + // 사용자 Role 확인 + Role userRole = oAuth2User.getRole(); + //토큰 생성 + String accessToken = jwtService.createAccessToken(oAuth2User.getEmail(), oAuth2User.getRole().name()); + String refreshToken = null; + if (userRole == Role.USER) { + refreshToken = jwtService.createRefreshToken(); + jwtService.updateRefreshToken(oAuth2User.getEmail(), refreshToken); + } + logTokens(accessToken, refreshToken); + setTokensInCookie(response, accessToken, refreshToken); + response.sendRedirect("http://localhost:3000/oauth2/callback"); + } catch (Exception e) { + log.error("OAuth2 로그인 처리 중 오류 발생: {} ", e.getMessage()); + throw e; + } + } + + // 쿠키 설정 메소드 생성 + private void setTokensInCookie(HttpServletResponse response, String accessToken, String refreshToken) { + + // Access Token 쿠키 설정 + Cookie accessTokenCookie = new Cookie("AccessToken", accessToken); + accessTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); + accessTokenCookie.setSecure(COOKIE_SECURE); + accessTokenCookie.setPath(COOKIE_PATH); + accessTokenCookie.setMaxAge(ACCESS_TOKEN_MAX_AGE); + + // Refresh Token 쿠키 설정 (필요 시) + Cookie refreshTokenCookie = null; + if (refreshToken != null) { + refreshTokenCookie = new Cookie("RefreshToken", refreshToken); + refreshTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); + refreshTokenCookie.setSecure(COOKIE_SECURE); + refreshTokenCookie.setPath(COOKIE_PATH); + refreshTokenCookie.setMaxAge(REFRESH_TOKEN_MAX_AGE); + } + + // SameSite 설정 + response.addHeader("Set-Cookie", "AccessToken=" + accessToken + + "; HttpOnly; Secure=" + COOKIE_SECURE + "; SameSite=None; Path=" + COOKIE_PATH + "; Max-Age=" + + ACCESS_TOKEN_MAX_AGE); + + if (refreshToken != null) { + response.addHeader("Set-Cookie", "RefreshToken=" + refreshToken + + "; HttpOnly; Secure=" + COOKIE_SECURE + "; SameSite=None; Path=" + COOKIE_PATH + "; Max-Age=" + + REFRESH_TOKEN_MAX_AGE); + } + // 응답에 쿠키 추가 + response.addCookie(accessTokenCookie); + if (refreshTokenCookie != null) { + response.addCookie(refreshTokenCookie); + } + + } + + // 로그용 (삭제해도 ok) + private void logTokens(String accessToken, String refreshToken) { + log.info("AccessToken: {}", accessToken); + if (refreshToken != null) { + log.info("RefreshToken: {}", refreshToken); + } + } } From fcc9319dab914fa7d0f2ba3e8e863624b91d008b Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 22:08:48 +0900 Subject: [PATCH 62/64] =?UTF-8?q?[HOTFIX]=20=ED=97=A4=EB=8D=94=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/oauth/OAuthLoginSuccessHandler.java | 2 +- .../eatmate/global/config/SecurityConfig.java | 65 ++++++++++--------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java index c60982e0..6cad806e 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java +++ b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java @@ -22,7 +22,7 @@ public class OAuthLoginSuccessHandler implements AuthenticationSuccessHandler { private static final boolean COOKIE_HTTP_ONLY = true; - private static final boolean COOKIE_SECURE = true; //https 환경에서는 true + private static final boolean COOKIE_SECURE = true; // https 환경에서는 true private static final String COOKIE_PATH = "/"; private static final int ACCESS_TOKEN_MAX_AGE = 60 * 60; // 1시간 private static final int REFRESH_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7일 diff --git a/src/main/java/com/example/eatmate/global/config/SecurityConfig.java b/src/main/java/com/example/eatmate/global/config/SecurityConfig.java index 5a9095d5..36ff92c3 100644 --- a/src/main/java/com/example/eatmate/global/config/SecurityConfig.java +++ b/src/main/java/com/example/eatmate/global/config/SecurityConfig.java @@ -37,34 +37,34 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .csrf(AbstractHttpConfigurer::disable) - .cors(Customizer.withDefaults()) - .headers( - headersConfigurer -> headersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests( - authorize -> authorize - .requestMatchers("/api/admin/**").hasRole("ADMIN") - // 아이콘, css, js 관련 - // 기본 페이지, css, image, js 하위 폴더에 있는 자료들은 모두 접근 가능, h2-console에 접근 가능 - // .requestMatchers("/", "/css/**", "/images/**", "/js/**", "/favicon.ico").permitAll() - // .requestMatchers("/v3/api-docs", "/v3/api-docs/", "/swagger-ui.html", "/swagger-ui/", "/swagger/**").permitAll() - // .requestMatchers("/register").permitAll() - .anyRequest().permitAll() - ) - .exceptionHandling(exceptionHandling -> - exceptionHandling - .authenticationEntryPoint((request, response, authException) -> { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); - }) - .accessDeniedHandler((request, response, accessDeniedException) -> { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied"); - }) - ) - .addFilterBefore(jwtAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class) // 필터 순서 확인 - //== 소셜 로그인 설정 ==// - .oauth2Login(oauth2 -> oauth2.successHandler(oAuthLoginSuccessHandler) - .failureHandler(oAuthLoginFailureHandler)); // 소셜 로그인 실패 시 핸들러 설정 + .csrf(AbstractHttpConfigurer::disable) + .cors(Customizer.withDefaults()) + .headers( + headersConfigurer -> headersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests( + authorize -> authorize + .requestMatchers("/api/admin/**").hasRole("ADMIN") + // 아이콘, css, js 관련 + // 기본 페이지, css, image, js 하위 폴더에 있는 자료들은 모두 접근 가능, h2-console에 접근 가능 + // .requestMatchers("/", "/css/**", "/images/**", "/js/**", "/favicon.ico").permitAll() + // .requestMatchers("/v3/api-docs", "/v3/api-docs/", "/swagger-ui.html", "/swagger-ui/", "/swagger/**").permitAll() + // .requestMatchers("/register").permitAll() + .anyRequest().permitAll() + ) + .exceptionHandling(exceptionHandling -> + exceptionHandling + .authenticationEntryPoint((request, response, authException) -> { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + }) + .accessDeniedHandler((request, response, accessDeniedException) -> { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied"); + }) + ) + .addFilterBefore(jwtAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class) // 필터 순서 확인 + //== 소셜 로그인 설정 ==// + .oauth2Login(oauth2 -> oauth2.successHandler(oAuthLoginSuccessHandler) + .failureHandler(oAuthLoginFailureHandler)); // 소셜 로그인 실패 시 핸들러 설정 //.userInfoEndpoint().userService(customOAuth2UserService)); // customUserService 설정 return http.build(); @@ -75,12 +75,13 @@ public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList( - "http://localhost:3000", - "https://develop.d4u0qurydeei4.amplifyapp.com" + "http://localhost:3000", + "https://develop.d4u0qurydeei4.amplifyapp.com" )); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE", "OPTIONS")); - configuration.setAllowedHeaders(Arrays.asList("*")); - configuration.setExposedHeaders(Arrays.asList("AccessToken", "RefreshToken", "Role", "accept")); //헤더에 노출할 정보 Role 포함 + configuration.setAllowedHeaders(Arrays.asList("Content-Type", "Authorization", "Cookie")); + configuration.setExposedHeaders( + Arrays.asList("Role", "accept")); //헤더에 노출할 정보 Role 포함 configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); From 125b11ec86cbd7d24b6ba03fb2892f23db45b53b Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Mon, 13 Jan 2025 22:38:51 +0900 Subject: [PATCH 63/64] =?UTF-8?q?[HOTFIX]=20=EC=BF=A0=ED=82=A4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=A9=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/oauth/OAuthLoginSuccessHandler.java | 52 ++++++++----------- .../eatmate/global/config/SecurityConfig.java | 3 +- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java index 6cad806e..98e93cab 100644 --- a/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java +++ b/src/main/java/com/example/eatmate/global/auth/login/oauth/OAuthLoginSuccessHandler.java @@ -10,7 +10,6 @@ import com.example.eatmate.global.auth.jwt.JwtService; import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; @@ -54,40 +53,33 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo // 쿠키 설정 메소드 생성 private void setTokensInCookie(HttpServletResponse response, String accessToken, String refreshToken) { - // Access Token 쿠키 설정 - Cookie accessTokenCookie = new Cookie("AccessToken", accessToken); - accessTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); - accessTokenCookie.setSecure(COOKIE_SECURE); - accessTokenCookie.setPath(COOKIE_PATH); - accessTokenCookie.setMaxAge(ACCESS_TOKEN_MAX_AGE); - - // Refresh Token 쿠키 설정 (필요 시) - Cookie refreshTokenCookie = null; - if (refreshToken != null) { - refreshTokenCookie = new Cookie("RefreshToken", refreshToken); - refreshTokenCookie.setHttpOnly(COOKIE_HTTP_ONLY); - refreshTokenCookie.setSecure(COOKIE_SECURE); - refreshTokenCookie.setPath(COOKIE_PATH); - refreshTokenCookie.setMaxAge(REFRESH_TOKEN_MAX_AGE); - } + String accessTokenCookieString = String.format("AccessToken=%s; " + + "Path=%s; " + + "Max-Age=%d; " + + "HttpOnly; " + + "Secure; " + + "SameSite=None", + accessToken, + COOKIE_PATH, + ACCESS_TOKEN_MAX_AGE); - // SameSite 설정 - response.addHeader("Set-Cookie", "AccessToken=" + accessToken + - "; HttpOnly; Secure=" + COOKIE_SECURE + "; SameSite=None; Path=" + COOKIE_PATH + "; Max-Age=" - + ACCESS_TOKEN_MAX_AGE); + response.addHeader("Set-Cookie", accessTokenCookieString); + // Refresh Token 쿠키 설정 if (refreshToken != null) { - response.addHeader("Set-Cookie", "RefreshToken=" + refreshToken + - "; HttpOnly; Secure=" + COOKIE_SECURE + "; SameSite=None; Path=" + COOKIE_PATH + "; Max-Age=" - + REFRESH_TOKEN_MAX_AGE); - } - // 응답에 쿠키 추가 - response.addCookie(accessTokenCookie); - if (refreshTokenCookie != null) { - response.addCookie(refreshTokenCookie); - } + String refreshTokenCookieString = String.format("RefreshToken=%s; " + + "Path=%s; " + + "Max-Age=%d; " + + "HttpOnly; " + + "Secure; " + + "SameSite=None", + refreshToken, + COOKIE_PATH, + REFRESH_TOKEN_MAX_AGE); + response.addHeader("Set-Cookie", refreshTokenCookieString); + } } // 로그용 (삭제해도 ok) diff --git a/src/main/java/com/example/eatmate/global/config/SecurityConfig.java b/src/main/java/com/example/eatmate/global/config/SecurityConfig.java index 36ff92c3..27d322e8 100644 --- a/src/main/java/com/example/eatmate/global/config/SecurityConfig.java +++ b/src/main/java/com/example/eatmate/global/config/SecurityConfig.java @@ -75,9 +75,10 @@ public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList( - "http://localhost:3000", + "http://localhost:3000/", "https://develop.d4u0qurydeei4.amplifyapp.com" )); + configuration.addAllowedOriginPattern("*"); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("Content-Type", "Authorization", "Cookie")); configuration.setExposedHeaders( From 37749f4d27013aa5a1c3275b087cecfebd8a4d32 Mon Sep 17 00:00:00 2001 From: EunHyunsu Date: Tue, 14 Jan 2025 00:13:41 +0900 Subject: [PATCH 64/64] =?UTF-8?q?[HOTFIX]=20UESR=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EB=8F=84=20info=20=EC=A0=91=EA=B7=BC=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JwtAuthenticationProcessingFilter.java | 273 +++++++++--------- 1 file changed, 137 insertions(+), 136 deletions(-) diff --git a/src/main/java/com/example/eatmate/global/auth/jwt/JwtAuthenticationProcessingFilter.java b/src/main/java/com/example/eatmate/global/auth/jwt/JwtAuthenticationProcessingFilter.java index f91b1b48..765d2017 100644 --- a/src/main/java/com/example/eatmate/global/auth/jwt/JwtAuthenticationProcessingFilter.java +++ b/src/main/java/com/example/eatmate/global/auth/jwt/JwtAuthenticationProcessingFilter.java @@ -1,15 +1,8 @@ package com.example.eatmate.global.auth.jwt; +import java.io.IOException; +import java.util.Arrays; -import com.example.eatmate.app.domain.member.domain.Member; -import com.example.eatmate.app.domain.member.domain.repository.MemberRepository; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; @@ -19,9 +12,16 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; -import java.rmi.server.ServerCloneException; -import java.util.Arrays; +import com.example.eatmate.app.domain.member.domain.Member; +import com.example.eatmate.app.domain.member.domain.repository.MemberRepository; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; /** * "/login" 이외의 URI 요청이 왔을 때 처리하는 필터 @@ -33,128 +33,129 @@ @Component public class JwtAuthenticationProcessingFilter extends OncePerRequestFilter { - private static final String NO_CHECK_URL = "/login"; // 로그인 요청은 필터 제외 - - private final JwtService jwtService; - private final MemberRepository memberRepository; - - private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - log.info("Processing request URI: {}", request.getRequestURI()); - - if (request.getRequestURI().equals(NO_CHECK_URL)) { - filterChain.doFilter(request, response); // /login 요청은 필터 제외 - return; - } - - // 요청에서 쿠키 추출 및 디버깅 로그 - log.info("Request Cookies: {}", Arrays.toString(request.getCookies())); - - // Refresh Token 처리 - String refreshToken = jwtService.extractRefreshTokenFromCookie(request) - .filter(jwtService::isTokenValid) - .orElse(null); - - if (refreshToken != null) { - log.info("Valid RefreshToken found. Processing token renewal..."); - handleRefreshToken(response, refreshToken); - return; // 토큰 재발급 후 필터 종료 - } - - // Access Token 처리 - try { - handleAccessToken(request, response, filterChain); - } catch (Exception e) { - log.error("Error while handling Access Token: {}", e.getMessage(), e); - sendErrorResponse(response, "Invalid Access Token"); - } - } - - /** - * Refresh Token 처리 및 Access Token 재발급 - */ - private void handleRefreshToken(HttpServletResponse response, String refreshToken) { - memberRepository.findByRefreshToken(refreshToken) - .ifPresentOrElse( - member -> { - String newAccessToken = jwtService.createAccessToken(member.getEmail(), member.getRole().name()); - String newRefreshToken = jwtService.createRefreshToken(); - member.updateRefreshToken(newRefreshToken); - memberRepository.saveAndFlush(member); - - // 쿠키에 토큰 설정 - setTokenInCookie(response, "AccessToken", newAccessToken, jwtService.getAccessTokenExpirationPeriod()); - setTokenInCookie(response, "RefreshToken", newRefreshToken, jwtService.getRefreshTokenExpirationPeriod()); - - log.info("Refresh Token 유효. Access Token 및 Refresh Token 재발급 완료."); - }, - () -> sendErrorResponse(response, "Invalid Refresh Token") - ); - } - - /** - * Access Token 처리 및 SecurityContext 설정 - */ - private void handleAccessToken(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - jwtService.extractAccessTokenFromCookie(request) - .filter(jwtService::isTokenValid) // AccessToken 유효성 검증 - .flatMap(jwtService::extractEmail) // 유효한 AccessToken에서 Email 추출 - .flatMap(memberRepository::findByEmail) // 이메일로 Member 조회 - .ifPresentOrElse( - member -> { - log.info("Authentication successful for user: {}", member.getEmail()); - setAuthentication(member); // 인증 정보 SecurityContext에 저장 - }, - () -> log.warn("Failed to authenticate user. Either token is invalid or member not found.") - ); - - filterChain.doFilter(request, response); - } - - - - /** - * 인증 정보 SecurityContext에 저장 - */ - private void setAuthentication(Member member) { - UserDetails userDetails = org.springframework.security.core.userdetails.User.builder() - .username(member.getEmail()) - .password("") // 비밀번호는 사용하지 않으므로 빈 문자열 - .roles(member.getRole().name()) - .build(); - - Authentication authentication = new UsernamePasswordAuthenticationToken( - userDetails, null, authoritiesMapper.mapAuthorities(userDetails.getAuthorities()) - ); - - SecurityContextHolder.getContext().setAuthentication(authentication); - } - - /** - * 에러 응답 전송 - */ - private void sendErrorResponse(HttpServletResponse response, String message) { - try { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - response.setHeader("Error-Message", message); // 에러 메시지를 헤더에 설정 - log.warn("에러 응답: {}", message); - } catch (Exception e) { - log.error("에러 응답 전송 중 오류 발생", e); - } - } - - /** - * 쿠키에 토큰 설정 - */ - private void setTokenInCookie(HttpServletResponse response, String name, String token, long maxAge) { - Cookie cookie = new Cookie(name, token); - cookie.setHttpOnly(true); - cookie.setSecure(true); - cookie.setPath("/"); - cookie.setMaxAge((int) (maxAge / 1000)); // maxAge는 초 단위로 설정 - response.addCookie(cookie); - log.info("{} 쿠키 설정 완료", name); - } + private static final String NO_CHECK_URL = "/login"; // 로그인 요청은 필터 제외 + + private final JwtService jwtService; + private final MemberRepository memberRepository; + + private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + log.info("Processing request URI: {}", request.getRequestURI()); + + if (request.getRequestURI().equals(NO_CHECK_URL)) { + filterChain.doFilter(request, response); // /login 요청은 필터 제외 + return; + } + + // 요청에서 쿠키 추출 및 디버깅 로그 + log.info("Request Cookies: {}", Arrays.toString(request.getCookies())); + + // Refresh Token 처리 + String refreshToken = jwtService.extractRefreshTokenFromCookie(request) + .filter(jwtService::isTokenValid) + .orElse(null); + + if (refreshToken != null) { + log.info("Valid RefreshToken found. Processing token renewal..."); + handleRefreshToken(response, refreshToken); + } + + // Access Token 처리 + try { + handleAccessToken(request, response, filterChain); + } catch (Exception e) { + log.error("Error while handling Access Token: {}", e.getMessage(), e); + sendErrorResponse(response, "Invalid Access Token"); + } + } + + /** + * Refresh Token 처리 및 Access Token 재발급 + */ + private void handleRefreshToken(HttpServletResponse response, String refreshToken) { + memberRepository.findByRefreshToken(refreshToken) + .ifPresentOrElse( + member -> { + String newAccessToken = jwtService.createAccessToken(member.getEmail(), member.getRole().name()); + String newRefreshToken = jwtService.createRefreshToken(); + member.updateRefreshToken(newRefreshToken); + memberRepository.saveAndFlush(member); + + // 쿠키에 토큰 설정 + setTokenInCookie(response, "AccessToken", newAccessToken, + jwtService.getAccessTokenExpirationPeriod()); + setTokenInCookie(response, "RefreshToken", newRefreshToken, + jwtService.getRefreshTokenExpirationPeriod()); + + log.info("Refresh Token 유효. Access Token 및 Refresh Token 재발급 완료."); + }, + () -> sendErrorResponse(response, "Invalid Refresh Token") + ); + } + + /** + * Access Token 처리 및 SecurityContext 설정 + */ + private void handleAccessToken(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + jwtService.extractAccessTokenFromCookie(request) + .filter(jwtService::isTokenValid) // AccessToken 유효성 검증 + .flatMap(jwtService::extractEmail) // 유효한 AccessToken에서 Email 추출 + .flatMap(memberRepository::findByEmail) // 이메일로 Member 조회 + .ifPresentOrElse( + member -> { + log.info("Authentication successful for user: {}", member.getEmail()); + setAuthentication(member); // 인증 정보 SecurityContext에 저장 + }, + () -> log.warn("Failed to authenticate user. Either token is invalid or member not found.") + ); + + filterChain.doFilter(request, response); + } + + /** + * 인증 정보 SecurityContext에 저장 + */ + private void setAuthentication(Member member) { + UserDetails userDetails = org.springframework.security.core.userdetails.User.builder() + .username(member.getEmail()) + .password("") // 비밀번호는 사용하지 않으므로 빈 문자열 + .roles(member.getRole().name()) + .build(); + + Authentication authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, authoritiesMapper.mapAuthorities(userDetails.getAuthorities()) + ); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + /** + * 에러 응답 전송 + */ + private void sendErrorResponse(HttpServletResponse response, String message) { + try { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setHeader("Error-Message", message); // 에러 메시지를 헤더에 설정 + log.warn("에러 응답: {}", message); + } catch (Exception e) { + log.error("에러 응답 전송 중 오류 발생", e); + } + } + + /** + * 쿠키에 토큰 설정 + */ + private void setTokenInCookie(HttpServletResponse response, String name, String token, long maxAge) { + Cookie cookie = new Cookie(name, token); + cookie.setHttpOnly(true); + cookie.setSecure(true); + cookie.setPath("/"); + cookie.setMaxAge((int)(maxAge / 1000)); // maxAge는 초 단위로 설정 + response.addCookie(cookie); + log.info("{} 쿠키 설정 완료", name); + } }