From de296d9b2df9d8be366e5c5cbb55abe147f28a35 Mon Sep 17 00:00:00 2001 From: YoonHeeJun Date: Mon, 24 Feb 2025 04:49:42 +0900 Subject: [PATCH] =?UTF-8?q?:recycle:Refactor:=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=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 --- .../card/controller/CardController.java | 36 +-- .../domain/card/dto/request/CardRequest.java | 24 -- .../card/dto/request/CreateCardRequest.java | 20 ++ .../domain/card/dto/response/CardDto.java | 29 -- .../card/dto/response/CardListResponse.java | 6 +- .../card/dto/response/CardListSummaryDto.java | 22 -- .../card/dto/response/CardResponse.java | 9 +- .../card/dto/response/CardSearchResponse.java | 19 -- .../card/dto/response/CreateCardResponse.java | 19 ++ .../card/dto/response/DeleteCardResponse.java | 19 ++ .../card/dto/response/RandomCardResponse.java | 21 ++ .../trendithon/domain/card/entity/Card.java | 17 +- .../domain/card/entity/UserCard.java | 55 ++++ .../card/repository/CardRepository.java | 6 +- .../domain/card/service/CardService.java | 252 ++++++++---------- .../domain/tag/Service/TagService.java | 89 ------- .../trendithon/domain/tag/dto/TagDto.java | 16 -- .../trendithon/domain/tag/entity/Tag.java | 40 --- .../domain/tag/repository/TagRepository.java | 13 - .../trendithon/domain/user/entity/User.java | 12 + 20 files changed, 298 insertions(+), 426 deletions(-) delete mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java create mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/request/CreateCardRequest.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java create mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/response/CreateCardResponse.java create mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/response/DeleteCardResponse.java create mode 100644 src/main/java/com/likelion/trendithon/domain/card/dto/response/RandomCardResponse.java create mode 100644 src/main/java/com/likelion/trendithon/domain/card/entity/UserCard.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java delete mode 100644 src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java diff --git a/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java b/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java index 57c9410..8cc5258 100644 --- a/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java +++ b/src/main/java/com/likelion/trendithon/domain/card/controller/CardController.java @@ -1,19 +1,21 @@ package com.likelion.trendithon.domain.card.controller; +import jakarta.servlet.http.HttpServletRequest; + import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.likelion.trendithon.domain.card.dto.request.CardRequest; +import com.likelion.trendithon.domain.card.dto.request.CreateCardRequest; import com.likelion.trendithon.domain.card.service.CardService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; @@ -27,20 +29,28 @@ public class CardController { @Operation(summary = "[ 토큰 O | 카드 등록 ]", description = "새로운 카드 등록") @PostMapping("/create") - public ResponseEntity createCard(@RequestBody CardRequest card) { - return cardService.createCard(card); + public ResponseEntity createCard( + @Parameter(description = "카드에 포함되는 내용") @RequestBody CreateCardRequest createCardRequest, + HttpServletRequest httpServletRequest) { + return cardService.createCard(createCardRequest, httpServletRequest); } - @Operation(summary = "[ 토큰 O | 카드 조회 ]", description = "ID를 통해 특정 카드 조회") + @Operation(summary = "[ 토큰 X | 카드 단일 조회 ]", description = "카드 ID를 통해 특정 카드 조회") @GetMapping("/{id}") - public ResponseEntity getCardById(@PathVariable Long id) { + public ResponseEntity getCardById(@Parameter(description = "카드 ID") @PathVariable Long id) { return cardService.getCardById(id); } - @Operation(summary = "[ 토큰 O | 카드 목록 조회 ]", description = "사용자 ID를 통해 특정 카드 조회") - @GetMapping("/all/{userId}") - public ResponseEntity getAllCards(@PathVariable String userId) { - return cardService.getAllCards(userId); + @Operation(summary = "[ 토큰 X | 랜덤 카드 3장 조회 ]", description = "경험 등록 후 랜덤 카드 3장의 ID 조회") + @GetMapping("/random") + public ResponseEntity getRandomCards() { + return cardService.getRandomCards(); + } + + @Operation(summary = "[ 토큰 X | 전체 카드 조회 | 테스트용 ]", description = "전체 카드 조회") + @GetMapping() + public ResponseEntity getAllCard() { + return cardService.getAllCards(); } @Operation(summary = "[ 토큰 O | 카드 삭제 ]", description = "ID를 통해 특정 카드 삭제") @@ -48,10 +58,4 @@ public ResponseEntity getAllCards(@PathVariable String userId) { public ResponseEntity deleteCard(@PathVariable Long id) { return cardService.deleteCard(id); } - - @Operation(summary = "[ 토큰 O | 카드 수정 ]", description = "ID를 통해 특정 카드 수정") - @PutMapping("/update/{id}") - public ResponseEntity updateCard(@PathVariable Long id, @RequestBody CardRequest updatedCard) { - return cardService.updateCard(id, updatedCard); - } } diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java b/src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java deleted file mode 100644 index 2322867..0000000 --- a/src/main/java/com/likelion/trendithon/domain/card/dto/request/CardRequest.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.likelion.trendithon.domain.card.dto.request; - -import java.util.List; - -import com.likelion.trendithon.domain.tag.dto.TagDto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; - -@Getter -public class CardRequest { - - @Schema(description = "카드 제목", example = "멋쟁이사자 되기") - private String title; - - @Schema(description = "카드 내용", example = "나는 오늘 멋쟁이 사자가 되다.") - private String content; - - @Schema(description = "이모지 Url") - private String imgUrl; - - @Schema(description = "태그 목록", example = "[{\"tagTitle\": \"팁\", \"tagContent\": \"열심히 하기\"}]") - private List tagItems; -} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/request/CreateCardRequest.java b/src/main/java/com/likelion/trendithon/domain/card/dto/request/CreateCardRequest.java new file mode 100644 index 0000000..d978c33 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/request/CreateCardRequest.java @@ -0,0 +1,20 @@ +package com.likelion.trendithon.domain.card.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +public class CreateCardRequest { + + @Schema(description = "카드 아이콘", example = "모바일 키보드 이모지") + private String emoji; + + @Schema(description = "카드 제목", example = "멋쟁이사자 되기") + private String title; + + @Schema(description = "카드 내용", example = "나는 오늘 멋쟁이 사자가 되었다.") + private String content; + + @Schema(description = "카드 표지", example = "#000000") + private String cover; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java deleted file mode 100644 index d73b05d..0000000 --- a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardDto.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.likelion.trendithon.domain.card.dto.response; - -import java.util.List; - -import com.likelion.trendithon.domain.tag.dto.TagDto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class CardDto { - - @Schema(description = "카드 제목", example = "멋쟁이사자 되기") - private String title; - - @Schema(description = "카드 내용", example = "나는 오늘 멋쟁이 사자가 되다.") - private String content; - - @Schema(description = "이모지 Url") - private String imgUrl; - - @Schema(description = "사용자 Id", example = "likelion") - private String userId; - - @Schema(description = "태그 목록", example = "[{\"tagTitle\": \"팁\", \"tagContent\": \"열심히 하기\"}]") - private List tagItems; -} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java index fb12184..8048dab 100644 --- a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListResponse.java @@ -2,6 +2,8 @@ import java.util.List; +import com.likelion.trendithon.domain.card.entity.Card; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; @@ -16,6 +18,6 @@ public class CardListResponse { @Schema(description = "응답 메세지", example = "성공적으로 카드가 생성되었습니다.") private String message; - @Schema(description = "보유한 카드 리스트") - private List cardList; + @Schema(description = "카드 리스트") + private List cardList; } diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java deleted file mode 100644 index 17b53e2..0000000 --- a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardListSummaryDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.likelion.trendithon.domain.card.dto.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@Builder -@NoArgsConstructor -public class CardListSummaryDto { - - @Schema(description = "카드 Id", example = "1234") - private Long cardId; - - @Schema(description = "카드 제목", example = "멋쟁이사자 되기") - private String title; -} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java index 883cbe8..2164e1f 100644 --- a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardResponse.java @@ -1,5 +1,7 @@ package com.likelion.trendithon.domain.card.dto.response; +import com.likelion.trendithon.domain.card.entity.Card; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; @@ -8,9 +10,12 @@ @Getter public class CardResponse { - @Schema(description = "카드 생성 결과", example = "true") + @Schema(description = "카드 조회 결과", example = "true") private boolean success; - @Schema(description = "응답 메세지", example = "카드가 생성 성공하였습니다.") + @Schema(description = "응답 메세지", example = "카드 조회에 성공하였습니다.") private String message; + + @Schema(description = "카드") + private Card card; } diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java deleted file mode 100644 index 4afecb3..0000000 --- a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CardSearchResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.likelion.trendithon.domain.card.dto.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -@Builder -@Getter -public class CardSearchResponse { - - @Schema(description = "카드 조회 결과", example = "true") - private boolean success; - - @Schema(description = "응답 메세지", example = "카드가 조회 성공하였습니다.") - private String message; - - @Schema(description = "카드") - private CardDto card; -} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/CreateCardResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CreateCardResponse.java new file mode 100644 index 0000000..75878b1 --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/CreateCardResponse.java @@ -0,0 +1,19 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class CreateCardResponse { + + @Schema(description = "카드 생성 결과", example = "true") + private boolean success; + + @Schema(description = "응답 메세지", example = "카드 생성에 성공하였습니다.") + private String message; + + @Schema(description = "생성된 카드 ID", example = "1") + private Long cardId; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/DeleteCardResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/DeleteCardResponse.java new file mode 100644 index 0000000..7496c9a --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/DeleteCardResponse.java @@ -0,0 +1,19 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class DeleteCardResponse { + + @Schema(description = "카드 삭제 결과", example = "true") + private boolean success; + + @Schema(description = "응답 메세지", example = "카드 삭제에 성공하였습니다.") + private String message; + + @Schema(description = "삭제된 카드 ID", example = "1") + private Long cardId; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/dto/response/RandomCardResponse.java b/src/main/java/com/likelion/trendithon/domain/card/dto/response/RandomCardResponse.java new file mode 100644 index 0000000..8e1099a --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/dto/response/RandomCardResponse.java @@ -0,0 +1,21 @@ +package com.likelion.trendithon.domain.card.dto.response; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class RandomCardResponse { + + @Schema(description = "랜덤 카드 3장 조회 결과", example = "true") + private boolean success; + + @Schema(description = "응답 메세지", example = "랜덤 카드 3장 조회에 성공하였습니다.") + private String message; + + @Schema(description = "랜덤 카드 3장 ID 리스트", example = "[1, 2, 3]") + private List cardIds; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java b/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java index 7f8258d..61a5105 100644 --- a/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java +++ b/src/main/java/com/likelion/trendithon/domain/card/entity/Card.java @@ -10,8 +10,6 @@ import jakarta.persistence.Id; import jakarta.persistence.OneToMany; -import com.likelion.trendithon.domain.tag.entity.Tag; - import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -30,18 +28,21 @@ public class Card { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long cardId; + @Column(name = "created_by") + private String loginId; + + @Column(name = "emoji") + private String emoji; + @Column(name = "title", nullable = false) private String title; @Column(name = "content", nullable = false) private String content; - @Column(name = "imgUrl") - private String imgUrl; - - @Column(name = "user_id") - private String userId; + @Column(name = "cover", nullable = false) + private String cover; @OneToMany(mappedBy = "card", cascade = CascadeType.ALL, orphanRemoval = true) - private List TagItems = new ArrayList<>(); + private List userCardList = new ArrayList<>(); } diff --git a/src/main/java/com/likelion/trendithon/domain/card/entity/UserCard.java b/src/main/java/com/likelion/trendithon/domain/card/entity/UserCard.java new file mode 100644 index 0000000..7b61edf --- /dev/null +++ b/src/main/java/com/likelion/trendithon/domain/card/entity/UserCard.java @@ -0,0 +1,55 @@ +package com.likelion.trendithon.domain.card.entity; + +import java.time.LocalDate; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +import com.likelion.trendithon.domain.user.entity.User; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder +public class UserCard { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long userCardId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "login_id", nullable = false) + @OnDelete(action = OnDeleteAction.CASCADE) + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "card_id", nullable = false) + @OnDelete(action = OnDeleteAction.CASCADE) + private Card card; + + @Column(name = "cover", nullable = false) + private String cover; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; +} diff --git a/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java b/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java index 28ac040..2e0cc3b 100644 --- a/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java +++ b/src/main/java/com/likelion/trendithon/domain/card/repository/CardRepository.java @@ -1,11 +1,7 @@ package com.likelion.trendithon.domain.card.repository; -import java.util.List; - import org.springframework.data.jpa.repository.JpaRepository; import com.likelion.trendithon.domain.card.entity.Card; -public interface CardRepository extends JpaRepository { - List findByUserId(String id); -} +public interface CardRepository extends JpaRepository {} diff --git a/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java b/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java index c099e02..3363a1e 100644 --- a/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java +++ b/src/main/java/com/likelion/trendithon/domain/card/service/CardService.java @@ -1,23 +1,27 @@ package com.likelion.trendithon.domain.card.service; -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; -import java.util.Optional; +import java.util.Random; +import java.util.Set; + +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.likelion.trendithon.domain.card.dto.request.CardRequest; -import com.likelion.trendithon.domain.card.dto.response.CardDto; +import com.likelion.trendithon.domain.card.dto.request.CreateCardRequest; import com.likelion.trendithon.domain.card.dto.response.CardListResponse; -import com.likelion.trendithon.domain.card.dto.response.CardListSummaryDto; import com.likelion.trendithon.domain.card.dto.response.CardResponse; -import com.likelion.trendithon.domain.card.dto.response.CardSearchResponse; +import com.likelion.trendithon.domain.card.dto.response.CreateCardResponse; +import com.likelion.trendithon.domain.card.dto.response.DeleteCardResponse; +import com.likelion.trendithon.domain.card.dto.response.RandomCardResponse; import com.likelion.trendithon.domain.card.entity.Card; import com.likelion.trendithon.domain.card.repository.CardRepository; -import com.likelion.trendithon.domain.tag.Service.TagService; -import com.likelion.trendithon.domain.tag.dto.TagDto; +import com.likelion.trendithon.domain.user.entity.User; +import com.likelion.trendithon.domain.user.repository.UserRepository; +import com.likelion.trendithon.global.auth.JwtUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -28,182 +32,148 @@ public class CardService { private CardRepository cardRepository; - private TagService tagService; + private UserRepository userRepository; + private JwtUtil jwtUtil; - // 카드 생성 - tag도 저장함 + // 카드 생성 @Transactional - public ResponseEntity createCard(CardRequest card) { + public ResponseEntity createCard( + CreateCardRequest createCardRequest, HttpServletRequest httpServletRequest) { + try { - List tags = card.getTagItems(); - Card newCard = + String loginId = + jwtUtil.extractLoginId(httpServletRequest.getHeader("Authorization").substring(7)); + User user = + userRepository + .findByLoginId(loginId) + .orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다.")); + + Card card = Card.builder() - .title(card.getTitle()) - .content(card.getContent()) - .imgUrl(card.getImgUrl()) + .loginId(user.getLoginId()) + .emoji(createCardRequest.getEmoji()) + .title(createCardRequest.getTitle()) + .content(createCardRequest.getContent()) + .cover(createCardRequest.getCover()) .build(); - cardRepository.save(newCard); - tagService.saveTag(tags, newCard); + cardRepository.save(card); + + user.setState(false); + userRepository.save(user); + + log.info( + "[POST /api/cards/create] 카드 생성 성공 - 생성한 사용자 ID: {}, 카드 ID: {}", + user.getLoginId(), + card.getCardId()); return ResponseEntity.ok( - CardResponse.builder().success(true).message("카드가 생성 성공하였습니다.").build()); + CreateCardResponse.builder() + .success(true) + .message("카드 생성에 성공하였습니다.") + .cardId(card.getCardId()) + .build()); } catch (Exception e) { + log.error("[POST /api/cards/create] 카드 생성 실패 - 에러: {}", e.getMessage()); return ResponseEntity.ok( - CardResponse.builder().success(false).message("카드 생성 실패하였습니다.").build()); + CreateCardResponse.builder().success(false).message("카드 생성에 실패하였습니다.").build()); } } - // 카드 한장 조회 + // 랜덤 카드 세 장 조회 @Transactional - public ResponseEntity getCardById(Long id) { + public ResponseEntity getRandomCards() { try { - Optional optionalCard = cardRepository.findById(id); - Card card; - - if (optionalCard.isPresent()) { - card = optionalCard.get(); - - List tags = - card.getTagItems().stream() - .map( - tag -> - TagDto.builder() - .tagTitle(tag.getTagTitle()) - .tagContent(tag.getTagContent()) - .build()) - .toList(); + List cardList = cardRepository.findAll(); + Set cardIds = new HashSet<>(); + if (cardList.size() < 3) { return ResponseEntity.ok( - CardSearchResponse.builder() - .success(true) - .message("카드 조회 성공하였습니다.") - .card( - CardDto.builder() - .title(card.getTitle()) - .content(card.getContent()) - .imgUrl(card.getImgUrl()) - .tagItems(tags) - .build()) - .build()); - } else - return ResponseEntity.ok( - CardSearchResponse.builder().success(false).message("카드가 존재하지 않습니다.").build()); + RandomCardResponse.builder().success(false).message("전체 카드 개수가 3개 미만입니다.").build()); + } else { + long seed = System.currentTimeMillis(); // 현재 시간 + Random random = new Random(seed); // seed 추가 + + while (cardIds.size() < 3) { + cardIds.add(random.nextLong(cardList.size())); + } + } + log.info("[GET /api/cards/random] 랜덤 카드 3장 조회 성공 - 조회한 카드 ID 리스트: {}", cardIds); + return ResponseEntity.ok( + RandomCardResponse.builder() + .success(true) + .message("랜덤 카드 3장 조회에 성공하였습니다.") + .cardIds(cardIds.stream().toList()) + .build()); } catch (Exception e) { + log.error("[GET /api/cards/random] 랜덤 카드 3장 조회 실패 - 에러: {}", e.getMessage()); return ResponseEntity.ok( - CardSearchResponse.builder().success(false).message("카드 조회 중 오류가 발생하였습니다.").build()); + RandomCardResponse.builder() + .success(false) + .message("랜덤 카드 3장 조회 중 오류가 발생하였습니다.") + .build()); } } - // 사용자 아이디로 모든 카드 목록 조회 + // 카드 한 장 조회 @Transactional - public ResponseEntity getAllCards(String userId) { - try { - - List cardList = cardRepository.findByUserId(userId); - List cardDtos = new ArrayList<>(); - - for (Card card : cardList) { - - // 제목이랑 카드 아이디만 추출 - cardDtos.add( - CardListSummaryDto.builder().cardId(card.getCardId()).title(card.getTitle()).build()); - } - - // 카드가 존재하는지 안하는지 검사 - if (!cardDtos.isEmpty()) - return ResponseEntity.ok( - CardListResponse.builder() - .success(true) - .message("전체 카드가 조회 되었습니다.") - .cardList(cardDtos) - .build()); - else - return ResponseEntity.ok( - CardListResponse.builder() - .success(false) - .message("카드가 존재하지 않습니다.") - .cardList(cardDtos) - .build()); + public ResponseEntity getCardById(Long id) { + try { + Card card = + cardRepository + .findById(id) + .orElseThrow(() -> new IllegalArgumentException("카드를 찾을 수 없습니다.")); + log.info("[GET /api/cards/{}] 특정 카드 조회 성공 - 조회한 카드 ID: {}", id, id); + return ResponseEntity.ok( + CardResponse.builder().success(true).message("카드 조회에 성공하였습니다.").card(card).build()); + } catch (IllegalArgumentException e) { + log.error("[GET /api/cards/{}] 특정 카드 조회 실패", id); + return ResponseEntity.ok( + CardResponse.builder().success(false).message(e.getMessage()).build()); } catch (Exception e) { + log.error("[GET /api/cards/{}] 특정 카드 조회 실패 - 에러: {}", id, e.getMessage()); return ResponseEntity.ok( - CardListResponse.builder() - .success(false) - .message("사용자의 카드 목록을 조회 중 에러가 발생했습니다.") - .build()); + CardResponse.builder().success(false).message("카드 조회 중 오류가 발생하였습니다.").build()); } } - // 카드 삭제 + // 모든 카드 조회 @Transactional - public ResponseEntity deleteCard(Long id) { - + public ResponseEntity getAllCards() { try { - Optional optionalCard = cardRepository.findById(id); - if (optionalCard.isPresent()) { + List cardList = cardRepository.findAll(); - Card card = optionalCard.get(); - cardRepository.delete(card); - return ResponseEntity.ok( - CardResponse.builder().success(true).message("카드 삭제 성공하였습니다.").build()); - - } else - return ResponseEntity.ok( - CardResponse.builder().success(false).message("해당 카드가 존재하지 않습니다.").build()); + log.info("[GET /api/cards] 카드 전체 조회 성공 - 조회한 카드 개수: {}", cardList.size()); + return ResponseEntity.ok( + CardListResponse.builder() + .success(true) + .message("카드 전체 조회에 성공하였습니다.") + .cardList(cardList) + .build()); } catch (Exception e) { + log.error("[GET /api/cards] 카드 전체 조회 실패 - 에러: {}", e.getMessage()); return ResponseEntity.ok( - CardResponse.builder().success(false).message("카드를 삭제 중 에러가 발생했습니다.").build()); + CardListResponse.builder().success(false).message("카드 전체 조회 중 오류가 발생하였습니다.").build()); } } - // 카드 수정- 수정 시 기존 태그 리스트와 비교하여 태그 삭제 수정 추가 + // 카드 삭제 @Transactional - public ResponseEntity updateCard(Long id, CardRequest updatedCard) { - + public ResponseEntity deleteCard(Long id) { try { - - Optional optionalCard = cardRepository.findById(id); - Card newCard; - - if (optionalCard.isPresent()) { - newCard = optionalCard.get(); - tagService.updateTags(newCard, updatedCard.getTagItems()); - - newCard.setContent(updatedCard.getContent()); - newCard.setTitle(updatedCard.getTitle()); - newCard.setImgUrl(updatedCard.getImgUrl()); - - List tags = - newCard.getTagItems().stream() - .map( - tag -> - TagDto.builder() - .tagTitle(tag.getTagTitle()) - .tagContent(tag.getTagContent()) - .build()) - .toList(); - - return ResponseEntity.ok( - CardSearchResponse.builder() - .success(true) - .message("카드 수정 성공하였습니다.") - .card( - CardDto.builder() - .title(newCard.getTitle()) - .content(newCard.getContent()) - .imgUrl(newCard.getImgUrl()) - .tagItems(tags) - .build()) - .build()); - } else - return ResponseEntity.ok( - CardSearchResponse.builder().success(false).message("해당 카드가 존재하지 않습니다.").build()); - + Card card = + cardRepository + .findById(id) + .orElseThrow(() -> new IllegalArgumentException("카드를 찾을 수 없습니다.")); + log.info("[DELETE /api/cards/{}] 특정 카드 삭제 성공 - 삭제한 카드 ID: {}", id, id); + return ResponseEntity.ok( + DeleteCardResponse.builder().success(true).message("카드 삭제에 성공하였습니다.").cardId(id).build()); } catch (Exception e) { return ResponseEntity.ok( - CardSearchResponse.builder().success(false).message("카드 수정 중 에러가 발생했습니다.").build()); + DeleteCardResponse.builder().success(false).message("카드 삭제 중 오류가 발생했습니다.").build()); } } } diff --git a/src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java b/src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java deleted file mode 100644 index 1fc4ea3..0000000 --- a/src/main/java/com/likelion/trendithon/domain/tag/Service/TagService.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.likelion.trendithon.domain.tag.Service; - -import java.util.List; -import java.util.Objects; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import com.likelion.trendithon.domain.card.entity.Card; -import com.likelion.trendithon.domain.tag.dto.TagDto; -import com.likelion.trendithon.domain.tag.entity.Tag; -import com.likelion.trendithon.domain.tag.repository.TagRepository; - -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Service -@AllArgsConstructor -@Slf4j -public class TagService { - - private TagRepository tagRepository; - - public void saveTag(List tags, Card newCard) { - List newTags = - tags.stream() - .map( - tagDto -> - Tag.builder() - .tagTitle(tagDto.getTagTitle()) - .tagContent(tagDto.getTagContent()) - .card(newCard) - .build()) - .toList(); - tagRepository.saveAll(newTags); - } - - @Transactional - public List getTags(Card card) { - - return tagRepository.findByCard(card); - } - - @Transactional - public void updateTags(Card card, List newTags) { - - List tags = tagRepository.findByCard(card); - - // tags엔 존재하는데 newTags에 존재하지 않으면 삭제 같으면 업뎃 - for (Tag tag : tags) { - boolean found = false; - for (TagDto newTag : newTags) { - if (Objects.equals(tag.getTagTitle(), newTag.getTagTitle())) { - tag.setTagTitle(newTag.getTagTitle()); - tag.setTagContent(newTag.getTagContent()); - found = true; - } - } - - if (!found) { - tagRepository.delete(tag); - } - } - - // newTags엔 존재하는데 tags엔 존재하지 않으면 추가 - for (TagDto newTag : newTags) { - // 기존 [1,2,3,4] 업데이트 [2,3,6] - boolean found = false; - - for (Tag tag : tags) { - if (Objects.equals(tag.getTagTitle(), newTag.getTagTitle())) { - found = true; - break; - } - } - - if (!found) { - - Tag tmp = - Tag.builder() - .tagTitle(newTag.getTagTitle()) - .tagContent(newTag.getTagContent()) - .card(card) - .build(); - tagRepository.save(tmp); - } - } - } -} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java b/src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java deleted file mode 100644 index ce69705..0000000 --- a/src/main/java/com/likelion/trendithon/domain/tag/dto/TagDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.likelion.trendithon.domain.tag.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Getter; - -@Builder -@Getter -public class TagDto { - - @Schema(description = "태그 제목", example = "팁") - private String tagTitle; - - @Schema(description = "태그 내용", example = "열심히 공부하기") - private String tagContent; -} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java b/src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java deleted file mode 100644 index c2d634d..0000000 --- a/src/main/java/com/likelion/trendithon/domain/tag/entity/Tag.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.likelion.trendithon.domain.tag.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; - -import com.likelion.trendithon.domain.card.entity.Card; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Entity -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class Tag { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long tagId; - - @Column(name = "title", nullable = false) - private String tagTitle; - - @Column(name = "content", nullable = false) - private String tagContent; - - @ManyToOne - @JoinColumn(name = "card_id", nullable = false) - private Card card; -} diff --git a/src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java b/src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java deleted file mode 100644 index 3a06b72..0000000 --- a/src/main/java/com/likelion/trendithon/domain/tag/repository/TagRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.likelion.trendithon.domain.tag.repository; - -import java.util.List; - -import org.springframework.data.jpa.repository.JpaRepository; - -import com.likelion.trendithon.domain.card.entity.Card; -import com.likelion.trendithon.domain.tag.entity.Tag; - -public interface TagRepository extends JpaRepository { - - List findByCard(Card card); -} diff --git a/src/main/java/com/likelion/trendithon/domain/user/entity/User.java b/src/main/java/com/likelion/trendithon/domain/user/entity/User.java index cf957fe..18b295b 100644 --- a/src/main/java/com/likelion/trendithon/domain/user/entity/User.java +++ b/src/main/java/com/likelion/trendithon/domain/user/entity/User.java @@ -1,10 +1,16 @@ package com.likelion.trendithon.domain.user.entity; +import java.util.ArrayList; +import java.util.List; + +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import com.likelion.trendithon.domain.card.entity.UserCard; import com.likelion.trendithon.global.common.BaseTimeEntity; import lombok.AllArgsConstructor; @@ -31,9 +37,15 @@ public class User extends BaseTimeEntity { @Column(name = "nickname", nullable = false, unique = true) private String nickname; + @Column(name = "state", nullable = false) + private Boolean state; + @Column(name = "refresh_token") private String refreshToken; @Column(name = "role") private String userRole; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List userCardList = new ArrayList<>(); }