From e8daf0ddd150ee532f0d06743e38448bed869a56 Mon Sep 17 00:00:00 2001 From: Ye jin Shin <108514552+shinyj0@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:38:49 +0900 Subject: [PATCH 1/4] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PlaceVoteRoomController.java | 8 +- .../domain/PlaceVoteCandidate.java | 68 ++--- .../domain/PlaceVoteCandidateMember.java | 29 +- .../placeVoteRoom/domain/PlaceVoteRoom.java | 46 +-- .../placeVoteRoom/dto/PlaceVoteRoomDTO.java | 116 ++++---- .../PlaceVoteCandidateMemberRepository.java | 7 +- .../PlaceVoteCandidateRepository.java | 7 +- .../repository/PlaceVoteRoomRepository.java | 9 +- .../service/PlaceVoteRoomService.java | 176 ++++++------ .../controller/TimeVoteRoomController.java | 4 +- .../timeVoteRoom/domain/MeetingDate.java | 27 +- .../domains/timeVoteRoom/domain/TimeVote.java | 57 ++-- .../timeVoteRoom/domain/TimeVoteRoom.java | 36 +-- .../timeVoteRoom/dto/TimeVoteRoomDTO.java | 131 ++++----- .../repository/MeetingDateRepository.java | 7 +- .../repository/TimeVoteRepository.java | 14 +- .../repository/TimeVoteRoomRepository.java | 8 +- .../service/TimeVoteRoomService.java | 269 +++++++++--------- 18 files changed, 534 insertions(+), 485 deletions(-) diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java index f97d68ad..d2b8f04b 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java @@ -1,5 +1,6 @@ package middle_point_search.backend.domains.placeVoteRoom.controller; +import static middle_point_search.backend.domains.placeVoteRoom.dto.PlaceVoteRoomDTO.*; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -15,19 +16,16 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import jakarta.validation.Valid; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import middle_point_search.backend.common.dto.BaseResponse; import middle_point_search.backend.common.dto.DataResponse; import middle_point_search.backend.common.dto.ErrorResponse; import middle_point_search.backend.common.util.MemberLoader; -import middle_point_search.backend.domains.placeVoteRoom.service.PlaceVoteRoomService; import middle_point_search.backend.domains.member.domain.Member; +import middle_point_search.backend.domains.placeVoteRoom.service.PlaceVoteRoomService; import middle_point_search.backend.domains.room.domain.Room; -import static middle_point_search.backend.domains.placeVoteRoom.dto.PlaceVoteRoomDTO.*; - - @Tag(name = "PLACE VOTE ROOM API", description = "장소 투표에 대한 API입니다.") diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidate.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidate.java index 0f7f47f0..ee6f5578 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidate.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidate.java @@ -4,6 +4,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; + import java.util.ArrayList; import java.util.List; @@ -14,48 +15,49 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PlaceVoteCandidate { - @Id - @Column(name = "place_vote_candidate_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @Column(name = "place_vote_candidate_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @Column(nullable = false) - private String name; + @Column(nullable = false) + private String name; - @Column(nullable = false) - private String siDo; + @Column(nullable = false) + private String siDo; - @Column(nullable = false) - private String siGunGu; + @Column(nullable = false) + private String siGunGu; - @Column(nullable = false) - private String roadNameAddress; + @Column(nullable = false) + private String roadNameAddress; - @Column(nullable = false) - private Double addressLatitude; + @Column(nullable = false) + private Double addressLatitude; - @Column(nullable = false) - private Double addressLongitude; + @Column(nullable = false) + private Double addressLongitude; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "place_vote_room_id") - private PlaceVoteRoom placeVoteRoom; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_vote_room_id") + private PlaceVoteRoom placeVoteRoom; - @OneToMany(mappedBy = "placeVoteCandidate", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true) - private List voters = new ArrayList<>(); + @OneToMany(mappedBy = "placeVoteCandidate", cascade = {CascadeType.PERSIST, + CascadeType.MERGE}, orphanRemoval = true) + private List voters = new ArrayList<>(); - public PlaceVoteCandidate(PlaceCandidateInfo candidate, PlaceVoteRoom placeVoteRoom) { - this.name = candidate.getName(); - this.siDo = candidate.getSiDo(); - this.siGunGu = candidate.getSiGunGu(); - this.roadNameAddress = candidate.getRoadNameAddress(); - this.addressLatitude = candidate.getAddressLat(); - this.addressLongitude = candidate.getAddressLong(); - this.placeVoteRoom = placeVoteRoom; - } + public PlaceVoteCandidate(PlaceCandidateInfo candidate, PlaceVoteRoom placeVoteRoom) { + this.name = candidate.getName(); + this.siDo = candidate.getSiDo(); + this.siGunGu = candidate.getSiGunGu(); + this.roadNameAddress = candidate.getRoadNameAddress(); + this.addressLatitude = candidate.getAddressLat(); + this.addressLongitude = candidate.getAddressLong(); + this.placeVoteRoom = placeVoteRoom; + } - public int getCount() { - return voters.size(); - } + public int getCount() { + return voters.size(); + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidateMember.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidateMember.java index 4a09176b..6ef2573a 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidateMember.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteCandidateMember.java @@ -11,21 +11,22 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PlaceVoteCandidateMember { - @Id - @Column(name = "place_vote_candidate_member_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @Column(name = "place_vote_candidate_member_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "place_vote_candidate_id") - private PlaceVoteCandidate placeVoteCandidate; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_vote_candidate_id") + private PlaceVoteCandidate placeVoteCandidate; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; - public PlaceVoteCandidateMember(PlaceVoteCandidate placeVoteCandidate, Member member) { - this.placeVoteCandidate = placeVoteCandidate; - this.member = member; - } + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + public PlaceVoteCandidateMember(PlaceVoteCandidate placeVoteCandidate, Member member) { + this.placeVoteCandidate = placeVoteCandidate; + this.member = member; + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteRoom.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteRoom.java index b24ab56f..6d55b85d 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteRoom.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/domain/PlaceVoteRoom.java @@ -16,28 +16,28 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class PlaceVoteRoom { - @Id - @Column(name = "place_vote_room_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @OneToOne - @JoinColumn(name = "room_id") - private Room room; - - @OneToMany(mappedBy = "placeVoteRoom", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List placeVoteCandidates = new ArrayList<>(); - - public PlaceVoteRoom(Room room, List candidates) { - this.room = room; - this.placeVoteCandidates.clear(); - for (PlaceCandidateInfo candidate : candidates) { - addPlaceVoteCandidate(candidate); - } - } - - public void addPlaceVoteCandidate(PlaceCandidateInfo candidate) { - this.placeVoteCandidates.add(new PlaceVoteCandidate(candidate, this)); - } + @Id + @Column(name = "place_vote_room_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + @JoinColumn(name = "room_id") + private Room room; + + @OneToMany(mappedBy = "placeVoteRoom", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List placeVoteCandidates = new ArrayList<>(); + + public PlaceVoteRoom(Room room, List candidates) { + this.room = room; + this.placeVoteCandidates.clear(); + for (PlaceCandidateInfo candidate : candidates) { + addPlaceVoteCandidate(candidate); + } + } + + public void addPlaceVoteCandidate(PlaceCandidateInfo candidate) { + this.placeVoteCandidates.add(new PlaceVoteCandidate(candidate, this)); + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/dto/PlaceVoteRoomDTO.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/dto/PlaceVoteRoomDTO.java index 322fb7cd..ef7c429b 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/dto/PlaceVoteRoomDTO.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/dto/PlaceVoteRoomDTO.java @@ -9,73 +9,75 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; +import java.util.List; public class PlaceVoteRoomDTO { - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - public static class PlaceVoteRoomCreateRequest { + @Getter + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class PlaceVoteRoomCreateRequest { + + @NotEmpty(message = "투표 후보가 제공되지 않았습니다.") + @Valid + private List placeCandidates; - @NotEmpty(message = "투표 후보가 제공되지 않았습니다.") - @Valid - private List placeCandidates; + @Getter + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static class PlaceCandidateInfo { - @Getter - @AllArgsConstructor(access = AccessLevel.PRIVATE) - public static class PlaceCandidateInfo { + @NotBlank(message = "name은 비어 있을 수 없습니다.") + private String name; + @NotBlank(message = "siDo는 비어 있을 수 없습니다.") + private String siDo; + @NotBlank(message = "siGunGu는 비어 있을 수 없습니다.") + private String siGunGu; + @NotBlank(message = "roadNameAddress는 비어 있을 수 없습니다.") + private String roadNameAddress; + @NotNull + @Positive(message = "addreesLat은 양수이어야 합니다.") + private Double addressLat; + @NotNull + @Positive(message = "addreesLong은 양수이어야 합니다.") + private Double addressLong; + } + } - @NotBlank(message = "name은 비어 있을 수 없습니다.") - private String name; - @NotBlank(message = "siDo는 비어 있을 수 없습니다.") - private String siDo; - @NotBlank(message = "siGunGu는 비어 있을 수 없습니다.") - private String siGunGu; - @NotBlank(message = "roadNameAddress는 비어 있을 수 없습니다.") - private String roadNameAddress; - @NotNull @Positive(message = "addreesLat은 양수이어야 합니다.") - private Double addressLat; - @NotNull - @Positive(message = "addreesLong은 양수이어야 합니다.") - private Double addressLong; - } - } + @Getter + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static class PlaceVoteRoomCreateResponse { + private final Long id; - @Getter - @AllArgsConstructor(access = AccessLevel.PRIVATE) - public static class PlaceVoteRoomCreateResponse { - private final Long id; - public static PlaceVoteRoomCreateResponse from(Long id) { - return new PlaceVoteRoomCreateResponse(id); - } - } + public static PlaceVoteRoomCreateResponse from(Long id) { + return new PlaceVoteRoomCreateResponse(id); + } + } - @Getter - @AllArgsConstructor - public static class PlaceVoteInfoResponse { - private List placeCandidates; + @Getter + @AllArgsConstructor + public static class PlaceVoteInfoResponse { + private List placeCandidates; - @Getter - @AllArgsConstructor - public static class PlaceVoteCandidateInfo { - private Long id; - private String name; - private String siDo; - private String siGunGu; - private String roadNameAddress; - private Double addressLat; - private Double addressLong; - private int count; - private List voters; - } - } + @Getter + @AllArgsConstructor + public static class PlaceVoteCandidateInfo { + private Long id; + private String name; + private String siDo; + private String siGunGu; + private String roadNameAddress; + private Double addressLat; + private Double addressLong; + private int count; + private List voters; + } + } - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - public static class PlaceVoteRequest{ + @Getter + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class PlaceVoteRequest { - @NotNull(message = "choicePlace은 비어 있을 수 없습니다.") - private Long choicePlace; - } + @NotNull(message = "choicePlace은 비어 있을 수 없습니다.") + private Long choicePlace; + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateMemberRepository.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateMemberRepository.java index 54c72f97..f02b9d73 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateMemberRepository.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateMemberRepository.java @@ -3,11 +3,14 @@ import middle_point_search.backend.domains.placeVoteRoom.domain.PlaceVoteCandidateMember; import middle_point_search.backend.domains.placeVoteRoom.domain.PlaceVoteRoom; import middle_point_search.backend.domains.member.domain.Member; + import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface PlaceVoteCandidateMemberRepository extends JpaRepository { - boolean existsByPlaceVoteCandidate_PlaceVoteRoomAndMember(PlaceVoteRoom placeVoteRoom, Member member); - List findAllByPlaceVoteCandidate_PlaceVoteRoomAndMember(PlaceVoteRoom placeVoteRoom, Member member); + boolean existsByPlaceVoteCandidate_PlaceVoteRoomAndMember(PlaceVoteRoom placeVoteRoom, Member member); + + List findAllByPlaceVoteCandidate_PlaceVoteRoomAndMember(PlaceVoteRoom placeVoteRoom, + Member member); } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateRepository.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateRepository.java index f24c7716..12caf82f 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateRepository.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteCandidateRepository.java @@ -1,10 +1,11 @@ package middle_point_search.backend.domains.placeVoteRoom.repository; -import middle_point_search.backend.domains.placeVoteRoom.domain.PlaceVoteCandidate; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.Optional; +import middle_point_search.backend.domains.placeVoteRoom.domain.PlaceVoteCandidate; public interface PlaceVoteCandidateRepository extends JpaRepository { - Optional findById(Long id); + Optional findById(Long id); } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteRoomRepository.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteRoomRepository.java index 582b7764..24078f05 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteRoomRepository.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/repository/PlaceVoteRoomRepository.java @@ -2,15 +2,18 @@ import middle_point_search.backend.domains.placeVoteRoom.domain.PlaceVoteRoom; import middle_point_search.backend.domains.room.domain.Room; + import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface PlaceVoteRoomRepository extends JpaRepository { - boolean existsByRoom(Room room); - boolean existsByRoomIdentityNumber(String identityNumber); - Optional findByRoom(Room room); + boolean existsByRoom(Room room); + + boolean existsByRoomIdentityNumber(String identityNumber); + + Optional findByRoom(Room room); } diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/service/PlaceVoteRoomService.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/service/PlaceVoteRoomService.java index 1186998e..593f6767 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/service/PlaceVoteRoomService.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/service/PlaceVoteRoomService.java @@ -10,6 +10,7 @@ import middle_point_search.backend.domains.placeVoteRoom.repository.PlaceVoteRoomRepository; import middle_point_search.backend.domains.member.domain.Member; import middle_point_search.backend.domains.room.domain.Room; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -25,108 +26,121 @@ @Transactional(readOnly = true) public class PlaceVoteRoomService { - private final PlaceVoteRoomRepository placeVoteRoomRepository; - private final PlaceVoteCandidateMemberRepository placeVoteCandidateMemberRepository; - private final PlaceVoteCandidateRepository placeVoteCandidateRepository; - - // 장소투표방 생성 - @Transactional(rollbackFor = {CustomException.class}) - public PlaceVoteRoomCreateResponse createPlaceVoteRoom(Room room,PlaceVoteRoomCreateRequest request) { - - boolean exists = placeVoteRoomRepository.existsByRoom(room); - - if (exists) { - throw new CustomException(DUPLICATE_VOTE_ROOM); - } - - PlaceVoteRoom placeVoteRoom = new PlaceVoteRoom(room,request.getPlaceCandidates()); - PlaceVoteRoom savedPlaceVoteRoom = placeVoteRoomRepository.save(placeVoteRoom); - - return PlaceVoteRoomCreateResponse.from(savedPlaceVoteRoom.getId()); - } + private final PlaceVoteRoomRepository placeVoteRoomRepository; + private final PlaceVoteCandidateMemberRepository placeVoteCandidateMemberRepository; + private final PlaceVoteCandidateRepository placeVoteCandidateRepository; + + // 장소투표방 생성 + @Transactional(rollbackFor = {CustomException.class}) + public PlaceVoteRoomCreateResponse createPlaceVoteRoom(Room room, PlaceVoteRoomCreateRequest request) { - //장소투표방 재생성 - @Transactional(rollbackFor = {CustomException.class}) - public PlaceVoteRoomCreateResponse recreatePlaceVoteRoom(Room room,PlaceVoteRoomCreateRequest request) { + boolean exists = placeVoteRoomRepository.existsByRoom(room); - // 기존 투표방 삭제 - PlaceVoteRoom existingPlaceVoteRoom = placeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + if (exists) { + throw new CustomException(DUPLICATE_VOTE_ROOM); + } - // 먼저 투표와 관련된 모든 데이터 삭제 - placeVoteRoomRepository.delete(existingPlaceVoteRoom); - placeVoteRoomRepository.flush(); + PlaceVoteRoom placeVoteRoom = new PlaceVoteRoom(room, request.getPlaceCandidates()); + PlaceVoteRoom savedPlaceVoteRoom = placeVoteRoomRepository.save(placeVoteRoom); - //투표방 생성 - PlaceVoteRoom placeVoteRoom = new PlaceVoteRoom(room,request.getPlaceCandidates()); - PlaceVoteRoom savedPlaceVoteRoom = placeVoteRoomRepository.save(placeVoteRoom); + return PlaceVoteRoomCreateResponse.from(savedPlaceVoteRoom.getId()); + } - return PlaceVoteRoomCreateResponse.from(savedPlaceVoteRoom.getId()); - } + //장소투표방 재생성 + @Transactional(rollbackFor = {CustomException.class}) + public PlaceVoteRoomCreateResponse recreatePlaceVoteRoom(Room room, PlaceVoteRoomCreateRequest request) { - // 장소투표방 조회 - public PlaceVoteInfoResponse getPlaceVoteRoom(Room room) { + // 기존 투표방 삭제 + PlaceVoteRoom existingPlaceVoteRoom = placeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room) - .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - List candidates = placeVoteRoom.getPlaceVoteCandidates().stream() - .map(candidate -> new PlaceVoteCandidateInfo(candidate.getId(), candidate.getName(), candidate.getSiDo(), candidate.getSiGunGu(), candidate.getRoadNameAddress(), candidate.getAddressLatitude(), candidate.getAddressLatitude(), candidate.getCount(), candidate.getVoters().stream().map(v -> v.getMember().getName()).collect(Collectors.toList()))).collect(Collectors.toList()); + // 먼저 투표와 관련된 모든 데이터 삭제 + placeVoteRoomRepository.delete(existingPlaceVoteRoom); + placeVoteRoomRepository.flush(); - return new PlaceVoteInfoResponse(candidates); - } + //투표방 생성 + PlaceVoteRoom placeVoteRoom = new PlaceVoteRoom(room, request.getPlaceCandidates()); + PlaceVoteRoom savedPlaceVoteRoom = placeVoteRoomRepository.save(placeVoteRoom); - // 투표 처리 - @Transactional(rollbackFor = {CustomException.class}) - public void vote(Member member, Room room, PlaceVoteRequest voteRequest) { + return PlaceVoteRoomCreateResponse.from(savedPlaceVoteRoom.getId()); + } - PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + // 장소투표방 조회 + public PlaceVoteInfoResponse getPlaceVoteRoom(Room room) { - boolean alreadyVoted = placeVoteCandidateMemberRepository.existsByPlaceVoteCandidate_PlaceVoteRoomAndMember(placeVoteRoom, member); - if (alreadyVoted) { - throw new CustomException(ALREADY_VOTED); - } - long candidateId = voteRequest.getChoicePlace(); - PlaceVoteCandidate candidate = placeVoteCandidateRepository.findById(candidateId) - .orElseThrow(() -> new CustomException(CANDIDATE_NOT_FOUND)); + PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + List candidates = placeVoteRoom.getPlaceVoteCandidates() + .stream() + .map(candidate -> new PlaceVoteCandidateInfo(candidate.getId(), candidate.getName(), candidate.getSiDo(), + candidate.getSiGunGu(), candidate.getRoadNameAddress(), candidate.getAddressLatitude(), + candidate.getAddressLatitude(), candidate.getCount(), + candidate.getVoters().stream().map(v -> v.getMember().getName()).collect(Collectors.toList()))) + .collect(Collectors.toList()); - PlaceVoteCandidateMember placeVoteCandidateMember = new PlaceVoteCandidateMember(candidate, member); - placeVoteCandidateMemberRepository.save(placeVoteCandidateMember); - } + return new PlaceVoteInfoResponse(candidates); + } - // 재투표 - @Transactional(rollbackFor = {CustomException.class}) - public void updateVote(Member member, Room room,PlaceVoteRequest voteRequest) { + // 투표 처리 + @Transactional(rollbackFor = {CustomException.class}) + public void vote(Member member, Room room, PlaceVoteRequest voteRequest) { - PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - //기존투표제거 - boolean alreadyVoted = placeVoteCandidateMemberRepository.existsByPlaceVoteCandidate_PlaceVoteRoomAndMember(placeVoteRoom, member); - if (!alreadyVoted) { - throw new CustomException(VOTE_NOT_FOUND); - } + boolean alreadyVoted = placeVoteCandidateMemberRepository.existsByPlaceVoteCandidate_PlaceVoteRoomAndMember( + placeVoteRoom, member); + if (alreadyVoted) { + throw new CustomException(ALREADY_VOTED); + } + long candidateId = voteRequest.getChoicePlace(); + PlaceVoteCandidate candidate = placeVoteCandidateRepository.findById(candidateId) + .orElseThrow(() -> new CustomException(CANDIDATE_NOT_FOUND)); - List existingVotes = placeVoteCandidateMemberRepository.findAllByPlaceVoteCandidate_PlaceVoteRoomAndMember(placeVoteRoom, member); - placeVoteCandidateMemberRepository.deleteAll(existingVotes); + PlaceVoteCandidateMember placeVoteCandidateMember = new PlaceVoteCandidateMember(candidate, member); + placeVoteCandidateMemberRepository.save(placeVoteCandidateMember); + } - // 새로 받은 항목으로 업데이트 - long candidateId = voteRequest.getChoicePlace(); - PlaceVoteCandidate candidate = placeVoteCandidateRepository.findById(candidateId) - .orElseThrow(() -> new CustomException(CANDIDATE_NOT_FOUND)); + // 재투표 + @Transactional(rollbackFor = {CustomException.class}) + public void updateVote(Member member, Room room, PlaceVoteRequest voteRequest) { - PlaceVoteCandidateMember placeVoteCandidateMember = new PlaceVoteCandidateMember(candidate, member); - placeVoteCandidateMemberRepository.save(placeVoteCandidateMember); - } + PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - //장소투표방 존재 여부 확인, 존재시 true, 존재하지 않을시 false 반환 - public boolean hasPlaceVoteRoom(String roomId) { + //기존투표제거 + boolean alreadyVoted = placeVoteCandidateMemberRepository.existsByPlaceVoteCandidate_PlaceVoteRoomAndMember( + placeVoteRoom, member); + if (!alreadyVoted) { + throw new CustomException(VOTE_NOT_FOUND); + } - return placeVoteRoomRepository.existsByRoomIdentityNumber(roomId); - } + List existingVotes = placeVoteCandidateMemberRepository.findAllByPlaceVoteCandidate_PlaceVoteRoomAndMember( + placeVoteRoom, member); + placeVoteCandidateMemberRepository.deleteAll(existingVotes); - //먼저 장소투표방이 없다면 시간투표방없다고 에러메세지, 그 다음 장소투표방이 있을때 투표했으면 true, 투표안했으면 false 반환 - public boolean hasVoted(Member member, Room room) { + // 새로 받은 항목으로 업데이트 + long candidateId = voteRequest.getChoicePlace(); + PlaceVoteCandidate candidate = placeVoteCandidateRepository.findById(candidateId) + .orElseThrow(() -> new CustomException(CANDIDATE_NOT_FOUND)); - PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + PlaceVoteCandidateMember placeVoteCandidateMember = new PlaceVoteCandidateMember(candidate, member); + placeVoteCandidateMemberRepository.save(placeVoteCandidateMember); + } + + //장소투표방 존재 여부 확인, 존재시 true, 존재하지 않을시 false 반환 + public boolean hasPlaceVoteRoom(String roomId) { + + return placeVoteRoomRepository.existsByRoomIdentityNumber(roomId); + } - return placeVoteCandidateMemberRepository.existsByPlaceVoteCandidate_PlaceVoteRoomAndMember(placeVoteRoom, member); - } + //먼저 장소투표방이 없다면 시간투표방없다고 에러메세지, 그 다음 장소투표방이 있을때 투표했으면 true, 투표안했으면 false 반환 + public boolean hasVoted(Member member, Room room) { + + PlaceVoteRoom placeVoteRoom = placeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + + return placeVoteCandidateMemberRepository.existsByPlaceVoteCandidate_PlaceVoteRoomAndMember(placeVoteRoom, + member); + } } \ No newline at end of file diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java index b5bde2dc..87094b8d 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java @@ -175,7 +175,7 @@ public ResponseEntity> timeVoteRoomRecr ) } ) - public ResponseEntity vote(@RequestBody TimeVoteRoomVoteRequest request) { + public ResponseEntity vote(@RequestBody @Valid TimeVoteRoomVoteRequest request) { Member member = memberLoader.getMember(); Room room = memberLoader.getRoom(); @@ -223,7 +223,7 @@ public ResponseEntity vote(@RequestBody TimeVoteRoomVoteRequest request) { ) } ) - public ResponseEntity voteUpdate(@RequestBody TimeVoteRoomVoteRequest request) { + public ResponseEntity voteUpdate(@RequestBody @Valid TimeVoteRoomVoteRequest request) { Member member = memberLoader.getMember(); Room room = memberLoader.getRoom(); diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/MeetingDate.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/MeetingDate.java index 21db9f2c..1b3cfc78 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/MeetingDate.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/MeetingDate.java @@ -4,26 +4,27 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; + import java.time.LocalDate; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class MeetingDate { - @Id - @Column(name = "meeting_date_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @Column(name = "meeting_date_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "time_vote_room_id") - private TimeVoteRoom timeVoteRoom; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "time_vote_room_id") + private TimeVoteRoom timeVoteRoom; - @Column(name = "date") - private LocalDate date; + @Column(name = "date") + private LocalDate date; - public MeetingDate(TimeVoteRoom timeVoteRoom, LocalDate date) { - this.timeVoteRoom = timeVoteRoom; - this.date = date; - } + public MeetingDate(TimeVoteRoom timeVoteRoom, LocalDate date) { + this.timeVoteRoom = timeVoteRoom; + this.date = date; + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVote.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVote.java index 8548be0c..c91d1bb0 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVote.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVote.java @@ -12,33 +12,34 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class TimeVote { - @Id - @Column(name = "time_vote_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne - @JoinColumn(name = "time_vote_room_id") - private TimeVoteRoom timeVoteRoom; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; - - @ManyToOne - @JoinColumn(name = "meeting_date_id") - private MeetingDate meetingDate; - - private LocalDateTime memberAvailableStartTime; - - private LocalDateTime memberAvailableEndTime; - - public TimeVote(TimeVoteRoom timeVoteRoom, MeetingDate meetingDate, Member member, LocalDateTime memberAvailableStartTime, LocalDateTime memberAvailableEndTime) { - this.timeVoteRoom = timeVoteRoom; - this.meetingDate =meetingDate; - this.member =member; - this.memberAvailableStartTime = memberAvailableStartTime; - this.memberAvailableEndTime = memberAvailableEndTime; - } + @Id + @Column(name = "time_vote_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "time_vote_room_id") + private TimeVoteRoom timeVoteRoom; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne + @JoinColumn(name = "meeting_date_id") + private MeetingDate meetingDate; + + private LocalDateTime memberAvailableStartTime; + + private LocalDateTime memberAvailableEndTime; + + public TimeVote(TimeVoteRoom timeVoteRoom, MeetingDate meetingDate, Member member, + LocalDateTime memberAvailableStartTime, LocalDateTime memberAvailableEndTime) { + this.timeVoteRoom = timeVoteRoom; + this.meetingDate = meetingDate; + this.member = member; + this.memberAvailableStartTime = memberAvailableStartTime; + this.memberAvailableEndTime = memberAvailableEndTime; + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVoteRoom.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVoteRoom.java index b78d6802..bb66dea1 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVoteRoom.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/domain/TimeVoteRoom.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import middle_point_search.backend.domains.room.domain.Room; + import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -15,27 +16,28 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class TimeVoteRoom { - @Id - @Column(name = "time_vote_room_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Id + @Column(name = "time_vote_room_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @OneToOne - @JoinColumn(name = "room_id",unique = true) - private Room room; + @OneToOne + @JoinColumn(name = "room_id", unique = true) + private Room room; - @OneToMany(mappedBy = "timeVoteRoom", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List timeVotes= new ArrayList<>(); + @OneToMany(mappedBy = "timeVoteRoom", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List timeVotes = new ArrayList<>(); - @OneToMany(mappedBy = "timeVoteRoom", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List meetingDates= new ArrayList<>();; + @OneToMany(mappedBy = "timeVoteRoom", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List meetingDates = new ArrayList<>(); + ; - public TimeVoteRoom(Room room, List dates) { - this.room = room; - this.meetingDates = dates.stream() - .map(date -> new MeetingDate(this, date)) - .collect(Collectors.toList()); - } + public TimeVoteRoom(Room room, List dates) { + this.room = room; + this.meetingDates = dates.stream() + .map(date -> new MeetingDate(this, date)) + .collect(Collectors.toList()); + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/dto/TimeVoteRoomDTO.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/dto/TimeVoteRoomDTO.java index 1e026cc4..7b9ade01 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/dto/TimeVoteRoomDTO.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/dto/TimeVoteRoomDTO.java @@ -1,6 +1,7 @@ package middle_point_search.backend.domains.timeVoteRoom.dto; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -8,6 +9,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; + import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; @@ -16,69 +18,70 @@ import java.util.Map; public class TimeVoteRoomDTO { - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - public static class TimeVoteRoomCreateRequest { - - @NotEmpty(message = "투표 후보가 제공되지 않았습니다.") - private List<@NotNull(message = "날짜는 비어있을 수 없습니다.") LocalDate> dates; - } - - @Getter - @AllArgsConstructor(access = AccessLevel.PRIVATE) - public static class TimeVoteRoomCreateResponse { - private final Long id; - public static TimeVoteRoomCreateResponse from(Long id) { - return new TimeVoteRoomCreateResponse(id); - } - } - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - public static class TimeVoteRoomVoteRequest { - private List dateTime; - - public TimeVoteRoomVoteRequest(List dateTime) { - this.dateTime = dateTime; - } - } - - - @Getter - @AllArgsConstructor(access = AccessLevel.PRIVATE) - public static class TimeVoteRoomResultResponse { - private Map> result; - private int totalMemberNum; - public static TimeVoteRoomResultResponse from(Map> result, int totalMemberNum) { - return new TimeVoteRoomResultResponse(result, totalMemberNum); - } - } - - @Getter - @AllArgsConstructor(access = AccessLevel.PRIVATE) - public static class TimeVoteDetail { - private String memberName; - private List dateTime; - - public static TimeVoteDetail from(String memberName, List dateTime) { - return new TimeVoteDetail(memberName, dateTime); - } - } - - @Getter - @NoArgsConstructor - @AllArgsConstructor(access = AccessLevel.PUBLIC) - public static class TimeRange { - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") - @Schema(type = "string", example = "2024-07-26 13:00") - private LocalDateTime memberAvailableStartTime; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") - @Schema(type = "string", example = "2024-07-26 19:00") - private LocalDateTime memberAvailableEndTime; - } + @Getter + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class TimeVoteRoomCreateRequest { + + @NotEmpty(message = "투표 후보가 제공되지 않았습니다.") + private List<@NotNull(message = "날짜는 비어있을 수 없습니다.") LocalDate> dates; + } + + @Getter + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static class TimeVoteRoomCreateResponse { + private final Long id; + + public static TimeVoteRoomCreateResponse from(Long id) { + return new TimeVoteRoomCreateResponse(id); + } + } + + @Getter + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class TimeVoteRoomVoteRequest { + private List dateTime; + + public TimeVoteRoomVoteRequest(List dateTime) { + this.dateTime = dateTime; + } + } + + @Getter + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static class TimeVoteRoomResultResponse { + private Map> result; + private int totalMemberNum; + + public static TimeVoteRoomResultResponse from(Map> result, int totalMemberNum) { + return new TimeVoteRoomResultResponse(result, totalMemberNum); + } + } + + @Getter + @AllArgsConstructor(access = AccessLevel.PRIVATE) + public static class TimeVoteDetail { + private String memberName; + private List dateTime; + + public static TimeVoteDetail from(String memberName, List dateTime) { + return new TimeVoteDetail(memberName, dateTime); + } + } + + @Getter + @NoArgsConstructor + @AllArgsConstructor(access = AccessLevel.PUBLIC) + public static class TimeRange { + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(type = "string", example = "2024-07-26 13:00") + private LocalDateTime memberAvailableStartTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") + @Schema(type = "string", example = "2024-07-26 19:00") + private LocalDateTime memberAvailableEndTime; + } } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/MeetingDateRepository.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/MeetingDateRepository.java index b4e663e6..8900a469 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/MeetingDateRepository.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/MeetingDateRepository.java @@ -2,12 +2,15 @@ import middle_point_search.backend.domains.timeVoteRoom.domain.MeetingDate; import middle_point_search.backend.domains.timeVoteRoom.domain.TimeVoteRoom; + import org.springframework.data.jpa.repository.JpaRepository; + import java.time.LocalDate; import java.util.List; import java.util.Optional; public interface MeetingDateRepository extends JpaRepository { - Optional findByTimeVoteRoomAndDate(TimeVoteRoom timeVoteRoom, LocalDate date); - List findByTimeVoteRoom(TimeVoteRoom timeVoteRoom); + Optional findByTimeVoteRoomAndDate(TimeVoteRoom timeVoteRoom, LocalDate date); + + List findByTimeVoteRoom(TimeVoteRoom timeVoteRoom); } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRepository.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRepository.java index 4977a9de..92efb9f9 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRepository.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRepository.java @@ -4,14 +4,18 @@ import middle_point_search.backend.domains.timeVoteRoom.domain.TimeVote; import middle_point_search.backend.domains.timeVoteRoom.domain.TimeVoteRoom; import middle_point_search.backend.domains.member.domain.Member; + import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; -public interface TimeVoteRepository extends JpaRepository { - boolean existsByTimeVoteRoomAndMember(TimeVoteRoom timeVoteRoom, Member member); - List findByTimeVoteRoomAndMember(TimeVoteRoom timeVoteRoom, Member member); - List findByTimeVoteRoomAndMeetingDate(TimeVoteRoom timeVoteRoom, MeetingDate meetingDate); - List findDistinctByTimeVoteRoom(TimeVoteRoom timeVoteRoom); +public interface TimeVoteRepository extends JpaRepository { + boolean existsByTimeVoteRoomAndMember(TimeVoteRoom timeVoteRoom, Member member); + + List findByTimeVoteRoomAndMember(TimeVoteRoom timeVoteRoom, Member member); + + List findByTimeVoteRoomAndMeetingDate(TimeVoteRoom timeVoteRoom, MeetingDate meetingDate); + + List findDistinctByTimeVoteRoom(TimeVoteRoom timeVoteRoom); } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRoomRepository.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRoomRepository.java index cd4e7440..d0b8d451 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRoomRepository.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/repository/TimeVoteRoomRepository.java @@ -2,13 +2,15 @@ import middle_point_search.backend.domains.timeVoteRoom.domain.TimeVoteRoom; import middle_point_search.backend.domains.room.domain.Room; + import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface TimeVoteRoomRepository extends JpaRepository { - boolean existsByRoom(Room room); - boolean existsByRoomIdentityNumber(String identityNumber); + boolean existsByRoom(Room room); + + boolean existsByRoomIdentityNumber(String identityNumber); - Optional findByRoom(Room room); + Optional findByRoom(Room room); } diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/service/TimeVoteRoomService.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/service/TimeVoteRoomService.java index 85a0fc9a..6b67ae9b 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/service/TimeVoteRoomService.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/service/TimeVoteRoomService.java @@ -10,6 +10,7 @@ import middle_point_search.backend.domains.timeVoteRoom.repository.TimeVoteRoomRepository; import middle_point_search.backend.domains.member.domain.Member; import middle_point_search.backend.domains.room.domain.Room; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,134 +25,142 @@ @Transactional(readOnly = true) public class TimeVoteRoomService { - private final TimeVoteRoomRepository timeVoteRoomRepository; - private final TimeVoteRepository timeVoteRepository; - private final MeetingDateRepository meetingDateRepository; - - //시간 투표방 생성 - @Transactional(rollbackFor = {CustomException.class}) - public TimeVoteRoomCreateResponse createTimeVoteRoom(Room room, TimeVoteRoomCreateRequest request) { - - boolean exists = timeVoteRoomRepository.existsByRoom(room); - - //방존재여부 확인 - if (exists) { - throw new CustomException(DUPLICATE_VOTE_ROOM); - } - - TimeVoteRoom timeVoteRoom = new TimeVoteRoom(room, request.getDates()); - TimeVoteRoom savedTimeVoteRoom = timeVoteRoomRepository.save(timeVoteRoom); - - return TimeVoteRoomCreateResponse.from(savedTimeVoteRoom.getId()); - } - - //시간투표방 재생성하기 - @Transactional(rollbackFor = {CustomException.class}) - public TimeVoteRoomCreateResponse recreateTimeVoteRoom(Room room, TimeVoteRoomCreateRequest request) { - - // 기존 투표방 삭제 - TimeVoteRoom existingTimeVoteRoom = timeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - - // 먼저 투표와 관련된 모든 데이터 삭제 - timeVoteRoomRepository.delete(existingTimeVoteRoom); - timeVoteRoomRepository.flush(); - - // 새로운 투표방 생성 - TimeVoteRoom timeVoteRoom = new TimeVoteRoom(room, request.getDates()); - TimeVoteRoom savedTimeVoteRoom = timeVoteRoomRepository.save(timeVoteRoom); - - return TimeVoteRoomCreateResponse.from(savedTimeVoteRoom.getId()); - } - - //시간투표하기 - @Transactional(rollbackFor = {CustomException.class}) - public void vote(Member member, Room room, TimeVoteRoomVoteRequest request) { - - TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - - boolean alreadyVoted = timeVoteRepository.existsByTimeVoteRoomAndMember(timeVoteRoom, member); - - if (alreadyVoted) { - throw new CustomException(ALREADY_VOTED); - } - List timeVotes = createNewTimeVotes(request.getDateTime(), timeVoteRoom, member); - timeVoteRepository.saveAll(timeVotes); - } - - // 시간 투표 수정 - @Transactional(rollbackFor = {CustomException.class}) - public void updateVote(Member member, Room room, TimeVoteRoomVoteRequest request) { - - TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - - List existingVotes = timeVoteRepository.findByTimeVoteRoomAndMember(timeVoteRoom, member); - if (existingVotes.isEmpty()) { - throw new CustomException(VOTE_NOT_FOUND); - } - // 기존 투표 삭제 - timeVoteRepository.deleteAll(existingVotes); - // 새로운 투표 추가 - List timeVotes = createNewTimeVotes(request.getDateTime(), timeVoteRoom, member); - timeVoteRepository.saveAll(timeVotes); - } - - private List createNewTimeVotes(List dateTimeRanges, TimeVoteRoom timeVoteRoom, Member member) { - List timeVotes = new ArrayList<>(); - for (TimeRange timeRange : dateTimeRanges) { - LocalDateTime memberAvailableStartTime = timeRange.getMemberAvailableStartTime(); - LocalDateTime memberAvailableEndTime = timeRange.getMemberAvailableEndTime(); - LocalDateTime startDateTime = memberAvailableStartTime.toLocalDate().atStartOfDay(); - Optional meetingDateOpt = meetingDateRepository.findByTimeVoteRoomAndDate(timeVoteRoom, startDateTime.toLocalDate()); - MeetingDate meetingDate = meetingDateOpt.orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - TimeVote timeVote = new TimeVote(timeVoteRoom, meetingDate, member, memberAvailableStartTime, memberAvailableEndTime); - timeVotes.add(timeVote); - } - return timeVotes; - } - - // 시간 투표 현황 정보 조회 - public TimeVoteRoomResultResponse getTimeVoteResult(Room room) { - TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - List meetingDates = meetingDateRepository.findByTimeVoteRoom(timeVoteRoom); - - Map> result = new LinkedHashMap<>(); - meetingDates.sort(Comparator.comparing(MeetingDate::getDate)); - - for (MeetingDate meetingDate : meetingDates) { - String date = meetingDate.getDate().toString(); - List details = new ArrayList<>(); - - // 해당 날짜의 모든 투표 정보 가져오기 - List timeVotes = timeVoteRepository.findByTimeVoteRoomAndMeetingDate(timeVoteRoom, meetingDate); - for (TimeVote vote : timeVotes) { - List dateTimeList = Arrays.asList( - new TimeRange( - vote.getMemberAvailableStartTime(), - vote.getMemberAvailableEndTime() - ) - ); - TimeVoteDetail detail = TimeVoteDetail.from(vote.getMember().getName(), dateTimeList); - details.add(detail); - } - result.put(date, details); - } - - List distinctVotes = timeVoteRepository.findDistinctByTimeVoteRoom(timeVoteRoom); - int totalMemberNum = (int) distinctVotes.stream().map(TimeVote::getMember).distinct().count(); - return TimeVoteRoomResultResponse.from(result, totalMemberNum); - } - - //시간투표방 존재 여부 확인, 존재시 true, 존재하지 않을시 false 반환 - public boolean hasTimeVoteRoom(String roomId) { - - return timeVoteRoomRepository.existsByRoomIdentityNumber(roomId); - } - - //먼저 시간투표방이 없다면 시간투표방없다고 에러메세지, 그 다음 시간 투표방이 있을때 투표했으면 true, 투표안했으면 false 반환 - public boolean hasVoted(Member member, Room room) { - - TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room).orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); - - return timeVoteRepository.existsByTimeVoteRoomAndMember(timeVoteRoom, member); - } + private final TimeVoteRoomRepository timeVoteRoomRepository; + private final TimeVoteRepository timeVoteRepository; + private final MeetingDateRepository meetingDateRepository; + + //시간 투표방 생성 + @Transactional(rollbackFor = {CustomException.class}) + public TimeVoteRoomCreateResponse createTimeVoteRoom(Room room, TimeVoteRoomCreateRequest request) { + + boolean exists = timeVoteRoomRepository.existsByRoom(room); + + //방존재여부 확인 + if (exists) { + throw new CustomException(DUPLICATE_VOTE_ROOM); + } + + TimeVoteRoom timeVoteRoom = new TimeVoteRoom(room, request.getDates()); + TimeVoteRoom savedTimeVoteRoom = timeVoteRoomRepository.save(timeVoteRoom); + + return TimeVoteRoomCreateResponse.from(savedTimeVoteRoom.getId()); + } + + //시간투표방 재생성하기 + @Transactional(rollbackFor = {CustomException.class}) + public TimeVoteRoomCreateResponse recreateTimeVoteRoom(Room room, TimeVoteRoomCreateRequest request) { + + // 기존 투표방 삭제 + TimeVoteRoom existingTimeVoteRoom = timeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + + // 먼저 투표와 관련된 모든 데이터 삭제 + timeVoteRoomRepository.delete(existingTimeVoteRoom); + timeVoteRoomRepository.flush(); + + // 새로운 투표방 생성 + TimeVoteRoom timeVoteRoom = new TimeVoteRoom(room, request.getDates()); + TimeVoteRoom savedTimeVoteRoom = timeVoteRoomRepository.save(timeVoteRoom); + + return TimeVoteRoomCreateResponse.from(savedTimeVoteRoom.getId()); + } + + //시간투표하기 + @Transactional(rollbackFor = {CustomException.class}) + public void vote(Member member, Room room, TimeVoteRoomVoteRequest request) { + + TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + + boolean alreadyVoted = timeVoteRepository.existsByTimeVoteRoomAndMember(timeVoteRoom, member); + + if (alreadyVoted) { + throw new CustomException(ALREADY_VOTED); + } + List timeVotes = createNewTimeVotes(request.getDateTime(), timeVoteRoom, member); + timeVoteRepository.saveAll(timeVotes); + } + + // 시간 투표 수정 + @Transactional(rollbackFor = {CustomException.class}) + public void updateVote(Member member, Room room, TimeVoteRoomVoteRequest request) { + + TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + + List existingVotes = timeVoteRepository.findByTimeVoteRoomAndMember(timeVoteRoom, member); + if (existingVotes.isEmpty()) { + throw new CustomException(VOTE_NOT_FOUND); + } + // 기존 투표 삭제 + timeVoteRepository.deleteAll(existingVotes); + // 새로운 투표 추가 + List timeVotes = createNewTimeVotes(request.getDateTime(), timeVoteRoom, member); + timeVoteRepository.saveAll(timeVotes); + } + + private List createNewTimeVotes(List dateTimeRanges, TimeVoteRoom timeVoteRoom, + Member member) { + List timeVotes = new ArrayList<>(); + for (TimeRange timeRange : dateTimeRanges) { + LocalDateTime memberAvailableStartTime = timeRange.getMemberAvailableStartTime(); + LocalDateTime memberAvailableEndTime = timeRange.getMemberAvailableEndTime(); + LocalDateTime startDateTime = memberAvailableStartTime.toLocalDate().atStartOfDay(); + Optional meetingDateOpt = meetingDateRepository.findByTimeVoteRoomAndDate(timeVoteRoom, + startDateTime.toLocalDate()); + MeetingDate meetingDate = meetingDateOpt.orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + TimeVote timeVote = new TimeVote(timeVoteRoom, meetingDate, member, memberAvailableStartTime, + memberAvailableEndTime); + timeVotes.add(timeVote); + } + return timeVotes; + } + + // 시간 투표 현황 정보 조회 + public TimeVoteRoomResultResponse getTimeVoteResult(Room room) { + TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + List meetingDates = meetingDateRepository.findByTimeVoteRoom(timeVoteRoom); + + Map> result = new LinkedHashMap<>(); + meetingDates.sort(Comparator.comparing(MeetingDate::getDate)); + + for (MeetingDate meetingDate : meetingDates) { + String date = meetingDate.getDate().toString(); + List details = new ArrayList<>(); + + // 해당 날짜의 모든 투표 정보 가져오기 + List timeVotes = timeVoteRepository.findByTimeVoteRoomAndMeetingDate(timeVoteRoom, meetingDate); + for (TimeVote vote : timeVotes) { + List dateTimeList = Arrays.asList( + new TimeRange( + vote.getMemberAvailableStartTime(), + vote.getMemberAvailableEndTime() + ) + ); + TimeVoteDetail detail = TimeVoteDetail.from(vote.getMember().getName(), dateTimeList); + details.add(detail); + } + result.put(date, details); + } + + List distinctVotes = timeVoteRepository.findDistinctByTimeVoteRoom(timeVoteRoom); + int totalMemberNum = (int)distinctVotes.stream().map(TimeVote::getMember).distinct().count(); + return TimeVoteRoomResultResponse.from(result, totalMemberNum); + } + + //시간투표방 존재 여부 확인, 존재시 true, 존재하지 않을시 false 반환 + public boolean hasTimeVoteRoom(String roomId) { + + return timeVoteRoomRepository.existsByRoomIdentityNumber(roomId); + } + + //먼저 시간투표방이 없다면 시간투표방없다고 에러메세지, 그 다음 시간 투표방이 있을때 투표했으면 true, 투표안했으면 false 반환 + public boolean hasVoted(Member member, Room room) { + + TimeVoteRoom timeVoteRoom = timeVoteRoomRepository.findByRoom(room) + .orElseThrow(() -> new CustomException(VOTE_ROOM_NOT_FOUND)); + + return timeVoteRepository.existsByTimeVoteRoomAndMember(timeVoteRoom, member); + } } From 7ac26ce680c6b3e28798fe41f3696bbc1f11029b Mon Sep 17 00:00:00 2001 From: Ye jin Shin <108514552+shinyj0@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:32:38 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=20=EB=B0=8F=20=EC=8B=A4=ED=96=89=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=B8=A1=EC=A0=95=20=EB=A1=9C=EA=B7=B8=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/build.gradle | 2 + .../backend/BackendApplication.java | 2 + .../backend/common/aop/LogAspect.java | 87 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java diff --git a/backend/build.gradle b/backend/build.gradle index 8b3c7da1..a88c1f5c 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -48,6 +48,8 @@ dependencies { //swagger implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.5.0' testImplementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-api', version: '2.5.0' + //aop + implementation 'org.springframework.boot:spring-boot-starter-aop' } tasks.named('test') { diff --git a/backend/src/main/java/middle_point_search/backend/BackendApplication.java b/backend/src/main/java/middle_point_search/backend/BackendApplication.java index e8d17ad6..fd0a921f 100644 --- a/backend/src/main/java/middle_point_search/backend/BackendApplication.java +++ b/backend/src/main/java/middle_point_search/backend/BackendApplication.java @@ -4,6 +4,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import io.swagger.v3.oas.annotations.OpenAPIDefinition; @@ -12,6 +13,7 @@ @SpringBootApplication @EnableJpaAuditing +@EnableAspectJAutoProxy @OpenAPIDefinition(servers = {@Server(url = "/", description = "https://www.api.cotato-midpoint.site")}) public class BackendApplication { diff --git a/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java b/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java new file mode 100644 index 00000000..f548b1e7 --- /dev/null +++ b/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java @@ -0,0 +1,87 @@ +package middle_point_search.backend.common.aop; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.boot.configurationprocessor.json.JSONException; +import org.springframework.boot.configurationprocessor.json.JSONObject; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.net.URLDecoder; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +@Aspect +@Slf4j +@Component +public class LogAspect { + + private static JSONObject getParams(HttpServletRequest request) throws JSONException { + JSONObject jsonObject = new JSONObject(); + Enumeration params = request.getParameterNames(); + while (params.hasMoreElements()) { + String param = params.nextElement(); + String replaceParam = param.replaceAll("\\.", "-"); + jsonObject.put(replaceParam, request.getParameter(param)); + } + return jsonObject; + } + + @Pointcut("execution(* middle_point_search.backend..*.*(..)) && !execution(* middle_point_search.backend.common..*(..))") + public void all() { + } + + @Pointcut("execution(* middle_point_search.backend..*Controller.*(..))") + public void controller() { + } + + @Around("all()") + public Object logging(ProceedingJoinPoint joinPoint) throws Throwable { + long start = System.currentTimeMillis(); + try { + Object result = joinPoint.proceed(); + return result; + } finally { + long end = System.currentTimeMillis(); + long timeinMs = end - start; + log.info("{} | time = {}ms", joinPoint.getSignature(), timeinMs); + } + } + + @Around("controller()") + public Object loggingBefore(ProceedingJoinPoint joinPoint) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + + String controllerName = joinPoint.getSignature().getDeclaringType().getName(); + String methodName = joinPoint.getSignature().getName(); + Map params = new HashMap<>(); + + try { + String decodedURI = URLDecoder.decode(request.getRequestURI(), "UTF-8"); + + params.put("controller", controllerName); + params.put("method", methodName); + params.put("params", getParams(request)); + params.put("log_time", System.currentTimeMillis()); + params.put("request_uri", decodedURI); + params.put("http_method", request.getMethod()); + } catch (Exception e) { + log.error("LoggerAspect error", e); + } + + log.info("[{}] {}", params.get("http_method"), params.get("request_uri")); + log.info("method: {}.{}", params.get("controller"), params.get("method")); + log.info("params: {}", params.get("params")); + + Object result = joinPoint.proceed(); + + return result; + } + +} From 8ff2f80c0c87bf0bc6003d726dee2e0bb91f76b6 Mon Sep 17 00:00:00 2001 From: Ye jin Shin <108514552+shinyj0@users.noreply.github.com> Date: Thu, 1 Aug 2024 23:44:16 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=ED=8F=AC=EB=A7=B7=20=EC=A7=80=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=20=ED=8C=8C=EC=9D=BC=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 +++- backend/src/main/resources/logback-spring.xml | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/resources/logback-spring.xml diff --git a/.gitignore b/.gitignore index 848c1b50..5bc12cc9 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,7 @@ out/ src/main/resources/application-security.properties ### applcation-api ### src/main/resources/application-api.properties -src/main/resources/application.properties \ No newline at end of file +src/main/resources/application.properties + +### log file +**/*.log \ No newline at end of file diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..aa62a49d --- /dev/null +++ b/backend/src/main/resources/logback-spring.xml @@ -0,0 +1,30 @@ + + + + + + + + + ${CONSOLE_LOG_PATTERN} + > + + + ./log/testFile.log + + ${FILE_LOG_PATTERN} + + + ./log/%d{yyyy-MM-dd}.%i.log + 100MB + 30 + 20GB + + + + + + + + + \ No newline at end of file From 07b96f12f1c3800c8da988998535681868f762d4 Mon Sep 17 00:00:00 2001 From: Ye jin Shin <108514552+shinyj0@users.noreply.github.com> Date: Sun, 4 Aug 2024 03:46:35 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=EB=B3=84=20=EB=A1=9C=EA=B7=B8=20=EB=A0=88=EB=B2=A8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 5 +- .gitignore | 2 +- backend/build.gradle | 8 ++ .../backend/BackendApplication.java | 11 +++ .../backend/common/aop/LogAspect.java | 51 +++--------- .../exception/errorCode/CommonErrorCode.java | 1 + .../common/filter/RateLimitFilter.java | 77 +++++++++++++++++++ .../controller/MidPointController.java | 4 +- .../place/controller/PlaceController.java | 8 +- .../controller/PlaceVoteRoomController.java | 14 ++-- .../controller/RecommendPlaceController.java | 2 +- .../room/controller/RoomController.java | 7 +- .../controller/TimeVoteRoomController.java | 18 ++--- .../src/main/resources/application.properties | 5 ++ backend/src/main/resources/logback-spring.xml | 30 -------- .../resources/logback/console-appender.xml | 7 ++ .../resources/logback/file-error-appender.xml | 18 +++++ .../resources/logback/file-info-appender.xml | 13 ++++ .../main/resources/logback/logback-spring.xml | 70 +++++++++++++++++ 19 files changed, 252 insertions(+), 99 deletions(-) create mode 100644 backend/src/main/java/middle_point_search/backend/common/filter/RateLimitFilter.java delete mode 100644 backend/src/main/resources/logback-spring.xml create mode 100644 backend/src/main/resources/logback/console-appender.xml create mode 100644 backend/src/main/resources/logback/file-error-appender.xml create mode 100644 backend/src/main/resources/logback/file-info-appender.xml create mode 100644 backend/src/main/resources/logback/logback-spring.xml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index ff7df4ae..43f899c9 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -4,9 +4,7 @@ name: Java CI with Gradle on: push: branches: [ "develop" ] - pull_request: - branches: [ "develop" ] - + jobs: build: @@ -53,7 +51,6 @@ jobs: needs: build runs-on: ubuntu-latest - # 위의 빌드작업한 JAR 파일 = 아티팩트를 다운로드 steps: - name: Download build artifact uses: actions/download-artifact@v2 diff --git a/.gitignore b/.gitignore index 5bc12cc9..98c7e886 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,4 @@ src/main/resources/application-api.properties src/main/resources/application.properties ### log file -**/*.log \ No newline at end of file +/log/ diff --git a/backend/build.gradle b/backend/build.gradle index a88c1f5c..c092c4a5 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -48,6 +48,8 @@ dependencies { //swagger implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.5.0' testImplementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-api', version: '2.5.0' + //bucket4j + implementation group: 'com.github.vladimir-bukhtoyarov', name: 'bucket4j-core', version: '8.0.1' //aop implementation 'org.springframework.boot:spring-boot-starter-aop' } @@ -55,3 +57,9 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +//profile별로 실행시 +bootRun { + String activeProfile = System.properties['spring.profiles.active'] + systemProperty "spring.profiles.active", activeProfile +} diff --git a/backend/src/main/java/middle_point_search/backend/BackendApplication.java b/backend/src/main/java/middle_point_search/backend/BackendApplication.java index fd0a921f..4afede31 100644 --- a/backend/src/main/java/middle_point_search/backend/BackendApplication.java +++ b/backend/src/main/java/middle_point_search/backend/BackendApplication.java @@ -4,12 +4,15 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.servers.Server; import jakarta.annotation.PostConstruct; +import middle_point_search.backend.common.filter.RateLimitFilter; @SpringBootApplication @EnableJpaAuditing @@ -26,4 +29,12 @@ public void init() { // timezone 설정 TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")); } + + @Bean + public FilterRegistrationBean rateLimitFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new RateLimitFilter()); + registrationBean.addUrlPatterns("/api/*"); + return registrationBean; + } } diff --git a/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java b/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java index f548b1e7..08f16000 100644 --- a/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java +++ b/backend/src/main/java/middle_point_search/backend/common/aop/LogAspect.java @@ -6,33 +6,15 @@ import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; -import org.springframework.boot.configurationprocessor.json.JSONException; -import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import java.net.URLDecoder; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - @Aspect @Slf4j @Component public class LogAspect { - private static JSONObject getParams(HttpServletRequest request) throws JSONException { - JSONObject jsonObject = new JSONObject(); - Enumeration params = request.getParameterNames(); - while (params.hasMoreElements()) { - String param = params.nextElement(); - String replaceParam = param.replaceAll("\\.", "-"); - jsonObject.put(replaceParam, request.getParameter(param)); - } - return jsonObject; - } - @Pointcut("execution(* middle_point_search.backend..*.*(..)) && !execution(* middle_point_search.backend.common..*(..))") public void all() { } @@ -56,32 +38,21 @@ public Object logging(ProceedingJoinPoint joinPoint) throws Throwable { @Around("controller()") public Object loggingBefore(ProceedingJoinPoint joinPoint) throws Throwable { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - - String controllerName = joinPoint.getSignature().getDeclaringType().getName(); - String methodName = joinPoint.getSignature().getName(); - Map params = new HashMap<>(); + final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + final String ipAddr = request.getRemoteAddr(); + final String method = request.getMethod(); + final String requestURI = request.getRequestURI(); + final Object[] args = joinPoint.getArgs(); + log.info("[REQUEST] {} {} {} args={}", ipAddr, method, requestURI, args); try { - String decodedURI = URLDecoder.decode(request.getRequestURI(), "UTF-8"); - - params.put("controller", controllerName); - params.put("method", methodName); - params.put("params", getParams(request)); - params.put("log_time", System.currentTimeMillis()); - params.put("request_uri", decodedURI); - params.put("http_method", request.getMethod()); + Object result = joinPoint.proceed(); + log.info("[RESPONSE] {}", result); + return result; } catch (Exception e) { - log.error("LoggerAspect error", e); + log.error("[RESPONSE] exception message = {} {}", e.getMessage(), e.getStackTrace()[0]); + throw e; } - - log.info("[{}] {}", params.get("http_method"), params.get("request_uri")); - log.info("method: {}.{}", params.get("controller"), params.get("method")); - log.info("params: {}", params.get("params")); - - Object result = joinPoint.proceed(); - - return result; } } diff --git a/backend/src/main/java/middle_point_search/backend/common/exception/errorCode/CommonErrorCode.java b/backend/src/main/java/middle_point_search/backend/common/exception/errorCode/CommonErrorCode.java index cf048ab9..55026081 100644 --- a/backend/src/main/java/middle_point_search/backend/common/exception/errorCode/CommonErrorCode.java +++ b/backend/src/main/java/middle_point_search/backend/common/exception/errorCode/CommonErrorCode.java @@ -16,6 +16,7 @@ public enum CommonErrorCode implements ErrorCode { INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생하였습니다."), DATA_BUFFER_LIMIT_ERROR(HttpStatus.PAYLOAD_TOO_LARGE, "요청의 페이로드가 너무 큽니다."), AUTHENTICATION_SERVICE_ERROR(HttpStatus.BAD_REQUEST, "요청한 content-type은 허락되지 않습니다."), + TOO_MANY_REQUESTS(HttpStatus.TOO_MANY_REQUESTS, "요청을 너무 많이 했습니다."), ; private final HttpStatus httpStatus; diff --git a/backend/src/main/java/middle_point_search/backend/common/filter/RateLimitFilter.java b/backend/src/main/java/middle_point_search/backend/common/filter/RateLimitFilter.java new file mode 100644 index 00000000..a2f06f52 --- /dev/null +++ b/backend/src/main/java/middle_point_search/backend/common/filter/RateLimitFilter.java @@ -0,0 +1,77 @@ +package middle_point_search.backend.common.filter; + +import static middle_point_search.backend.common.exception.errorCode.CommonErrorCode.*; + +import java.io.IOException; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.http.HttpStatus; +import org.springframework.web.filter.OncePerRequestFilter; + +import io.github.bucket4j.Bandwidth; +import io.github.bucket4j.Bucket; +import io.github.bucket4j.Bucket4j; +import io.github.bucket4j.Refill; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import middle_point_search.backend.common.dto.ErrorResponse; +import middle_point_search.backend.common.util.ResponseWriter; + +public class RateLimitFilter extends OncePerRequestFilter { + + private static final String DEFAULT_ROOM_CREATE_REQUEST_URL = "/api/rooms"; + private static final String HTTP_METHOD = "POST"; + private static final int REQUEST_LIMIT_PER_TIME = 20; + private static final int TIME = 1; //분 + + private final Map buckets = new ConcurrentHashMap<>(); + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + String requestURI = request.getRequestURI(); + String httpMethod = request.getMethod(); + + if (shouldApplyRateLimiting(requestURI, httpMethod)) { + String clientIp = getClientIP(request); + + Bucket bucket = buckets.computeIfAbsent(clientIp, this::newBucket); + + if (bucket.tryConsume(1)) { + filterChain.doFilter(request, response); + } else { + ErrorResponse errorResponse = ErrorResponse.from(TOO_MANY_REQUESTS); + + ResponseWriter.writeResponse(response, errorResponse, HttpStatus.TOO_MANY_REQUESTS); + } + } else { + filterChain.doFilter(request, response); + } + + } + + //url 및 httpMethod 확인하여 일치하면 true + private boolean shouldApplyRateLimiting(String requestURI, String httpMethod) { + return requestURI.startsWith(DEFAULT_ROOM_CREATE_REQUEST_URL) && HTTP_METHOD.equalsIgnoreCase(httpMethod); + } + + //Bucket 생성 + private Bucket newBucket(String clientIp) { + Bandwidth limit = Bandwidth.classic(REQUEST_LIMIT_PER_TIME, Refill.greedy(REQUEST_LIMIT_PER_TIME, Duration.ofMinutes(TIME))); + return Bucket4j.builder().addLimit(limit).build(); + } + + //사용자의 IP 가져오기 + private String getClientIP(HttpServletRequest request) { + String xfHeader = request.getHeader("X-Forwarded-For"); + if (xfHeader == null) { + return request.getRemoteAddr(); + } + return xfHeader.split(",")[0]; + } +} diff --git a/backend/src/main/java/middle_point_search/backend/domains/midPoint/controller/MidPointController.java b/backend/src/main/java/middle_point_search/backend/domains/midPoint/controller/MidPointController.java index 4d13a1ea..f159ba99 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/midPoint/controller/MidPointController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/midPoint/controller/MidPointController.java @@ -35,10 +35,10 @@ public class MidPointController { summary = "중간 지점 추천 장소 조회", description = """ 중간 지점 추천 장소 조회하기. - + AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( diff --git a/backend/src/main/java/middle_point_search/backend/domains/place/controller/PlaceController.java b/backend/src/main/java/middle_point_search/backend/domains/place/controller/PlaceController.java index 8a417ebe..40928ffb 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/place/controller/PlaceController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/place/controller/PlaceController.java @@ -48,7 +48,7 @@ public class PlaceController { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -90,7 +90,7 @@ public ResponseEntity placeSaveOrUpdate(@RequestBody @Valid PlaceS AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -127,7 +127,7 @@ public ResponseEntity placesSaveOrUpdateBySelf(@RequestBody Places AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -161,7 +161,7 @@ public ResponseEntity> placeFind() { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( diff --git a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java index d2b8f04b..b939b430 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/placeVoteRoom/controller/PlaceVoteRoomController.java @@ -48,7 +48,7 @@ public class PlaceVoteRoomController { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -96,7 +96,7 @@ public ResponseEntity> placeVoteRoomCr AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -143,7 +143,7 @@ public ResponseEntity> placeVoteRoomRe AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -184,7 +184,7 @@ public ResponseEntity> placeVoteRoomGet() { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -236,7 +236,7 @@ public ResponseEntity vote(@RequestBody @Valid PlaceVoteRequest request) { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -288,7 +288,7 @@ public ResponseEntity voteUpdate(@RequestBody @Valid PlaceVoteRequest request AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -324,7 +324,7 @@ public ResponseEntity> placeVoteRoomHas() { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( diff --git a/backend/src/main/java/middle_point_search/backend/domains/recommendPlace/controller/RecommendPlaceController.java b/backend/src/main/java/middle_point_search/backend/domains/recommendPlace/controller/RecommendPlaceController.java index caf1a0fc..0ca6e28b 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/recommendPlace/controller/RecommendPlaceController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/recommendPlace/controller/RecommendPlaceController.java @@ -44,7 +44,7 @@ public class RecommendPlaceController { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( diff --git a/backend/src/main/java/middle_point_search/backend/domains/room/controller/RoomController.java b/backend/src/main/java/middle_point_search/backend/domains/room/controller/RoomController.java index 57f73ae4..8898c6d5 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/room/controller/RoomController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/room/controller/RoomController.java @@ -41,6 +41,11 @@ public class RoomController { @ApiResponse( responseCode = "200", description = "성공" + ), + @ApiResponse( + responseCode = "429", + description = "요청을 너무 많이 했습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) ) } ) @@ -76,7 +81,7 @@ public ResponseEntity> roomExistenceChe accessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( diff --git a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java index 87094b8d..3b279359 100644 --- a/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java +++ b/backend/src/main/java/middle_point_search/backend/domains/timeVoteRoom/controller/TimeVoteRoomController.java @@ -37,6 +37,8 @@ public class TimeVoteRoomController { private final MemberLoader memberLoader; //투표방 생성 + //투표방 재생성 + @PostMapping @Operation( summary = "시간투표방 생성하기", @@ -47,7 +49,7 @@ public class TimeVoteRoomController { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -85,8 +87,6 @@ public ResponseEntity> timeVoteRoomCrea return ResponseEntity.ok(DataResponse.from(response)); } - - //투표방 재생성 @PutMapping @Operation( summary = "시간투표방 재생성하기", @@ -97,7 +97,7 @@ public ResponseEntity> timeVoteRoomCrea AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -145,7 +145,7 @@ public ResponseEntity> timeVoteRoomRecr AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -194,7 +194,7 @@ public ResponseEntity vote(@RequestBody @Valid TimeVoteRoomVoteRequest reques AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -242,7 +242,7 @@ public ResponseEntity voteUpdate(@RequestBody @Valid TimeVoteRoomVoteRequest AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -279,7 +279,7 @@ public ResponseEntity> timeVoteRoomHas() { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( @@ -322,7 +322,7 @@ public ResponseEntity> votedHas() { AccessToken 필요.""", parameters = { - @Parameter(name = "RoomId", description = "roomId 필요", required = true, in = ParameterIn.HEADER) + @Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER) }, responses = { @ApiResponse( diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 1bebd37a..721d056a 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -6,6 +6,8 @@ spring.profiles.include=security, api spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.highlight_sql=true +logging.level.org.hibernate.orm.jdbc.bind = trace spring.devtools.livereload.enabled=true spring.devtools.restart.enabled=true @@ -21,5 +23,8 @@ springdoc.api-docs.path=/api-docs springdoc.default-consumes-media-type=application/json;charset=UTF-8 springdoc.default-produces-media-type=application/json;charset=UTF-8 +#log File +logging.file.name=./log/pium-dev.log +logging.file.path=./log diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml deleted file mode 100644 index aa62a49d..00000000 --- a/backend/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - ${CONSOLE_LOG_PATTERN} - > - - - ./log/testFile.log - - ${FILE_LOG_PATTERN} - - - ./log/%d{yyyy-MM-dd}.%i.log - 100MB - 30 - 20GB - - - - - - - - - \ No newline at end of file diff --git a/backend/src/main/resources/logback/console-appender.xml b/backend/src/main/resources/logback/console-appender.xml new file mode 100644 index 00000000..f85a9286 --- /dev/null +++ b/backend/src/main/resources/logback/console-appender.xml @@ -0,0 +1,7 @@ + + + + ${CONSOLE_LOG_PATTERN} + + + \ No newline at end of file diff --git a/backend/src/main/resources/logback/file-error-appender.xml b/backend/src/main/resources/logback/file-error-appender.xml new file mode 100644 index 00000000..9893d653 --- /dev/null +++ b/backend/src/main/resources/logback/file-error-appender.xml @@ -0,0 +1,18 @@ + + + + ERROR + ACCEPT + DENY + + + ${FILE_LOG_PATTERN} + + + ./log/pium-prod-%d{yyyy-MM-dd}.%i.log + 50MB + 30 + 3GB + + + \ No newline at end of file diff --git a/backend/src/main/resources/logback/file-info-appender.xml b/backend/src/main/resources/logback/file-info-appender.xml new file mode 100644 index 00000000..ae5c8ef9 --- /dev/null +++ b/backend/src/main/resources/logback/file-info-appender.xml @@ -0,0 +1,13 @@ + + + + ${FILE_LOG_PATTERN} + + + ./log/info-%d{yyyy-MM-dd}.%i.log + 50MB + 30 + 1GB + + + \ No newline at end of file diff --git a/backend/src/main/resources/logback/logback-spring.xml b/backend/src/main/resources/logback/logback-spring.xml new file mode 100644 index 00000000..0fb00411 --- /dev/null +++ b/backend/src/main/resources/logback/logback-spring.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +