From 808439f68ebb3f59796943eec2d4a179376f3ed5 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jul 2023 15:54:01 +0900 Subject: [PATCH 01/58] =?UTF-8?q?=F0=9F=A5=95Feat:=20[=EA=B0=80=EA=B3=84?= =?UTF-8?q?=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.1.1/checksums/checksums.lock | Bin 17 -> 17 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .idea/misc.xml | 3 + build.gradle | 7 +- out/production/resources/application.yml | 6 +- .../controller/DongnaeBoardController.java | 45 ++++++++++ .../domain/dongnae/dto/DongnaeBoardDto.java | 66 ++++++++++++++ .../domain/dongnae/entity/DongnaeBoard.java | 8 ++ .../respository/DongnaeBoardRepository.java | 21 +++++ .../respository/DongnaeCommentRepository.java | 10 +++ .../respository/DongnaeImgRepository.java | 15 ++++ .../DongnaeSympathyRepository.java | 8 ++ .../dongnae/service/DongnaeBoardService.java | 12 +++ .../service/DongnaeBoardServiceImpl.java | 82 ++++++++++++++++++ .../domain/type/DongnaeBoardCategory.java | 9 ++ .../domain/user/entity/User.java | 2 +- src/main/resources/application.yml | 6 +- 19 files changed, 292 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock index c860a62cf855d590da5714bc773649c03c4fcac6..bed4d053db82310e6ba3f2b41d02baec4b7ac0c8 100644 GIT binary patch literal 17 UcmZS1@)rBFze>lD0RpB104o0j>;M1& literal 17 ScmZS1@)rBFze>lD0SW*rY6DjQ diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index 27b0e26aaabc2dff79de4b28c5b93fb3779276ea..1edfd7e836b0b90686a6140be7d086d1f9481ff5 100644 GIT binary patch literal 17 UcmZR6(Xu4+XJ*)A1_%%a06&%m8vp + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 689a83e..b6ac063 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ plugins { id 'io.spring.dependency-management' version '1.0.15.RELEASE' } + group = 'com.umc' version = '0.0.1-SNAPSHOT' @@ -31,11 +32,15 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + } tasks.named('test') { useJUnitPlatform() } + + jar { enabled = false -} +} \ No newline at end of file diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml index 7878137..196b4bb 100644 --- a/out/production/resources/application.yml +++ b/out/production/resources/application.yml @@ -13,8 +13,8 @@ spring: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: df1234 + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create \ No newline at end of file + hibernate.ddl-auto: update \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java new file mode 100644 index 0000000..0383347 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -0,0 +1,45 @@ +package com.umc.DongnaeFriend.domain.dongnae.controller; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +/* + * [ 가계부 공유 ] + * */ + +@RestController +@RequestMapping("/account-books/sharing") +public class DongnaeBoardController { + + @Autowired + DongnaeBoardRepository dongnaeBoardRepository; + + @Autowired + DongnaeBoardService dongnaeBoardService; + + /* + * 게시글 검색 (전체) + * */ + @GetMapping("/search") + public ResponseEntity getBoards(@RequestParam("keyword") String keyword, + @RequestParam("category") int category, + @RequestParam("sortBy") int sort) { + return ResponseEntity.ok(dongnaeBoardService.getBoard(keyword, category)); + } + + + @PostMapping("") + public ResponseEntity postBoard(@RequestBody DongnaeBoardDto.Request req, + @AuthenticationPrincipal Authentication auth) { + dongnaeBoardRepository.save(req.toEntity()); + return null; + } + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java new file mode 100644 index 0000000..2e70308 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -0,0 +1,66 @@ +package com.umc.DongnaeFriend.domain.dongnae.dto; + + + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import lombok.*; + +import java.util.List; + +import static com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory.*; + + +public class DongnaeBoardDto { + + @Getter @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class Request { + private int category; + private String title; + private String content; + private List images; + + public DongnaeBoard toEntity() { + return DongnaeBoard.builder() + .category(category == 0 ? RESTAURANT: + category == 1 ? FACILITY: + category == 2 ? SHARE_INFORMATION: + category == 3 ? TOGETHER: + category == 4 ? COMMUNICATION: + category == 5 ? ETC : null) + .title(title) + .content(content) + .build(); + } + + } + + + @Getter @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ListResponse { + private String town; + + private int category; + + private String title; + + private String content; + + private String imageUrl; + + private String createdAt; + + private int view; + + private int commentCount; + + private int likes; + } + + + +} + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java index fe9b18b..401fda8 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java @@ -6,11 +6,13 @@ import static lombok.AccessLevel.PRIVATE; import static lombok.AccessLevel.PROTECTED; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.umc.DongnaeFriend.domain.BaseTimeEntity; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import javax.persistence.*; import lombok.*; +import org.hibernate.annotations.ColumnDefault; @Getter @Builder @@ -42,6 +44,12 @@ public class DongnaeBoard extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String content; + @Column(name = "view", nullable = false) + @ColumnDefault("0") + private Integer view = 0; + private String place; // 사용자 장소 공유시 장소 이름(ex. "00키친") private String placeLocation; // 장소의 정확한 위치 + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java new file mode 100644 index 0000000..9a78681 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -0,0 +1,21 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Repository +public interface DongnaeBoardRepository extends JpaRepository { + + @Query(value = "select * from dongnae_board where title like %?1% or content like %?1% and category = ?2 ;", nativeQuery = true) + public List findByKeyword(String keyword, String category); + + @Query(nativeQuery = true, value = "SELECT * FROM dongnae_board WHERE title like %:keyword% or content like %:keyword% ") + public List searchBoard(@Param("keyword") String keyword); + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java new file mode 100644 index 0000000..0e988b5 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java @@ -0,0 +1,10 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DongnaeCommentRepository extends JpaRepository { + public int countAllByDongnaeBoardId(Long dongnae_board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java new file mode 100644 index 0000000..0a40a02 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java @@ -0,0 +1,15 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface DongnaeImgRepository extends JpaRepository { + + @Query(value = "SELECT * FROM dongnae_img WHERE dongnae_board_id = ?1 ORDER BY created_at ASC LIMIT 1", nativeQuery = true) + Optional findFirst(long dongnae_board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java new file mode 100644 index 0000000..44e5944 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java @@ -0,0 +1,8 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeSympathy; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DongnaeSympathyRepository extends JpaRepository { + public int countAllByDongnaeBoardId(Long dongnae_board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java new file mode 100644 index 0000000..9b1dce1 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.domain.dongnae.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; + +import java.util.List; + +public interface DongnaeBoardService { + + public List getBoard(String keyword, int category); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java new file mode 100644 index 0000000..c466010 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -0,0 +1,82 @@ +package com.umc.DongnaeFriend.domain.dongnae.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeImgRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeSympathyRepository; +import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class DongnaeBoardServiceImpl implements DongnaeBoardService { + + @Autowired + private DongnaeBoardRepository dongnaeBoardRepository; + + @Autowired + private DongnaeImgRepository dongnaeImgRepository; + + @Autowired + private DongnaeCommentRepository dongnaeCommentRepository; + + @Autowired + private DongnaeSympathyRepository dongnaeSympathyRepository; + + +// @Transactional(propagation = Propagation.REQUIRED) + public List getBoard(String keyword, int category) { + String categoryName = DongnaeBoardCategory.valueOf(category).name(); + List dongnaeBoardList = dongnaeBoardRepository.findByKeyword(keyword, categoryName); + + return dongnaeBoardList.stream() + .map(origin -> DongnaeBoardDto.ListResponse.builder() + .town(origin.getPlace()) + .category(origin.getCategory().getValue()) + .title(origin.getTitle()) + .content(origin.getContent()) + .imageUrl( + dongnaeImgRepository.findFirst(origin.getId()).map(DongnaeImg::getImageUrl).orElse("") + ) + .createdAt( + getTime(origin.getCreatedAt()) + ) + .view(origin.getView()) + .commentCount( + dongnaeCommentRepository.countAllByDongnaeBoardId(origin.getId()) + ) + .likes( + dongnaeSympathyRepository.countAllByDongnaeBoardId(origin.getId()) + ) + .build()) + .collect(Collectors.toList()); + } + + + private String getTime(LocalDateTime time) { + LocalDateTime now = LocalDateTime.now(); // 현재 시간 + Duration duration = Duration.between(time, now); + + long days = duration.toDays(); + long hours = duration.toHours() % 24; + long minutes = duration.toMinutes() % 60; + long seconds = duration.getSeconds() % 60; + + return minutes + "분 전"; + } +} + + + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java index 23ce7ee..b22db9f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java @@ -15,4 +15,13 @@ public enum DongnaeBoardCategory { private final Integer value; private final String category; + + public static DongnaeBoardCategory valueOf(Integer value) { + for (DongnaeBoardCategory category : DongnaeBoardCategory.values()) { + if (category.getValue().equals(value)) { + return category; + } + } + throw new IllegalArgumentException("Invalid Category: " + value); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java index 1d96f63..665c1db 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java @@ -20,7 +20,7 @@ @AllArgsConstructor(access = PRIVATE) @Entity @Table(name = "users") -public class User extends BaseTimeEntity { +public class User extends BaseTimeEntity { @Id @GeneratedValue(strategy = IDENTITY) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7878137..196b4bb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,8 +13,8 @@ spring: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: df1234 + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create \ No newline at end of file + hibernate.ddl-auto: update \ No newline at end of file From 11efef482ad66e1a51bf1c3d7dbe53c57f9e0696 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jul 2023 16:03:15 +0900 Subject: [PATCH 02/58] =?UTF-8?q?=F0=9F=A5=95Feat:=20[=EA=B0=80=EA=B3=84?= =?UTF-8?q?=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/dongnae/service/DongnaeBoardServiceImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index c466010..8ea0dd2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -72,9 +72,12 @@ private String getTime(LocalDateTime time) { long days = duration.toDays(); long hours = duration.toHours() % 24; long minutes = duration.toMinutes() % 60; - long seconds = duration.getSeconds() % 60; - return minutes + "분 전"; + if (days > 1) return days + "일 전"; + else if (hours >= 1) { + return -hours + "시간 전"; + } else return -minutes + "분 전"; + } } From 3740ae46b4a52c751b1f4067dc0f1dffac33aa52 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jul 2023 16:05:27 +0900 Subject: [PATCH 03/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFix:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=20=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/dongnae/service/DongnaeBoardServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 8ea0dd2..18caf1c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -75,7 +75,7 @@ private String getTime(LocalDateTime time) { if (days > 1) return days + "일 전"; else if (hours >= 1) { - return -hours + "시간 전"; + return hours + "시간 전"; } else return -minutes + "분 전"; } From ea91f550dc02f14a09533b373fa711d056c42208 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jul 2023 17:10:53 +0900 Subject: [PATCH 04/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFix:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EC=A2=8B=EC=95=84?= =?UTF-8?q?=EC=9A=94=EC=88=9C=20=EC=BF=BC=EB=A6=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dongnae/controller/DongnaeBoardController.java | 2 +- .../domain/dongnae/entity/DongnaeBoard.java | 2 ++ .../dongnae/respository/DongnaeBoardRepository.java | 13 +++++++++---- .../domain/dongnae/service/DongnaeBoardService.java | 2 +- .../dongnae/service/DongnaeBoardServiceImpl.java | 12 ++++++++++-- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index 0383347..051d207 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -30,7 +30,7 @@ public class DongnaeBoardController { public ResponseEntity getBoards(@RequestParam("keyword") String keyword, @RequestParam("category") int category, @RequestParam("sortBy") int sort) { - return ResponseEntity.ok(dongnaeBoardService.getBoard(keyword, category)); + return ResponseEntity.ok(dongnaeBoardService.getBoard(keyword, category, sort)); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java index 401fda8..da83d40 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java @@ -48,8 +48,10 @@ public class DongnaeBoard extends BaseTimeEntity { @ColumnDefault("0") private Integer view = 0; + private String place; // 사용자 장소 공유시 장소 이름(ex. "00키친") private String placeLocation; // 장소의 정확한 위치 + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index 9a78681..a5031ab 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -12,10 +12,15 @@ @Repository public interface DongnaeBoardRepository extends JpaRepository { - @Query(value = "select * from dongnae_board where title like %?1% or content like %?1% and category = ?2 ;", nativeQuery = true) - public List findByKeyword(String keyword, String category); + @Query(value = "select * from dongnae_board where title like %?1% or content like %?1% and category = ?2 ORDER BY created_at DESC;", nativeQuery = true) + List findByKeywordOrderByCreatedAt(String keyword, String category); + + @Query(value = "SELECT dongnae_board.*, COUNT(dongnae_sympathy.dongnae_board_id) AS cnt FROM dongnae_board\n" + + "LEFT JOIN dongnae_sympathy ON dongnae_board.dongnae_board_id = dongnae_sympathy.dongnae_board_id\n" + + "WHERE (dongnae_board.title LIKE %?1% OR dongnae_board.content LIKE %?2%)\n" + + "AND dongnae_board.category = ?2 GROUP BY dongnae_board.dongnae_board_id ORDER BY cnt DESC ;", nativeQuery = true) + List findByKeywordOrderByLikes(String keyword, String category); + - @Query(nativeQuery = true, value = "SELECT * FROM dongnae_board WHERE title like %:keyword% or content like %:keyword% ") - public List searchBoard(@Param("keyword") String keyword); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 9b1dce1..ec12e51 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -8,5 +8,5 @@ public interface DongnaeBoardService { - public List getBoard(String keyword, int category); + public List getBoard(String keyword, int category, int sort); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 18caf1c..141fb4d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -16,6 +16,7 @@ import java.time.Duration; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -37,9 +38,16 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { // @Transactional(propagation = Propagation.REQUIRED) - public List getBoard(String keyword, int category) { + public List getBoard(String keyword, int category, int sort) { String categoryName = DongnaeBoardCategory.valueOf(category).name(); - List dongnaeBoardList = dongnaeBoardRepository.findByKeyword(keyword, categoryName); + + + List dongnaeBoardList = new ArrayList<>(); + if (sort == 0) { + dongnaeBoardList = dongnaeBoardRepository.findByKeywordOrderByCreatedAt(keyword, categoryName); + } else { + dongnaeBoardList = dongnaeBoardRepository.findByKeywordOrderByLikes(keyword, categoryName); + } return dongnaeBoardList.stream() .map(origin -> DongnaeBoardDto.ListResponse.builder() From 7db9cfb052d365e6063c2a3c49091f1590974651 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jul 2023 18:24:29 +0900 Subject: [PATCH 05/58] =?UTF-8?q?=F0=9F=A5=95Fieat=20:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EA=B2=80=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 25 +++++++------ .../respository/DongnaeBoardRepository.java | 8 ++++ .../dongnae/service/DongnaeBoardService.java | 6 +-- .../service/DongnaeBoardServiceImpl.java | 37 +++++++++++++++++-- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index 051d207..b4a6d0b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -1,12 +1,10 @@ package com.umc.DongnaeFriend.domain.dongnae.controller; -import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; +import lombok.Getter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; /* @@ -24,21 +22,26 @@ public class DongnaeBoardController { DongnaeBoardService dongnaeBoardService; /* - * 게시글 검색 (전체) - * */ + * [가계부 공유] 게시글 검색 + * @param keyword + * @param category + * @param sort + */ @GetMapping("/search") public ResponseEntity getBoards(@RequestParam("keyword") String keyword, @RequestParam("category") int category, @RequestParam("sortBy") int sort) { - return ResponseEntity.ok(dongnaeBoardService.getBoard(keyword, category, sort)); + return ResponseEntity.ok(dongnaeBoardService.searchByKeyword(keyword, category, sort)); } - @PostMapping("") - public ResponseEntity postBoard(@RequestBody DongnaeBoardDto.Request req, - @AuthenticationPrincipal Authentication auth) { - dongnaeBoardRepository.save(req.toEntity()); - return null; + /* + * [가계부 공유] 게시글 목록 조회 + * @param sort + */ + @GetMapping("") + public ResponseEntity postBoard(@RequestParam("sortBy") int sort) { + return ResponseEntity.ok(dongnaeBoardService.searchAll(sort)); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index a5031ab..d4e7b12 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -21,6 +21,14 @@ public interface DongnaeBoardRepository extends JpaRepository findByKeywordOrderByLikes(String keyword, String category); + @Query(value = "select * from dongnae_board ORDER BY created_at DESC;", nativeQuery = true) + List findAllOrderByCreatedAt(); + + @Query(value = "SELECT dongnae_board.*, COUNT(dongnae_sympathy.dongnae_board_id) AS cnt FROM dongnae_board\n" + + "LEFT JOIN dongnae_sympathy ON dongnae_board.dongnae_board_id = dongnae_sympathy.dongnae_board_id\n" + + "GROUP BY dongnae_board.dongnae_board_id ORDER BY cnt DESC ;", nativeQuery = true) + List findAllOrderByLikes(); + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index ec12e51..dde8c95 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -1,12 +1,12 @@ package com.umc.DongnaeFriend.domain.dongnae.service; import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; -import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import java.util.List; public interface DongnaeBoardService { - public List getBoard(String keyword, int category, int sort); + List searchByKeyword(String keyword, int category, int sort); + + List searchAll(int sort); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 141fb4d..25982bf 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -16,6 +16,7 @@ import java.time.Duration; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -37,18 +38,40 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { private DongnaeSympathyRepository dongnaeSympathyRepository; + + // @Transactional(propagation = Propagation.REQUIRED) - public List getBoard(String keyword, int category, int sort) { + public List searchByKeyword(String keyword, int category, int sort) { String categoryName = DongnaeBoardCategory.valueOf(category).name(); - List dongnaeBoardList = new ArrayList<>(); + List dongnaeBoardList; if (sort == 0) { dongnaeBoardList = dongnaeBoardRepository.findByKeywordOrderByCreatedAt(keyword, categoryName); } else { dongnaeBoardList = dongnaeBoardRepository.findByKeywordOrderByLikes(keyword, categoryName); } + return getListResponses(dongnaeBoardList); + } + + /* + * [가계부 공유] 게시글 목록 조회 + * @param sort + */ + public List searchAll(int sort) { + + List dongnaeBoardList; + if (sort == 0) { + dongnaeBoardList = dongnaeBoardRepository.findAllOrderByCreatedAt(); + } else { + dongnaeBoardList = dongnaeBoardRepository.findAllOrderByLikes(); + } + + return getListResponses(dongnaeBoardList); + } + + private List getListResponses(List dongnaeBoardList) { return dongnaeBoardList.stream() .map(origin -> DongnaeBoardDto.ListResponse.builder() .town(origin.getPlace()) @@ -75,18 +98,24 @@ public List getBoard(String keyword, int category, private String getTime(LocalDateTime time) { LocalDateTime now = LocalDateTime.now(); // 현재 시간 - Duration duration = Duration.between(time, now); + Duration duration = Duration.between(now, time); + log.info(now.toString()); + log.info(time.toString()); long days = duration.toDays(); + log.info(" days: "+ days); long hours = duration.toHours() % 24; + log.info(" hours: "+ hours); long minutes = duration.toMinutes() % 60; + log.info(" minutes: "+ minutes); if (days > 1) return days + "일 전"; else if (hours >= 1) { return hours + "시간 전"; - } else return -minutes + "분 전"; + } else return minutes + "분 전"; } + } From f2b174d7a3b97c7b55b7aa024dc2d3776974c02a Mon Sep 17 00:00:00 2001 From: soogoori Date: Thu, 20 Jul 2023 00:06:21 +0900 Subject: [PATCH 06/58] =?UTF-8?q?=F0=9F=92=B0Feat=20#21=20:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80]=20=EC=98=88=EC=82=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A9=94=EB=AA=A8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.1.1/checksums/checksums.lock | Bin 17 -> 17 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .idea/gradle.xml | 3 - .idea/misc.xml | 3 + build.gradle | 25 +++++++ out/production/resources/application.yml | 4 +- .../config/QuerydslConfiguration.java | 20 ++++++ .../controller/AccountBookController.java | 29 ++++++++ .../book/controller/MemoController.java | 43 ++++++++++++ .../account/book/dto/AccountBookDto.java | 59 ++++++++++++++++ .../domain/account/book/dto/MemoDto.java | 64 +++++++++++++++++ .../account/book/entity/AccountBook.java | 7 +- .../domain/account/book/entity/Memo.java | 3 - .../account/book/entity/Transaction.java | 2 +- .../accountBook/AccountBookRepository.java | 15 ++++ .../AccountBookRepositoryCustom.java | 5 ++ .../AccountBookRepositoryCustomImpl.java | 12 ++++ .../book/repository/memo/MemoRepository.java | 15 ++++ .../repository/memo/MemoRepositoryCustom.java | 6 ++ .../memo/MemoRepositoryCustomImpl.java | 30 ++++++++ .../book/service/AccountBookService.java | 40 +++++++++++ .../account/book/service/MemoService.java | 65 ++++++++++++++++++ src/main/resources/application.yml | 4 +- 25 files changed, 440 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock index c860a62cf855d590da5714bc773649c03c4fcac6..e1fd04a65f90b5d0b3ff8b18e6110e9df7eac7ef 100644 GIT binary patch literal 17 UcmZS1@)rBFze>lD0Ss6a04kCLdjJ3c literal 17 ScmZS1@)rBFze>lD0SW*rY6DjQ diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index 27b0e26aaabc2dff79de4b28c5b93fb3779276ea..bcebded2b67760436c418d4afab390d256962a20 100644 GIT binary patch literal 17 UcmZR6(Xu4+XJ*)A1_)pS06&QZ4gdfE literal 17 TcmZR6(Xu4+XJ*)A1}FdkKZ6Ab diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index 22cabd2d9ddb1f852d5a0b15f57114772ff9be97..ec0e6c6374a612071839bd64a9281f4a16627aed 100644 GIT binary patch literal 17 UcmZQxwBy}@)CWuC86aRL077I1tpET3 literal 17 TcmZQxwBy}@)CWuC8K3|FLCXac diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 6394df6637da5efc22b0a872ed0973eb0b0a24de..ba39c1de61638a0bf7f5838c0a2e6c1fb4ad36f4 100644 GIT binary patch literal 17 TcmZSP49tkBPWf@20Rn^oD^LUC literal 17 TcmZSP49tkBPWf@20Rk8SD?bC# diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 859c9b3..446c193 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -6,15 +6,12 @@ - diff --git a/.idea/misc.xml b/.idea/misc.xml index 4bc4fc6..5821b2f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,8 @@ + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 689a83e..6516761 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '2.7.13' id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } group = 'com.umc' @@ -26,6 +27,11 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' + + // querydsl 추가 + implementation "com.querydsl:querydsl-jpa:5.0.0" + implementation "com.querydsl:querydsl-apt:5.0.0" + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' @@ -39,3 +45,22 @@ tasks.named('test') { jar { enabled = false } + +// Qtype 생성 경로 +def querydslDir = "$buildDir/generated/querydsl" +querydsl { + jpa = true + querydslSourcesDir = querydslDir +} +sourceSets { + main.java.srcDir querydslDir +} +compileQuerydsl{ + options.annotationProcessorPath = configurations.querydsl +} +configurations { + compileOnly { + extendsFrom annotationProcessor + } + querydsl.extendsFrom compileClasspath +} diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml index 7878137..9cdc5de 100644 --- a/out/production/resources/application.yml +++ b/out/production/resources/application.yml @@ -14,7 +14,7 @@ spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false username: dongnae - password: df1234 + password: Tnqls9004^^ driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create \ No newline at end of file + hibernate.ddl-auto: create-drop \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java b/src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java new file mode 100644 index 0000000..bcfc8e4 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java @@ -0,0 +1,20 @@ +package com.umc.DongnaeFriend.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +@Configuration +public class QuerydslConfiguration { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java new file mode 100644 index 0000000..a560ad4 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -0,0 +1,29 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/account") +public class AccountBookController { + + private final AccountBookService accountBookService; + + @GetMapping("/budget") + public AccountBookDto.BudgetResponse getBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return accountBookService.getBudget(year, month); + } + + @PostMapping("/budget") + public void createBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestParam(value = "amount", required = false) Long budget){ + accountBookService.createBudget(year, month, budget); + } + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java new file mode 100644 index 0000000..d53509f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java @@ -0,0 +1,43 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + +import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; +import com.umc.DongnaeFriend.domain.account.book.service.MemoService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/account/memo") +public class MemoController { + + private final MemoService memoService; + + /** + * 유저 권한 확인 필요 + */ + @GetMapping + public MemoDto.MemoListResponse getMemoList(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return memoService.getMemoList(year, month); + } + + @PostMapping + public void createMemo(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestBody MemoDto.MemoRequest requestDto){ + memoService.createMemo(requestDto, year,month); + } + + @PutMapping + public void updateMemo(@RequestParam(value = "id", required = false) Long id, + @RequestBody MemoDto.MemoRequest requestDto){ + memoService.updateMemo(requestDto, id); + } + + @DeleteMapping + public void deleteMemo(@RequestParam(value = "id", required = false) Long id){ + memoService.deleteMemo(id); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java new file mode 100644 index 0000000..c34c389 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java @@ -0,0 +1,59 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class AccountBookDto { + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AccountBookResponse{ + private Long accountBookId; + private Long expenditure; + private Long income; + private Long budget; + private Integer month; + private Integer year; + + public static AccountBookResponse of(Long accountBookId, Long expenditure, Long income, + Long nowBudget, Integer month, Integer year){ + return AccountBookResponse.builder() + .accountBookId(accountBookId) + .expenditure(expenditure) + .income(income) + .budget(nowBudget-expenditure) + .month(month) + .year(year) + .build(); + } + } + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class BudgetResponse{ + private Long accountBookId; + private Long budget; + + public static BudgetResponse of(Long accountBookId, Long budget){ + return new BudgetResponse(accountBookId, budget); + } + } + + @Getter + public static class BudgetRequest{ + public static AccountBook toEntity(Integer year, Integer month, Long amount){ + return AccountBook.builder() + .budget(amount) + .year(year) + .month(month) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java new file mode 100644 index 0000000..526dd13 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java @@ -0,0 +1,64 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.security.core.parameters.P; + +import java.util.List; +import java.util.stream.Collectors; + +public class MemoDto { + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MemoResponse{ + private Long memoId; + private String memo; + private Boolean done; + + public static MemoResponse from(Memo memo){ + return new MemoResponse( + memo.getId(), + memo.getMemo(), + memo.getDone()); + } + } + + @Getter + public static class MemoListResponse{ + private List memos; + + public MemoListResponse(List memos){ + this.memos = memos; + } + + public static MemoListResponse of(List memoList){ + List memoResponses = memoList + .stream() + .map(MemoDto.MemoResponse::from) + .collect(Collectors.toList()); + + return new MemoListResponse(memoResponses); + } + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class MemoRequest{ + private String memo; + private Boolean done; + + public Memo toEntity(AccountBook accountBook){ + return Memo.builder() + .accountBook(accountBook) + .memo(memo) + .done(done) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java index 0f90154..fd4f4b8 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java @@ -23,15 +23,16 @@ public class AccountBook extends BaseTimeEntity { private Long id; @ManyToOne(fetch = LAZY) - @JoinColumn(name = "user_id", nullable = false) + //@JoinColumn(name = "user_id", nullable = false) + @JoinColumn(name = "user_id") private User user; private Long budget; - @Column(nullable = false) + //@Column(nullable = false) private Long expenditure; - @Column(nullable = false) + //@Column(nullable = false) private Long income; @Column(nullable = false) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java index dfb8f7c..32b72d6 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java @@ -27,7 +27,4 @@ public class Memo extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String memo; - - @Column(nullable = false) - private Boolean done; // 완료 여부 } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java index 7d1c3ab..4bcbf99 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java @@ -38,7 +38,7 @@ public class Transaction extends BaseTimeEntity { private PayCategory payCategory; //현금, 체크카드 등 @Enumerated(value = STRING) - @Column(nullable = false) + //@Column(nullable = false) private TransactionCategory transactionCategory; //식비, 교육 등 @Column(columnDefinition = "MEDIUMTEXT") diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java new file mode 100644 index 0000000..a0703a5 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java @@ -0,0 +1,15 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface AccountBookRepository extends JpaRepository, AccountBookRepositoryCustom { + + // 지난 달 지출액 확인 + + Optional findByIdAndYearAndMonth(Long accountBookId, Integer year, Integer month); + Optional findByYearAndMonth(Integer year, Integer month); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java new file mode 100644 index 0000000..ba4b8c5 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java @@ -0,0 +1,5 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; + + +public interface AccountBookRepositoryCustom { +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java new file mode 100644 index 0000000..b2c92a7 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AccountBookRepositoryCustomImpl implements AccountBookRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java new file mode 100644 index 0000000..1b5da1a --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java @@ -0,0 +1,15 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.memo; + +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface MemoRepository extends JpaRepository, MemoRepositoryCustom{ + Optional findByAccountBookId(Long accountBookId); + @Query("select m from Memo m where m.accountBook.id = :accountBookId") + List findMemoListByAccountBookId(@Param("accountBookId") Long accountBookId); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java new file mode 100644 index 0000000..6c33afd --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java @@ -0,0 +1,6 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.memo; + +public interface MemoRepositoryCustom { + + Integer getMemoCnt(Integer year, Integer month); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java new file mode 100644 index 0000000..ad1664e --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java @@ -0,0 +1,30 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.memo; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import com.umc.DongnaeFriend.domain.account.book.entity.QAccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.QMemo; + +import static org.springframework.data.jpa.domain.Specification.where; + +public class MemoRepositoryCustomImpl implements MemoRepositoryCustom{ + + private final JPAQueryFactory jpaQueryFactory; + + public MemoRepositoryCustomImpl(JPAQueryFactory jpaQueryFactory) { + this.jpaQueryFactory = jpaQueryFactory; + } + + @Override + public Integer getMemoCnt(Integer year, Integer month) { + QMemo memo = QMemo.memo1; + QAccountBook accountBook = QAccountBook.accountBook; + return Math.toIntExact(jpaQueryFactory + .select(memo.count()) + .from(memo) + .innerJoin(memo.accountBook, accountBook) + .where(memo.accountBook.month.eq(month) + .and(accountBook.year.eq(year))) + .fetchFirst()); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java new file mode 100644 index 0000000..f93c28b --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -0,0 +1,40 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; +import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AccountBookService { + + // User 권한 확인 // + + private final AccountBookRepository accountBookRepository; + private final TransactionRepository transactionRepository; + + + // 가계부 예산 설정 (한달) + @Transactional + public void createBudget(Integer year, Integer month, Long budget){ + + accountBookRepository.save(AccountBookDto.BudgetRequest.toEntity(year, month, budget)); + } + + // 가계부 예산 설정 조회 + public AccountBookDto.BudgetResponse getBudget(Integer year, Integer month){ + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + return AccountBookDto.BudgetResponse.of(accountBook.getId(),accountBook.getBudget()); + } + + + // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 -> 가계부 예산 총합 조회 로직 필요 + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java new file mode 100644 index 0000000..ae2ceda --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java @@ -0,0 +1,65 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; +import com.umc.DongnaeFriend.domain.account.book.repository.memo.MemoRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MemoService { + + private final MemoRepository memoRepository; + private final AccountBookRepository accountBookRepository; + + // 메모 전체 조회 -> 리스트 + public MemoDto.MemoListResponse getMemoList(Integer year, Integer month){ + + // User 권한 확인 + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + List memoList = memoRepository.findMemoListByAccountBookId(accountBook.getId()); + return MemoDto.MemoListResponse.of(memoList); + } + + // 메모 등록 + @Transactional + public void createMemo(MemoDto.MemoRequest memoRequest, Integer year, Integer month){ + + // User 권한 확인 + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + Integer memoCnt = memoRepository.getMemoCnt(year, month); + + if(memoCnt<5){ + memoRepository.save(memoRequest.toEntity(accountBook)); + }else{ + // 개수 초과 예외처리 + log.info("메모 개수 초과 발생 !"); + } + } + + // 메모 수정 + @Transactional + public void updateMemo(MemoDto.MemoRequest memoRequest, Long memoId){ + + // User 권한 확인 + Memo memo = memoRepository.findById(memoId).orElseThrow(); + memo.updateMemo(memoRequest); + } + + // 메모 삭제 + @Transactional + public void deleteMemo(Long memoId){ + + // User 권한 확인 + Memo memo = memoRepository.findById(memoId).orElseThrow(); + memoRepository.deleteById(memo.getId()); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7878137..9cdc5de 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -14,7 +14,7 @@ spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false username: dongnae - password: df1234 + password: Tnqls9004^^ driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create \ No newline at end of file + hibernate.ddl-auto: create-drop \ No newline at end of file From 19980f4cf04053d5ef69554c0a53acb7fb468420 Mon Sep 17 00:00:00 2001 From: soogoori Date: Thu, 20 Jul 2023 00:17:32 +0900 Subject: [PATCH 07/58] =?UTF-8?q?=F0=9F=92=B0Feat=20#21=20:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80]=20=EC=98=88=EC=82=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A9=94=EB=AA=A8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriend/domain/account/book/entity/Memo.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java index 32b72d6..6eafd97 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java @@ -7,6 +7,8 @@ import com.umc.DongnaeFriend.domain.BaseTimeEntity; import javax.persistence.*; + +import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; import lombok.*; @Getter @@ -27,4 +29,12 @@ public class Memo extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String memo; + + @Column(nullable = false) + private Boolean done; + + public void updateMemo(MemoDto.MemoRequest request){ + this.memo = request.getMemo(); + this.done = request.getDone(); + } } From ed28a4e9e7b4f21da1578babecc5bbbb1fc118d8 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 01:07:30 +0900 Subject: [PATCH 08/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFix=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20Mapping=20Uri=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 21 +++++++++++++++---- .../domain/dongnae/dto/DongnaeBoardDto.java | 18 ++++++++++------ .../service/DongnaeBoardServiceImpl.java | 7 +++++-- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index b4a6d0b..33bd156 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -1,5 +1,7 @@ package com.umc.DongnaeFriend.domain.dongnae.controller; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; import lombok.Getter; @@ -12,7 +14,7 @@ * */ @RestController -@RequestMapping("/account-books/sharing") +@RequestMapping("/town-information") public class DongnaeBoardController { @Autowired @@ -22,7 +24,7 @@ public class DongnaeBoardController { DongnaeBoardService dongnaeBoardService; /* - * [가계부 공유] 게시글 검색 + * [동네정보] 게시글 검색 * @param keyword * @param category * @param sort @@ -34,9 +36,8 @@ public ResponseEntity getBoards(@RequestParam("keyword") String keyword, return ResponseEntity.ok(dongnaeBoardService.searchByKeyword(keyword, category, sort)); } - /* - * [가계부 공유] 게시글 목록 조회 + * [동네정보] 게시글 목록조회 * @param sort */ @GetMapping("") @@ -45,4 +46,16 @@ public ResponseEntity postBoard(@RequestParam("sortBy") int sort) { } + /* + * [동네정보] 게시글 등록 + * @param sort + */ + @PostMapping("") + public ResponseEntity createBoard(@RequestBody DongnaeBoardDto req { + return ResponseEntity.ok(); + } + + + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 2e70308..a86b5c2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -3,6 +3,7 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import lombok.*; import java.util.List; @@ -20,15 +21,20 @@ public static class Request { private String title; private String content; private List images; + private String place; + + private String placeLocation; public DongnaeBoard toEntity() { return DongnaeBoard.builder() - .category(category == 0 ? RESTAURANT: - category == 1 ? FACILITY: - category == 2 ? SHARE_INFORMATION: - category == 3 ? TOGETHER: - category == 4 ? COMMUNICATION: - category == 5 ? ETC : null) + .category(DongnaeBoardCategory.valueOf(category) +// category == 0 ? RESTAURANT: +// category == 1 ? FACILITY: +// category == 2 ? SHARE_INFORMATION: +// category == 3 ? TOGETHER: +// category == 4 ? COMMUNICATION: +// category == 5 ? ETC : null + ) .title(title) .content(content) .build(); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 25982bf..f484f28 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -38,7 +38,10 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { private DongnaeSympathyRepository dongnaeSympathyRepository; - + /* + * [동네정보] 게시글 검색 + * @param sort + */ // @Transactional(propagation = Propagation.REQUIRED) public List searchByKeyword(String keyword, int category, int sort) { @@ -56,7 +59,7 @@ public List searchByKeyword(String keyword, int ca } /* - * [가계부 공유] 게시글 목록 조회 + * [동네정보] 게시글 목록 조회 * @param sort */ public List searchAll(int sort) { From b26bf673ea891e46a15bf81eb462d2fb2c500421 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 01:30:39 +0900 Subject: [PATCH 09/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFeat=20:=20[?= =?UTF-8?q?=EB=8F=99=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 7 +++++-- .../domain/dongnae/dto/DongnaeBoardDto.java | 10 +++++++++- .../domain/dongnae/entity/DongnaeBoard.java | 1 - .../dongnae/service/DongnaeBoardService.java | 2 ++ .../dongnae/service/DongnaeBoardServiceImpl.java | 16 ++++++++++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index 33bd156..b4c1061 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -51,11 +51,14 @@ public ResponseEntity postBoard(@RequestParam("sortBy") int sort) { * @param sort */ @PostMapping("") - public ResponseEntity createBoard(@RequestBody DongnaeBoardDto req { - return ResponseEntity.ok(); + public ResponseEntity createBoard(@RequestBody DongnaeBoardDto.Request req) { + dongnaeBoardService.createBoard(req); + return ResponseEntity.ok("요청에 성공했습니다."); } + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index a86b5c2..bd61910 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -2,8 +2,10 @@ +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.*; import java.util.List; @@ -25,8 +27,9 @@ public static class Request { private String placeLocation; - public DongnaeBoard toEntity() { + public DongnaeBoard toEntity(User user, Dongnae dongnae) { return DongnaeBoard.builder() + .user(user) .category(DongnaeBoardCategory.valueOf(category) // category == 0 ? RESTAURANT: // category == 1 ? FACILITY: @@ -37,6 +40,11 @@ public DongnaeBoard toEntity() { ) .title(title) .content(content) + .place(place) + .placeLocation(placeLocation) + + .dongnae(dongnae) + .view(0) .build(); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java index da83d40..f254018 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java @@ -53,5 +53,4 @@ public class DongnaeBoard extends BaseTimeEntity { private String placeLocation; // 장소의 정확한 위치 - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index dde8c95..10836da 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -9,4 +9,6 @@ public interface DongnaeBoardService { List searchByKeyword(String keyword, int category, int sort); List searchAll(int sort); + + void createBoard(DongnaeBoardDto.Request req); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index f484f28..140f818 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -1,13 +1,18 @@ package com.umc.DongnaeFriend.domain.dongnae.service; import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeImgRepository; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeSympathyRepository; +import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -74,6 +79,17 @@ public List searchAll(int sort) { return getListResponses(dongnaeBoardList); } + /* + * [동네정보] 게시글 목록 조회 + */ + public void createBoard(DongnaeBoardDto.Request req) { + //TODO : User Mapping UserRepository 필요. + Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + User user = User.builder().age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + dongnaeBoardRepository.save(req.toEntity(user, dongnae)); + } + private List getListResponses(List dongnaeBoardList) { return dongnaeBoardList.stream() .map(origin -> DongnaeBoardDto.ListResponse.builder() From 405ecd57fd38639f38048b0055f42ed7e4109ce9 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Thu, 20 Jul 2023 11:03:31 +0900 Subject: [PATCH 10/58] =?UTF-8?q?:sparkles:=20Feat=20#19:=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/exception/CustomException.java | 20 +++++++++ .../global/exception/ErrorCode.java | 45 +++++++++++++++++++ .../global/exception/ErrorResponse.java | 16 +++++++ .../exception/GlobalExceptionHandler.java | 40 +++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java b/src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java new file mode 100644 index 0000000..0465158 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java @@ -0,0 +1,20 @@ +package com.umc.DongnaeFriend.global.exception; + +import lombok.Getter; +@Getter +public class CustomException extends RuntimeException { + + private ErrorCode errorCode; + private String errorMessage; + + public CustomException(ErrorCode errorCode) { + this.errorCode = errorCode; + this.errorMessage = errorCode.getDetail(); + } + + //@Valid 오류처리 + public CustomException(ErrorCode errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java new file mode 100644 index 0000000..9ac2371 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java @@ -0,0 +1,45 @@ +package com.umc.DongnaeFriend.global.exception; + +import static org.springframework.http.HttpStatus.*; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ErrorCode { + /* 10* 가계부 */ + + /* 20* 동네정보 */ + + /* 50* 스크랩 */ + + + /* 400 BAD_REQUEST : 잘못된 요청 */ + INVALID_REFRESH_TOKEN(BAD_REQUEST, 400, "리프레시 토큰이 유효하지 않습니다"), + MISMATCH_REFRESH_TOKEN(BAD_REQUEST, 400, "리프레시 토큰의 유저 정보가 일치하지 않습니다"), + CANNOT_FOLLOW_MYSELF(BAD_REQUEST, 400,"자기 자신은 팔로우 할 수 없습니다"), + INVALID_VALUE(BAD_REQUEST, 400, "잘못된 값입니다." ), + + + /* 401 UNAUTHORIZED : 인증되지 않은 사용자 */ + INVALID_AUTH_TOKEN(UNAUTHORIZED,401, "권한 정보가 없는 토큰입니다"), + UNAUTHORIZED_MEMBER(UNAUTHORIZED,401, "현재 내 계정 정보가 존재하지 않습니다"), + + /* 404 NOT_FOUND : Resource 를 찾을 수 없음 */ + MEMBER_NOT_FOUND(NOT_FOUND,404, "해당 유저 정보를 찾을 수 없습니다"), + REFRESH_TOKEN_NOT_FOUND(NOT_FOUND, 404,"로그아웃 된 사용자입니다"), + NOT_FOLLOW(NOT_FOUND,404, "팔로우 중이지 않습니다"), + + /* 409 CONFLICT : Resource 의 현재 상태와 충돌. 보통 중복된 데이터 존재 */ + DUPLICATE_RESOURCE(CONFLICT,409, "데이터가 이미 존재합니다"), + + //500 INTERNAL SERVER ERROR + SERVER_ERROR(INTERNAL_SERVER_ERROR, 500, "서버 에러입니다."); + + + private final HttpStatus httpStatus; + private final int errorCode; + private final String detail; +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java new file mode 100644 index 0000000..82a6fe2 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java @@ -0,0 +1,16 @@ +package com.umc.DongnaeFriend.global.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class ErrorResponse { + + private final String message; + + public ErrorResponse(CustomException e){ + this.message = e.getErrorMessage(); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..986c73d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java @@ -0,0 +1,40 @@ +package com.umc.DongnaeFriend.global.exception; + +import static com.umc.DongnaeFriend.global.exception.ErrorCode.*; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.*; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + //custom Exception + @ExceptionHandler({CustomException.class}) + protected ResponseEntity handlecustomException(CustomException e) { + return ResponseEntity + .status(e.getErrorCode().getHttpStatus()) + .body(new ErrorResponse(e)); + } + + //@valid Exception + @ExceptionHandler({MethodArgumentNotValidException.class}) + protected ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + CustomException validException = new CustomException(INVALID_VALUE, message); + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(new ErrorResponse(validException)); + } + + //일반 예외처리 + @ExceptionHandler({Exception.class}) + protected ResponseEntity handleServerException(Exception ex) { + CustomException exception = new CustomException(SERVER_ERROR); + return ResponseEntity + .status(SERVER_ERROR.getHttpStatus()) + .body(new ErrorResponse(exception)); + } +} \ No newline at end of file From 1bd0361f11dfaf5a1b4f9ff626d265b663ea39e0 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 11:34:19 +0900 Subject: [PATCH 11/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EA=B2=80=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 10 +++++++++ .../respository/DongnaeBoardRepository.java | 3 +++ .../dongnae/service/DongnaeBoardService.java | 2 ++ .../service/DongnaeBoardServiceImpl.java | 21 +++++++++++++++---- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index b4c1061..4449f7c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -23,6 +23,16 @@ public class DongnaeBoardController { @Autowired DongnaeBoardService dongnaeBoardService; + /* + * [동네정보] 홈 화면 + */ + @GetMapping("/home") + public ResponseEntity home(@RequestParam("category") int category, + @RequestParam("sortBy") int sort) { + return ResponseEntity.ok(dongnaeBoardService.home(category)); + } + + /* * [동네정보] 게시글 검색 * @param keyword diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index d4e7b12..3547e9b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -29,6 +29,9 @@ public interface DongnaeBoardRepository extends JpaRepository findAllOrderByLikes(); + @Query(value = "select * from dongnae_board where category = ?1 ORDER BY created_at DESC LIMIT 1 ;", nativeQuery = true) + List findTwoByCategoryOrderByCreatedAt(String category); + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 10836da..85ba577 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -11,4 +11,6 @@ public interface DongnaeBoardService { List searchAll(int sort); void createBoard(DongnaeBoardDto.Request req); + + List home(int category); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 140f818..4037ba2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -16,13 +16,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; import java.time.Duration; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; + import java.util.List; import java.util.stream.Collectors; @@ -42,6 +39,19 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { @Autowired private DongnaeSympathyRepository dongnaeSympathyRepository; + /* + * [동네정보] 홈 화면 + * 카테고리 별 게시글 2개씩 반환 + * @param sort + */ + public List home(int category) { + String category_String = DongnaeBoardCategory.valueOf(category).name(); + //TODO : 동네 인증 여부 확인하기 - (User 필요) + String category_ = "RESTAURANT"; + List dongnaeBoardList = dongnaeBoardRepository.findTwoByCategoryOrderByCreatedAt(category_); + return getListResponses(dongnaeBoardList); + } + /* * [동네정보] 게시글 검색 @@ -90,6 +100,8 @@ public void createBoard(DongnaeBoardDto.Request req) { dongnaeBoardRepository.save(req.toEntity(user, dongnae)); } + + //ListResponse 변환 private List getListResponses(List dongnaeBoardList) { return dongnaeBoardList.stream() .map(origin -> DongnaeBoardDto.ListResponse.builder() @@ -115,6 +127,7 @@ private List getListResponses(List d } + //시간 계산 private String getTime(LocalDateTime time) { LocalDateTime now = LocalDateTime.now(); // 현재 시간 Duration duration = Duration.between(now, time); From 1f715450631bed4d0421d1d0b443a7158c6d8346 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 12:44:11 +0900 Subject: [PATCH 12/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EC=A0=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dongnae/controller/DongnaeBoardController.java | 12 ++++++++++++ .../domain/dongnae/dto/UserLocationDto.java | 10 ++++++++++ .../domain/dongnae/service/DongnaeBoardService.java | 3 +++ .../dongnae/service/DongnaeBoardServiceImpl.java | 10 ++++++++++ 4 files changed, 35 insertions(+) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index 4449f7c..c302f16 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -26,12 +26,24 @@ public class DongnaeBoardController { /* * [동네정보] 홈 화면 */ + //TODO : 파라미터 다시 확인해보기 @GetMapping("/home") public ResponseEntity home(@RequestParam("category") int category, @RequestParam("sortBy") int sort) { return ResponseEntity.ok(dongnaeBoardService.home(category)); } + /* + * [동네정보] 사용자 위치 정보 + */ + //TODO : 파라미터 다시 확인해보기 + @GetMapping("/user/location") + public ResponseEntity getLocation() { + return ResponseEntity.ok(dongnaeBoardService.getUserLocaiton()); + } + + + /* * [동네정보] 게시글 검색 diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java new file mode 100644 index 0000000..cb2906d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java @@ -0,0 +1,10 @@ +package com.umc.DongnaeFriend.domain.dongnae.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class UserLocationDto { + private String town; +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 85ba577..5c223d1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -1,6 +1,7 @@ package com.umc.DongnaeFriend.domain.dongnae.service; import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; import java.util.List; @@ -13,4 +14,6 @@ public interface DongnaeBoardService { void createBoard(DongnaeBoardDto.Request req); List home(int category); + + public UserLocationDto getUserLocaiton(); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 4037ba2..6fef235 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -1,6 +1,7 @@ package com.umc.DongnaeFriend.domain.dongnae.service; import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; @@ -52,6 +53,15 @@ public List home(int category) { return getListResponses(dongnaeBoardList); } + /* + * [동네정보] 사용자 위치 정보 + */ + public UserLocationDto getUserLocaiton() { + //TODO : 사용자 식별자 가져오기 - (User 필요) + long user_id = 1; + return new UserLocationDto("서울도시"); + } + /* * [동네정보] 게시글 검색 From 9f885760c50acca5f94bdefa70c4bce38883d183 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 21:40:44 +0900 Subject: [PATCH 13/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 16 +++-- .../domain/dongnae/dto/DongnaeBoardDto.java | 35 +++++++++++ .../respository/DongnaeBoardRepository.java | 2 - .../respository/DongnaeImgRepository.java | 3 + .../DongnaeSympathyRepository.java | 7 ++- .../dongnae/service/DongnaeBoardService.java | 4 +- .../service/DongnaeBoardServiceImpl.java | 60 ++++++++++++++++++- 7 files changed, 115 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index c302f16..c5c1644 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -1,10 +1,8 @@ package com.umc.DongnaeFriend.domain.dongnae.controller; import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; -import lombok.Getter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -36,15 +34,12 @@ public ResponseEntity home(@RequestParam("category") int category, /* * [동네정보] 사용자 위치 정보 */ - //TODO : 파라미터 다시 확인해보기 @GetMapping("/user/location") public ResponseEntity getLocation() { - return ResponseEntity.ok(dongnaeBoardService.getUserLocaiton()); + return ResponseEntity.ok(dongnaeBoardService.getUserLocation()); } - - /* * [동네정보] 게시글 검색 * @param keyword @@ -78,6 +73,15 @@ public ResponseEntity createBoard(@RequestBody DongnaeBoardDto.Request req) { return ResponseEntity.ok("요청에 성공했습니다."); } + /* + * [동네정보] 게시글 상세 조회 + * @param sort + */ + @GetMapping("/{townInformationId}") + public ResponseEntity getBoard(@PathVariable("townInformationId") int board_id) { + return ResponseEntity.ok(dongnaeBoardService.getBoard(board_id)); + } + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index bd61910..62603ab 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -74,6 +74,41 @@ public static class ListResponse { private int likes; } + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Response { + private String profileImage; + + private String nickname; + + private int category; + + private String title; + + private String content; + + private List images; + + private String place; + + private String placeLocation; + + private String createdAt; + + private int townCertification; + + //게시글 조회한 사람이 작성자인지? + private boolean isWriter; + + private boolean likeOrNot; + + private boolean ScrapOrNot; + + private int view; + + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index 3547e9b..28671d1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -32,6 +32,4 @@ public interface DongnaeBoardRepository extends JpaRepository findTwoByCategoryOrderByCreatedAt(String category); - - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java index 0a40a02..8a20d65 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java @@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -12,4 +13,6 @@ public interface DongnaeImgRepository extends JpaRepository { @Query(value = "SELECT * FROM dongnae_img WHERE dongnae_board_id = ?1 ORDER BY created_at ASC LIMIT 1", nativeQuery = true) Optional findFirst(long dongnae_board_id); + + List findAllByDongnaeBoard_Id(long id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java index 44e5944..3437511 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java @@ -2,7 +2,12 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeSympathy; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.web.PageableDefault; + +import java.util.Optional; public interface DongnaeSympathyRepository extends JpaRepository { - public int countAllByDongnaeBoardId(Long dongnae_board_id); + int countAllByDongnaeBoardId(Long dongnae_board_id); + + Optional findByUser_Id(long user_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 5c223d1..9cce64d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -15,5 +15,7 @@ public interface DongnaeBoardService { List home(int category); - public UserLocationDto getUserLocaiton(); + UserLocationDto getUserLocation(); + + DongnaeBoardDto.Response getBoard(long board_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 6fef235..2c7ffaa 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -16,18 +16,24 @@ import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @Slf4j @Service public class DongnaeBoardServiceImpl implements DongnaeBoardService { + //임시 유저 + Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + User user = User.builder().age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + @Autowired private DongnaeBoardRepository dongnaeBoardRepository; @@ -45,6 +51,7 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { * 카테고리 별 게시글 2개씩 반환 * @param sort */ + @Override public List home(int category) { String category_String = DongnaeBoardCategory.valueOf(category).name(); //TODO : 동네 인증 여부 확인하기 - (User 필요) @@ -56,7 +63,8 @@ public List home(int category) { /* * [동네정보] 사용자 위치 정보 */ - public UserLocationDto getUserLocaiton() { + @Override + public UserLocationDto getUserLocation() { //TODO : 사용자 식별자 가져오기 - (User 필요) long user_id = 1; return new UserLocationDto("서울도시"); @@ -68,6 +76,7 @@ public UserLocationDto getUserLocaiton() { * @param sort */ + @Override // @Transactional(propagation = Propagation.REQUIRED) public List searchByKeyword(String keyword, int category, int sort) { String categoryName = DongnaeBoardCategory.valueOf(category).name(); @@ -87,6 +96,7 @@ public List searchByKeyword(String keyword, int ca * [동네정보] 게시글 목록 조회 * @param sort */ + @Override public List searchAll(int sort) { List dongnaeBoardList; @@ -100,8 +110,9 @@ public List searchAll(int sort) { } /* - * [동네정보] 게시글 목록 조회 + * [동네정보] 게시글 등록 */ + @Override public void createBoard(DongnaeBoardDto.Request req) { //TODO : User Mapping UserRepository 필요. Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); @@ -111,6 +122,51 @@ public void createBoard(DongnaeBoardDto.Request req) { } + /* + * [동네정보] 게시글 상세 조회 + */ + @Override + public DongnaeBoardDto.Response getBoard(long board_id) { + //TODO : User 식별자 필요. + int user_id = 1; + Optional board = dongnaeBoardRepository.findById(board_id); + if (board.isEmpty()) { + throw new RuntimeException(); + } + + //Get Images + List imgs = dongnaeImgRepository.findAllByDongnaeBoard_Id(board_id); + + //Writer인지 검사 + boolean isWriter = board.get().getUser().getId() == user_id; + + //LikeOrNot 검사 + boolean likeOrNot = dongnaeSympathyRepository.findByUser_Id(user_id).isPresent(); + + //TODO: ScrapRepository 필요 + //scrapOrNot 검사 + boolean scrapOrNot = false; + + return DongnaeBoardDto.Response.builder() + .profileImage(user.getProfileImage()) + .nickname(user.getNickname()) + .category(board.get().getCategory().getValue()) + .title(board.get().getTitle()) + .content(board.get().getContent()) + .images(imgs.stream().map(DongnaeImg::getImageUrl).collect(Collectors.toList())) + .place(board.get().getPlace()) + .placeLocation(board.get().getPlaceLocation()) + .createdAt(getTime(board.get().getCreatedAt())) + .townCertification(user.getTownCertCnt()) + .isWriter(isWriter) + .likeOrNot(likeOrNot) + .ScrapOrNot(scrapOrNot) + .view(board.get().getView()).build(); + } + + + + //ListResponse 변환 private List getListResponses(List dongnaeBoardList) { return dongnaeBoardList.stream() From f62863aee2f7d70b7b45069018ea9b3bf66f4a54 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 22:05:02 +0900 Subject: [PATCH 14/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 14 ++++++++++++-- .../domain/dongnae/entity/DongnaeBoard.java | 11 +++++++++++ .../respository/DongnaeBoardRepository.java | 3 +-- .../dongnae/service/DongnaeBoardService.java | 2 ++ .../service/DongnaeBoardServiceImpl.java | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index c5c1644..8c152ee 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -65,7 +65,7 @@ public ResponseEntity postBoard(@RequestParam("sortBy") int sort) { /* * [동네정보] 게시글 등록 - * @param sort + * @param DongnaeBoardDto.Request */ @PostMapping("") public ResponseEntity createBoard(@RequestBody DongnaeBoardDto.Request req) { @@ -75,13 +75,23 @@ public ResponseEntity createBoard(@RequestBody DongnaeBoardDto.Request req) { /* * [동네정보] 게시글 상세 조회 - * @param sort + * @param board_id */ @GetMapping("/{townInformationId}") public ResponseEntity getBoard(@PathVariable("townInformationId") int board_id) { return ResponseEntity.ok(dongnaeBoardService.getBoard(board_id)); } + /* + * [동네정보] 게시글 수정 + * @param sort + */ + @PutMapping("/{townInformationId}") + public ResponseEntity updateBoard(@PathVariable("townInformationId") int board_id, + @RequestBody DongnaeBoardDto.Request request) { + dongnaeBoardService.updateBoard(board_id, request); + return ResponseEntity.ok("요청에 성공했습니다."); + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java index f254018..c5fc447 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java @@ -8,12 +8,15 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.umc.DongnaeFriend.domain.BaseTimeEntity; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import javax.persistence.*; import lombok.*; import org.hibernate.annotations.ColumnDefault; +import java.util.List; + @Getter @Builder @NoArgsConstructor(access = PROTECTED) @@ -52,5 +55,13 @@ public class DongnaeBoard extends BaseTimeEntity { private String place; // 사용자 장소 공유시 장소 이름(ex. "00키친") private String placeLocation; // 장소의 정확한 위치 + public void updateBoard(DongnaeBoardDto.Request request) { + this.category = DongnaeBoardCategory.valueOf(request.getCategory()); + this.title = request.getTitle(); + this.content = request.getContent(); + this.place = request.getPlace(); + this.placeLocation = request.getPlaceLocation(); + } + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index 28671d1..0c70194 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -3,9 +3,8 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import org.springframework.web.bind.annotation.RequestParam; + import java.util.List; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 9cce64d..64ae066 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -18,4 +18,6 @@ public interface DongnaeBoardService { UserLocationDto getUserLocation(); DongnaeBoardDto.Response getBoard(long board_id); + + void updateBoard(long board_id, DongnaeBoardDto.Request request); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 2c7ffaa..8c77e3f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -19,6 +19,7 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import javax.persistence.EntityNotFoundException; import java.time.Duration; import java.time.LocalDateTime; @@ -165,6 +166,24 @@ public DongnaeBoardDto.Response getBoard(long board_id) { } + /* + * [동네정보] 게시글 수정 + */ + @Override + public void updateBoard(long board_id, DongnaeBoardDto.Request request) { + Optional board = dongnaeBoardRepository.findById(board_id); + if (board.isPresent()) { + board.get().updateBoard(request); + dongnaeBoardRepository.save(board.get()); + } else { + throw new EntityNotFoundException(); + } + } + + + + + //ListResponse 변환 From c99e5cf1b7bbb9549eb119c91426a835f0db3f07 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 22:10:55 +0900 Subject: [PATCH 15/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFix=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dongnae/respository/DongnaeSympathyRepository.java | 3 ++- .../domain/dongnae/service/DongnaeBoardServiceImpl.java | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java index 3437511..1f7e3a7 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java @@ -4,10 +4,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.web.PageableDefault; +import java.util.List; import java.util.Optional; public interface DongnaeSympathyRepository extends JpaRepository { int countAllByDongnaeBoardId(Long dongnae_board_id); - Optional findByUser_Id(long user_id); + List findByUser_Id(long user_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 8c77e3f..54286eb 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -18,6 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityNotFoundException; import java.time.Duration; @@ -33,7 +35,7 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { //임시 유저 Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + User user = User.builder().age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); @Autowired private DongnaeBoardRepository dongnaeBoardRepository; @@ -117,7 +119,7 @@ public List searchAll(int sort) { public void createBoard(DongnaeBoardDto.Request req) { //TODO : User Mapping UserRepository 필요. Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); dongnaeBoardRepository.save(req.toEntity(user, dongnae)); } @@ -127,6 +129,7 @@ public void createBoard(DongnaeBoardDto.Request req) { * [동네정보] 게시글 상세 조회 */ @Override + @Transactional(propagation = Propagation.REQUIRED) public DongnaeBoardDto.Response getBoard(long board_id) { //TODO : User 식별자 필요. int user_id = 1; @@ -142,7 +145,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { boolean isWriter = board.get().getUser().getId() == user_id; //LikeOrNot 검사 - boolean likeOrNot = dongnaeSympathyRepository.findByUser_Id(user_id).isPresent(); + boolean likeOrNot = !dongnaeSympathyRepository.findByUser_Id(user_id).isEmpty(); //TODO: ScrapRepository 필요 //scrapOrNot 검사 From 0e8cc2f6ca0233f51d6550bed731bfa5764c3cd7 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 22:20:38 +0900 Subject: [PATCH 16/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFix=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EC=8B=9C=EA=B0=84=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dongnae/service/DongnaeBoardServiceImpl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 54286eb..8727afa 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -222,14 +222,20 @@ private String getTime(LocalDateTime time) { log.info(now.toString()); log.info(time.toString()); - long days = duration.toDays(); + long days = -duration.toDays(); log.info(" days: "+ days); - long hours = duration.toHours() % 24; + long hours = -duration.toHours() % 24; log.info(" hours: "+ hours); - long minutes = duration.toMinutes() % 60; + long minutes = -duration.toMinutes() % 60; log.info(" minutes: "+ minutes); - if (days > 1) return days + "일 전"; + if (days >= 1){ + if (days == 1) { + return "어제"; + } + return days + "일 전"; + } + else if (hours >= 1) { return hours + "시간 전"; } else return minutes + "분 전"; From 3b8af742e32880030803051bc755cab115b36436 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 20 Jul 2023 22:57:56 +0900 Subject: [PATCH 17/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DongnaeBoardController.java | 17 +++++++++-- .../domain/dongnae/dto/DongnaeBoardDto.java | 1 + .../dongnae/service/DongnaeBoardService.java | 5 +++- .../service/DongnaeBoardServiceImpl.java | 29 +++++++++++++++---- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index 8c152ee..c8e7d7f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -7,6 +7,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import javax.naming.AuthenticationException; + /* * [ 가계부 공유 ] * */ @@ -84,15 +86,26 @@ public ResponseEntity getBoard(@PathVariable("townInformationId") int board_i /* * [동네정보] 게시글 수정 - * @param sort + * @param baord_id + * @param DongnaeBoardDto.Request */ @PutMapping("/{townInformationId}") public ResponseEntity updateBoard(@PathVariable("townInformationId") int board_id, - @RequestBody DongnaeBoardDto.Request request) { + @RequestBody DongnaeBoardDto.Request request) throws AuthenticationException { dongnaeBoardService.updateBoard(board_id, request); return ResponseEntity.ok("요청에 성공했습니다."); } + /* + * [동네정보] 게시글 삭제 + * @param board_id + */ + @DeleteMapping("/{townInformationId}") + public ResponseEntity deleteBoard(@PathVariable("townInformationId") int board_id) throws AuthenticationException { + dongnaeBoardService.deleteBoard(board_id); + return ResponseEntity.ok("요청에 성공했습니다."); + } + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 62603ab..8fcf7bd 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -74,6 +74,7 @@ public static class ListResponse { private int likes; } + @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 64ae066..8f1c978 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -3,6 +3,7 @@ import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import javax.naming.AuthenticationException; import java.util.List; public interface DongnaeBoardService { @@ -19,5 +20,7 @@ public interface DongnaeBoardService { DongnaeBoardDto.Response getBoard(long board_id); - void updateBoard(long board_id, DongnaeBoardDto.Request request); + void updateBoard(long board_id, DongnaeBoardDto.Request request) throws AuthenticationException; + + void deleteBoard(long board_id) throws AuthenticationException; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 8727afa..a03569f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -16,16 +16,17 @@ import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import javax.naming.AuthenticationException; import javax.persistence.EntityNotFoundException; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -35,7 +36,7 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { //임시 유저 Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); @Autowired private DongnaeBoardRepository dongnaeBoardRepository; @@ -139,7 +140,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { } //Get Images - List imgs = dongnaeImgRepository.findAllByDongnaeBoard_Id(board_id); + List images = dongnaeImgRepository.findAllByDongnaeBoard_Id(board_id); //Writer인지 검사 boolean isWriter = board.get().getUser().getId() == user_id; @@ -157,7 +158,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { .category(board.get().getCategory().getValue()) .title(board.get().getTitle()) .content(board.get().getContent()) - .images(imgs.stream().map(DongnaeImg::getImageUrl).collect(Collectors.toList())) + .images(images.stream().map(DongnaeImg::getImageUrl).collect(Collectors.toList())) .place(board.get().getPlace()) .placeLocation(board.get().getPlaceLocation()) .createdAt(getTime(board.get().getCreatedAt())) @@ -173,9 +174,13 @@ public DongnaeBoardDto.Response getBoard(long board_id) { * [동네정보] 게시글 수정 */ @Override - public void updateBoard(long board_id, DongnaeBoardDto.Request request) { + public void updateBoard(long board_id, DongnaeBoardDto.Request request) throws AuthenticationException { Optional board = dongnaeBoardRepository.findById(board_id); if (board.isPresent()) { + //User Validaiton + if (!Objects.equals(board.get().getUser().getId(), user.getId())) { + throw new AuthenticationException(); + } board.get().updateBoard(request); dongnaeBoardRepository.save(board.get()); } else { @@ -183,6 +188,20 @@ public void updateBoard(long board_id, DongnaeBoardDto.Request request) { } } + @Override + public void deleteBoard(long board_id) throws AuthenticationException { + Optional board = dongnaeBoardRepository.findById(board_id); + + if (board.isEmpty()) throw new EntityNotFoundException(); + //User Validation + if (!Objects.equals(board.get().getUser().getId(), user.getId())) { + throw new AuthenticationException(); + } else { + dongnaeBoardRepository.deleteById(board_id); + } + + } + From 43f2a9ab7069cc6071bb318094cf31d0c19ab5c4 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 21 Jul 2023 10:58:24 +0900 Subject: [PATCH 18/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/dongnae/service/DongnaeBoardServiceImpl.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index a03569f..c0a861a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -203,11 +203,6 @@ public void deleteBoard(long board_id) throws AuthenticationException { } - - - - - //ListResponse 변환 private List getListResponses(List dongnaeBoardList) { return dongnaeBoardList.stream() From 91977649f732c7f306920486a5006518b5ba74ae Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 21 Jul 2023 21:47:31 +0900 Subject: [PATCH 19/58] =?UTF-8?q?=F0=9F=A5=95Feat=20:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accountBookSharingController.java | 20 ++++++++++ .../domain/account/book/dto/SharingDto.java | 34 +++++++++++++++++ .../repository/SharingBoardRepository.java | 12 ++++++ .../service/accountBookSharingService.java | 4 ++ .../accountBookSharingServiceImpl.java | 38 +++++++++++++++++++ .../domain/dongnae/entity/Dongnae.java | 2 +- 6 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/SharingDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingService.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java new file mode 100644 index 0000000..5dca23c --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java @@ -0,0 +1,20 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/account-books/sharing") +public class accountBookSharingController { + + /** + * [가계부 공유] 게시글 검색 + */ + + @GetMapping("/search") + public ResponseEntity searchAll(@RequestParam("keyword")String keyword, Pageable pageable) { + + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/SharingDto.java new file mode 100644 index 0000000..cc7101d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/SharingDto.java @@ -0,0 +1,34 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class SharingDto { + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ListResponse { + private String id; + + private int category; + + private String title; + + private String content; + + private String imageUrl; + + private String createdAt; + + private int view; + + private int commentCount; + + private int likes; + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java new file mode 100644 index 0000000..a334c39 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.domain.account.book.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface SharingBoardRepository extends JpaRepository { + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingService.java new file mode 100644 index 0000000..435bebb --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingService.java @@ -0,0 +1,4 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +public interface accountBookSharingService { +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java new file mode 100644 index 0000000..2e1a00d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java @@ -0,0 +1,38 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.umc.DongnaeFriend.domain.account.book.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.book.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class accountBookSharingServiceImpl implements accountBookSharingService { + + + //임시 유저 + Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + + @Autowired + private SharingBoardRepository sharingBoardRepository; + + /* + * [가계부 공유] 게시글 검 + * Pageable : page, size, sortBy + * @param sort + */ + public List searchByKeyword(String keyword, int category, Pageable pageable) { + sharingBoardRepository + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java index 62d39d5..1d542f3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java @@ -21,7 +21,7 @@ public class Dongnae extends BaseTimeEntity { private Long id; @Column(nullable = false) - private String townName; + private String townName; //동 이름 @Column(nullable = false) private String city; //시 From 907ea44c8f7ab4eaa256bf5d442ede7be79b34d8 Mon Sep 17 00:00:00 2001 From: soogoori Date: Fri, 21 Jul 2023 21:48:49 +0900 Subject: [PATCH 20/58] =?UTF-8?q?=F0=9F=92=B0Feat=20#21=20:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80]=20=EA=B0=80=EA=B3=84=EB=B6=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=BF=BC=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AccountBookController.java | 13 +++ .../controller/TransactionController.java | 39 +++++++ .../account/book/dto/AccountBookDto.java | 61 +++++++--- .../domain/account/book/dto/MemoDto.java | 9 +- .../account/book/dto/TransactionDto.java | 108 ++++++++++++++++++ .../domain/account/book/entity/Memo.java | 2 +- .../account/book/entity/Transaction.java | 13 +++ .../accountBook/AccountBookRepository.java | 40 ++++++- .../AccountBookRepositoryCustom.java | 6 + .../AccountBookRepositoryCustomImpl.java | 29 +++++ .../memo/MemoRepositoryCustomImpl.java | 8 +- .../transaction/TransactionRepository.java | 23 ++++ .../TransactionRepositoryCustom.java | 4 + .../TransactionRepositoryCustomImpl.java | 4 + .../book/service/AccountBookService.java | 16 ++- .../account/book/service/MemoService.java | 2 +- .../book/service/TransactionService.java | 100 ++++++++++++++++ 17 files changed, 442 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java index a560ad4..badd49a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -5,6 +5,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequiredArgsConstructor @RequestMapping("/api/account") @@ -25,5 +27,16 @@ public void createBudget(@RequestParam(value = "year", required = false) Integer accountBookService.createBudget(year, month, budget); } + @GetMapping("/category") + public List getTransactionAll(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return accountBookService.getAccountBook(year, month); + } + + @GetMapping("/all") + public AccountBookDto.AccountBookResponse getAccountBook(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return accountBookService.getAccountBookResponse(year, month); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java new file mode 100644 index 0000000..417203d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java @@ -0,0 +1,39 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + + +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; +import com.umc.DongnaeFriend.domain.account.book.service.TransactionService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import javax.transaction.Transactional; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/account") +public class TransactionController { + + private final TransactionService transactionService; + + @PostMapping + public void createTransaction(@RequestBody TransactionDto.TransactionRequest request){ + transactionService.createTransaction(request); + } + + @GetMapping + public TransactionDto.TransactionListResponse getTransaction(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return transactionService.getTransactions(year, month); + } + + @PutMapping + public void updateTransaction(@RequestBody TransactionDto.TransactionRequest requestDto, + @RequestParam(value = "id", required = false) Long id){ + transactionService.updateTransaction(requestDto, id); + } + + @DeleteMapping + public void deleteTransaction(@RequestParam(value = "id", required = false) Long id){ + transactionService.deleteTransaction(id); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java index c34c389..df29a9c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java @@ -1,39 +1,30 @@ package com.umc.DongnaeFriend.domain.account.book.dto; +import com.querydsl.core.annotations.QueryProjection; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import com.umc.DongnaeFriend.domain.type.TransactionCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.List; +import java.util.stream.Collectors; + public class AccountBookDto { @Getter @Builder @NoArgsConstructor @AllArgsConstructor - public static class AccountBookResponse{ - private Long accountBookId; - private Long expenditure; - private Long income; - private Long budget; - private Integer month; - private Integer year; - - public static AccountBookResponse of(Long accountBookId, Long expenditure, Long income, - Long nowBudget, Integer month, Integer year){ - return AccountBookResponse.builder() - .accountBookId(accountBookId) - .expenditure(expenditure) - .income(income) - .budget(nowBudget-expenditure) - .month(month) - .year(year) - .build(); - } + public static class AccountBookCategoryResponse{ + private TransactionCategory transactionCategory; + private Long price; } + @Getter @NoArgsConstructor @AllArgsConstructor @@ -50,10 +41,42 @@ public static BudgetResponse of(Long accountBookId, Long budget){ public static class BudgetRequest{ public static AccountBook toEntity(Integer year, Integer month, Long amount){ return AccountBook.builder() + .expenditure(0L) + .income(0L) .budget(amount) .year(year) .month(month) .build(); } } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AccountBookResponse { + private Long expenditure; + private Long income; + private Long budget; + + private ExpenseDto expenseDto; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ExpenseDto{ + private Long food; + private Long transport; + private Long culture; + private Long daily; + private Long trade; + private Long beauty; + private Long health; + private Long education; + private Long fix; + private Long OTT; + private Long etc; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java index 526dd13..c984bbd 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java @@ -30,16 +30,16 @@ public static MemoResponse from(Memo memo){ @Getter public static class MemoListResponse{ - private List memos; + private List memos; - public MemoListResponse(List memos){ + public MemoListResponse(List memos){ this.memos = memos; } public static MemoListResponse of(List memoList){ - List memoResponses = memoList + List memoResponses = memoList .stream() - .map(MemoDto.MemoResponse::from) + .map(MemoResponse::from) .collect(Collectors.toList()); return new MemoListResponse(memoResponses); @@ -57,7 +57,6 @@ public Memo toEntity(AccountBook accountBook){ return Memo.builder() .accountBook(accountBook) .memo(memo) - .done(done) .build(); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java new file mode 100644 index 0000000..7587d89 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java @@ -0,0 +1,108 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import com.umc.DongnaeFriend.domain.type.PayCategory; +import com.umc.DongnaeFriend.domain.type.TransactionCategory; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.stream.Collectors; + +public class TransactionDto { + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class TransactionRequest{ + private Integer year; + private Integer month; + private Integer day; + private Integer type; + private Long price; + private TransactionCategory transactionCategory; + private PayCategory payCategory; + private String categoryMemo; + + public Transaction toEntity(AccountBook accountBook){ + return Transaction.builder() + .type(type) // 0이면 지출, 1이면 수입 + .transactionCategory(transactionCategory) + .year(year) + .month(month) + .day(day) + .price(price) + .payCategory(payCategory) + .categoryMemo(categoryMemo) + .accountBook(accountBook) + .build(); + } + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class TransactionResponse{ + private Long id; + private Integer type; + private TransactionCategory transactionCategory; + private Integer year; + private Integer month; + private Integer day; + private Long price; + private PayCategory payCategory; + private String memo; + + public static TransactionResponse from(Transaction transaction){ + return new TransactionResponse( + transaction.getId(), + transaction.getType(), + transaction.getTransactionCategory(), + transaction.getYear(), + transaction.getMonth(), + transaction.getDay(), + transaction.getPrice(), + transaction.getPayCategory(), + transaction.getCategoryMemo()); + } + } + + @Getter + public static class TransactionListResponse{ + private List transactions; + + public TransactionListResponse(List transactions){ + this.transactions = transactions; + } + + public static TransactionListResponse of(List transactionList){ + List transactionResponses = transactionList + .stream() + .map(TransactionResponse::from) + .collect(Collectors.toList()); + + return new TransactionListResponse(transactionResponses); + } + } + + + @Getter + @NoArgsConstructor + public static class TransactionByCategory{ + private TransactionCategory transactionCategory; + private Long price; + private Long expenditure; + private Long income; + private Long budget; + + public TransactionByCategory(TransactionCategory transactionCategory, Long price, Long expenditure, Long income, Long budget) { + this.transactionCategory = transactionCategory; + this.price = price; + this.expenditure = expenditure; + this.income = income; + this.budget = budget; + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java index 6eafd97..bc13412 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java @@ -30,7 +30,7 @@ public class Memo extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String memo; - @Column(nullable = false) + //@Column(nullable = false) private Boolean done; public void updateMemo(MemoDto.MemoRequest request){ diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java index 4bcbf99..3c7c7e1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java @@ -7,6 +7,8 @@ import static lombok.AccessLevel.PROTECTED; import com.umc.DongnaeFriend.domain.BaseTimeEntity; +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; import com.umc.DongnaeFriend.domain.type.PayCategory; import com.umc.DongnaeFriend.domain.type.TransactionCategory; import javax.persistence.*; @@ -52,4 +54,15 @@ public class Transaction extends BaseTimeEntity { @Column(nullable = false) private Integer day; + + public void updateTransaction(TransactionDto.TransactionRequest request, AccountBook accountBook){ + this.accountBook = accountBook; + this.categoryMemo = request.getCategoryMemo(); + this.year = request.getYear(); + this.month =request.getMonth(); + this.day = request.getDay(); + this.price = request.getPrice(); + this.payCategory = request.getPayCategory(); + + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java index a0703a5..6db1810 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java @@ -3,13 +3,47 @@ import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import javax.transaction.Transactional; import java.util.Optional; public interface AccountBookRepository extends JpaRepository, AccountBookRepositoryCustom { - // 지난 달 지출액 확인 - - Optional findByIdAndYearAndMonth(Long accountBookId, Integer year, Integer month); + //Optional findByIdAndYearAndMonth(Long accountBookId, Integer year, Integer month); Optional findByYearAndMonth(Integer year, Integer month); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.expenditure = ab.expenditure + :expenditure " + + "where ab.id = :accountBookId") + void updateAccountBookExpenditure(@Param("accountBookId")Long accountBookId, @Param("expenditure")Long expenditure); + + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.income = ab.income + :income " + + "where ab.id = :accountBookId") + void updateAccountBookIncome(@Param("accountBookId")Long accountBookId, @Param("income")Long income); + + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.expenditure = ab.expenditure - :expenditure " + + "where ab.id = :accountBookId") + void updateAccountBookExpenditureDelete(@Param("accountBookId")Long accountBookId, @Param("expenditure")Long expenditure); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.income = ab.income - :income " + + "where ab.id = :accountBookId") + void updateAccountBookIncomeDelete(@Param("accountBookId")Long accountBookId, @Param("income")Long income); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.expenditure = ab.expenditure - :expenditureGap " + + "where ab.id = :accountBookId") + void updateAccountBookExpenditureEdit(@Param("accountBookId")Long accountBookId, @Param("expenditureGap")Long expenditureGap); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.income = ab.income + :incomeGap " + + "where ab.id = :accountBookId") + void updateAccountBookIncomeEdit(@Param("accountBookId")Long accountBookId, @Param("incomeGap")Long incomeGap); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java index ba4b8c5..aed8d63 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java @@ -1,5 +1,11 @@ package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; +import com.querydsl.core.Tuple; +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; + +import java.util.List; + public interface AccountBookRepositoryCustom { + List getAccountBook(Integer year, Integer month); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java index b2c92a7..cf34ec9 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -1,12 +1,41 @@ package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; +import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; + +import static com.umc.DongnaeFriend.domain.account.book.entity.QTransaction.transaction; + +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import lombok.RequiredArgsConstructor; +import java.util.ArrayList; +import java.util.List; + @RequiredArgsConstructor public class AccountBookRepositoryCustomImpl implements AccountBookRepositoryCustom { private final JPAQueryFactory queryFactory; + @Override + public AccountBookDto.ExpenseDto getAccountBook(Integer year, Integer month) { + + List result = queryFactory + .select(transaction.transactionCategory, transaction.price.sum()) + .from(transaction) + .where(transaction.month.eq(month).and(transaction.year.eq(year))) + .groupBy(transaction.transactionCategory) + .fetch(); + + AccountBookDto.ExpenseDto accountBookList = new AccountBookDto.ExpenseDto(); + for (Tuple tuple : result) { + AccountBookDto.AccountBookCategoryResponse response + = AccountBookDto.AccountBookCategoryResponse.builder() + .price(tuple.get(transaction.price.sum())) + .transactionCategory(tuple.get(transaction.transactionCategory)) + .build(); + accountBookList. + } + return accountBookList; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java index ad1664e..e6d216e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java @@ -1,11 +1,9 @@ package com.umc.DongnaeFriend.domain.account.book.repository.memo; import com.querydsl.jpa.impl.JPAQueryFactory; -import com.umc.DongnaeFriend.domain.account.book.entity.Memo; -import com.umc.DongnaeFriend.domain.account.book.entity.QAccountBook; +import static com.umc.DongnaeFriend.domain.account.book.entity.QAccountBook.accountBook; import com.umc.DongnaeFriend.domain.account.book.entity.QMemo; -import static org.springframework.data.jpa.domain.Specification.where; public class MemoRepositoryCustomImpl implements MemoRepositoryCustom{ @@ -17,8 +15,8 @@ public MemoRepositoryCustomImpl(JPAQueryFactory jpaQueryFactory) { @Override public Integer getMemoCnt(Integer year, Integer month) { - QMemo memo = QMemo.memo1; - QAccountBook accountBook = QAccountBook.accountBook; + QMemo memo = QMemo.qMemo; + return Math.toIntExact(jpaQueryFactory .select(memo.count()) .from(memo) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java new file mode 100644 index 0000000..402b53a --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java @@ -0,0 +1,23 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.transaction; + +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface TransactionRepository extends JpaRepository, TransactionRepositoryCustom { + + @Query(value = "select t from Transaction t where t.year = :year and t.month = :month") + List findByYearAndMonth(@Param("year") Integer year, @Param("month") Integer month); + +/* @Query(value = "select new com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto.TransactionByCategory(tr.transactionCategory, SUM(tr.price)) " + + "from Transaction tr " + + "where tr.year = :year and tr.month = :month " + + "group by tr.transactionCategory") + TransactionDto.TransactionByCategory getTransactionByYearAndMonth(@Param("year") Integer year, @Param("month") Integer month);*/ +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java new file mode 100644 index 0000000..7fd97e0 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java @@ -0,0 +1,4 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.transaction; + +public interface TransactionRepositoryCustom { +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java new file mode 100644 index 0000000..1c64433 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java @@ -0,0 +1,4 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.transaction; + +public class TransactionRepositoryCustomImpl implements TransactionRepositoryCustom{ +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java index f93c28b..2d407fc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -1,5 +1,6 @@ package com.umc.DongnaeFriend.domain.account.book.service; +import com.querydsl.core.Tuple; import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.util.List; @Slf4j @Service @@ -18,7 +20,6 @@ public class AccountBookService { // User 권한 확인 // private final AccountBookRepository accountBookRepository; - private final TransactionRepository transactionRepository; // 가계부 예산 설정 (한달) @@ -36,5 +37,18 @@ public AccountBookDto.BudgetResponse getBudget(Integer year, Integer month){ // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 -> 가계부 예산 총합 조회 로직 필요 + public AccountBookDto.ExpenseDto getAccountBook(Integer year, Integer month){ + return accountBookRepository.getAccountBook(year, month); + } + + public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, Integer month){ + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + return AccountBookDto.AccountBookResponse.builder() + .income(accountBook.getIncome()) + .expenditure(accountBook.getExpenditure()) + .expenseDto(getAccountBook(year, month)) + .build(); + } + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java index ae2ceda..22ad46c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java @@ -37,7 +37,7 @@ public void createMemo(MemoDto.MemoRequest memoRequest, Integer year, Integer mo AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); Integer memoCnt = memoRepository.getMemoCnt(year, month); - if(memoCnt<5){ + if(memoCnt<8){ memoRepository.save(memoRequest.toEntity(accountBook)); }else{ // 개수 초과 예외처리 diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java new file mode 100644 index 0000000..53aabba --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java @@ -0,0 +1,100 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.querydsl.core.Tuple; +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; +import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TransactionService { + + /** + * 월별 가계부 지출 및 수입 업데이트 시 지출(예산) 총액이 0보다 작아지면 예외 발생하게 만들기 + * 유저 권한 확인 필요 + */ + + private final TransactionRepository transactionRepository; + private final AccountBookRepository accountBookRepository; + + // 지출 또는 수입 내역 추가 + @Transactional + public void createTransaction(TransactionDto.TransactionRequest request){ + + log.info("Year : " + request.getYear() + " Month : " + request.getMonth()); + AccountBook accountBook = findTarget(request.getYear(), request.getMonth()); + + transactionRepository.save(request.toEntity(accountBook)); + + // AccountBook income, expenditure 값 변경 + + if(request.getType()==1){ + log.info("Price 추가 : " + request.getPrice()); + + accountBookRepository.updateAccountBookIncome(accountBook.getId(), request.getPrice()); + }else{ + log.info("Price 추가 : " + request.getPrice()); + + accountBookRepository.updateAccountBookExpenditure(accountBook.getId(), request.getPrice()); + } + } + + // 지출 또는 수입 내역 조회 + public TransactionDto.TransactionListResponse getTransactions(Integer year, Integer month){ + + List transactionList = transactionRepository.findByYearAndMonth(year, month); + return TransactionDto.TransactionListResponse.of(transactionList); + } + + // 지출 또는 수입 내역 삭제 + @Transactional + public void deleteTransaction(Long transactionId){ + + Transaction transaction = transactionRepository.findById(transactionId).orElseThrow(); + AccountBook accountBook = findTarget(transaction.getYear(), transaction.getMonth()); + + // AccountBook income, expenditure 값이 변경되어야 함. + if(transaction.getType()==1){ + log.info("Price 삭제: " + transaction.getPrice()); + accountBookRepository.updateAccountBookIncomeDelete(accountBook.getId(), transaction.getPrice()); + }else{ + log.info("Price 삭제 : " + transaction.getPrice()); + + accountBookRepository.updateAccountBookExpenditureDelete(accountBook.getId(), transaction.getPrice()); + } + transactionRepository.deleteById(transaction.getId()); + } + + // 지출 또는 수입 내역 수정 + @Transactional + public void updateTransaction(TransactionDto.TransactionRequest request, Long transactionId){ + Transaction transaction = transactionRepository.findById(transactionId).orElseThrow(); + AccountBook accountBook = findTarget(transaction.getYear(), transaction.getMonth()); + + Transaction updateTrans = request.toEntity(accountBook); + Long priceGap = updateTrans.getPrice()-transaction.getPrice(); + log.info("priceGap : " + priceGap); + + if(transaction.getType()==1){ + accountBookRepository.updateAccountBookIncomeEdit(accountBook.getId(), priceGap); + }else{ + accountBookRepository.updateAccountBookExpenditureEdit(accountBook.getId(), priceGap); + } + + transaction.updateTransaction(request, accountBook); + } + + private AccountBook findTarget(Integer year, Integer month){ + return accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + } +} From 7cb42e418b24f68ec209ad3c81196e41bccede03 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 22 Jul 2023 01:38:58 +0900 Subject: [PATCH 21/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#21:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80]=20=EA=B0=80=EA=B3=84=EB=B6=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.1.1/checksums/checksums.lock | Bin 17 -> 17 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes build.gradle | 3 ++ out/production/resources/application.yml | 6 +-- .../controller/AccountBookController.java | 2 +- .../account/book/dto/AccountBookDto.java | 38 +++++++------- .../domain/account/book/dto/Expense.java | 13 +++++ .../accountBook/AccountBookRepository.java | 8 +++ .../AccountBookRepositoryCustom.java | 5 +- .../AccountBookRepositoryCustomImpl.java | 49 ++++++++---------- .../memo/MemoRepositoryCustomImpl.java | 4 +- .../book/service/AccountBookService.java | 15 ++++-- .../domain/type/TransactionCategory.java | 1 + src/main/resources/application.yml | 6 +-- 16 files changed, 89 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock index e1fd04a65f90b5d0b3ff8b18e6110e9df7eac7ef..f434bb1cbf351ec2e6a24efd38f21df209785d4d 100644 GIT binary patch literal 17 UcmZS1@)rBFze>lD0Ss7d0V=Npm;e9( literal 17 UcmZS1@)rBFze>lD0Ss6a04kCLdjJ3c diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index bcebded2b67760436c418d4afab390d256962a20..b1970b69e24d5ad7350ed16e15041d73bc83238a 100644 GIT binary patch literal 17 UcmZR6(Xu4+XJ*)A1_%%b06&@q9{>OV literal 17 UcmZR6(Xu4+XJ*)A1_)pS06&QZ4gdfE diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index ec0e6c6374a612071839bd64a9281f4a16627aed..e0dd6bbd3642215954c748349d07a28e5234b81c 100644 GIT binary patch literal 17 VcmZQxwBy}@)CWuC8Nh%^002SX1ttIh literal 17 UcmZQxwBy}@)CWuC86aRL077I1tpET3 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index ba39c1de61638a0bf7f5838c0a2e6c1fb4ad36f4..1054d292247ebbb034ff05fc3331097137480bd9 100644 GIT binary patch literal 17 TcmZSP49tkBPWf@20Rj>LE1m=} literal 17 TcmZSP49tkBPWf@20Rn^oD^LUC diff --git a/build.gradle b/build.gradle index 6516761..a19ad82 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,9 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + //gson + implementation 'com.google.code.gson:gson:2.8.8' } tasks.named('test') { diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml index 9cdc5de..196b4bb 100644 --- a/out/production/resources/application.yml +++ b/out/production/resources/application.yml @@ -13,8 +13,8 @@ spring: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: Tnqls9004^^ + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create-drop \ No newline at end of file + hibernate.ddl-auto: update \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java index badd49a..488b574 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -30,7 +30,7 @@ public void createBudget(@RequestParam(value = "year", required = false) Integer @GetMapping("/category") public List getTransactionAll(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month){ - return accountBookService.getAccountBook(year, month); + return null; } @GetMapping("/all") diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java index df29a9c..f4161dd 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java @@ -1,17 +1,11 @@ package com.umc.DongnaeFriend.domain.account.book.dto; -import com.querydsl.core.annotations.QueryProjection; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; -import com.umc.DongnaeFriend.domain.account.book.entity.Memo; import com.umc.DongnaeFriend.domain.type.TransactionCategory; -import com.umc.DongnaeFriend.domain.user.entity.User; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; +import lombok.extern.slf4j.Slf4j; import java.util.List; -import java.util.stream.Collectors; public class AccountBookDto { @@ -59,24 +53,30 @@ public static class AccountBookResponse { private Long income; private Long budget; - private ExpenseDto expenseDto; + private List expense; } @Getter @Builder @NoArgsConstructor @AllArgsConstructor + @Slf4j public static class ExpenseDto{ - private Long food; - private Long transport; - private Long culture; - private Long daily; - private Long trade; - private Long beauty; - private Long health; - private Long education; - private Long fix; + private Long FOODS; + private Long TRANSPORTATION; + private Long CULTURE; + private Long DAILY_NECESSITY; + private Long SECOND_HAND; + private Long FASHION; + private Long HEALTH; + private Long EDUCATION; + private Long FIXED_EXPENSES; private Long OTT; - private Long etc; + private Long ETC; + + + } + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java new file mode 100644 index 0000000..83107ce --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java @@ -0,0 +1,13 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.type.TransactionCategory; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Expense { + public TransactionCategory category; + public long price; + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java index 6db1810..31c14b6 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java @@ -1,5 +1,6 @@ package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; import org.springframework.data.jpa.repository.JpaRepository; @@ -8,6 +9,7 @@ import org.springframework.data.repository.query.Param; import javax.transaction.Transactional; +import java.util.List; import java.util.Optional; public interface AccountBookRepository extends JpaRepository, AccountBookRepositoryCustom { @@ -46,4 +48,10 @@ public interface AccountBookRepository extends JpaRepository, + "set ab.income = ab.income + :incomeGap " + "where ab.id = :accountBookId") void updateAccountBookIncomeEdit(@Param("accountBookId")Long accountBookId, @Param("incomeGap")Long incomeGap); + + @Query(value = "SELECT transaction.transaction_category, SUM(transaction.price) as sum_price " + + "from transaction " + + "where transaction.month = :month and transaction.year = :year " + + "group by transaction.transaction_category", nativeQuery = true) + Object[] getAccountBookGroupByCategory (@Param("month") long month, @Param("year") long year); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java index aed8d63..fb2a534 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java @@ -1,11 +1,10 @@ package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; -import com.querydsl.core.Tuple; -import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.dto.Expense; import java.util.List; public interface AccountBookRepositoryCustom { - List getAccountBook(Integer year, Integer month); + List getAccountBook(Integer year, Integer month); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java index cf34ec9..35e8771 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -1,41 +1,38 @@ package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; -import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; -import static com.umc.DongnaeFriend.domain.account.book.entity.QTransaction.transaction; - -import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.dto.Expense; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; -import java.util.ArrayList; +import javax.persistence.EntityManager; import java.util.List; +@Slf4j @RequiredArgsConstructor +@Repository public class AccountBookRepositoryCustomImpl implements AccountBookRepositoryCustom { - private final JPAQueryFactory queryFactory; + private final EntityManager em; @Override - public AccountBookDto.ExpenseDto getAccountBook(Integer year, Integer month) { - - List result = queryFactory - .select(transaction.transactionCategory, transaction.price.sum()) - .from(transaction) - .where(transaction.month.eq(month).and(transaction.year.eq(year))) - .groupBy(transaction.transactionCategory) - .fetch(); - - AccountBookDto.ExpenseDto accountBookList = new AccountBookDto.ExpenseDto(); - - for (Tuple tuple : result) { - AccountBookDto.AccountBookCategoryResponse response - = AccountBookDto.AccountBookCategoryResponse.builder() - .price(tuple.get(transaction.price.sum())) - .transactionCategory(tuple.get(transaction.transactionCategory)) - .build(); - accountBookList. - } - return accountBookList; + public List getAccountBook (@Param("year") Integer year,@Param("month") Integer month) { + + return em.createQuery( + "select new com.umc.DongnaeFriend.domain.account.book.dto.Expense(t.transactionCategory, sum(t.price))" + + "from Transaction t where t.year= :year and t.month= :month group by t.transactionCategory", Expense.class) + .setParameter("year", year) + .setParameter("month", month) + .getResultList(); } } + +// .select(transaction.transactionCategory, transaction.price.sum()) +// .from(transaction) +// .where(transaction.month.eq(month).and(transaction.year.eq(year))) +// .groupBy(transaction.transactionCategory) +// .fetch().toArray(); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java index e6d216e..91c16a3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java @@ -4,6 +4,8 @@ import static com.umc.DongnaeFriend.domain.account.book.entity.QAccountBook.accountBook; import com.umc.DongnaeFriend.domain.account.book.entity.QMemo; +import javax.persistence.EntityManager; + public class MemoRepositoryCustomImpl implements MemoRepositoryCustom{ @@ -15,7 +17,7 @@ public MemoRepositoryCustomImpl(JPAQueryFactory jpaQueryFactory) { @Override public Integer getMemoCnt(Integer year, Integer month) { - QMemo memo = QMemo.qMemo; + QMemo memo = QMemo.memo1; return Math.toIntExact(jpaQueryFactory .select(memo.count()) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java index 2d407fc..ed5f07f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -1,5 +1,10 @@ package com.umc.DongnaeFriend.domain.account.book.service; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.util.JSONPObject; +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; import com.querydsl.core.Tuple; import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; @@ -7,9 +12,11 @@ import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.jackson.JsonObjectSerializer; import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.util.Arrays; import java.util.List; @Slf4j @@ -37,16 +44,14 @@ public AccountBookDto.BudgetResponse getBudget(Integer year, Integer month){ // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 -> 가계부 예산 총합 조회 로직 필요 - public AccountBookDto.ExpenseDto getAccountBook(Integer year, Integer month){ - return accountBookRepository.getAccountBook(year, month); - } - public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, Integer month){ + public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, Integer month) { AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); return AccountBookDto.AccountBookResponse.builder() .income(accountBook.getIncome()) .expenditure(accountBook.getExpenditure()) - .expenseDto(getAccountBook(year, month)) + .budget(accountBook.getBudget()) + .expense(accountBookRepository.getAccountBook(year,month)) .build(); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java index a77a048..f1e4902 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java @@ -1,6 +1,7 @@ package com.umc.DongnaeFriend.domain.type; import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9cdc5de..196b4bb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,8 +13,8 @@ spring: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: Tnqls9004^^ + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create-drop \ No newline at end of file + hibernate.ddl-auto: update \ No newline at end of file From ccc02cc6c5b4a5b23fdcaabcd569b30323b28420 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sun, 23 Jul 2023 20:10:30 +0900 Subject: [PATCH 22/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#21:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EA=B2=80=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/SharingBoardRepository.java | 12 ------------ .../accountBookSharingController.java | 12 ++++++++++-- .../{book => sharing}/dto/SharingDto.java | 0 .../repository/SharingBoardRepository.java | 19 +++++++++++++++++++ .../service/AccountBookSharingService.java} | 0 .../AccountBookSharingServiceImpl.java} | 5 ++--- 6 files changed, 31 insertions(+), 17 deletions(-) delete mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java rename src/main/java/com/umc/DongnaeFriend/domain/account/{book => sharing}/controller/accountBookSharingController.java (65%) rename src/main/java/com/umc/DongnaeFriend/domain/account/{book => sharing}/dto/SharingDto.java (100%) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java rename src/main/java/com/umc/DongnaeFriend/domain/account/{book/service/accountBookSharingService.java => sharing/service/AccountBookSharingService.java} (100%) rename src/main/java/com/umc/DongnaeFriend/domain/account/{book/service/accountBookSharingServiceImpl.java => sharing/service/AccountBookSharingServiceImpl.java} (88%) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java deleted file mode 100644 index a334c39..0000000 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/SharingBoardRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.umc.DongnaeFriend.domain.account.book.repository; - -import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; - -import java.util.List; - -public interface SharingBoardRepository extends JpaRepository { - -} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java similarity index 65% rename from src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java rename to src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index 5dca23c..f8da3e5 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -10,11 +10,19 @@ public class accountBookSharingController { /** * [가계부 공유] 게시글 검색 + * @param keyword + * @param pageable + * + * + * size : 페이지 사이즈 + * page : 페이지 + * sortBy : 정렬순 + * - */ @GetMapping("/search") - public ResponseEntity searchAll(@RequestParam("keyword")String keyword, Pageable pageable) { - + public ResponseEntity searchAll(@RequestParam("keyword")String keyword, @RequestParam("category") int category, Pageable pageable) { + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java similarity index 100% rename from src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/SharingDto.java rename to src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java new file mode 100644 index 0000000..51e1b58 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -0,0 +1,19 @@ +package com.umc.DongnaeFriend.domain.account.book.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface SharingBoardRepository extends JpaRepository { + + @Query(value = "SELECT sharing_board.*, COUNT(sharing_sympathy.sharing_board_id) AS like FROM sharing_board\n" + + "LEFT JOIN sharing_sympathy ON sharing_board.sharing_board_id = sharing_sympathy.sharing_board_id\n" + + "WHERE (sharing_board.title LIKE %?1% OR sharing_board.content LIKE %?2%)\n" + + "AND sharing_board.category = ?2 GROUP BY sharing_board.sharing_board_id ;", nativeQuery = true) + List findByKeywordAAndCategory(String keyword, String category, Pageable pageable); + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java similarity index 100% rename from src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingService.java rename to src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java similarity index 88% rename from src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java rename to src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index 2e1a00d..b437742 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/accountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -5,6 +5,7 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.SharingCategory; import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; import org.springframework.beans.factory.annotation.Autowired; @@ -28,11 +29,9 @@ public class accountBookSharingServiceImpl implements accountBookSharingService /* * [가계부 공유] 게시글 검 - * Pageable : page, size, sortBy - * @param sort */ public List searchByKeyword(String keyword, int category, Pageable pageable) { - sharingBoardRepository + sharingBoardRepository.findByKeywordAAndCategory(keyword, SharingCategory.valueOf(category).name(), pageable); } } From 2b8bd4898ad846f6ab117b963086bfcf099867a0 Mon Sep 17 00:00:00 2001 From: soogoori Date: Mon, 24 Jul 2023 00:19:12 +0900 Subject: [PATCH 23/58] =?UTF-8?q?=E2=9C=A8Feat=20#29=20:=20[=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.1.1/checksums/checksums.lock | Bin 17 -> 17 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../domain/user/entity/User.class | Bin 3648 -> 4634 bytes out/production/resources/application.yml | 7 ++- .../account/book/dto/AccountBookDto.java | 25 --------- .../domain/account/book/dto/Expense.java | 1 - .../AccountBookRepositoryCustomImpl.java | 2 - .../book/service/AccountBookService.java | 23 ++------ .../book/service/TransactionService.java | 2 - .../domain/dongnae/dto/UserLocationDto.java | 11 ++++ .../profile/controller/MyPageController.java | 27 +++++++++ .../profile/dto/AccountBookProfileDto.java | 4 ++ .../domain/profile/dto/DongnaeProfileDto.java | 9 +++ .../domain/profile/dto/MyPageDto.java | 53 ++++++++++++++++++ .../domain/profile/service/MyPageService.java | 51 +++++++++++++++++ .../domain/type/TransactionCategory.java | 28 ++++++--- .../domain/user/entity/User.java | 41 ++++++++++++++ .../user/repository/UserRepository.java | 11 ++++ src/main/resources/application.yml | 7 ++- 21 files changed, 240 insertions(+), 62 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock index f434bb1cbf351ec2e6a24efd38f21df209785d4d..5333e79891f1e639e39ae5bedb6ee0c6b21f244f 100644 GIT binary patch literal 17 UcmZS1@)rBFze>lD0Ss6?04llzqW}N^ literal 17 UcmZS1@)rBFze>lD0Ss7d0V=Npm;e9( diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index b1970b69e24d5ad7350ed16e15041d73bc83238a..8ce92417067146e05fb80162cf7b064fc94e2a26 100644 GIT binary patch literal 17 UcmZR6(Xu4+XJ*)A1_+P^06(AwB>(^b literal 17 UcmZR6(Xu4+XJ*)A1_%%b06&@q9{>OV diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index e0dd6bbd3642215954c748349d07a28e5234b81c..a403c63737924b673cd2c141dd1666284acee29e 100644 GIT binary patch literal 17 VcmZQxwBy}@)CWuC8Nh%k1OP%K1!@2Q literal 17 VcmZQxwBy}@)CWuC8Nh%^002SX1ttIh diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 1054d292247ebbb034ff05fc3331097137480bd9..69550e3fe73a2285b9b907cdca629ae03104e629 100644 GIT binary patch literal 17 TcmZSP49tkBPWf@20Rl1rE2acE literal 17 TcmZSP49tkBPWf@20Rj>LE1m=} diff --git a/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class b/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class index df7c8953399c7d97fa16c1b8929c33efefe76df6..a2e78b92fc90039fa19996038bb0aaad9ebdc58e 100644 GIT binary patch literal 4634 zcmb7GYj+bx7=AaG=C-}i(rU^@1cWv%L{a3f_KGQOfi_f&Aa0Xsx-{7>$p)z69sNCe z4k_p8Iezqmzs29+@p)%AX}V0(aB|MfJ3H_5%zK^5KmYyl7ZF{cUt=^#kK!20ELB)? zSgNx0n58EyJ!NT|rLQCOO`H<+jK6%#!*@J<&%+Nq{K&&kJp3G|A$k^}=Mnlvqr{zx zC{I?+VqTOr(leGN%2P$7QV|u60%l&LzWIm7VTTll!Qi+D!hHbUPbb7#WL{i{Cv(XrK_b}dfNRo zTQ-H2Pv`BDVOp4^URuCoXS=Qg$|H*N77S}UYu~ikwD7ucavN&BS>Ezo2+dF2h51Jn zbaS?8HC%{$mPqrXR<&3(5c?nsh7dQ)%x$_p_Ddo+U&~I}lo<;PI8#J|x61aqSrnO) zQGoAJ$9`f>iL#^7X!|fYhs`y)rOe`W zRAJqYDGR0yGt#{d z$l9C2Ld9$vn}(f1?Q~bS@+i__Wj+-_G!S5T2tb{-Mxoi{D9SS_uI za+dR{QUAQ1Gm0xl+2pnNG30ERXs+~Y9;8v+wUv+6sK;F_Hfm*Xq$$*1v9NL7%Z`!T zTrjrkHtq4)E1sD95phFK_6dP3AC54y>n_mEkw#}a!Fma0xaUQtk*M)b2;ACbd}OVD z-CY~mr|SKgJIQhMZc8rnf^fJX`oZ(cB^k%2ccW-@VZW1FUNZ^M>?Z8so|78w9fi`2 z+u^+sy~_0R#0=R+pO5Wl$(~N{X~N3h9Nc5TZg<9@SWoD9M@KYT6pii3A{y-o=k_T( zwOaw~^wOSg<>=q2H*D8c(=wfpa2t%E0JN3ns+Uh%`?hM4o2Ha|iRkD{+t;Qk_)TQ> zFt;~TV!fz#pviIUK+Wx&CSzXpRfdo|E52-3%Q-QN2S%e9_sUsr3-#MPBOg?BQBsoc z{l_5h9qushKwNx@MNx4U1YeUCoz7BPrwq;MbeXQ`bdzrBbd|2@v_OkGy~n%ry!#Qo zuhVT>(&$p#sJCl#oi@nSDM`aRouqekdY9?XG4n;bq|?W|{Dg*akG<9z8jZEppEN2W zi~m?|nCNZ%a~r}_uTy|+!IOUot6>V#Va!LcJ}T%fItE4jb*j(_=)qi1?+{j}AfFaA zLZg(z5;|ivewWTbMm#;m1ZHONHsGsz12M+20gi*GFoe|ykk1SH5PxBtNDwA936ke+ zbYpG;2RNIpwvg0TTgZj93hBT+2(<~C#5jf3BiI+fJenGNLD~)lcn9g6=hsirXwQy0cbih`(*rs++ZL7-<5%IlB_d6C5UavduiL7zg>@I#Gy$KUjh zkB|M$N7P7T{vgkK)%|7+)ZW^IU2SVdC*UO59Iej{-6c9TSQId==WCSF+cel z$a5eUEy&$kYmjsNvL5*{nRKG)pOjdAN&0VyohH-Sg_)=y;~iS@v^l!`HJo}u-K-jD zQavnB*IflK;~FCRxdPnd2Om>{SLv<-togwwl;AIv;9fuYloEVT36A)|BTDdn`ch$b zpC3G~1V5m!6yO7Xa9RmAXiWhQ`oZUv;2h-@;IJQjUI`XTpJRUTMJ0G$8SQ>Q__7jQ zP?qO_AAD5-4)Lq_iq9|UAa_`EZ4W5G0e~NR;D4dr4a{5$V7?c-Q{y%2Nu9wBnM#Ig z)SF6%YZOT(yK2;zN=9mQAeD^PD40sdYUrnAyhgE9GEt-cR8p_efZu|H(t_viDUJJd z&U;1q-sN|aZ}2&J$GUehzkDJ2jjzVAl=!jZmtc-xeu_wmub-%t_?C-FiEoX#l=wkP rNQs{$9gLe;1*j-r?_NkHtS!Xic!g}*!Xku40#6Kqf~7%vgJS;!tWny4 literal 3648 zcmb7H=~5d<5bhPawHO-%iF^egv0=eh;)M8if;k*vAv++G;2icM4PuQnOYN?l@IMcf zR7K^gq$&@PXUQ|9^7Uv@#4^YVKYDw1`s?ZL`MOv9_0R8r645PkQ}i-R2EEGANwQgN zv8b}Bu@Ee_S=3qVuy9zsX0gknk)>1gDn-o{NrQ6Fec?T7IgOg|3^I#S3U8rd`@ZlE zia9ldPL^KVZ|p+Dmi0o(mGyfD<=0v=aGGMn@tv)Pn3vKG?7(p)FcZrBr^24_e8&%j ztcpUh2GAwV#$$ow>_F5u>_$t#DD4NluJ8A?$4Qm_J!M~9Tq;+Jl}&@rX#6j@jaE~_ zZ(Q0+sScMIqKZkdf++g#u5U_G;qOtp1bWdM6qetk$XCDf0PTt3k;g>UxonnE^G?F z>>@Q?tV^=h?A#^i{)X?rt?RF|+dScrX{!Yc+73h@IuDxr!Mdr@dLBBkhdPmuq zZwJ)jPP@|6Zip_v;MP#4k&+`txz*efUWG3e1+0sJj~c}RN7`?+V;y7Q0i?)zWvF?ZABB)o`$-t?V{J;m>Fc2MU2VJd7`)d4KIjsuu= zW>ZfvM{`wQFBF!t>u$@die(H!gEHKbH@M04-;gCW_|YhN<^1rMO*J3(65Lp5zg$`P z!K&a+#_CSr8b*7ucQ%-`L0_9RM&l-ZK$9j-lV#Eji&+-e>4r(4(5EKN(Pt)p8QeDM z4!^t0yZ30^pzHtZaD!(0+CQ>=QNbs_Qw_R^9}=hV)9OL>Pw}q-7w}rbva)*KAKO<2Ft5Szw&OwZ9HyfHflv_Okk8MH*p zkWp|v3ZB%0AJdl_a3Tu6tOXaf;A9khRSRCxf>TlOlotGiN}90KQShu5yh>#aI1>dI zwBV=oOasnF!8f(wuV_sJ&PBme_z<2>Gu z4Hl?k6 zs!bUypKepu%4gb?v+~(CnN~j6reP~@w&_GPf-x1r&z)1k?!tND)MJh38aMNb8eIH? ze1#`9#g)dRDWNnTPD!Ql2udl9XHHsaJYq6R expense; } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Slf4j - public static class ExpenseDto{ - private Long FOODS; - private Long TRANSPORTATION; - private Long CULTURE; - private Long DAILY_NECESSITY; - private Long SECOND_HAND; - private Long FASHION; - private Long HEALTH; - private Long EDUCATION; - private Long FIXED_EXPENSES; - private Long OTT; - private Long ETC; - - - - } - - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java index 83107ce..29ee3e9 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java @@ -9,5 +9,4 @@ public class Expense { public TransactionCategory category; public long price; - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java index 35e8771..13bf271 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -1,11 +1,9 @@ package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; -import com.querydsl.jpa.impl.JPAQueryFactory; import com.umc.DongnaeFriend.domain.account.book.dto.Expense; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java index ed5f07f..b254a1a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -1,30 +1,20 @@ package com.umc.DongnaeFriend.domain.account.book.service; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.util.JSONPObject; -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; -import com.querydsl.core.Tuple; import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; -import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.jackson.JsonObjectSerializer; import org.springframework.stereotype.Service; - import javax.transaction.Transactional; -import java.util.Arrays; -import java.util.List; + @Slf4j @Service @RequiredArgsConstructor public class AccountBookService { - // User 권한 확인 // + // User 권한 확인 필요 // private final AccountBookRepository accountBookRepository; @@ -32,7 +22,9 @@ public class AccountBookService { // 가계부 예산 설정 (한달) @Transactional public void createBudget(Integer year, Integer month, Long budget){ - + this.accountBookRepository.findByYearAndMonth(year, month) + .ifPresent(ab->{throw new IllegalStateException("이미 예산이 설정되어있습니다."); + }); accountBookRepository.save(AccountBookDto.BudgetRequest.toEntity(year, month, budget)); } @@ -43,8 +35,7 @@ public AccountBookDto.BudgetResponse getBudget(Integer year, Integer month){ } - // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 -> 가계부 예산 총합 조회 로직 필요 - + // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, Integer month) { AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); return AccountBookDto.AccountBookResponse.builder() @@ -54,6 +45,4 @@ public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, I .expense(accountBookRepository.getAccountBook(year,month)) .build(); } - - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java index 53aabba..469ca7e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java @@ -1,6 +1,5 @@ package com.umc.DongnaeFriend.domain.account.book.service; -import com.querydsl.core.Tuple; import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; @@ -8,7 +7,6 @@ import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.stereotype.Service; import javax.transaction.Transactional; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java new file mode 100644 index 0000000..d258c4d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java @@ -0,0 +1,11 @@ +package com.umc.DongnaeFriend.domain.dongnae.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class UserLocationDto { + + private String town; +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java new file mode 100644 index 0000000..56b6664 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java @@ -0,0 +1,27 @@ +package com.umc.DongnaeFriend.domain.profile.controller; + + +import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; +import com.umc.DongnaeFriend.domain.profile.service.MyPageService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class MyPageController { + + private final MyPageService myPageService; + + @GetMapping("/api/user") + public MyPageDto.MyPageResponseDto getMyPage(){ + return myPageService.getMyPage(); + } + + @PutMapping("/api/user") + public void updateMyPage(@RequestBody MyPageDto.MyPageRequestDto myPageRequest){ + myPageService.updateMyPage(myPageRequest); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java new file mode 100644 index 0000000..979eb6b --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java @@ -0,0 +1,4 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +public class AccountBookProfileDto { +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java new file mode 100644 index 0000000..e58f617 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java @@ -0,0 +1,9 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class DongnaeProfileDto { + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java new file mode 100644 index 0000000..c127ad6 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java @@ -0,0 +1,53 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class MyPageDto { + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MyPageResponseDto{ + private String nickname; + private String profileImage; + private String town; + private Age age; + private Gender gender; + + public static MyPageResponseDto of(User user, UserLocationDto userLocation){ + return new MyPageResponseDto( + user.getNickname(), + user.getProfileImage(), + userLocation.getTown(), + user.getAge(), + user.getGender()); + } + } + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MyPageRequestDto{ + private String nickname; + private String profileImage; + private Age age; + private Gender gender; + private YesNo infoCert; + + public User toEntity(){ + return User.builder() + .nickname(nickname) + .profileImage(profileImage) + .age(age) + .gender(gender) + .infoCert(infoCert) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java new file mode 100644 index 0000000..7f733b3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java @@ -0,0 +1,51 @@ +package com.umc.DongnaeFriend.domain.profile.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MyPageService { + + /** + * 사용자 정보 확인 필요 ! + */ + + //임시 유저 & 동네 + Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + private final UserRepository userRepository; + + public MyPageDto.MyPageResponseDto getMyPage(){ + //User user = userRepository.findById(userId).orElseThrow(); + return MyPageDto.MyPageResponseDto.of(user, getUserLocation()); + } + + public void updateMyPage(MyPageDto.MyPageRequestDto myPageRequest){ + //User user = userRepository.findById(userId).orElseThrow(); + User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + user.updateProfile(myPageRequest.toEntity()); + + log.info("유저 닉네임 : " + user.getNickname()); + log.info("유저 프로필 : " + user.getProfileImage()); + log.info("유저 age : " + user.getAge()); + log.info("유저 gender : " + user.getGender()); + log.info("유저 infocert : " + user.getInfoCert()); + } + + public UserLocationDto getUserLocation(){ + return new UserLocationDto("한남동"); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java index f1e4902..0c1dfa4 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java @@ -8,18 +8,28 @@ @Getter @RequiredArgsConstructor public enum TransactionCategory { + FOODS(0, "식비"), - TRANSPORTATION(1, "교통비"), - CULTURE(2, "문화"), - DAILY_NECESSITY(3, "생필품"), - SECOND_HAND(4, "중고거래"), - FASHION(5, "미용/패션"), + CAFE_SNACK(1, "카페/간식"), + MART(2, "편의점/마트"), + ALCOHOL_PARTY(3, "술/유흥"), + SHOPPING(4, "쇼핑"), + HOBBY_LEISURE(5, "취미/여가"), HEALTH(6, "건강"), - EDUCATION(7, "교육"), - FIXED_EXPENSES(8, "고정 지출"), - OTT(9, "OTT"), - ETC(10, "기타"); + LIVING_COMMUNICATION(7, "주거/통신"), + INSURANCE_FINANCE(8, "보험/금융"), + BEAUTY(9, "미용"), + TRANSPORTATION(10, "교통비"), + TRAVEL_LODGE(11, "여행/숙박"), + EDUCATION(12, "교육"), + SAVING_INVESTMENT(13, "저축/투자"), + EXPENDITURE_ETC(14, "기타(지출)"), + SALARY(15, "월급"), + ALLOWANCE(16, "용돈"), + TRANSFER(17, "이월"), + WITHDRAW(18, "자산인출"), + INCOME_ETC(18, "기타(수입)"); private final Integer value; private final String category; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java index 1d96f63..c0012ef 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java @@ -58,4 +58,45 @@ public class User extends BaseTimeEntity { private String refreshToken; private Long kakaoId; + + /** + * 유저 정보 업데이트 로직 + */ + public void updateProfile(User updateUser){ + updateNickname(updateUser.nickname); + updateGender(updateUser.gender); + updateAge(updateUser.age); + updateProfileImage(updateUser.profileImage); + updateInfoCert(updateUser.infoCert); + } + + public void updateNickname(String nickname){ + if(nickname!=null){ + this.nickname=nickname; + } + } + + public void updateProfileImage(String profileImage){ + if(profileImage!=null){ + this.profileImage=profileImage; + } + } + + public void updateAge(Age age){ + if(age!=null){ + this.age =age; + } + } + + public void updateGender(Gender gender){ + if(gender!=null){ + this.gender=gender; + } + } + + public void updateInfoCert(YesNo infoCert){ + if(infoCert!=null){ + this.infoCert=infoCert; + } + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java new file mode 100644 index 0000000..fbb81ef --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java @@ -0,0 +1,11 @@ +package com.umc.DongnaeFriend.domain.user.repository; + +import com.umc.DongnaeFriend.domain.user.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 196b4bb..d293f14 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,8 +13,9 @@ spring: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: root - password: qwe335577! + username: dongnae + password: Tnqls9004^^ driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: update \ No newline at end of file + hibernate.ddl-auto: update + database: mysql \ No newline at end of file From 0bc6e0dfc55d5c020c4dfe47146562dc421c1d7e Mon Sep 17 00:00:00 2001 From: soogoori Date: Mon, 24 Jul 2023 00:24:14 +0900 Subject: [PATCH 24/58] =?UTF-8?q?=E2=9C=A8Feat=20#29=20:=20[=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriend/domain/account/book/dto/AccountBookDto.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java index 0ade4e8..5c632c1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java @@ -3,7 +3,6 @@ import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.type.TransactionCategory; import lombok.*; -import lombok.extern.slf4j.Slf4j; import java.util.List; From e6f3a92c65c2f55af0da986023297b9c4bfba93e Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 00:57:09 +0900 Subject: [PATCH 25/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFix=20#25:=20[?= =?UTF-8?q?=EA=B0=80=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EA=B2=80=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- out/production/resources/application.yml | 1 + .../accountBookSharingController.java | 29 ++++++-- .../account/sharing/dto/SharingDto.java | 7 +- .../account/sharing/entity/SharingBoard.java | 5 ++ .../repository/SharingBoardRepository.java | 38 ++++++++-- .../repository/SharingCommentRepository.java | 11 +++ .../repository/SharingImgRepository.java | 15 ++++ .../repository/SharingSympathyRepository.java | 14 ++++ .../service/AccountBookSharingService.java | 11 ++- .../AccountBookSharingServiceImpl.java | 71 ++++++++++++++++--- .../domain/dongnae/dto/DongnaeBoardDto.java | 3 +- .../domain/dongnae/entity/DongnaeBoard.java | 3 - .../service/DongnaeBoardServiceImpl.java | 34 ++------- .../domain/type/SharingCategory.java | 11 +++ .../global/exception/ErrorCode.java | 3 + .../DongnaeFriend/global/util/FileUtil.java | 25 +++++++ .../DongnaeFriend/global/util/TimeUtil.java | 29 ++++++++ src/main/resources/application.yml | 1 + src/main/resources/static/img/.keep | 0 19 files changed, 253 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java create mode 100644 src/main/resources/static/img/.keep diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml index 196b4bb..04772a2 100644 --- a/out/production/resources/application.yml +++ b/out/production/resources/application.yml @@ -8,6 +8,7 @@ spring: properties: hibernate: format_sql: true + show_sql: true --- # Settings for local spring: diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index f8da3e5..eb4c425 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -1,28 +1,47 @@ -package com.umc.DongnaeFriend.domain.account.book.controller; +package com.umc.DongnaeFriend.domain.account.sharing.controller; +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.sharing.service.AccountBookSharingService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; + +@Slf4j @RestController @RequestMapping("/account-books/sharing") public class accountBookSharingController { + @Autowired + AccountBookSharingService accountBookSharingService; + /** * [가계부 공유] 게시글 검색 * @param keyword * @param pageable * - * + * @param pageable * size : 페이지 사이즈 * page : 페이지 * sortBy : 정렬순 - * - + * - like + * - createdAt */ @GetMapping("/search") - public ResponseEntity searchAll(@RequestParam("keyword")String keyword, @RequestParam("category") int category, Pageable pageable) { - + + public ResponseEntity searchAll(@RequestParam("keyword") String keyword, @RequestParam("category") int category, Pageable pageable) { + log.info("searching : " + keyword + category); + List res = accountBookSharingService.searchByKeyword(keyword, category, pageable); + log.info("res "); + return ResponseEntity.ok(res); } + + + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index cc7101d..e9155d7 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -1,4 +1,4 @@ -package com.umc.DongnaeFriend.domain.account.book.dto; +package com.umc.DongnaeFriend.domain.account.sharing.dto; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,7 +12,7 @@ public class SharingDto { @AllArgsConstructor @NoArgsConstructor public static class ListResponse { - private String id; + private Long id; private int category; @@ -29,6 +29,9 @@ public static class ListResponse { private int commentCount; private int likes; + } + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java index 343fa87..8b84595 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java @@ -12,6 +12,7 @@ import com.umc.DongnaeFriend.domain.user.entity.User; import javax.persistence.*; import lombok.*; +import org.hibernate.annotations.ColumnDefault; @Getter @Builder @@ -38,4 +39,8 @@ public class SharingBoard extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String content; + + @Column(name = "view") + @ColumnDefault("0") + private Integer view; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java index 51e1b58..44692ff 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -1,19 +1,45 @@ -package com.umc.DongnaeFriend.domain.account.book.repository; +package com.umc.DongnaeFriend.domain.account.sharing.repository; +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; import java.util.List; -public interface SharingBoardRepository extends JpaRepository { +@Repository +public interface SharingBoardRepository extends JpaRepository { - @Query(value = "SELECT sharing_board.*, COUNT(sharing_sympathy.sharing_board_id) AS like FROM sharing_board\n" + + +// private final EntityManager em; +// +// public SharingBoardRepository(EntityManager em) { +// this.em = em; +// } + +// public List findByKeywordAAndCategory(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable) { +// return em.createQuery("SELECT new com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto.ListResponse(s.id, s.category, s.title, s.content, s.createdAt, s.view, likes), count(SharingSympathy.sharingBoard.id) as likes " + +// "FROM SharingBoard s left join SharingSympathy on s.id=SharingSympathy.sharingBoard.id " + +// "WHERE (s.title LIKE %:keyword% or s.content LIKE % :keyword%) and s.category = :category " + +// "group by s.id", SharingDto.ListResponse.class) +// .setParameter("keyword", keyword) +// .setParameter("category", category) +// .getResultList(); +// } + + + @Query(value = "SELECT sharing_board.*, COUNT(sharing_sympathy.sharing_board_id) AS cnt FROM sharing_board\n" + "LEFT JOIN sharing_sympathy ON sharing_board.sharing_board_id = sharing_sympathy.sharing_board_id\n" + - "WHERE (sharing_board.title LIKE %?1% OR sharing_board.content LIKE %?2%)\n" + - "AND sharing_board.category = ?2 GROUP BY sharing_board.sharing_board_id ;", nativeQuery = true) - List findByKeywordAAndCategory(String keyword, String category, Pageable pageable); + "WHERE (sharing_board.title LIKE %:keyword% OR sharing_board.content LIKE %:keyword%)\n" + + "AND sharing_board.category = :category GROUP BY sharing_board.sharing_board_id ", nativeQuery = true) + List findByKeywordOrderByLikes(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); + + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java new file mode 100644 index 0000000..91ff0ee --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java @@ -0,0 +1,11 @@ +package com.umc.DongnaeFriend.domain.account.sharing.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SharingCommentRepository extends JpaRepository { + + public int countAllBySharingBoardId(Long sharing_board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java new file mode 100644 index 0000000..2ce7801 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java @@ -0,0 +1,15 @@ +package com.umc.DongnaeFriend.domain.account.sharing.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface SharingImgRepository extends JpaRepository { + + @Query(value = "SELECT * FROM sharing_img WHERE sharing_board_id = ?1 ORDER BY created_at ASC LIMIT 1", nativeQuery = true) + Optional findFirst(long sharing_board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java new file mode 100644 index 0000000..fdd5e38 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java @@ -0,0 +1,14 @@ +package com.umc.DongnaeFriend.domain.account.sharing.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingSympathy; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeSympathy; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface SharingSympathyRepository extends JpaRepository { + + int countAllBySharingBoardId(Long sharing_board_id); + + List findByUser_Id(long user_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java index 435bebb..c16a8f5 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java @@ -1,4 +1,11 @@ -package com.umc.DongnaeFriend.domain.account.book.service; +package com.umc.DongnaeFriend.domain.account.sharing.service; -public interface accountBookSharingService { +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +public interface AccountBookSharingService { + + List searchByKeyword(String keyword, int category, Pageable pageable); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index b437742..c2a03d0 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -1,37 +1,92 @@ -package com.umc.DongnaeFriend.domain.account.book.service; +package com.umc.DongnaeFriend.domain.account.sharing.service; -import com.umc.DongnaeFriend.domain.account.book.dto.SharingDto; -import com.umc.DongnaeFriend.domain.account.book.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingCommentRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingImgRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingSympathyRepository; import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.Gender; import com.umc.DongnaeFriend.domain.type.SharingCategory; import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; +import java.util.stream.Collectors; +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +@Slf4j @Service -public class accountBookSharingServiceImpl implements accountBookSharingService { +public class AccountBookSharingServiceImpl implements AccountBookSharingService { //임시 유저 Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); - @Autowired private SharingBoardRepository sharingBoardRepository; + @Autowired + private SharingImgRepository sharingImgRepository; + + @Autowired + private SharingCommentRepository sharingCommentRepository; + + @Autowired + private SharingSympathyRepository sharingSympathyRepository; + + /* - * [가계부 공유] 게시글 검 + * [가계부 공유] 게시글 검색 */ + @Override public List searchByKeyword(String keyword, int category, Pageable pageable) { - sharingBoardRepository.findByKeywordAAndCategory(keyword, SharingCategory.valueOf(category).name(), pageable); + //TODO : 전체 카테고리 처리 + List sharingBoards = sharingBoardRepository.findByKeywordOrderByLikes(keyword, SharingCategory.valueOf(category).name(), pageable); + if (sharingBoards.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + log.info("board found" + sharingBoards.get(0).getId()); + return getListResponses(sharingBoards); } + + //ListResponse 변환 + private List getListResponses(List sharingBoardList) { + return sharingBoardList.stream() + .map(origin -> SharingDto.ListResponse.builder() + .id(origin.getId()) + .category(origin.getCategory().getValue()) + .title(origin.getTitle()) + .content(origin.getContent()) + .imageUrl( + sharingImgRepository.findFirst(origin.getId()).map(SharingImg::getImageUrl).orElse("") + ) + .createdAt( + getTime(origin.getCreatedAt()) + ) + .view(origin.getView()) + .commentCount( + sharingCommentRepository.countAllBySharingBoardId(origin.getId()) + ) + .likes( + sharingSympathyRepository.countAllBySharingBoardId(origin.getId()) + ) + .build()) + .collect(Collectors.toList()); + } + + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 8fcf7bd..0dc62ea 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -10,8 +10,6 @@ import java.util.List; -import static com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory.*; - public class DongnaeBoardDto { @@ -55,6 +53,7 @@ public DongnaeBoard toEntity(User user, Dongnae dongnae) { @AllArgsConstructor @NoArgsConstructor public static class ListResponse { + private Long id; private String town; private int category; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java index c5fc447..e25e247 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java @@ -6,7 +6,6 @@ import static lombok.AccessLevel.PRIVATE; import static lombok.AccessLevel.PROTECTED; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.umc.DongnaeFriend.domain.BaseTimeEntity; import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; @@ -15,8 +14,6 @@ import lombok.*; import org.hibernate.annotations.ColumnDefault; -import java.util.List; - @Getter @Builder @NoArgsConstructor(access = PROTECTED) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index c0a861a..e75a0d7 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -22,14 +22,14 @@ import javax.naming.AuthenticationException; import javax.persistence.EntityNotFoundException; -import java.time.Duration; -import java.time.LocalDateTime; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + @Slf4j @Service public class DongnaeBoardServiceImpl implements DongnaeBoardService { @@ -119,9 +119,6 @@ public List searchAll(int sort) { @Override public void createBoard(DongnaeBoardDto.Request req) { //TODO : User Mapping UserRepository 필요. - Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); - dongnaeBoardRepository.save(req.toEntity(user, dongnae)); } @@ -153,6 +150,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { boolean scrapOrNot = false; return DongnaeBoardDto.Response.builder() + .profileImage(user.getProfileImage()) .nickname(user.getNickname()) .category(board.get().getCategory().getValue()) @@ -207,6 +205,7 @@ public void deleteBoard(long board_id) throws AuthenticationException { private List getListResponses(List dongnaeBoardList) { return dongnaeBoardList.stream() .map(origin -> DongnaeBoardDto.ListResponse.builder() + .id(origin.getId()) .town(origin.getPlace()) .category(origin.getCategory().getValue()) .title(origin.getTitle()) @@ -229,32 +228,7 @@ private List getListResponses(List d } - //시간 계산 - private String getTime(LocalDateTime time) { - LocalDateTime now = LocalDateTime.now(); // 현재 시간 - Duration duration = Duration.between(now, time); - log.info(now.toString()); - log.info(time.toString()); - long days = -duration.toDays(); - log.info(" days: "+ days); - long hours = -duration.toHours() % 24; - log.info(" hours: "+ hours); - long minutes = -duration.toMinutes() % 60; - log.info(" minutes: "+ minutes); - - if (days >= 1){ - if (days == 1) { - return "어제"; - } - return days + "일 전"; - } - - else if (hours >= 1) { - return hours + "시간 전"; - } else return minutes + "분 전"; - - } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java index bfd3248..e10aa9d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java @@ -1,5 +1,7 @@ package com.umc.DongnaeFriend.domain.type; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -13,4 +15,13 @@ public enum SharingCategory { private final Integer value; private final String category; + + public static SharingCategory valueOf(Integer value) { + for (SharingCategory category : SharingCategory.values()) { + if (category.getValue().equals(value)) { + return category; + } else throw new CustomException(ErrorCode.INVALID_VALUE); + } + throw new IllegalArgumentException("Invalid Category: " + value); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java index 9ac2371..a3a73e9 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java @@ -15,6 +15,8 @@ public enum ErrorCode { /* 50* 스크랩 */ + /* 200 NO_CONTENT : 자료를 찾을 수 없음 */ + NO_CONTENT_FOUND(NO_CONTENT, 204, "요청된 자료를 찾을 수 없습니다."), /* 400 BAD_REQUEST : 잘못된 요청 */ INVALID_REFRESH_TOKEN(BAD_REQUEST, 400, "리프레시 토큰이 유효하지 않습니다"), @@ -32,6 +34,7 @@ public enum ErrorCode { REFRESH_TOKEN_NOT_FOUND(NOT_FOUND, 404,"로그아웃 된 사용자입니다"), NOT_FOLLOW(NOT_FOUND,404, "팔로우 중이지 않습니다"), + /* 409 CONFLICT : Resource 의 현재 상태와 충돌. 보통 중복된 데이터 존재 */ DUPLICATE_RESOURCE(CONFLICT,409, "데이터가 이미 존재합니다"), diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java new file mode 100644 index 0000000..5f72d7a --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java @@ -0,0 +1,25 @@ +package com.umc.DongnaeFriend.global.util; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class FileUtil { + + public static String fileUpload(List files) throws IOException { + String filepath = "/resources/static/img"; + + List list = new ArrayList<>(); + for (MultipartFile file : files) { + String originalfileName = file.getOriginalFilename(); + File dest = new File(filepath + originalfileName); + file.transferTo(dest); + list.add(dest.getPath()); + } + return String.join(",", list); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java new file mode 100644 index 0000000..527175e --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java @@ -0,0 +1,29 @@ +package com.umc.DongnaeFriend.global.util; + +import java.time.Duration; +import java.time.LocalDateTime; + +public class TimeUtil { + + //시간 계산 + public static String getTime(LocalDateTime time) { + LocalDateTime now = LocalDateTime.now(); // 현재 시간 + Duration duration = Duration.between(now, time); + + long days = -duration.toDays(); + long hours = -duration.toHours() % 24; + long minutes = -duration.toMinutes() % 60; + + if (days >= 1){ + if (days == 1) { + return "어제"; + } + return days + "일 전"; + } + + else if (hours >= 1) { + return hours + "시간 전"; + } else return minutes + "분 전"; + + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 196b4bb..04772a2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,6 +8,7 @@ spring: properties: hibernate: format_sql: true + show_sql: true --- # Settings for local spring: diff --git a/src/main/resources/static/img/.keep b/src/main/resources/static/img/.keep new file mode 100644 index 0000000..e69de29 From a87f1a6a96f1f35cafbe5883e3acef185bbeed21 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 01:11:39 +0900 Subject: [PATCH 26/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#25:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accountBookSharingController.java | 13 ++++++++++++- .../account/sharing/dto/SharingDto.java | 19 +++++++++++++++++++ .../service/AccountBookSharingService.java | 2 ++ .../AccountBookSharingServiceImpl.java | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index eb4c425..bb9ac15 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -18,7 +19,7 @@ public class accountBookSharingController { @Autowired AccountBookSharingService accountBookSharingService; - /** + /* * [가계부 공유] 게시글 검색 * @param keyword * @param pageable @@ -40,7 +41,17 @@ public ResponseEntity searchAll(@RequestParam("keyword") String keyword, @Req return ResponseEntity.ok(res); } + /* + * [가계부 공유] 게시글 등록 + * + * @param RequestDto + */ + + public ResponseEntity createPost(@RequestBody SharingDto.Request req) { + accountBookSharingService.createPost(req); + return new ResponseEntity<>(HttpStatus.OK); + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index e9155d7..e2d0fc2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -5,8 +5,27 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.List; + public class SharingDto { + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Request { + private int category; + + private String title; + + private String content; + + private List images; + } + + + + @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java index c16a8f5..1f1d50b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java @@ -8,4 +8,6 @@ public interface AccountBookSharingService { List searchByKeyword(String keyword, int category, Pageable pageable); + + void createPost(SharingDto.Request req); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index c2a03d0..fad6545 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -61,6 +61,24 @@ public List searchByKeyword(String keyword, int categor return getListResponses(sharingBoards); } + /* + * [가계부 공유] 게시글 등록 + */ + @Override + public void createPost(SharingDto.Request req) { + sharingBoardRepository.save(SharingBoard.builder() + .category(SharingCategory.valueOf(req.getCategory())) + .title(req.getTitle()) + .content(req.getContent()) + .build() + ); + //TODO : Img 파일 업로드 + } + + + + + //ListResponse 변환 private List getListResponses(List sharingBoardList) { From d1ca7cae599b0f8d650d5fcde75ef11cadd768c0 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 01:28:13 +0900 Subject: [PATCH 27/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#25:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accountBookSharingController.java | 12 ++++- .../account/sharing/dto/SharingDto.java | 34 +++++++++++++ .../repository/SharingImgRepository.java | 4 ++ .../service/AccountBookSharingService.java | 5 ++ .../AccountBookSharingServiceImpl.java | 49 ++++++++++++++++--- .../domain/dongnae/dto/DongnaeBoardDto.java | 2 +- .../service/DongnaeBoardServiceImpl.java | 7 ++- 7 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index bb9ac15..788c35c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -48,11 +48,19 @@ public ResponseEntity searchAll(@RequestParam("keyword") String keyword, @Req * @param RequestDto */ + @PostMapping("") public ResponseEntity createPost(@RequestBody SharingDto.Request req) { accountBookSharingService.createPost(req); return new ResponseEntity<>(HttpStatus.OK); } - - + /* + * [가계부 공유] 게시글 상세조회 + * + * @PathVariable accountBookId + */ + @GetMapping("/{accountBookId}") + public ResponseEntity getPost(@PathVariable("accountBookId") int board_id) { + return ResponseEntity.ok(accountBookSharingService.getBoard(board_id)); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index e2d0fc2..dcacacd 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -1,5 +1,11 @@ package com.umc.DongnaeFriend.domain.account.sharing.dto; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import com.umc.DongnaeFriend.domain.type.SharingCategory; +import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -21,6 +27,34 @@ public static class Request { private String content; private List images; + + public SharingBoard toEntity(User user) { + return SharingBoard.builder() + .user(user) + .category(SharingCategory.valueOf(category)) + .title(title) + .content(content) + .view(0) + .build(); + } + } + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Response{ + String profileImage; + String nickname; + int category; + String title; + String content; + List images; + String createdAt; + boolean isWriter; + boolean likeOrNot; + boolean scrapOrNot; + int view; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java index 2ce7801..d3f924d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java @@ -1,10 +1,12 @@ package com.umc.DongnaeFriend.domain.account.sharing.repository; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -12,4 +14,6 @@ public interface SharingImgRepository extends JpaRepository { @Query(value = "SELECT * FROM sharing_img WHERE sharing_board_id = ?1 ORDER BY created_at ASC LIMIT 1", nativeQuery = true) Optional findFirst(long sharing_board_id); + + List findAllBySharingBoard_Id(long id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java index 1f1d50b..ba3711d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java @@ -10,4 +10,9 @@ public interface AccountBookSharingService { List searchByKeyword(String keyword, int category, Pageable pageable); void createPost(SharingDto.Request req); + + /* + * [가계부 공유] 게시글 상세 조회 + */ + SharingDto.Response getBoard(long board_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index fad6545..53c2a69 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -21,6 +21,8 @@ import org.springframework.stereotype.Service; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; @@ -32,7 +34,7 @@ public class AccountBookSharingServiceImpl implements AccountBookSharingService //임시 유저 Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + User user = User.builder().profileImage("profileImage").id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); @Autowired private SharingBoardRepository sharingBoardRepository; @@ -66,16 +68,49 @@ public List searchByKeyword(String keyword, int categor */ @Override public void createPost(SharingDto.Request req) { - sharingBoardRepository.save(SharingBoard.builder() - .category(SharingCategory.valueOf(req.getCategory())) - .title(req.getTitle()) - .content(req.getContent()) - .build() - ); + sharingBoardRepository.save(req.toEntity(user)); //TODO : Img 파일 업로드 } + /* + * [가계부 공유] 게시글 상세 조회 + */ + @Override + public SharingDto.Response getBoard(long board_id) { + //TODO : User 식별자 필요. + Optional board = sharingBoardRepository.findById(board_id); + if (board.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + + //Get Images + List images = sharingImgRepository.findAllBySharingBoard_Id(board_id); + + //Writer인지 검사 + boolean isWriter = Objects.equals(board.get().getUser().getId(), user.getId()); + + //LikeOrNot 검사 + boolean likeOrNot = !sharingSympathyRepository.findByUser_Id(user.getId()).isEmpty(); + + //TODO: ScrapRepository 필요 + //scrapOrNot 검사 + boolean scrapOrNot = false; + + return SharingDto.Response.builder() + .profileImage(user.getProfileImage()) + .nickname(user.getNickname()) + .category(board.get().getCategory().getValue()) + .title(board.get().getTitle()) + .content(board.get().getContent()) + .images(images.stream().map(SharingImg::getImageUrl).collect(Collectors.toList())) + .createdAt(getTime(board.get().getCreatedAt())) + .isWriter(isWriter) + .likeOrNot(likeOrNot) + .scrapOrNot(scrapOrNot) + .view(board.get().getView()).build(); + } + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 0dc62ea..f639334 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -104,7 +104,7 @@ public static class Response { private boolean likeOrNot; - private boolean ScrapOrNot; + private boolean scrapOrNot; private int view; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index e75a0d7..8ae14e8 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -130,7 +130,6 @@ public void createBoard(DongnaeBoardDto.Request req) { @Transactional(propagation = Propagation.REQUIRED) public DongnaeBoardDto.Response getBoard(long board_id) { //TODO : User 식별자 필요. - int user_id = 1; Optional board = dongnaeBoardRepository.findById(board_id); if (board.isEmpty()) { throw new RuntimeException(); @@ -140,10 +139,10 @@ public DongnaeBoardDto.Response getBoard(long board_id) { List images = dongnaeImgRepository.findAllByDongnaeBoard_Id(board_id); //Writer인지 검사 - boolean isWriter = board.get().getUser().getId() == user_id; + boolean isWriter = Objects.equals(board.get().getUser().getId(), user.getId()); //LikeOrNot 검사 - boolean likeOrNot = !dongnaeSympathyRepository.findByUser_Id(user_id).isEmpty(); + boolean likeOrNot = !dongnaeSympathyRepository.findByUser_Id(user.getId()).isEmpty(); //TODO: ScrapRepository 필요 //scrapOrNot 검사 @@ -163,7 +162,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { .townCertification(user.getTownCertCnt()) .isWriter(isWriter) .likeOrNot(likeOrNot) - .ScrapOrNot(scrapOrNot) + .scrapOrNot(scrapOrNot) .view(board.get().getView()).build(); } From f1da149651f940ac549ee0915b93c20e16709992 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 01:41:01 +0900 Subject: [PATCH 28/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#25:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accountBookSharingController.java | 17 +++++++++++++++-- .../account/sharing/entity/SharingBoard.java | 8 ++++++++ .../repository/SharingImgRepository.java | 2 ++ .../service/AccountBookSharingService.java | 5 +++++ .../service/AccountBookSharingServiceImpl.java | 14 ++++++++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index 788c35c..50c2087 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -55,12 +55,25 @@ public ResponseEntity createPost(@RequestBody SharingDto.Request req) { } /* - * [가계부 공유] 게시글 상세조회 + * [가계부 공유] 게시글 상세 조회 * * @PathVariable accountBookId */ @GetMapping("/{accountBookId}") - public ResponseEntity getPost(@PathVariable("accountBookId") int board_id) { + public ResponseEntity updatePost(@PathVariable("accountBookId") long board_id) { return ResponseEntity.ok(accountBookSharingService.getBoard(board_id)); } + + /* + * [가계부 공유] 게시글 수정 + * + * @PathVariable accountBookId + * @RequestBody SharingDto.Request + */ + @PutMapping("/{accountBookId}") + public ResponseEntity updateBoard(@PathVariable("accountBookId") int board_id, @RequestBody SharingDto.Request req) { + accountBookSharingService.updateBoard(board_id, req); + return new ResponseEntity<>(HttpStatus.OK); + } + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java index 8b84595..bee611c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java @@ -8,6 +8,8 @@ import com.fasterxml.jackson.databind.ser.Serializers.Base; import com.umc.DongnaeFriend.domain.BaseTimeEntity; +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.type.SharingCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import javax.persistence.*; @@ -43,4 +45,10 @@ public class SharingBoard extends BaseTimeEntity { @Column(name = "view") @ColumnDefault("0") private Integer view; + + public void updateBoard(SharingDto.Request req) { + this.category = SharingCategory.valueOf(req.getCategory()); + this.title = req.getTitle(); + this.content = req.getContent(); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java index d3f924d..e5de29b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java @@ -16,4 +16,6 @@ public interface SharingImgRepository extends JpaRepository { Optional findFirst(long sharing_board_id); List findAllBySharingBoard_Id(long id); + + void deleteAllById(long id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java index ba3711d..930b4cd 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java @@ -15,4 +15,9 @@ public interface AccountBookSharingService { * [가계부 공유] 게시글 상세 조회 */ SharingDto.Response getBoard(long board_id); + + /* + * [가계부 공유] 게시글 수정 + */ + void updateBoard(long board_id, SharingDto.Request req); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index 53c2a69..510fbfa 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -111,6 +111,20 @@ public SharingDto.Response getBoard(long board_id) { .view(board.get().getView()).build(); } + /* + * [가계부 공유] 게시글 수정 + */ + @Override + public void updateBoard(long board_id, SharingDto.Request req) { + SharingBoard board = sharingBoardRepository.findById(board_id).orElseThrow( + () -> new CustomException(ErrorCode.INVALID_VALUE)); + + board.updateBoard(req); + sharingBoardRepository.save(board); + + sharingImgRepository.deleteAllById(board_id); + //TODO: Img Upload + } From 66af4e829960f3de7efa0d1e6d207da02b89e030 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 01:43:18 +0900 Subject: [PATCH 29/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#25:=20[=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/accountBookSharingController.java | 11 +++++++++++ .../sharing/service/AccountBookSharingService.java | 6 ++++++ .../service/AccountBookSharingServiceImpl.java | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index 50c2087..67d39ea 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -76,4 +76,15 @@ public ResponseEntity updateBoard(@PathVariable("accountBookId") int board_id return new ResponseEntity<>(HttpStatus.OK); } + /* + * [가계부 공유] 게시글 삭제 + * + * @PathVariable accountBookId + */ + @DeleteMapping("/{accountBookId}") + public ResponseEntity deleteBoard(@PathVariable("accountBookId") int board_id) { + accountBookSharingService.deleteBoard(board_id); + return new ResponseEntity<>(HttpStatus.OK); + } + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java index 930b4cd..e85afc6 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java @@ -20,4 +20,10 @@ public interface AccountBookSharingService { * [가계부 공유] 게시글 수정 */ void updateBoard(long board_id, SharingDto.Request req); + + + /* + * [가계부 공유] 게시글 삭제 + */ + void deleteBoard(long board_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index 510fbfa..01e836a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -126,6 +126,14 @@ public void updateBoard(long board_id, SharingDto.Request req) { //TODO: Img Upload } + /* + * [가계부 공유] 게시글 수정 + */ + @Override + public void deleteBoard(long board_id) { + sharingBoardRepository.deleteById(board_id); + } + From c27969113a796c3a4844d6341d3a2b9cf2ac0678 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 01:45:46 +0900 Subject: [PATCH 30/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#25:=20[=EA=B3=B5?= =?UTF-8?q?=ED=86=B5]=20=EC=8B=A0=EA=B3=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/controller/ReportController.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java diff --git a/src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java b/src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java new file mode 100644 index 0000000..cda1bf4 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java @@ -0,0 +1,16 @@ +package com.umc.DongnaeFriend.global.report.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/accuse") +public class ReportController { + + public ResponseEntity reportBoard(@RequestBody int id) { + return new ResponseEntity<>(HttpStatus.OK); + } +} From 77e276331a4c3189c488c04e62687692d8502b15 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Mon, 24 Jul 2023 09:56:26 +0900 Subject: [PATCH 31/58] =?UTF-8?q?:see=5Fno=5Fevil:=20Chore:=20.gradle,=20.?= =?UTF-8?q?idea=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.1.1/checksums/checksums.lock | Bin 17 -> 0 bytes .../dependencies-accessors.lock | Bin 17 -> 0 bytes .../dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.lock | Bin 17 -> 0 bytes .gradle/8.1.1/fileChanges/last-build.bin | Bin 1 -> 0 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .gradle/8.1.1/gc.properties | 0 .../buildOutputCleanup.lock | Bin 17 -> 0 bytes .gradle/buildOutputCleanup/cache.properties | 2 - .gradle/vcs-1/gc.properties | 0 .idea/$CACHE_FILE$ | 17 - .idea/.gitignore | 3 - .idea/.name | 1 - .idea/compiler.xml | 16 - .idea/dbnavigator.xml | 463 ------------------ .idea/dictionaries | 6 - .idea/gradle.xml | 21 - .idea/jarRepositories.xml | 20 - .idea/misc.xml | 8 - .idea/vcs.xml | 6 - 20 files changed, 563 deletions(-) delete mode 100644 .gradle/8.1.1/checksums/checksums.lock delete mode 100644 .gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock delete mode 100644 .gradle/8.1.1/dependencies-accessors/gc.properties delete mode 100644 .gradle/8.1.1/executionHistory/executionHistory.lock delete mode 100644 .gradle/8.1.1/fileChanges/last-build.bin delete mode 100644 .gradle/8.1.1/fileHashes/fileHashes.lock delete mode 100644 .gradle/8.1.1/gc.properties delete mode 100644 .gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 .gradle/buildOutputCleanup/cache.properties delete mode 100644 .gradle/vcs-1/gc.properties delete mode 100644 .idea/$CACHE_FILE$ delete mode 100644 .idea/.gitignore delete mode 100644 .idea/.name delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/dbnavigator.xml delete mode 100644 .idea/dictionaries delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/jarRepositories.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/vcs.xml diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock deleted file mode 100644 index bed4d053db82310e6ba3f2b41d02baec4b7ac0c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZS1@)rBFze>lD0RpB104o0j>;M1& diff --git a/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock b/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock deleted file mode 100644 index aea0c51845f746fc65748d2649b89e197af667b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZR6K9_e({p9263{U_7Ico%o diff --git a/.gradle/8.1.1/dependencies-accessors/gc.properties b/.gradle/8.1.1/dependencies-accessors/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock deleted file mode 100644 index 1edfd7e836b0b90686a6140be7d086d1f9481ff5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZR6(Xu4+XJ*)A1_%%a06&%m8vp - - - - - - - - - - Android - - - - - - \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 37e6a33..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -DongnaeFriend \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index a4b7174..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml deleted file mode 100644 index d68d958..0000000 --- a/.idea/dbnavigator.xml +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dictionaries b/.idea/dictionaries deleted file mode 100644 index 149349d..0000000 --- a/.idea/dictionaries +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 859c9b3..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index fdc392f..0000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 5821b2f..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 81dd90337a21465bedc054c15ee4c1a636d7334d Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Mon, 24 Jul 2023 10:08:52 +0900 Subject: [PATCH 32/58] =?UTF-8?q?:see=5Fno=5Fevil:=20Chore:=20out=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriendApplication.class | Bin 917 -> 0 bytes .../DongnaeFriend/HealthCheckController.class | Bin 645 -> 0 bytes .../domain/user/entity/User.class | Bin 3648 -> 0 bytes out/production/resources/application.yml | 21 ------------------ .../DongnaeFriendApplicationTests.class | Bin 568 -> 0 bytes 5 files changed, 21 deletions(-) delete mode 100644 out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class delete mode 100644 out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class delete mode 100644 out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class delete mode 100644 out/production/resources/application.yml delete mode 100644 out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class diff --git a/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class b/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class deleted file mode 100644 index 9880d22bb3d2ed366960a2fee4594093f11fce1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmb7C!EO^V5PeS5ZW;nDDHIA6#4XLC<^+eJN@<`6v;v8saOlaqaTkYOd*!uD`&pbo z9QXh}3NhYPB$aXiA7=Ds>^E;_{Ok9Rp8#IqNgGYvi*Ub=nNNiid{zo>WoatqjJ@Qk z(Pt{-uXX7DO(}+cs$3AuaI}&nF~)J>oteM%R`PLO=a>>pDv2PH7isRp*vJ1$Rms#_ zm^>#k%4%V^3aQJ^Kitwm|eLQB^UhL;xGLxxe=&zbu-SE7{ zrS|AwSx<{jdP{pA<)W$vD^`23vVWSOlNXNv?JKNt@tY_d(gQq2gT8k-4Y1HP*@zG) z&&aR$zkz+N(=D)lhZ6uW-_Vq62< diff --git a/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class b/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class deleted file mode 100644 index 4f3fc496f2dc7506acd53efa6ea8b6bc419a151f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 645 zcmb7B%T60X5UlnC6Pu@bg`D8VLogR4kP<~gj)23GND%qLX?7Xxv3F;z*;)Iyl2fD{ z_y9gCqK8G8Lk=*~cB`hVrn-9{{{6iNaE#3+YFL}adIK8`d?d_#(MJ2PgzC<2mr(22 zTSZumv{B!SELQHPj8nd8M>dgZS2`W=^JUHVbxt^l5}S!4OT;&8dPb@l{C6YGXzqGAzi_LVPOajyKO9F58+>tmS~JWE5A4G@~wws46$(_zF< z|LylM^hP*&v*ne_{i|{3P{#~mrL^2i!Zx<-aGMWd{~e1XEKS$+BOa*4V;fcepW#$M z!H8pnk>E_6>wAAdzn{vp977pQ_`q?lB%p~FBVs(yj|A}nqrj`SE5A5ZFqO7mNvqG& a1?DWUV3EJ28&HmA*0i6LD_kjUSAj>gJe{!s diff --git a/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class b/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class deleted file mode 100644 index df7c8953399c7d97fa16c1b8929c33efefe76df6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 zcmb7H=~5d<5bhPawHO-%iF^egv0=eh;)M8if;k*vAv++G;2icM4PuQnOYN?l@IMcf zR7K^gq$&@PXUQ|9^7Uv@#4^YVKYDw1`s?ZL`MOv9_0R8r645PkQ}i-R2EEGANwQgN zv8b}Bu@Ee_S=3qVuy9zsX0gknk)>1gDn-o{NrQ6Fec?T7IgOg|3^I#S3U8rd`@ZlE zia9ldPL^KVZ|p+Dmi0o(mGyfD<=0v=aGGMn@tv)Pn3vKG?7(p)FcZrBr^24_e8&%j ztcpUh2GAwV#$$ow>_F5u>_$t#DD4NluJ8A?$4Qm_J!M~9Tq;+Jl}&@rX#6j@jaE~_ zZ(Q0+sScMIqKZkdf++g#u5U_G;qOtp1bWdM6qetk$XCDf0PTt3k;g>UxonnE^G?F z>>@Q?tV^=h?A#^i{)X?rt?RF|+dScrX{!Yc+73h@IuDxr!Mdr@dLBBkhdPmuq zZwJ)jPP@|6Zip_v;MP#4k&+`txz*efUWG3e1+0sJj~c}RN7`?+V;y7Q0i?)zWvF?ZABB)o`$-t?V{J;m>Fc2MU2VJd7`)d4KIjsuu= zW>ZfvM{`wQFBF!t>u$@die(H!gEHKbH@M04-;gCW_|YhN<^1rMO*J3(65Lp5zg$`P z!K&a+#_CSr8b*7ucQ%-`L0_9RM&l-ZK$9j-lV#Eji&+-e>4r(4(5EKN(Pt)p8QeDM z4!^t0yZ30^pzHtZaD!(0+CQ>=QNbs_Qw_R^9}=hV)9OL>Pw}q-7w}rbva)*KAKO<2Ft5Szw&OwZ9HyfHflv_Okk8MH*p zkWp|v3ZB%0AJdl_a3Tu6tOXaf;A9khRSRCxf>TlOlotGiN}90KQShu5yh>#aI1>dI zwBV=oOasnF!8f(wuV_sJ&PBme_z<2>Gu z4Hl?k6 zs!bUypKepu%4gb?v+~(CnN~j6reP~@w&_GPf-x1r&z)1k?!tND)MJh38aMNb8eIH? ze1#`9#g)dRDWNnTPD!Ql2udl9XHHsaJYq6R%&hqEi`v(A=!bS^fu;xS0hjj+cb5v+A7}R$6#tiCLdLkKgLR9jm z%pz$95xX6)LQl!)x>e9q= zfYquy3tRl2dpH$Og29OsEOLV?xi=z{&)PilNNdY2Y4Z7MeCRqZ33sCcs6&In(LWx{ zpj(aRsZa^OjixfTuniu4Ms+;8Bn|W<6mjy5d}IF&*sCl1WSb83VTs~k)&R@Uq70x- iWY3WgD67bSi0vOlHYWzuSjn!C_h8l84vEjuF2FZU-im7g From d14923bc97af5b18f2fa9975b9cdafd778f6dcce Mon Sep 17 00:00:00 2001 From: soogoori Date: Mon, 24 Jul 2023 10:10:31 +0900 Subject: [PATCH 33/58] =?UTF-8?q?:wrench:=20Chore:=20.gradle,=20.idea=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20&=20merge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gradle/8.1.1/checksums/checksums.lock | Bin 17 -> 0 bytes .../dependencies-accessors.lock | Bin 17 -> 0 bytes .../dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.lock | Bin 17 -> 0 bytes .gradle/8.1.1/fileChanges/last-build.bin | Bin 1 -> 0 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .gradle/8.1.1/gc.properties | 0 .../buildOutputCleanup.lock | Bin 17 -> 0 bytes .gradle/buildOutputCleanup/cache.properties | 2 - .gradle/vcs-1/gc.properties | 0 .idea/$CACHE_FILE$ | 17 - .idea/.gitignore | 3 - .idea/.name | 1 - .idea/compiler.xml | 16 - .idea/dbnavigator.xml | 463 ------------------ .idea/dictionaries | 6 - .idea/gradle.xml | 18 - .idea/jarRepositories.xml | 20 - .idea/misc.xml | 8 - .idea/vcs.xml | 6 - out/production/resources/application.yml | 9 +- 21 files changed, 1 insertion(+), 568 deletions(-) delete mode 100644 .gradle/8.1.1/checksums/checksums.lock delete mode 100644 .gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock delete mode 100644 .gradle/8.1.1/dependencies-accessors/gc.properties delete mode 100644 .gradle/8.1.1/executionHistory/executionHistory.lock delete mode 100644 .gradle/8.1.1/fileChanges/last-build.bin delete mode 100644 .gradle/8.1.1/fileHashes/fileHashes.lock delete mode 100644 .gradle/8.1.1/gc.properties delete mode 100644 .gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 .gradle/buildOutputCleanup/cache.properties delete mode 100644 .gradle/vcs-1/gc.properties delete mode 100644 .idea/$CACHE_FILE$ delete mode 100644 .idea/.gitignore delete mode 100644 .idea/.name delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/dbnavigator.xml delete mode 100644 .idea/dictionaries delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/jarRepositories.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/vcs.xml diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock deleted file mode 100644 index 5333e79891f1e639e39ae5bedb6ee0c6b21f244f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZS1@)rBFze>lD0Ss6?04llzqW}N^ diff --git a/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock b/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock deleted file mode 100644 index aea0c51845f746fc65748d2649b89e197af667b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZR6K9_e({p9263{U_7Ico%o diff --git a/.gradle/8.1.1/dependencies-accessors/gc.properties b/.gradle/8.1.1/dependencies-accessors/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock deleted file mode 100644 index 8ce92417067146e05fb80162cf7b064fc94e2a26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZR6(Xu4+XJ*)A1_+P^06(AwB>(^b diff --git a/.gradle/8.1.1/fileChanges/last-build.bin b/.gradle/8.1.1/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock deleted file mode 100644 index a403c63737924b673cd2c141dd1666284acee29e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZQxwBy}@)CWuC8Nh%k1OP%K1!@2Q diff --git a/.gradle/8.1.1/gc.properties b/.gradle/8.1.1/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index 69550e3fe73a2285b9b907cdca629ae03104e629..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZSP49tkBPWf@20Rl1rE2acE diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index d8d5482..0000000 --- a/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Jul 03 14:30:27 KST 2023 -gradle.version=8.1.1 diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/$CACHE_FILE$ b/.idea/$CACHE_FILE$ deleted file mode 100644 index f9784d3..0000000 --- a/.idea/$CACHE_FILE$ +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - Android - - - - - - \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 37e6a33..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -DongnaeFriend \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index a4b7174..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml deleted file mode 100644 index d68d958..0000000 --- a/.idea/dbnavigator.xml +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dictionaries b/.idea/dictionaries deleted file mode 100644 index 149349d..0000000 --- a/.idea/dictionaries +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 446c193..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index fdc392f..0000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 5821b2f..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml index 3425929..482cdcd 100644 --- a/out/production/resources/application.yml +++ b/out/production/resources/application.yml @@ -14,17 +14,10 @@ spring: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false -<<<<<<< HEAD username: dongnae password: Tnqls9004^^ driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update database: mysql -======= - username: root - password: qwe335577! - driver-class-name: com.mysql.cj.jdbc.Driver - jpa: - hibernate.ddl-auto: update ->>>>>>> develop + From 17ae4de9f4ca99a651806d0752c73bf36090e44d Mon Sep 17 00:00:00 2001 From: soogoori Date: Mon, 24 Jul 2023 10:12:43 +0900 Subject: [PATCH 34/58] =?UTF-8?q?:wrench:=20Chore:=20.gradle,=20.idea=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20&=20merge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriendApplication.class | Bin 917 -> 0 bytes .../DongnaeFriend/HealthCheckController.class | Bin 645 -> 0 bytes .../domain/user/entity/User.class | Bin 4634 -> 0 bytes out/production/resources/application.yml | 23 ------------------ .../DongnaeFriendApplicationTests.class | Bin 568 -> 0 bytes 5 files changed, 23 deletions(-) delete mode 100644 out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class delete mode 100644 out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class delete mode 100644 out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class delete mode 100644 out/production/resources/application.yml delete mode 100644 out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class diff --git a/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class b/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class deleted file mode 100644 index 9880d22bb3d2ed366960a2fee4594093f11fce1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmb7C!EO^V5PeS5ZW;nDDHIA6#4XLC<^+eJN@<`6v;v8saOlaqaTkYOd*!uD`&pbo z9QXh}3NhYPB$aXiA7=Ds>^E;_{Ok9Rp8#IqNgGYvi*Ub=nNNiid{zo>WoatqjJ@Qk z(Pt{-uXX7DO(}+cs$3AuaI}&nF~)J>oteM%R`PLO=a>>pDv2PH7isRp*vJ1$Rms#_ zm^>#k%4%V^3aQJ^Kitwm|eLQB^UhL;xGLxxe=&zbu-SE7{ zrS|AwSx<{jdP{pA<)W$vD^`23vVWSOlNXNv?JKNt@tY_d(gQq2gT8k-4Y1HP*@zG) z&&aR$zkz+N(=D)lhZ6uW-_Vq62< diff --git a/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class b/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class deleted file mode 100644 index 4f3fc496f2dc7506acd53efa6ea8b6bc419a151f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 645 zcmb7B%T60X5UlnC6Pu@bg`D8VLogR4kP<~gj)23GND%qLX?7Xxv3F;z*;)Iyl2fD{ z_y9gCqK8G8Lk=*~cB`hVrn-9{{{6iNaE#3+YFL}adIK8`d?d_#(MJ2PgzC<2mr(22 zTSZumv{B!SELQHPj8nd8M>dgZS2`W=^JUHVbxt^l5}S!4OT;&8dPb@l{C6YGXzqGAzi_LVPOajyKO9F58+>tmS~JWE5A4G@~wws46$(_zF< z|LylM^hP*&v*ne_{i|{3P{#~mrL^2i!Zx<-aGMWd{~e1XEKS$+BOa*4V;fcepW#$M z!H8pnk>E_6>wAAdzn{vp977pQ_`q?lB%p~FBVs(yj|A}nqrj`SE5A5ZFqO7mNvqG& a1?DWUV3EJ28&HmA*0i6LD_kjUSAj>gJe{!s diff --git a/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class b/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class deleted file mode 100644 index a2e78b92fc90039fa19996038bb0aaad9ebdc58e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4634 zcmb7GYj+bx7=AaG=C-}i(rU^@1cWv%L{a3f_KGQOfi_f&Aa0Xsx-{7>$p)z69sNCe z4k_p8Iezqmzs29+@p)%AX}V0(aB|MfJ3H_5%zK^5KmYyl7ZF{cUt=^#kK!20ELB)? zSgNx0n58EyJ!NT|rLQCOO`H<+jK6%#!*@J<&%+Nq{K&&kJp3G|A$k^}=Mnlvqr{zx zC{I?+VqTOr(leGN%2P$7QV|u60%l&LzWIm7VTTll!Qi+D!hHbUPbb7#WL{i{Cv(XrK_b}dfNRo zTQ-H2Pv`BDVOp4^URuCoXS=Qg$|H*N77S}UYu~ikwD7ucavN&BS>Ezo2+dF2h51Jn zbaS?8HC%{$mPqrXR<&3(5c?nsh7dQ)%x$_p_Ddo+U&~I}lo<;PI8#J|x61aqSrnO) zQGoAJ$9`f>iL#^7X!|fYhs`y)rOe`W zRAJqYDGR0yGt#{d z$l9C2Ld9$vn}(f1?Q~bS@+i__Wj+-_G!S5T2tb{-Mxoi{D9SS_uI za+dR{QUAQ1Gm0xl+2pnNG30ERXs+~Y9;8v+wUv+6sK;F_Hfm*Xq$$*1v9NL7%Z`!T zTrjrkHtq4)E1sD95phFK_6dP3AC54y>n_mEkw#}a!Fma0xaUQtk*M)b2;ACbd}OVD z-CY~mr|SKgJIQhMZc8rnf^fJX`oZ(cB^k%2ccW-@VZW1FUNZ^M>?Z8so|78w9fi`2 z+u^+sy~_0R#0=R+pO5Wl$(~N{X~N3h9Nc5TZg<9@SWoD9M@KYT6pii3A{y-o=k_T( zwOaw~^wOSg<>=q2H*D8c(=wfpa2t%E0JN3ns+Uh%`?hM4o2Ha|iRkD{+t;Qk_)TQ> zFt;~TV!fz#pviIUK+Wx&CSzXpRfdo|E52-3%Q-QN2S%e9_sUsr3-#MPBOg?BQBsoc z{l_5h9qushKwNx@MNx4U1YeUCoz7BPrwq;MbeXQ`bdzrBbd|2@v_OkGy~n%ry!#Qo zuhVT>(&$p#sJCl#oi@nSDM`aRouqekdY9?XG4n;bq|?W|{Dg*akG<9z8jZEppEN2W zi~m?|nCNZ%a~r}_uTy|+!IOUot6>V#Va!LcJ}T%fItE4jb*j(_=)qi1?+{j}AfFaA zLZg(z5;|ivewWTbMm#;m1ZHONHsGsz12M+20gi*GFoe|ykk1SH5PxBtNDwA936ke+ zbYpG;2RNIpwvg0TTgZj93hBT+2(<~C#5jf3BiI+fJenGNLD~)lcn9g6=hsirXwQy0cbih`(*rs++ZL7-<5%IlB_d6C5UavduiL7zg>@I#Gy$KUjh zkB|M$N7P7T{vgkK)%|7+)ZW^IU2SVdC*UO59Iej{-6c9TSQId==WCSF+cel z$a5eUEy&$kYmjsNvL5*{nRKG)pOjdAN&0VyohH-Sg_)=y;~iS@v^l!`HJo}u-K-jD zQavnB*IflK;~FCRxdPnd2Om>{SLv<-togwwl;AIv;9fuYloEVT36A)|BTDdn`ch$b zpC3G~1V5m!6yO7Xa9RmAXiWhQ`oZUv;2h-@;IJQjUI`XTpJRUTMJ0G$8SQ>Q__7jQ zP?qO_AAD5-4)Lq_iq9|UAa_`EZ4W5G0e~NR;D4dr4a{5$V7?c-Q{y%2Nu9wBnM#Ig z)SF6%YZOT(yK2;zN=9mQAeD^PD40sdYUrnAyhgE9GEt-cR8p_efZu|H(t_viDUJJd z&U;1q-sN|aZ}2&J$GUehzkDJ2jjzVAl=!jZmtc-xeu_wmub-%t_?C-FiEoX#l=wkP rNQs{$9gLe;1*j-r?_NkHtS!Xic!g}*!Xku40#6Kqf~7%vgJS;!tWny4 diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml deleted file mode 100644 index 482cdcd..0000000 --- a/out/production/resources/application.yml +++ /dev/null @@ -1,23 +0,0 @@ -logging: - level: - com.example.carrotmarket: debug - org.hibernate.SQL: debug - -spring: - jpa: - properties: - hibernate: - format_sql: true - show_sql: true ---- -# Settings for local -spring: - datasource: - url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: Tnqls9004^^ - driver-class-name: com.mysql.cj.jdbc.Driver - jpa: - hibernate.ddl-auto: update - database: mysql - diff --git a/out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class b/out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class deleted file mode 100644 index 2e115dc789d2a9d2951f8c95bf72e839594cd0af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 568 zcmbVJJ5R$f5I(1mKpSW&EJzH9iHC#-1Pmag0_qfjM62#jYQmMojvNR0TTDm{`~ZFw z;^KCouwlvf`0l>%&hqEi`v(A=!bS^fu;xS0hjj+cb5v+A7}R$6#tiCLdLkKgLR9jm z%pz$95xX6)LQl!)x>e9q= zfYquy3tRl2dpH$Og29OsEOLV?xi=z{&)PilNNdY2Y4Z7MeCRqZ33sCcs6&In(LWx{ zpj(aRsZa^OjixfTuniu4Ms+;8Bn|W<6mjy5d}IF&*sCl1WSb83VTs~k)&R@Uq70x- iWY3WgD67bSi0vOlHYWzuSjn!C_h8l84vEjuF2FZU-im7g From 00a376fbee61638198d63abb5601664fbab6382b Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 22:22:44 +0900 Subject: [PATCH 35/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#23:=20[OAuth2]=20?= =?UTF-8?q?=EC=86=8C=EC=85=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 + .../umc/DongnaeFriend/config/JwtConfig.java | 12 +++ .../DongnaeFriend/config/SecurityConfig.java | 33 ++++++++ .../controller/DongnaeBoardController.java | 1 + .../user/contorller/UserController.java | 56 ++++++++++++++ .../domain/user/dto/UserDto.java | 40 ++++++++++ .../domain/user/entity/User.java | 2 +- .../user/repository/UserRepository.java | 11 +++ .../domain/user/service/KakaoService.java | 12 +++ .../domain/user/service/KakaoServiceimpl.java | 76 +++++++++++++++++++ .../domain/user/service/UserService.java | 58 ++++++++++++++ .../global/util/JwtTokenProvider.java | 53 +++++++++++++ .../DongnaeFriend/global/util/JwtUtil.java | 39 ++++++++++ .../security/JwtTokenFilter.java | 45 +++++++++++ src/main/resources/application.yml | 17 +++-- 15 files changed, 451 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java create mode 100644 src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java create mode 100644 src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java create mode 100644 src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java diff --git a/build.gradle b/build.gradle index b6ac063..f8c9d8b 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,10 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' + //jwt + implementation 'io.jsonwebtoken:jjwt:0.9.1' + + } tasks.named('test') { diff --git a/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java b/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java new file mode 100644 index 0000000..af15fc2 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JwtConfig { + + @Value("${jwt.secret-key}") + public static String SECRET_KEY; + +} diff --git a/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java new file mode 100644 index 0000000..6931738 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java @@ -0,0 +1,33 @@ +package com.umc.DongnaeFriend.config; + +import com.umc.DongnaeFriend.security.JwtTokenFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; + +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private JwtTokenFilter jwtTokenFilter; + + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/user/login").permitAll() // 인증 없이 접근 허용하는 URL + .antMatchers("/user/reissuance").permitAll() // 인증 없이 접근 허용하는 URL + .anyRequest().authenticated(); // 그 외의 URL은 인증 필요 + http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class); + } + + // 나머지 코드는 이전 예제와 동일 +} + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index c8e7d7f..b168f28 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -5,6 +5,7 @@ import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.naming.AuthenticationException; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java new file mode 100644 index 0000000..be5b883 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java @@ -0,0 +1,56 @@ +package com.umc.DongnaeFriend.domain.user.contorller; + +import com.umc.DongnaeFriend.domain.user.dto.UserDto; +import com.umc.DongnaeFriend.domain.user.service.KakaoService; +import com.umc.DongnaeFriend.domain.user.service.UserService; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.HashMap; + +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + KakaoService kakaoService; + + @Autowired + UserService userService; + + JwtTokenProvider jwtTokenProvider; + + /** + * 유저 로그인 / 회원가입 + * 인증 절차 + */ + @PostMapping("/login") + public ResponseEntity userLogin(@RequestBody UserDto.Request request) { + try { + //사용자 정보 가져오기 + HashMap userInfo = kakaoService.getUserInfo(request.getAccessToken()); + + //사용자 확인 기존 회원 -> 넘어가고, 없는 회원 -> 회원가입 + userService.userValidation(userInfo); + + //토큰 생성 + String access_token = jwtTokenProvider.createAccessToken((Long) userInfo.get("usreId")); + + return ResponseEntity.ok(access_token); + + } catch (IOException e) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } + } + + @PostMapping("/user/reissuance") + public ResponseEntity reiussnaceToken(String access_oto) + + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java b/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java new file mode 100644 index 0000000..469dcdb --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java @@ -0,0 +1,40 @@ +package com.umc.DongnaeFriend.domain.user.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +public class UserDto { + + @Getter + @AllArgsConstructor + public static class Request { + + String accessToken; + + String type; + + } + + @Getter + @AllArgsConstructor + public static class Response { + + String accessToken; + + String refreshToken; + + } + + @Getter + @AllArgsConstructor + public static class SignUpDto { + + String nickName; + + String email; + + Long kakaoId; + + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java index 665c1db..b6e8772 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java @@ -28,7 +28,7 @@ public class User extends BaseTimeEntity { private Long id; @ManyToOne(fetch = LAZY) - @JoinColumn(name = "dongnae_id", nullable = false) + @JoinColumn(name = "dongnae_id") private Dongnae dongnae; @Column(nullable = false) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java new file mode 100644 index 0000000..869602d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java @@ -0,0 +1,11 @@ +package com.umc.DongnaeFriend.domain.user.repository; + +import com.umc.DongnaeFriend.domain.user.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + + Optional findById(Long id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java new file mode 100644 index 0000000..a4b2aaf --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.domain.user.service; + + +import java.io.IOException; +import java.util.HashMap; + +public interface KakaoService { + + HashMap getUserInfo(String access_Token) throws IOException; +} + + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java new file mode 100644 index 0000000..4955e10 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java @@ -0,0 +1,76 @@ +package com.umc.DongnaeFriend.domain.user.service; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +@Service +public class KakaoServiceimpl implements KakaoService { + +// @Autowired +// public IACDao dao; + + @SuppressWarnings("unchecked") + @Override + public HashMap getUserInfo(String access_Token) throws IOException { + // 클라이언트 요청 정보 + HashMap userInfo = new HashMap(); + + + //------kakao GET 요청------ + String reqURL = "https://kapi.kakao.com/v2/user/me"; + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Authorization", "Bearer " + access_Token); + + int responseCode = conn.getResponseCode(); + System.out.println("responseCode : " + responseCode); + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = ""; + String result = ""; + + while ((line = br.readLine()) != null) { + result += line; + } + System.out.println("response body : " + result); + System.out.println("result type" + result.getClass().getName()); // java.lang.String + + // jackson objectmapper 객체 생성 + ObjectMapper objectMapper = new ObjectMapper(); + // JSON String -> Map + Map jsonMap = objectMapper.readValue(result, new TypeReference>() { + }); + + System.out.println(jsonMap.get("properties")); + + Map properties = (Map) jsonMap.get("properties"); + Map kakao_account = (Map) jsonMap.get("kakao_account"); + + // System.out.println(properties.get("nickname")); + // System.out.println(kakao_account.get("email")); + + String nickname = properties.get("nickname").toString(); + String email = kakao_account.get("email").toString(); + String gender = kakao_account.get("gender").toString(); + String age = kakao_account.get("age").toString(); + + userInfo.put("nickname", nickname); + userInfo.put("email", email); + userInfo.put("gender", gender); + userInfo.put("age", age); + + return userInfo; + } + +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java new file mode 100644 index 0000000..61a0500 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -0,0 +1,58 @@ +package com.umc.DongnaeFriend.domain.user.service; + +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.dto.UserDto; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Optional; + +@Service +public class UserService { + + @Autowired + UserRepository userRepository; + + KakaoService kakaoService; + + public void userValidation(HashMap userInfo) { + Optional user= userRepository.findById((Long) userInfo.get("userId")); + if (user.isEmpty()) { + userRegister(userInfo); + } + } + + + //유저 회원가입 + public void userRegister(HashMap userInfo) { + //필수 + String nickName = userInfo.get("nickname").toString(); + //필수 + String email = userInfo.get("email").toString(); + + Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); + Optional age = Optional.ofNullable(userInfo.get("age").toString()); + + + + userRepository.save( + User.builder() + .nickname(nickName) + .email(email) + //TODO : Gender 결정 + .gender(Gender.FEMALE) + //TODO : Age 결정 + .age(Age.AGE10) + .townCert(YesNo.NO) + .townCertCnt(0) + .infoCert(YesNo.NO) + .build() + ); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java new file mode 100644 index 0000000..427a8bd --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java @@ -0,0 +1,53 @@ +package com.umc.DongnaeFriend.global.util; + +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import io.jsonwebtoken.*; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import java.util.Date; + +import static com.umc.DongnaeFriend.config.JwtConfig.SECRET_KEY; + +@Log4j2 +@Component +public class JwtTokenProvider { + + @Autowired + private UserRepository userRepository; + + public JwtTokenProvider(UserRepository userRepository) { + this.userRepository = userRepository; + } + + private final Long ACCESS_TOKEN_EXPIRE_LENGTH = 1000L * 60 * 60 * 24 * 14; //2WEEK + private final Long REFRESH_TOKEN_EXPIRE_LENGTH = 1000L * 60 * 60 * 24 * 30; //30DAY + + + //accessToken 생성 + public String createAccessToken(Long userId) { + Date now = new Date(); //현재 시간 + Date validity = new Date(now.getTime() + ACCESS_TOKEN_EXPIRE_LENGTH); + + +// CustomAuthentication user = (CustomAuthentication) authentication.getPrincipal(); +// +// Claims claims = Jwts.claims().setSubject(user.getUsername()); +// claims.put("userId", user.getId()); // 사용자 아이디 +// claims.put("email", user.getEmail()); // 사용자 이메일 + + return Jwts.builder() + .signWith(SignatureAlgorithm.HS512, String.valueOf(SECRET_KEY)) + .claim("userId", userId) + .setIssuedAt(now) //token 발행 시간 + .setExpiration(validity) + .compact(); + } + + + + + +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java new file mode 100644 index 0000000..84ea9b2 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java @@ -0,0 +1,39 @@ +package com.umc.DongnaeFriend.global.util; + +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.*; + +import static com.umc.DongnaeFriend.config.JwtConfig.SECRET_KEY; + +public class JwtUtil { + + public static Long getUserIdFromToken(String token) { + Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); + return Long.parseLong(claims.get("userId").toString()); + } + + //token 유효성 검증 + public static Boolean validateToken(String token) { + try { + Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); + return true; + } catch (SignatureException ex) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (MalformedJwtException ex) { + log.error("Invalid JWT token"); + } catch (ExpiredJwtException ex) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (UnsupportedJwtException ex) { + log.error("Unsupported JWT token"); + } catch (IllegalArgumentException ex) { + log.error("JWT claims string is empty."); + } catch (NullPointerException ex){ + log.error("JWT is empty"); + } catch (IllegalStateException e) { + log.info("JWT is illegal"); + } + return false; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java new file mode 100644 index 0000000..df0fd76 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java @@ -0,0 +1,45 @@ +package com.umc.DongnaeFriend.security; + +import com.umc.DongnaeFriend.global.util.JwtUtil; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class JwtTokenFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // Request Header에서 JWT 토큰 가져오기 + String authorizationHeader = request.getHeader("Authorization"); + + // JWT 토큰이 "Bearer "로 시작하는지 확인하고 토큰 추출 + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + String token = authorizationHeader.substring(7); + + try { + // JWT 토큰 검증 + JwtUtil.validateToken(token); + + // JWT 토큰에서 사용자 정보 추출 (예: 사용자 ID) + Long userId = JwtUtil.getUserIdFromToken(token); + + // 인증 객체 생성 + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(userId, null, null); + + // SecurityContextHolder에 인증 객체 저장 + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } catch (Exception e) { + // JWT 토큰 검증 실패 시, 인증 객체를 null로 설정 + SecurityContextHolder.clearContext(); + } + } + + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 04772a2..588b310 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,12 +3,6 @@ logging: com.example.carrotmarket: debug org.hibernate.SQL: debug -spring: - jpa: - properties: - hibernate: - format_sql: true - show_sql: true --- # Settings for local spring: @@ -18,4 +12,13 @@ spring: password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: update \ No newline at end of file + hibernate.ddl-auto: update + properties: + hibernate: + format_sql: true + show_sql: true + + + +jwt: + secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 \ No newline at end of file From 35a0121e62df0369dbc9c859896774612c501a7b Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Mon, 24 Jul 2023 22:26:09 +0900 Subject: [PATCH 36/58] =?UTF-8?q?=F0=9F=A5=95Feat=20#23:=20[OAuth2]=20?= =?UTF-8?q?=EC=86=8C=EC=85=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/user/contorller/UserController.java | 4 +++- .../domain/user/service/UserService.java | 1 + .../umc/DongnaeFriend/global/util/JwtUtil.java | 16 ++-------------- src/main/resources/application.yml | 4 ++-- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java index be5b883..b5b9805 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java @@ -49,7 +49,9 @@ public ResponseEntity userLogin(@RequestBody UserDto.Request request) { } @PostMapping("/user/reissuance") - public ResponseEntity reiussnaceToken(String access_oto) + public ResponseEntity reiussnaceToken(String access_oto) { + return null; + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java index 61a0500..3e16261 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -37,6 +37,7 @@ public void userRegister(HashMap userInfo) { String email = userInfo.get("email").toString(); Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); + Optional age = Optional.ofNullable(userInfo.get("age").toString()); diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java index 84ea9b2..09f0e95 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java @@ -19,21 +19,9 @@ public static Boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; - } catch (SignatureException ex) { + } catch (SignatureException | IllegalArgumentException | MalformedJwtException | ExpiredJwtException | + UnsupportedJwtException | NullPointerException | IllegalStateException ex) { throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); - } catch (MalformedJwtException ex) { - log.error("Invalid JWT token"); - } catch (ExpiredJwtException ex) { - throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); - } catch (UnsupportedJwtException ex) { - log.error("Unsupported JWT token"); - } catch (IllegalArgumentException ex) { - log.error("JWT claims string is empty."); - } catch (NullPointerException ex){ - log.error("JWT is empty"); - } catch (IllegalStateException e) { - log.info("JWT is illegal"); } - return false; } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 588b310..857383e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,8 +8,8 @@ logging: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: root - password: qwe335577! + username: + password: driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update From 7c61d7b16f7eb5eabaecf95f06710448725b4647 Mon Sep 17 00:00:00 2001 From: soogoori Date: Mon, 24 Jul 2023 22:49:14 +0900 Subject: [PATCH 37/58] =?UTF-8?q?:zap:=20Refactor:=20=EA=B0=80=EA=B3=84?= =?UTF-8?q?=EB=B6=80=20=EC=A7=80=EC=B6=9C=20=EB=82=B4=EC=97=AD=20=EB=82=B4?= =?UTF-8?q?=EB=A6=BC=EC=B0=A8=EC=88=9C=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/controller/AccountBookController.java | 1 + .../book/controller/TransactionController.java | 6 ++++-- .../accountBook/AccountBookRepository.java | 4 ++-- .../accountBook/AccountBookRepositoryCustom.java | 1 + .../AccountBookRepositoryCustomImpl.java | 8 +++++--- .../transaction/TransactionRepository.java | 6 ++++-- .../account/book/service/AccountBookService.java | 3 ++- .../account/book/service/TransactionService.java | 5 +++-- .../domain/profile/dto/DongnaeProfileDto.java | 8 ++++++++ .../domain/profile/dto/UserProfileDto.java | 14 ++++++++++++++ 10 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java index 488b574..24a2b90 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -3,6 +3,7 @@ import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.*; import java.util.List; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java index 417203d..eb475fc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java @@ -4,6 +4,7 @@ import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; import com.umc.DongnaeFriend.domain.account.book.service.TransactionService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.*; import javax.transaction.Transactional; @@ -22,8 +23,9 @@ public void createTransaction(@RequestBody TransactionDto.TransactionRequest req @GetMapping public TransactionDto.TransactionListResponse getTransaction(@RequestParam(value = "year", required = false) Integer year, - @RequestParam(value = "month", required = false) Integer month){ - return transactionService.getTransactions(year, month); + @RequestParam(value = "month", required = false) Integer month, + @RequestParam(value = "day", required = false) Integer day, Pageable pageable){ + return transactionService.getTransactions(year, month, day, pageable); } @PutMapping diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java index 31c14b6..ed98f65 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java @@ -49,9 +49,9 @@ public interface AccountBookRepository extends JpaRepository, + "where ab.id = :accountBookId") void updateAccountBookIncomeEdit(@Param("accountBookId")Long accountBookId, @Param("incomeGap")Long incomeGap); - @Query(value = "SELECT transaction.transaction_category, SUM(transaction.price) as sum_price " + + /*@Query(value = "SELECT transaction.transaction_category, SUM(transaction.price) as sum_price " + "from transaction " + "where transaction.month = :month and transaction.year = :year " + "group by transaction.transaction_category", nativeQuery = true) - Object[] getAccountBookGroupByCategory (@Param("month") long month, @Param("year") long year); + Object[] getAccountBookGroupByCategory (@Param("month") long month, @Param("year") long year);*/ } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java index fb2a534..ffb4e1f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java @@ -2,6 +2,7 @@ import com.umc.DongnaeFriend.domain.account.book.dto.Expense; +import org.springframework.data.domain.Pageable; import java.util.List; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java index 13bf271..73a7d99 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -4,6 +4,7 @@ import com.umc.DongnaeFriend.domain.account.book.dto.Expense; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -18,11 +19,12 @@ public class AccountBookRepositoryCustomImpl implements AccountBookRepositoryCus private final EntityManager em; @Override - public List getAccountBook (@Param("year") Integer year,@Param("month") Integer month) { + public List getAccountBook (@Param("year") Integer year, @Param("month") Integer month) { return em.createQuery( - "select new com.umc.DongnaeFriend.domain.account.book.dto.Expense(t.transactionCategory, sum(t.price))" + - "from Transaction t where t.year= :year and t.month= :month group by t.transactionCategory", Expense.class) + "select new com.umc.DongnaeFriend.domain.account.book.dto.Expense(t.transactionCategory, sum(t.price)) " + + "from Transaction t where t.year= :year and t.month= :month group by t.transactionCategory " + + "order by sum(t.price) desc", Expense.class) .setParameter("year", year) .setParameter("month", month) .getResultList(); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java index 402b53a..79321bf 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java @@ -3,6 +3,7 @@ import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -12,8 +13,9 @@ public interface TransactionRepository extends JpaRepository, TransactionRepositoryCustom { - @Query(value = "select t from Transaction t where t.year = :year and t.month = :month") - List findByYearAndMonth(@Param("year") Integer year, @Param("month") Integer month); + @Query(value = "select t from Transaction t where t.year = :year and t.month = :month and t.day = :day") + List findByYearAndMonth(@Param("year") Integer year, @Param("month") Integer month, + @Param("day") Integer day, Pageable pageable); /* @Query(value = "select new com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto.TransactionByCategory(tr.transactionCategory, SUM(tr.price)) " + "from Transaction tr " + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java index b254a1a..3caaf36 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -5,6 +5,7 @@ import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -41,7 +42,7 @@ public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, I return AccountBookDto.AccountBookResponse.builder() .income(accountBook.getIncome()) .expenditure(accountBook.getExpenditure()) - .budget(accountBook.getBudget()) + .budget(accountBook.getBudget()+accountBook.getIncome()-accountBook.getExpenditure()) .expense(accountBookRepository.getAccountBook(year,month)) .build(); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java index 469ca7e..c492a7f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java @@ -7,6 +7,7 @@ import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -48,9 +49,9 @@ public void createTransaction(TransactionDto.TransactionRequest request){ } // 지출 또는 수입 내역 조회 - public TransactionDto.TransactionListResponse getTransactions(Integer year, Integer month){ + public TransactionDto.TransactionListResponse getTransactions(Integer year, Integer month, Integer day, Pageable pageable){ - List transactionList = transactionRepository.findByYearAndMonth(year, month); + List transactionList = transactionRepository.findByYearAndMonth(year, month, day, pageable); return TransactionDto.TransactionListResponse.of(transactionList); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java index e58f617..3ba55ec 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java @@ -6,4 +6,12 @@ public class DongnaeProfileDto { + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class DongnaeProfileResponse{ + private int postTotalCount; + private int commentTotalCount; + private int likedTotalCount; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java new file mode 100644 index 0000000..c9a7955 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java @@ -0,0 +1,14 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class UserProfileDto { + + private String nickname; + private String profileImage; + private String town; +} From bccffcb1fcfa078ef78a2f2ff463430fb626b6da Mon Sep 17 00:00:00 2001 From: soogoori Date: Tue, 25 Jul 2023 23:11:07 +0900 Subject: [PATCH 38/58] =?UTF-8?q?=F0=9F=8F=9D=EF=B8=8F:=20Feat=20#29:=20[?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/sharing/dto/SharingDto.java | 3 - .../AccountBookSharingServiceImpl.java | 4 +- .../domain/dongnae/dto/DongnaeBoardDto.java | 25 +++++ .../respository/DongnaeBoardRepository.java | 6 ++ .../respository/DongnaeCommentRepository.java | 9 ++ .../respository/DongnaeRepository.java | 7 ++ .../DongnaeSympathyRepository.java | 1 + .../service/DongnaeBoardServiceImpl.java | 23 ++-- .../controller/DongnaeProfileController.java | 31 ++++++ .../profile/controller/MyPageController.java | 15 +-- .../domain/profile/dto/DongnaeProfileDto.java | 15 ++- .../domain/profile/dto/MyPageDto.java | 4 +- .../domain/profile/dto/UserProfileDto.java | 31 ++++-- .../service/DongnaeProfileService.java | 100 ++++++++++++++++++ .../domain/profile/service/MyPageService.java | 27 ++++- .../domain/user/entity/User.java | 2 +- .../exception/GlobalExceptionHandler.java | 4 +- .../DongnaeFriend/global/util/FileUtil.java | 22 ++-- src/main/resources/application.yml | 2 + .../resources/static/img/ProfileImage_1.png | Bin 0 -> 133508 bytes 20 files changed, 281 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java create mode 100644 src/main/resources/static/img/ProfileImage_1.png diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index dcacacd..7825ef8 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -57,9 +57,6 @@ public static class Response{ int view; } - - - @Getter @Builder @AllArgsConstructor diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index 01e836a..6687692 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -68,6 +68,7 @@ public List searchByKeyword(String keyword, int categor */ @Override public void createPost(SharingDto.Request req) { + sharingBoardRepository.save(req.toEntity(user)); //TODO : Img 파일 업로드 } @@ -161,7 +162,4 @@ private List getListResponses(List sharin .build()) .collect(Collectors.toList()); } - - - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index f639334..6489bcf 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -4,11 +4,15 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.*; import java.util.List; +import java.util.stream.Collectors; public class DongnaeBoardDto { @@ -25,7 +29,12 @@ public static class Request { private String placeLocation; + + public DongnaeBoard toEntity(User user, Dongnae dongnae) { + dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + return DongnaeBoard.builder() .user(user) .category(DongnaeBoardCategory.valueOf(category) @@ -107,7 +116,23 @@ public static class Response { private boolean scrapOrNot; private int view; + } + /** + * 프로필 조회 시 필요한 정보 + */ + @Getter @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class DongnaeProfileListResponse { + private Long id; + private String town; + private int category; + private String title; + private String imageUrl; + private String createdAt; + private int commentCount; + private int likeCount; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index 0c70194..eaded3e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -3,6 +3,8 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Repository; @@ -31,4 +33,8 @@ public interface DongnaeBoardRepository extends JpaRepository findTwoByCategoryOrderByCreatedAt(String category); + + public int countAllByUserId(Long userId); + + List findAllByUserId(Long userId); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java index 0e988b5..c5368cf 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java @@ -2,9 +2,18 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface DongnaeCommentRepository extends JpaRepository { public int countAllByDongnaeBoardId(Long dongnae_board_id); + public int countAllByUserId(Long userId); + + @Query(value = "select c from DongnaeComment c join fetch c.dongnaeBoard d " + + "where c.user.id = :userId order by c.createdAt desc") + List getCommentByUserIdAndBoard(@Param("userId") Long userId); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java new file mode 100644 index 0000000..b242442 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java @@ -0,0 +1,7 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DongnaeRepository extends JpaRepository { +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java index 1f7e3a7..1f274ba 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java @@ -9,6 +9,7 @@ public interface DongnaeSympathyRepository extends JpaRepository { int countAllByDongnaeBoardId(Long dongnae_board_id); + int countAllByUserId(Long userId); List findByUser_Id(long user_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 8ae14e8..5d127bc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -5,15 +5,13 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; -import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; -import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; -import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeImgRepository; -import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeSympathyRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.*; import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import com.umc.DongnaeFriend.domain.type.Gender; import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -50,6 +48,13 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { @Autowired private DongnaeSympathyRepository dongnaeSympathyRepository; + // 임시 유저, 동네 등록 // + @Autowired + private UserRepository userRepository; + + @Autowired + private DongnaeRepository dongnaeRepository; + /* * [동네정보] 홈 화면 * 카테고리 별 게시글 2개씩 반환 @@ -119,6 +124,12 @@ public List searchAll(int sort) { @Override public void createBoard(DongnaeBoardDto.Request req) { //TODO : User Mapping UserRepository 필요. + + Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + dongnaeRepository.save(dongnae); + userRepository.save(user); dongnaeBoardRepository.save(req.toEntity(user, dongnae)); } @@ -225,10 +236,6 @@ private List getListResponses(List d .build()) .collect(Collectors.toList()); } - - - - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java new file mode 100644 index 0000000..cdeb93b --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java @@ -0,0 +1,31 @@ +package com.umc.DongnaeFriend.domain.profile.controller; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.profile.dto.DongnaeProfileDto; +import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; +import com.umc.DongnaeFriend.domain.profile.service.DongnaeProfileService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.repository.query.Param; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class DongnaeProfileController { + + private final DongnaeProfileService dongnaeProfileService; + + // 동네정보 프로필 조회 + @GetMapping({"/api/my/town", "/api/{userId}/town"}) + public DongnaeProfileDto.DongnaeProfileResponse getProfile(@PathVariable(value = "userId", required = false) Long userId, + @RequestParam int category){ + return dongnaeProfileService.getDongnaeProfile(userId, category); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java index 56b6664..06a5527 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java @@ -4,11 +4,11 @@ import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; import com.umc.DongnaeFriend.domain.profile.service.MyPageService; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +@Slf4j @RestController @RequiredArgsConstructor public class MyPageController { @@ -21,7 +21,10 @@ public MyPageDto.MyPageResponseDto getMyPage(){ } @PutMapping("/api/user") - public void updateMyPage(@RequestBody MyPageDto.MyPageRequestDto myPageRequest){ - myPageService.updateMyPage(myPageRequest); + public void updateMyPage(@RequestPart(value = "request", required = false) MyPageDto.MyPageRequestDto myPageRequest, + @RequestPart(value = "image", required = false) MultipartFile image){ + + log.info("updateMyPage - 프로필 사진 변경"); + myPageService.updateMyPage(myPageRequest, image); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java index 3ba55ec..64df6cf 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java @@ -1,17 +1,30 @@ package com.umc.DongnaeFriend.domain.profile.dto; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -public class DongnaeProfileDto { +import java.util.List; + +public class DongnaeProfileDto { @Getter + @Builder @AllArgsConstructor + @NoArgsConstructor public static class DongnaeProfileResponse{ + + private Long userId; + private boolean isMine; + private String nickname; + private String profileImage; private int postTotalCount; private int commentTotalCount; private int likedTotalCount; + private UserProfileDto.UserProfileResponseDto profile; + private List content; } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java index c127ad6..4eeb2e3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java @@ -35,15 +35,15 @@ public static MyPageResponseDto of(User user, UserLocationDto userLocation){ @AllArgsConstructor public static class MyPageRequestDto{ private String nickname; - private String profileImage; private Age age; + //private String profileImage; private Gender gender; private YesNo infoCert; public User toEntity(){ return User.builder() .nickname(nickname) - .profileImage(profileImage) + //.profileImage(profileImage) .age(age) .gender(gender) .infoCert(infoCert) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java index c9a7955..117ecbc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java @@ -1,14 +1,31 @@ package com.umc.DongnaeFriend.domain.profile.dto; +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class UserProfileDto { - private String nickname; - private String profileImage; - private String town; +public class UserProfileDto{ + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class UserProfileResponseDto { + private String nickname; + private String profileImage; + private String town; + private Age age; + private Gender gender; + + public static UserProfileDto.UserProfileResponseDto of(User user) { + return new UserProfileDto.UserProfileResponseDto( + user.getNickname(), + user.getProfileImage(), + user.getDongnae().getTownName(), + user.getAge(), + user.getGender()); + } + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java new file mode 100644 index 0000000..a00dfd3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java @@ -0,0 +1,100 @@ +package com.umc.DongnaeFriend.domain.profile.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeImgRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeSympathyRepository; +import com.umc.DongnaeFriend.domain.profile.dto.DongnaeProfileDto; +import com.umc.DongnaeFriend.domain.profile.dto.UserProfileDto; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +@Service +@RequiredArgsConstructor +public class DongnaeProfileService { + + private final DongnaeSympathyRepository dongnaeSympathyRepository; + private final DongnaeCommentRepository commentRepository; + private final DongnaeBoardRepository dongnaeBoardRepository; + private final DongnaeImgRepository dongnaeImgRepository; + private final UserRepository userRepository; + + + // 본인 or 타사용자 확인 + private User checkUser(Long userId){ + User user; + if(userId==null){ // 유저아이디가 없으면 본인 + user = userRepository.findById(userId/*본인인증 필요*/) + .orElseThrow(); + }else{ + user = userRepository.findById(userId) + .orElseThrow(); + } + return user; + } + + /** + * 동네 정보 프로필 조회 + */ + public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, int category){ + User user = checkUser(userId); + + // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 + + return DongnaeProfileDto.DongnaeProfileResponse.builder() + .userId(userId==null ? user.getId() /*본인인증 필요*/ : userId) + .nickname(user.getNickname()) + .isMine(userId.equals(user.getId() /*본인인증 필오*/)) + .profileImage(user.getProfileImage()) + .postTotalCount(dongnaeBoardRepository.countAllByUserId(user.getId())) + .commentTotalCount(commentRepository.countAllByUserId(user.getId())) + .likedTotalCount(dongnaeSympathyRepository.countAllByUserId(user.getId())) + .profile(UserProfileDto.UserProfileResponseDto.of(user)) + .content(getWrittenContent(user.getId(), category)) + .build(); + } +🏝️ + /** + * 동네정보 - 작성한 글 , 작성한 댓글의 게시글 조회 + * TODO : 공감, 스크랩 게시물 조회 필요 + */ + public List getWrittenContent(Long userId, int category) { + User user = checkUser(userId); + + List dongnaeBoardList; + if(category==0){ + dongnaeBoardList= dongnaeBoardRepository.findAllByUserId(user.getId()); + }else{ + dongnaeBoardList = commentRepository.getCommentByUserIdAndBoard(user.getId()) + .stream().map(DongnaeComment::getDongnaeBoard).distinct().collect(Collectors.toList()); + } + return getProfileListResponse(dongnaeBoardList); + } +🏝️ + //ListResponse 변환 + private List getProfileListResponse(List dongnaeBoardList){ + return dongnaeBoardList.stream() + .map(dongnaeBoard -> DongnaeBoardDto.DongnaeProfileListResponse.builder() + .id(dongnaeBoard.getId()) + .town(dongnaeBoard.getPlaceLocation()) + .category(dongnaeBoard.getCategory().getValue()) + .title(dongnaeBoard.getTitle()) + .imageUrl(dongnaeImgRepository.findFirst(dongnaeBoard.getId()).map(DongnaeImg::getImageUrl).orElse("")) + .createdAt(getTime(dongnaeBoard.getCreatedAt())) + .commentCount(commentRepository.countAllByDongnaeBoardId(dongnaeBoard.getId())) + .likeCount(dongnaeSympathyRepository.countAllByDongnaeBoardId(dongnaeBoard.getId())) + .build()) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java index 7f733b3..baf763a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java @@ -8,9 +8,13 @@ import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.util.FileUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; @Slf4j @Service @@ -23,20 +27,36 @@ public class MyPageService { //임시 유저 & 동네 Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(30).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); - private final UserRepository userRepository; public MyPageDto.MyPageResponseDto getMyPage(){ //User user = userRepository.findById(userId).orElseThrow(); return MyPageDto.MyPageResponseDto.of(user, getUserLocation()); } - public void updateMyPage(MyPageDto.MyPageRequestDto myPageRequest){ + public void updateMyPage(MyPageDto.MyPageRequestDto myPageRequest, MultipartFile image){ //User user = userRepository.findById(userId).orElseThrow(); + User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + String fileName = "ProfileImage_" + user.getId().toString()+".png"; + + log.info("fileName : " + fileName); + + try { + log.info("fileUpload 시작합니당"); + log.info("image : " + image.isEmpty()); + log.info("filename : " + fileName); + FileUtil.fileUpload(image, fileName); + + }catch (IOException e){ + throw new RuntimeException(e); + } + user.updateProfileImage(fileName); + log.info("프로필 이미지 업데이트완료"); user.updateProfile(myPageRequest.toEntity()); + log.info("프로필 업데이트 완료"); log.info("유저 닉네임 : " + user.getNickname()); log.info("유저 프로필 : " + user.getProfileImage()); @@ -44,7 +64,6 @@ public void updateMyPage(MyPageDto.MyPageRequestDto myPageRequest){ log.info("유저 gender : " + user.getGender()); log.info("유저 infocert : " + user.getInfoCert()); } - public UserLocationDto getUserLocation(){ return new UserLocationDto("한남동"); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java index a54de81..ea0df4c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java @@ -66,7 +66,7 @@ public void updateProfile(User updateUser){ updateNickname(updateUser.nickname); updateGender(updateUser.gender); updateAge(updateUser.age); - updateProfileImage(updateUser.profileImage); + updateProfileImage(this.profileImage); updateInfoCert(updateUser.infoCert); } diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java index 986c73d..da2dd2c 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java @@ -29,12 +29,12 @@ protected ResponseEntity handleMethodArgumentNotValidException(MethodArgument .body(new ErrorResponse(validException)); } - //일반 예외처리 + /*//일반 예외처리 @ExceptionHandler({Exception.class}) protected ResponseEntity handleServerException(Exception ex) { CustomException exception = new CustomException(SERVER_ERROR); return ResponseEntity .status(SERVER_ERROR.getHttpStatus()) .body(new ErrorResponse(exception)); - } + }*/ } \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java index 5f72d7a..6f332ba 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java @@ -1,25 +1,21 @@ package com.umc.DongnaeFriend.global.util; +import lombok.extern.slf4j.Slf4j; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +@Slf4j public class FileUtil { - public static String fileUpload(List files) throws IOException { - String filepath = "/resources/static/img"; + public static void fileUpload(MultipartFile file, String fileName) throws IOException{ + String filePath = "/Users/soobin/UMC/Server/src/main/resources/static/img/"; - List list = new ArrayList<>(); - for (MultipartFile file : files) { - String originalfileName = file.getOriginalFilename(); - File dest = new File(filepath + originalfileName); - file.transferTo(dest); - list.add(dest.getPath()); - } - return String.join(",", list); - } + log.info("fileupload 들어옴!!"); + File dest = new File(filePath + fileName); + log.info("dest : " + dest); + file.transferTo(dest); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 482cdcd..09b0758 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -21,3 +21,5 @@ spring: hibernate.ddl-auto: update database: mysql +jwt: + secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 \ No newline at end of file diff --git a/src/main/resources/static/img/ProfileImage_1.png b/src/main/resources/static/img/ProfileImage_1.png new file mode 100644 index 0000000000000000000000000000000000000000..db2c4a5a0181cf0af61b926b12d850955e0a3aa4 GIT binary patch literal 133508 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%0AM7|bXg!}O`cz{Vd9gVlqbP-8#anfq}D^4FA7 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 z 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 q(A`!4s7w7-Dam-iD*3 Date: Tue, 25 Jul 2023 23:12:34 +0900 Subject: [PATCH 39/58] =?UTF-8?q?=F0=9F=8F=9D=EF=B8=8F:=20Feat=20#29:=20[?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 09b0758..d7b9410 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,11 +15,8 @@ spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false username: dongnae - password: Tnqls9004^^ + password: driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update database: mysql - -jwt: - secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 \ No newline at end of file From c35a069c14f63327db8cb5118cd9f0d73787a1f2 Mon Sep 17 00:00:00 2001 From: soogoori Date: Tue, 25 Jul 2023 23:22:46 +0900 Subject: [PATCH 40/58] =?UTF-8?q?=F0=9F=8F=9D=EF=B8=8FFeat=20#29:=20[?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EB=8F=99?= =?UTF-8?q?=EB=84=A4=EC=A0=95=EB=B3=B4=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/profile/service/DongnaeProfileService.java | 2 -- src/main/resources/application.yml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java index a00dfd3..5930e3a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java @@ -64,7 +64,6 @@ public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, i .content(getWrittenContent(user.getId(), category)) .build(); } -🏝️ /** * 동네정보 - 작성한 글 , 작성한 댓글의 게시글 조회 * TODO : 공감, 스크랩 게시물 조회 필요 @@ -81,7 +80,6 @@ public List getWrittenContent(Long u } return getProfileListResponse(dongnaeBoardList); } -🏝️ //ListResponse 변환 private List getProfileListResponse(List dongnaeBoardList){ return dongnaeBoardList.stream() diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d7b9410..a8707ff 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,7 +15,7 @@ spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false username: dongnae - password: + password: Tnqls9004^^ driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update From 921e7a8e5b0406a28186a4296ca2675242037e57 Mon Sep 17 00:00:00 2001 From: Limwngur Date: Wed, 26 Jul 2023 09:07:19 +0900 Subject: [PATCH 41/58] =?UTF-8?q?=E2=9A=BDfeat#23:=20[Auth2]=20refresh=20T?= =?UTF-8?q?oken=20=EC=83=9D=EC=84=B1,=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85,=20AccessToken=EC=9E=AC=EB=B0=9C=EA=B8=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/contorller/UserController.java | 23 +++++++-- .../user/repository/UserRepository.java | 2 + .../domain/user/service/UserService.java | 47 ++++++++++++++++--- .../global/util/JwtTokenProvider.java | 13 +++++ .../security/JwtTokenFilter.java | 17 ++++++- 5 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java index b5b9805..d8d0374 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java @@ -6,8 +6,9 @@ import com.umc.DongnaeFriend.global.exception.CustomException; import com.umc.DongnaeFriend.global.exception.ErrorCode; import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import java.io.IOException; @@ -15,6 +16,7 @@ @RestController @RequestMapping("/user") +@Slf4j public class UserController { @Autowired @@ -25,6 +27,8 @@ public class UserController { JwtTokenProvider jwtTokenProvider; + + /** * 유저 로그인 / 회원가입 * 인증 절차 @@ -32,6 +36,7 @@ public class UserController { @PostMapping("/login") public ResponseEntity userLogin(@RequestBody UserDto.Request request) { try { + log.info("userLogin 진입"); //사용자 정보 가져오기 HashMap userInfo = kakaoService.getUserInfo(request.getAccessToken()); @@ -39,8 +44,8 @@ public ResponseEntity userLogin(@RequestBody UserDto.Request request) { userService.userValidation(userInfo); //토큰 생성 - String access_token = jwtTokenProvider.createAccessToken((Long) userInfo.get("usreId")); - + String access_token = jwtTokenProvider.createAccessToken((Long) userInfo.get("userId")); + log.info("access_token : {}", access_token); return ResponseEntity.ok(access_token); } catch (IOException e) { @@ -49,8 +54,16 @@ public ResponseEntity userLogin(@RequestBody UserDto.Request request) { } @PostMapping("/user/reissuance") - public ResponseEntity reiussnaceToken(String access_oto) { - return null; + public ResponseEntity reiussnaceToken(String refreshToken) { + try { + + //토큰 재발급 + String access_token = userService.createAccessTokenFromRefreshToken(refreshToken); + return ResponseEntity.ok(access_token); + } catch (Exception e) { + // RefreshToken만료 + throw new CustomException(ErrorCode.INVALID_REFRESH_TOKEN); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java index 869602d..5edd72b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java @@ -8,4 +8,6 @@ public interface UserRepository extends JpaRepository { Optional findById(Long id); + + Optional findByRefreshToken(String refresh_token); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java index 3e16261..3f7e6f1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -3,17 +3,21 @@ import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.Gender; import com.umc.DongnaeFriend.domain.type.YesNo; -import com.umc.DongnaeFriend.domain.user.dto.UserDto; import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import com.umc.DongnaeFriend.global.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.io.IOException; import java.util.HashMap; import java.util.Optional; @Service +@Slf4j public class UserService { @Autowired @@ -21,8 +25,11 @@ public class UserService { KakaoService kakaoService; + JwtTokenProvider jwtTokenProvider; + public void userValidation(HashMap userInfo) { Optional user= userRepository.findById((Long) userInfo.get("userId")); + if (user.isEmpty()) { userRegister(userInfo); } @@ -37,23 +44,51 @@ public void userRegister(HashMap userInfo) { String email = userInfo.get("email").toString(); Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); + String strGender = ""; + log.info("Gender : {}", gender.get()); + if(gender.get()=="F"){ + strGender="여성"; + }else { + strGender = "남성"; + } + log.info("strGender : {}", strGender); + Optional age = Optional.ofNullable(userInfo.get("age").toString()); + String[] ageRange = age.get().split("-"); + // refreshToken userId를 claim 으로 생성 뒤, User의 필드에 넣고 User를 저장 + String refresh_Token = jwtTokenProvider.createRefreshToken((Long) userInfo.get("usreId")); userRepository.save( User.builder() .nickname(nickName) .email(email) - //TODO : Gender 결정 - .gender(Gender.FEMALE) - //TODO : Age 결정 - .age(Age.AGE10) + //TODO : Gender 결정[O] + .gender(Gender.valueOf(strGender)) + //TODO : Age 결정[O] + .age(Age.valueOf(ageRange[0]+"대")) .townCert(YesNo.NO) .townCertCnt(0) .infoCert(YesNo.NO) + .refreshToken(refresh_Token) .build() ); } + + // RefreshToken으로 AccessToken 재발급 + public String createAccessTokenFromRefreshToken(String refreshToken) { + String accessToken = ""; + + // 전달받은 RefreshToken 정보로 사용자 조회(유효하지 않은 토큰일 시, 예외 발생) + Optional userByRefreshToken =Optional.ofNullable(userRepository.findByRefreshToken(refreshToken) + .orElseThrow(()-> new CustomException(ErrorCode.INVALID_REFRESH_TOKEN,"해당 refreshToken 이 존재하지 않음"))); + + // AccessToken 재발행 + accessToken = jwtTokenProvider.createAccessToken(userByRefreshToken.get().getId()); + log.info("AcessToken 재발행 성공"); + + return accessToken; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java index 427a8bd..85fd74b 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java @@ -7,6 +7,7 @@ import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; +import javax.persistence.Id; import java.util.Date; import static com.umc.DongnaeFriend.config.JwtConfig.SECRET_KEY; @@ -46,6 +47,18 @@ public String createAccessToken(Long userId) { .compact(); } + // RefreshToken 생성 + public String createRefreshToken(Long userId) { + Date now = new Date(); + Date validity = new Date(now.getTime() + REFRESH_TOKEN_EXPIRE_LENGTH); + + return Jwts.builder() + .signWith(SignatureAlgorithm.ES512, String.valueOf(SECRET_KEY)) + .claim("userId", userId) + .setIssuedAt(now) + .setExpiration(validity) + .compact(); + } diff --git a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java index df0fd76..76834db 100644 --- a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java +++ b/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java @@ -1,6 +1,8 @@ package com.umc.DongnaeFriend.security; import com.umc.DongnaeFriend.global.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; @@ -11,20 +13,27 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; +@Configuration +@Slf4j public class JwtTokenFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + + log.info("JwtTOkenFilter 진입"); + // Request Header에서 JWT 토큰 가져오기 String authorizationHeader = request.getHeader("Authorization"); + log.info("authorizationHeader : {}",authorizationHeader); - // JWT 토큰이 "Bearer "로 시작하는지 확인하고 토큰 추출 + //🛑 첫 로그인 시에도 이곳에서 걸리기 때문에 로그인이 안됨.(null) if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); - + log.info("token : {}",token); try { // JWT 토큰 검증 JwtUtil.validateToken(token); + log.info("JWT 토큰 검증완료"); // JWT 토큰에서 사용자 정보 추출 (예: 사용자 ID) Long userId = JwtUtil.getUserIdFromToken(token); @@ -35,7 +44,11 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // SecurityContextHolder에 인증 객체 저장 SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + } catch (Exception e) { + log.info("예외발생"); + // JWT 토큰 검증 실패 시, 인증 객체를 null로 설정 SecurityContextHolder.clearContext(); } From 62d71b3dfaf2cb41c5334196c03cbe66a42610c9 Mon Sep 17 00:00:00 2001 From: soogoori Date: Wed, 26 Jul 2023 12:31:33 +0900 Subject: [PATCH 42/58] =?UTF-8?q?=F0=9F=8F=9D=EF=B8=8FFeat=20#36:=20[?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/sharing/dto/SharingDto.java | 17 ++- .../repository/SharingBoardRepository.java | 3 +- .../repository/SharingCommentRepository.java | 10 ++ .../repository/SharingSympathyRepository.java | 2 +- .../domain/dongnae/dto/DongnaeBoardDto.java | 2 - .../AccountBookProfileController.java | 25 +++++ .../profile/dto/AccountBookProfileDto.java | 25 +++++ .../domain/profile/dto/DongnaeProfileDto.java | 1 - .../service/AccountBookProfileService.java | 102 ++++++++++++++++++ 9 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index 7825ef8..c5b8a74 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -82,6 +82,21 @@ public static class ListResponse { } - + /** + * 프로필 조회 시 필요한 정보 + */ + @Getter @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class AccountBookProfileListResponse { + private Long id; + //private String town; + private int category; + private String title; + private String imageUrl; + private String createdAt; + private int commentCount; + private int likeCount; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java index 44692ff..b508037 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -39,7 +39,8 @@ public interface SharingBoardRepository extends JpaRepository "AND sharing_board.category = :category GROUP BY sharing_board.sharing_board_id ", nativeQuery = true) List findByKeywordOrderByLikes(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); - + List findAllByUserId(Long userId); + int countAllByUserId(Long userId); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java index 91ff0ee..afb4b9e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java @@ -1,11 +1,21 @@ package com.umc.DongnaeFriend.domain.account.sharing.repository; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface SharingCommentRepository extends JpaRepository { public int countAllBySharingBoardId(Long sharing_board_id); + int countAllByUserId(Long userId); + + @Query(value = "select c from SharingComment c join fetch c.sharingBoard sb " + + "where c.user.id = :userId order by c.createdAt desc") + List getCommentByUserIdAndBoard(@Param("userId") Long userId); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java index fdd5e38..929aef3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java @@ -9,6 +9,6 @@ public interface SharingSympathyRepository extends JpaRepository { int countAllBySharingBoardId(Long sharing_board_id); - + int countAllByUserId(Long userId); List findByUser_Id(long user_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 6489bcf..b4cb5e2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -134,7 +134,5 @@ public static class DongnaeProfileListResponse { private int commentCount; private int likeCount; } - - } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java new file mode 100644 index 0000000..c070924 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java @@ -0,0 +1,25 @@ +package com.umc.DongnaeFriend.domain.profile.controller; + +import com.umc.DongnaeFriend.domain.profile.dto.AccountBookProfileDto; +import com.umc.DongnaeFriend.domain.profile.service.AccountBookProfileService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class AccountBookProfileController { + + private final AccountBookProfileService accountBookProfileService; + + // 동네정보 프로필 조회 + @GetMapping({"/api/my/account-books", "/api/{userId}/account-books"}) + public AccountBookProfileDto.AccountBookProfileResponse getProfile(@PathVariable(value = "userId", required = false) Long userId, + @RequestParam int category){ + return accountBookProfileService.getAbSharing(userId, category); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java index 979eb6b..339d690 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java @@ -1,4 +1,29 @@ package com.umc.DongnaeFriend.domain.profile.dto; +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + public class AccountBookProfileDto { + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class AccountBookProfileResponse{ + + private Long userId; + private boolean isMine; + private String nickname; + private String profileImage; + private int postTotalCount; + private int commentTotalCount; + private int likedTotalCount; + private UserProfileDto.UserProfileResponseDto profile; + private List content; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java index 64df6cf..ada69b9 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java @@ -13,7 +13,6 @@ public class DongnaeProfileDto { @Getter @Builder @AllArgsConstructor - @NoArgsConstructor public static class DongnaeProfileResponse{ diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java new file mode 100644 index 0000000..9cedbf7 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java @@ -0,0 +1,102 @@ +package com.umc.DongnaeFriend.domain.profile.service; + +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingCommentRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingImgRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingSympathyRepository; +import com.umc.DongnaeFriend.domain.profile.dto.AccountBookProfileDto; +import com.umc.DongnaeFriend.domain.profile.dto.UserProfileDto; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +@Service +@RequiredArgsConstructor +public class AccountBookProfileService { + + private final UserRepository userRepository; + private final SharingBoardRepository sharingBoardRepository; + private final SharingCommentRepository sharingCommentRepository; + private final SharingSympathyRepository sharingSympathyRepository; + private final SharingImgRepository sharingImgRepository; + + // 본인 or 타사용자 확인 + private User checkUser(Long userId){ + User user; + if(userId==null){ // 유저아이디가 없으면 본인 + user = userRepository.findById(userId/*본인인증 필요*/) + .orElseThrow(); + }else{ + user = userRepository.findById(userId) + .orElseThrow(); + } + return user; + } + + /** + * 가계부 공유 프로필 조회 + */ + public AccountBookProfileDto.AccountBookProfileResponse getAbSharing(Long userId, int category){ + User user = checkUser(userId); + + // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 + + return AccountBookProfileDto.AccountBookProfileResponse.builder() + .userId(userId==null ? user.getId() /*본인인증 필요*/ : userId) + .nickname(user.getNickname()) + .isMine(userId.equals(user.getId() /*본인인증 필오*/)) + .profileImage(user.getProfileImage()) + .postTotalCount(sharingBoardRepository.countAllByUserId(user.getId())) + .commentTotalCount(sharingCommentRepository.countAllByUserId(user.getId())) + .likedTotalCount(sharingSympathyRepository.countAllByUserId(user.getId())) + .profile(UserProfileDto.UserProfileResponseDto.of(user)) + .content(getWrittenContent(user.getId(), category)) + .build(); + } + /** + * 가계부 공유 - 작성한 글 , 작성한 댓글의 게시글 조회 + */ + public List getWrittenContent(Long userId, int category) { + User user = checkUser(userId); + + List sharingBoardList; + if(category==0){ + sharingBoardList= sharingBoardRepository.findAllByUserId(user.getId()); + }else{ + sharingBoardList = sharingCommentRepository.getCommentByUserIdAndBoard(user.getId()) + .stream().map(SharingComment::getSharingBoard).distinct().collect(Collectors.toList()); + } + return getProfileListResponse(sharingBoardList); + } + + /** + * TODO : 공감, 스크랩 게시물 조회 필요 + */ + + + //ListResponse 변환 + private List getProfileListResponse(List sharingBoardList){ + return sharingBoardList.stream() + .map(sharingBoard -> SharingDto.AccountBookProfileListResponse.builder() + .id(sharingBoard.getId()) + //.town(sharingBoard.getPlaceLocation()) + .category(sharingBoard.getCategory().getValue()) + .title(sharingBoard.getTitle()) + .imageUrl(sharingImgRepository.findFirst(sharingBoard.getId()).map(SharingImg::getImageUrl).orElse("")) + .createdAt(getTime(sharingBoard.getCreatedAt())) + .commentCount(sharingCommentRepository.countAllBySharingBoardId(sharingBoard.getId())) + .likeCount(sharingSympathyRepository.countAllBySharingBoardId(sharingBoard.getId())) + .build()) + .collect(Collectors.toList()); + } +} From ad6f7ce017003da1e488041817a62720b3144880 Mon Sep 17 00:00:00 2001 From: soogoori Date: Wed, 26 Jul 2023 12:32:50 +0900 Subject: [PATCH 43/58] =?UTF-8?q?=F0=9F=8F=9D=EF=B8=8FFeat=20#36:=20[?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=EA=B0=80?= =?UTF-8?q?=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriend/domain/account/sharing/dto/SharingDto.java | 3 --- .../account/sharing/repository/SharingBoardRepository.java | 2 -- .../account/sharing/repository/SharingCommentRepository.java | 1 - .../account/sharing/repository/SharingSympathyRepository.java | 1 - .../umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java | 1 - .../domain/profile/dto/AccountBookProfileDto.java | 1 - 6 files changed, 9 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index c5b8a74..101fc37 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -1,9 +1,6 @@ package com.umc.DongnaeFriend.domain.account.sharing.dto; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; -import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; -import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import com.umc.DongnaeFriend.domain.type.SharingCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java index b508037..1191920 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -1,8 +1,6 @@ package com.umc.DongnaeFriend.domain.account.sharing.repository; -import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java index afb4b9e..0eef074 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java @@ -1,7 +1,6 @@ package com.umc.DongnaeFriend.domain.account.sharing.repository; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java index 929aef3..f559723 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java @@ -1,7 +1,6 @@ package com.umc.DongnaeFriend.domain.account.sharing.repository; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingSympathy; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeSympathy; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index b4cb5e2..2076f50 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -12,7 +12,6 @@ import lombok.*; import java.util.List; -import java.util.stream.Collectors; public class DongnaeBoardDto { diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java index 339d690..18e910d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java @@ -1,7 +1,6 @@ package com.umc.DongnaeFriend.domain.profile.dto; import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; -import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; From 2baa9d3f1f8cbbbf5bd788117c83e00c5d32ef31 Mon Sep 17 00:00:00 2001 From: soogoori Date: Wed, 26 Jul 2023 12:54:47 +0900 Subject: [PATCH 44/58] =?UTF-8?q?:pencil2:=20Fix=20#36=20:=20[=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80]=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A1=B0=ED=9A=8C=20DTO=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriend/domain/account/sharing/dto/SharingDto.java | 4 ++-- .../umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java | 4 ++-- .../domain/profile/dto/AccountBookProfileDto.java | 2 -- .../DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java | 2 -- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index 101fc37..7f3b2b2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -86,11 +86,11 @@ public static class ListResponse { @AllArgsConstructor @NoArgsConstructor public static class AccountBookProfileListResponse { - private Long id; - //private String town; + private Long boardId; private int category; private String title; private String imageUrl; + //private String town; private String createdAt; private int commentCount; private int likeCount; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 2076f50..b956d4f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -124,11 +124,11 @@ public static class Response { @AllArgsConstructor @NoArgsConstructor public static class DongnaeProfileListResponse { - private Long id; - private String town; + private Long boardId; private int category; private String title; private String imageUrl; + private String town; private String createdAt; private int commentCount; private int likeCount; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java index 18e910d..bc06ca6 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java @@ -17,8 +17,6 @@ public static class AccountBookProfileResponse{ private Long userId; private boolean isMine; - private String nickname; - private String profileImage; private int postTotalCount; private int commentTotalCount; private int likedTotalCount; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java index ada69b9..f0e74b3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java @@ -18,8 +18,6 @@ public static class DongnaeProfileResponse{ private Long userId; private boolean isMine; - private String nickname; - private String profileImage; private int postTotalCount; private int commentTotalCount; private int likedTotalCount; From cde7adcfa0de1dd06b88458183a1190334c12a28 Mon Sep 17 00:00:00 2001 From: soogoori Date: Thu, 27 Jul 2023 13:53:44 +0900 Subject: [PATCH 45/58] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Feat=20#36=20:=20[?= =?UTF-8?q?=EA=B0=80=EA=B3=84=EB=B6=80]=20=EC=98=88=EC=82=B0=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=88=98=EC=A0=95=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 8196 bytes .../book/controller/AccountBookController.java | 7 +++++++ .../domain/account/book/entity/AccountBook.java | 4 ++++ .../account/book/service/AccountBookService.java | 10 ++++++++-- .../service/AccountBookProfileService.java | 2 +- .../profile/service/DongnaeProfileService.java | 4 +--- src/main/resources/application.yml | 1 + 7 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a178c9f76b1b7a98dfbbe423c9a26119f2a2baf1 GIT binary patch literal 8196 zcmeHML5tHs82zU0Zd0n*gDZOx0$!K3u8SgGvb75e3bGYFsMMwjYuGd?O}a%&AxFjk z;9v0OPw~Ha()Z1bYm#=0CvkN?n0b@Qdy~n_*UV0qh(u@V-6Gm1A`6AF)kL)-_&k@T zsOX*+P(V*KCZC41OYdm3#5Ntq0poyiz&KzWFb@0;4q(mZu+CZc)mc*;2aE&%r33ta zuu&KtjhRCE>Odv80Kgi$WuVR50oK?W9gUenoIwaB1uCh~TMVJ(=(jb`(U>VzauRy; zA@r4n-k}J2b&PLIItfRisf`21fn^8y=hCDBcJ5L>z@PP7S0BVtItU_vA_alxgYxP{ z5P9*e6Hg;Ak=mX*VKuBqzjbXsZ|~T*@9r&j?D@StwD<4qFBT1J>&DIdNBxs<6vgi` zdxX$0GrFvf&*~3o74H7DH;KYHI%W|{J?{+7NuV;)eKo&Z;jD{~;Ps3R+f$d~}RnNm`m zv*0Yqv#)^dgO`FI;jWXl`Nlrw)m88(G%Q|2`m%!cPvn@s<5G6P78#srHVUJoF;mE0 z+;7%@Ho}B)-~u{ORde3v{r}wu_rd)*G$a#dfU;#J;8d4s~i nyiB2#pep1${I&wrVu>{^C3XmU@GIlA9dgdH>f7e literal 0 HcmV?d00001 diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java index 24a2b90..6dd5e69 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -28,6 +28,13 @@ public void createBudget(@RequestParam(value = "year", required = false) Integer accountBookService.createBudget(year, month, budget); } + @PutMapping("/budget") + public void updateBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestParam(value = "amount", required = false) Long budget){ + accountBookService.updateBudget(year, month, budget); + } + @GetMapping("/category") public List getTransactionAll(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month){ diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java index fd4f4b8..65f6afb 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java @@ -40,4 +40,8 @@ public class AccountBook extends BaseTimeEntity { @Column(nullable = false) private Integer month; + + public void updateBudget(Long budget){ + this.budget = budget; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java index 3caaf36..d932ecc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -23,9 +23,9 @@ public class AccountBookService { // 가계부 예산 설정 (한달) @Transactional public void createBudget(Integer year, Integer month, Long budget){ - this.accountBookRepository.findByYearAndMonth(year, month) + /*this.accountBookRepository.findByYearAndMonth(year, month) .ifPresent(ab->{throw new IllegalStateException("이미 예산이 설정되어있습니다."); - }); + });*/ accountBookRepository.save(AccountBookDto.BudgetRequest.toEntity(year, month, budget)); } @@ -35,6 +35,12 @@ public AccountBookDto.BudgetResponse getBudget(Integer year, Integer month){ return AccountBookDto.BudgetResponse.of(accountBook.getId(),accountBook.getBudget()); } + // 가계부 예산 설정 수정 + public void updateBudget(Integer year, Integer month, Long budget){ + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + accountBook.updateBudget(budget); + } + // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, Integer month) { diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java index 9cedbf7..42b9057 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java @@ -88,7 +88,7 @@ public List getWrittenContent(Long us private List getProfileListResponse(List sharingBoardList){ return sharingBoardList.stream() .map(sharingBoard -> SharingDto.AccountBookProfileListResponse.builder() - .id(sharingBoard.getId()) + .boardId(sharingBoard.getId()) //.town(sharingBoard.getPlaceLocation()) .category(sharingBoard.getCategory().getValue()) .title(sharingBoard.getTitle()) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java index 5930e3a..74834c5 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java @@ -54,9 +54,7 @@ public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, i return DongnaeProfileDto.DongnaeProfileResponse.builder() .userId(userId==null ? user.getId() /*본인인증 필요*/ : userId) - .nickname(user.getNickname()) .isMine(userId.equals(user.getId() /*본인인증 필오*/)) - .profileImage(user.getProfileImage()) .postTotalCount(dongnaeBoardRepository.countAllByUserId(user.getId())) .commentTotalCount(commentRepository.countAllByUserId(user.getId())) .likedTotalCount(dongnaeSympathyRepository.countAllByUserId(user.getId())) @@ -84,7 +82,7 @@ public List getWrittenContent(Long u private List getProfileListResponse(List dongnaeBoardList){ return dongnaeBoardList.stream() .map(dongnaeBoard -> DongnaeBoardDto.DongnaeProfileListResponse.builder() - .id(dongnaeBoard.getId()) + .boardId(dongnaeBoard.getId()) .town(dongnaeBoard.getPlaceLocation()) .category(dongnaeBoard.getCategory().getValue()) .title(dongnaeBoard.getTitle()) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a8707ff..482cdcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,3 +20,4 @@ spring: jpa: hibernate.ddl-auto: update database: mysql + From b6ebe091bcd5c41f9df94c16a45a96e5c4b8f772 Mon Sep 17 00:00:00 2001 From: soogoori Date: Thu, 27 Jul 2023 17:48:11 +0900 Subject: [PATCH 46/58] =?UTF-8?q?=E2=9C=8F=20Fix=20#36=20:=20[=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=A1=B0=ED=9A=8C]=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/controller/AccountBookController.java | 2 -- .../accountBook/AccountBookRepositoryCustomImpl.java | 1 - .../sharing/repository/SharingBoardRepository.java | 2 +- .../controller/AccountBookProfileController.java | 5 +++-- .../profile/controller/DongnaeProfileController.java | 5 +++-- .../profile/service/AccountBookProfileService.java | 11 +++++------ .../domain/profile/service/DongnaeProfileService.java | 7 ++++--- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java index 6dd5e69..a9f0475 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -3,7 +3,6 @@ import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -34,7 +33,6 @@ public void updateBudget(@RequestParam(value = "year", required = false) Integer @RequestParam(value = "amount", required = false) Long budget){ accountBookService.updateBudget(year, month, budget); } - @GetMapping("/category") public List getTransactionAll(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month){ diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java index 73a7d99..d0b9eb6 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -4,7 +4,6 @@ import com.umc.DongnaeFriend.domain.account.book.dto.Expense; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Pageable; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java index 1191920..6596961 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -37,7 +37,7 @@ public interface SharingBoardRepository extends JpaRepository "AND sharing_board.category = :category GROUP BY sharing_board.sharing_board_id ", nativeQuery = true) List findByKeywordOrderByLikes(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); - List findAllByUserId(Long userId); + List findAllByUserId(Long userId, Pageable pageable); int countAllByUserId(Long userId); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java index c070924..89ee471 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java @@ -4,6 +4,7 @@ import com.umc.DongnaeFriend.domain.profile.service.AccountBookProfileService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -19,7 +20,7 @@ public class AccountBookProfileController { // 동네정보 프로필 조회 @GetMapping({"/api/my/account-books", "/api/{userId}/account-books"}) public AccountBookProfileDto.AccountBookProfileResponse getProfile(@PathVariable(value = "userId", required = false) Long userId, - @RequestParam int category){ - return accountBookProfileService.getAbSharing(userId, category); + @RequestParam int category, Pageable pageable){ + return accountBookProfileService.getAbSharing(userId, category, pageable); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java index cdeb93b..7b01050 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java @@ -6,6 +6,7 @@ import com.umc.DongnaeFriend.domain.profile.service.DongnaeProfileService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; import org.springframework.data.repository.query.Param; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -24,8 +25,8 @@ public class DongnaeProfileController { // 동네정보 프로필 조회 @GetMapping({"/api/my/town", "/api/{userId}/town"}) public DongnaeProfileDto.DongnaeProfileResponse getProfile(@PathVariable(value = "userId", required = false) Long userId, - @RequestParam int category){ - return dongnaeProfileService.getDongnaeProfile(userId, category); + @RequestParam int category, Pageable pageable){ + return dongnaeProfileService.getDongnaeProfile(userId, category, pageable); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java index 42b9057..aef7669 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java @@ -13,6 +13,7 @@ import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; @@ -46,32 +47,30 @@ private User checkUser(Long userId){ /** * 가계부 공유 프로필 조회 */ - public AccountBookProfileDto.AccountBookProfileResponse getAbSharing(Long userId, int category){ + public AccountBookProfileDto.AccountBookProfileResponse getAbSharing(Long userId, int category, Pageable pageable){ User user = checkUser(userId); // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 return AccountBookProfileDto.AccountBookProfileResponse.builder() .userId(userId==null ? user.getId() /*본인인증 필요*/ : userId) - .nickname(user.getNickname()) .isMine(userId.equals(user.getId() /*본인인증 필오*/)) - .profileImage(user.getProfileImage()) .postTotalCount(sharingBoardRepository.countAllByUserId(user.getId())) .commentTotalCount(sharingCommentRepository.countAllByUserId(user.getId())) .likedTotalCount(sharingSympathyRepository.countAllByUserId(user.getId())) .profile(UserProfileDto.UserProfileResponseDto.of(user)) - .content(getWrittenContent(user.getId(), category)) + .content(getWrittenContent(user.getId(), category, pageable)) .build(); } /** * 가계부 공유 - 작성한 글 , 작성한 댓글의 게시글 조회 */ - public List getWrittenContent(Long userId, int category) { + public List getWrittenContent(Long userId, int category, Pageable pageable) { User user = checkUser(userId); List sharingBoardList; if(category==0){ - sharingBoardList= sharingBoardRepository.findAllByUserId(user.getId()); + sharingBoardList= sharingBoardRepository.findAllByUserId(user.getId(), pageable); }else{ sharingBoardList = sharingCommentRepository.getCommentByUserIdAndBoard(user.getId()) .stream().map(SharingComment::getSharingBoard).distinct().collect(Collectors.toList()); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java index 74834c5..e24c6f5 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java @@ -13,6 +13,7 @@ import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; @@ -47,7 +48,7 @@ private User checkUser(Long userId){ /** * 동네 정보 프로필 조회 */ - public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, int category){ + public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, int category, Pageable pageable){ User user = checkUser(userId); // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 @@ -59,14 +60,14 @@ public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, i .commentTotalCount(commentRepository.countAllByUserId(user.getId())) .likedTotalCount(dongnaeSympathyRepository.countAllByUserId(user.getId())) .profile(UserProfileDto.UserProfileResponseDto.of(user)) - .content(getWrittenContent(user.getId(), category)) + .content(getWrittenContent(user.getId(), category, pageable)) .build(); } /** * 동네정보 - 작성한 글 , 작성한 댓글의 게시글 조회 * TODO : 공감, 스크랩 게시물 조회 필요 */ - public List getWrittenContent(Long userId, int category) { + public List getWrittenContent(Long userId, int category, Pageable pageable) { User user = checkUser(userId); List dongnaeBoardList; From 2e33b3a31264645229bb1d94540f7b349dac05c2 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Thu, 27 Jul 2023 23:43:38 +0900 Subject: [PATCH 47/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFeat=20#23:=20[Secur?= =?UTF-8?q?ity]=20User=20Security=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umc/DongnaeFriend/config/JwtConfig.java | 2 +- .../DongnaeFriend/config/SecurityConfig.java | 4 +- .../accountBookSharingController.java | 3 +- .../repository/SharingBoardRepository.java | 1 - .../controller/DongnaeBoardController.java | 5 ++ .../user/contorller/UserController.java | 23 ++++-- .../domain/user/dto/UserDto.java | 2 + .../domain/user/entity/User.java | 2 + .../user/repository/UserRepository.java | 2 + .../domain/user/service/KakaoService.java | 4 + .../domain/user/service/KakaoServiceimpl.java | 17 ++-- .../domain/user/service/UserService.java | 82 +++++++++++++------ .../exception/GlobalExceptionHandler.java | 14 ++-- .../{ => global}/security/JwtTokenFilter.java | 36 ++++++-- .../global/util/JwtTokenProvider.java | 16 ++-- .../DongnaeFriend/global/util/JwtUtil.java | 48 +++++++++-- src/main/resources/application.yml | 6 +- 17 files changed, 190 insertions(+), 77 deletions(-) rename src/main/java/com/umc/DongnaeFriend/{ => global}/security/JwtTokenFilter.java (70%) diff --git a/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java b/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java index af15fc2..902da00 100644 --- a/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java +++ b/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java @@ -7,6 +7,6 @@ public class JwtConfig { @Value("${jwt.secret-key}") - public static String SECRET_KEY; + public String SECRET_KEY; } diff --git a/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java index 6931738..865fbbf 100644 --- a/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java +++ b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java @@ -1,6 +1,7 @@ package com.umc.DongnaeFriend.config; -import com.umc.DongnaeFriend.security.JwtTokenFilter; + +import com.umc.DongnaeFriend.global.security.JwtTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -30,4 +31,3 @@ protected void configure(HttpSecurity http) throws Exception { // 나머지 코드는 이전 예제와 동일 } - diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java index 67d39ea..d067631 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -7,6 +7,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -35,9 +36,7 @@ public class accountBookSharingController { @GetMapping("/search") public ResponseEntity searchAll(@RequestParam("keyword") String keyword, @RequestParam("category") int category, Pageable pageable) { - log.info("searching : " + keyword + category); List res = accountBookSharingService.searchByKeyword(keyword, category, pageable); - log.info("res "); return ResponseEntity.ok(res); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java index 44692ff..54bc584 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -9,7 +9,6 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import javax.persistence.EntityManager; import java.util.List; @Repository diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index b168f28..51c4fe2 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -3,6 +3,7 @@ import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.core.context.SecurityContextHolder; @@ -14,6 +15,7 @@ * [ 가계부 공유 ] * */ +@Slf4j @RestController @RequestMapping("/town-information") public class DongnaeBoardController { @@ -53,6 +55,9 @@ public ResponseEntity getLocation() { public ResponseEntity getBoards(@RequestParam("keyword") String keyword, @RequestParam("category") int category, @RequestParam("sortBy") int sort) { + + + log.info("User Id: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return ResponseEntity.ok(dongnaeBoardService.searchByKeyword(keyword, category, sort)); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java index d8d0374..cc30211 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java @@ -8,9 +8,12 @@ import com.umc.DongnaeFriend.global.util.JwtTokenProvider; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.repository.query.Param; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; @@ -25,6 +28,7 @@ public class UserController { @Autowired UserService userService; + @Autowired JwtTokenProvider jwtTokenProvider; @@ -34,19 +38,24 @@ public class UserController { * 인증 절차 */ @PostMapping("/login") - public ResponseEntity userLogin(@RequestBody UserDto.Request request) { + public ResponseEntity userLogin(@RequestParam("accessToken") String accessToken, HttpServletRequest request, HttpServletResponse httpServletResponse) { + log.info("LoginController 진입"); + +// if (!type.equals("kakao")) { +// throw new CustomException(ErrorCode.SERVER_ERROR); +// } + + try { log.info("userLogin 진입"); //사용자 정보 가져오기 - HashMap userInfo = kakaoService.getUserInfo(request.getAccessToken()); + HashMap userInfo = kakaoService.getUserInfo(accessToken); //사용자 확인 기존 회원 -> 넘어가고, 없는 회원 -> 회원가입 - userService.userValidation(userInfo); - //토큰 생성 - String access_token = jwtTokenProvider.createAccessToken((Long) userInfo.get("userId")); - log.info("access_token : {}", access_token); - return ResponseEntity.ok(access_token); + UserDto.Response response = userService.userValidation(userInfo); + + return ResponseEntity.ok(response); } catch (IOException e) { throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java b/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java index 469dcdb..0ebf5bc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java @@ -1,6 +1,7 @@ package com.umc.DongnaeFriend.domain.user.dto; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; public class UserDto { @@ -16,6 +17,7 @@ public static class Request { } @Getter + @Builder @AllArgsConstructor public static class Response { diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java index b6e8772..201db2e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java @@ -13,6 +13,7 @@ import com.umc.DongnaeFriend.domain.type.YesNo; import javax.persistence.*; import lombok.*; +import org.springframework.lang.Nullable; @Getter @Builder @@ -29,6 +30,7 @@ public class User extends BaseTimeEntity { @ManyToOne(fetch = LAZY) @JoinColumn(name = "dongnae_id") + @Nullable private Dongnae dongnae; @Column(nullable = false) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java index 5edd72b..d6d323a 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java @@ -10,4 +10,6 @@ public interface UserRepository extends JpaRepository { Optional findById(Long id); Optional findByRefreshToken(String refresh_token); + + Optional findByKakaoId(Long id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java index a4b2aaf..d3cd29f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java @@ -1,11 +1,15 @@ package com.umc.DongnaeFriend.domain.user.service; +import org.springframework.beans.factory.annotation.Value; + import java.io.IOException; import java.util.HashMap; public interface KakaoService { + + @SuppressWarnings("unchecked") HashMap getUserInfo(String access_Token) throws IOException; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java index 4955e10..6c147f5 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.io.BufferedReader; @@ -12,6 +13,7 @@ import java.util.HashMap; import java.util.Map; +@Slf4j @Service public class KakaoServiceimpl implements KakaoService { @@ -52,23 +54,26 @@ public HashMap getUserInfo(String access_Token) throws IOExcepti Map jsonMap = objectMapper.readValue(result, new TypeReference>() { }); + System.out.println(jsonMap.get("properties")); + Long id = (Long) jsonMap.get("id"); Map properties = (Map) jsonMap.get("properties"); Map kakao_account = (Map) jsonMap.get("kakao_account"); + Map profile = (Map) kakao_account.get("profile"); - // System.out.println(properties.get("nickname")); - // System.out.println(kakao_account.get("email")); + log.info("profile : " + profile.toString()); + log.info("kakao_acount : " + kakao_account.toString()); String nickname = properties.get("nickname").toString(); + String profileImage = properties.get("profile_image").toString(); String email = kakao_account.get("email").toString(); - String gender = kakao_account.get("gender").toString(); - String age = kakao_account.get("age").toString(); + userInfo.put("id", id); userInfo.put("nickname", nickname); + userInfo.put("profileImage", profileImage); userInfo.put("email", email); - userInfo.put("gender", gender); - userInfo.put("age", age); + return userInfo; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java index 3f7e6f1..40e600c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -3,6 +3,7 @@ import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.Gender; import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.dto.UserDto; import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import com.umc.DongnaeFriend.global.exception.CustomException; @@ -25,53 +26,80 @@ public class UserService { KakaoService kakaoService; + @Autowired JwtTokenProvider jwtTokenProvider; - public void userValidation(HashMap userInfo) { - Optional user= userRepository.findById((Long) userInfo.get("userId")); + public UserDto.Response userValidation(HashMap userInfo) { + Long kakao_id = (Long) userInfo.get("id"); + Optional user= userRepository.findByKakaoId(kakao_id); if (user.isEmpty()) { - userRegister(userInfo); + User new_user = userRegister(userInfo); + return UserDto.Response.builder() + .accessToken(jwtTokenProvider.createAccessToken(new_user.getId())) + .refreshToken(new_user.getRefreshToken()) + .build(); + } else { + return UserDto.Response.builder() + .accessToken(jwtTokenProvider.createAccessToken(user.get().getId())) + .refreshToken(user.get().getRefreshToken()) + .build(); } + } - //유저 회원가입 - public void userRegister(HashMap userInfo) { + //유저 회원가입 -> Refresh Token을 return + public User userRegister(HashMap userInfo) { //필수 String nickName = userInfo.get("nickname").toString(); //필수 String email = userInfo.get("email").toString(); - Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); - String strGender = ""; - log.info("Gender : {}", gender.get()); - if(gender.get()=="F"){ - strGender="여성"; - }else { - strGender = "남성"; - } - log.info("strGender : {}", strGender); - - - Optional age = Optional.ofNullable(userInfo.get("age").toString()); - String[] ageRange = age.get().split("-"); - - - // refreshToken userId를 claim 으로 생성 뒤, User의 필드에 넣고 User를 저장 - String refresh_Token = jwtTokenProvider.createRefreshToken((Long) userInfo.get("usreId")); - - userRepository.save( + String profileImage = userInfo.get("profileImage").toString(); + + Long kakaoId = (Long) userInfo.get("id"); + +// Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); +// String strGender = ""; +// log.info("Gender : {}", gender.get()); +// if(gender.get()=="F"){ +// strGender="여성"; +// }else { +// strGender = "남성"; +// } +// log.info("strGender : {}", strGender); +// +// +// Optional age = Optional.ofNullable(userInfo.get("age").toString()); +// String[] ageRange = age.get().split("-"); +// +// +// // refreshToken userId를 claim 으로 생성 뒤, User의 필드에 넣고 User를 저장 + String refresh_Token = jwtTokenProvider.createRefreshToken((Long) userInfo.get("id")); + + return userRepository.save( User.builder() .nickname(nickName) +// .dongnae( +// +// ) .email(email) //TODO : Gender 결정[O] - .gender(Gender.valueOf(strGender)) + .gender( +// Gender.valueOf(strGender) + Gender.MALE + ) //TODO : Age 결정[O] - .age(Age.valueOf(ageRange[0]+"대")) + .age( +// Age.valueOf(ageRange[0]+"대") + Age.AGE20 + ) .townCert(YesNo.NO) .townCertCnt(0) .infoCert(YesNo.NO) + .profileImage(profileImage) + .kakaoId(kakaoId) .refreshToken(refresh_Token) .build() ); @@ -91,4 +119,6 @@ public String createAccessTokenFromRefreshToken(String refreshToken) { return accessToken; } + + } diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java index 986c73d..37fb335 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java @@ -30,11 +30,11 @@ protected ResponseEntity handleMethodArgumentNotValidException(MethodArgument } //일반 예외처리 - @ExceptionHandler({Exception.class}) - protected ResponseEntity handleServerException(Exception ex) { - CustomException exception = new CustomException(SERVER_ERROR); - return ResponseEntity - .status(SERVER_ERROR.getHttpStatus()) - .body(new ErrorResponse(exception)); - } +// @ExceptionHandler({Exception.class}) +// protected ResponseEntity handleServerException(Exception ex) { +// CustomException exception = new CustomException(SERVER_ERROR); +// return ResponseEntity +// .status(SERVER_ERROR.getHttpStatus()) +// .body(new ErrorResponse(exception)); +// } } \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java similarity index 70% rename from src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java rename to src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java index 76834db..6c0cb55 100644 --- a/src/main/java/com/umc/DongnaeFriend/security/JwtTokenFilter.java +++ b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java @@ -1,9 +1,10 @@ -package com.umc.DongnaeFriend.security; +package com.umc.DongnaeFriend.global.security; import com.umc.DongnaeFriend.global.util.JwtUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; @@ -17,10 +18,22 @@ @Slf4j public class JwtTokenFilter extends OncePerRequestFilter { + + private final JwtUtil jwtUtil; + + public JwtTokenFilter(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; + } + + @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - log.info("JwtTOkenFilter 진입"); + log.info("JwtTokenFilter 진입"); + + if (request.getServletPath().contains("/user/login")) { + log.info("/user/login 진입"); + } // Request Header에서 JWT 토큰 가져오기 String authorizationHeader = request.getHeader("Authorization"); @@ -29,30 +42,37 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse //🛑 첫 로그인 시에도 이곳에서 걸리기 때문에 로그인이 안됨.(null) if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); - log.info("token : {}",token); + log.info("token : {}", token); try { // JWT 토큰 검증 - JwtUtil.validateToken(token); + jwtUtil.validateToken(token); log.info("JWT 토큰 검증완료"); // JWT 토큰에서 사용자 정보 추출 (예: 사용자 ID) - Long userId = JwtUtil.getUserIdFromToken(token); + Long userId = jwtUtil.getUserIdFromToken(token); // 인증 객체 생성 UsernamePasswordAuthenticationToken authenticationToken = - new UsernamePasswordAuthenticationToken(userId, null, null); + new UsernamePasswordAuthenticationToken( userId,null, null); // SecurityContextHolder에 인증 객체 저장 + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + filterChain.doFilter(request, response); + } catch (Exception e) { - log.info("예외발생"); + e.printStackTrace(); // JWT 토큰 검증 실패 시, 인증 객체를 null로 설정 SecurityContextHolder.clearContext(); + filterChain.doFilter(request, response); } + } else { + log.info("Header None"); + filterChain.doFilter(request, response); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java index 85fd74b..344ba00 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java @@ -1,25 +1,27 @@ package com.umc.DongnaeFriend.global.util; +import com.umc.DongnaeFriend.config.JwtConfig; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import io.jsonwebtoken.*; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; -import javax.persistence.Id; import java.util.Date; -import static com.umc.DongnaeFriend.config.JwtConfig.SECRET_KEY; + @Log4j2 @Component public class JwtTokenProvider { + private final JwtConfig jwtConfig; + @Autowired private UserRepository userRepository; - public JwtTokenProvider(UserRepository userRepository) { + public JwtTokenProvider(JwtConfig jwtConfig, UserRepository userRepository) { + this.jwtConfig = jwtConfig; this.userRepository = userRepository; } @@ -29,6 +31,8 @@ public JwtTokenProvider(UserRepository userRepository) { //accessToken 생성 public String createAccessToken(Long userId) { + + log.info("SECRET KEY FROM PROVIDER: "+ jwtConfig.SECRET_KEY); Date now = new Date(); //현재 시간 Date validity = new Date(now.getTime() + ACCESS_TOKEN_EXPIRE_LENGTH); @@ -40,7 +44,7 @@ public String createAccessToken(Long userId) { // claims.put("email", user.getEmail()); // 사용자 이메일 return Jwts.builder() - .signWith(SignatureAlgorithm.HS512, String.valueOf(SECRET_KEY)) + .signWith(SignatureAlgorithm.HS512, String.valueOf(jwtConfig.SECRET_KEY)) .claim("userId", userId) .setIssuedAt(now) //token 발행 시간 .setExpiration(validity) @@ -53,7 +57,7 @@ public String createRefreshToken(Long userId) { Date validity = new Date(now.getTime() + REFRESH_TOKEN_EXPIRE_LENGTH); return Jwts.builder() - .signWith(SignatureAlgorithm.ES512, String.valueOf(SECRET_KEY)) + .signWith(SignatureAlgorithm.HS512, String.valueOf(jwtConfig.SECRET_KEY)) .claim("userId", userId) .setIssuedAt(now) .setExpiration(validity) diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java index 09f0e95..a1c15b9 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java @@ -1,26 +1,60 @@ package com.umc.DongnaeFriend.global.util; +import com.umc.DongnaeFriend.config.JwtConfig; import com.umc.DongnaeFriend.global.exception.CustomException; import com.umc.DongnaeFriend.global.exception.ErrorCode; import io.jsonwebtoken.Claims; import io.jsonwebtoken.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; -import static com.umc.DongnaeFriend.config.JwtConfig.SECRET_KEY; +@Slf4j +@Component public class JwtUtil { - public static Long getUserIdFromToken(String token) { - Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); + private final JwtConfig jwtConfig; + + public JwtUtil(JwtConfig jwtConfig) { + this.jwtConfig = jwtConfig; + } + + public Long getUserIdFromToken(String token) { + log.info("token에서 ID 추출"); + Claims claims = Jwts.parser().setSigningKey(jwtConfig.SECRET_KEY).parseClaimsJws(token).getBody(); return Long.parseLong(claims.get("userId").toString()); } //token 유효성 검증 - public static Boolean validateToken(String token) { + public Boolean validateToken(String token) { try { - Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); + log.info("SECRET KEY :"+ jwtConfig.SECRET_KEY); + + Jwts.parser().setSigningKey(jwtConfig.SECRET_KEY).parseClaimsJws(token); return true; - } catch (SignatureException | IllegalArgumentException | MalformedJwtException | ExpiredJwtException | - UnsupportedJwtException | NullPointerException | IllegalStateException ex) { + } catch (SignatureException e) { + log.info("Sign 오류"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (IllegalArgumentException e) { + log.info("잘못된 토큰"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (MalformedJwtException e) { + log.info("토큰 잘림"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (ExpiredJwtException e) { + log.info("만료된 토큰"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (NullPointerException e) { + log.info("토큰 없음"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (UnsupportedJwtException e) { + log.info("지원되지 않는 토큰"); + e.printStackTrace(); throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 857383e..c0bae2f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,8 +8,8 @@ logging: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: - password: + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update @@ -18,7 +18,5 @@ spring: format_sql: true show_sql: true - - jwt: secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 \ No newline at end of file From d2f267efa62083a407ccc8a0a5884bf5f59479cb Mon Sep 17 00:00:00 2001 From: soogoori Date: Fri, 28 Jul 2023 00:49:13 +0900 Subject: [PATCH 48/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20Fix=20#36=20:=20C?= =?UTF-8?q?ontroller=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AccountBookController.java | 25 ++++++++++--------- .../book/controller/MemoController.java | 20 ++++++++++----- .../controller/TransactionController.java | 17 +++++++++---- .../AccountBookProfileController.java | 8 +++--- .../controller/DongnaeProfileController.java | 8 +++--- .../profile/controller/MyPageController.java | 10 +++++--- 6 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java index a9f0475..ee6b422 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -3,6 +3,8 @@ import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -15,34 +17,33 @@ public class AccountBookController { private final AccountBookService accountBookService; @GetMapping("/budget") - public AccountBookDto.BudgetResponse getBudget(@RequestParam(value = "year", required = false) Integer year, - @RequestParam(value = "month", required = false) Integer month){ - return accountBookService.getBudget(year, month); + public ResponseEntity getBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return ResponseEntity.status(HttpStatus.OK).body(accountBookService.getBudget(year, month)); } @PostMapping("/budget") - public void createBudget(@RequestParam(value = "year", required = false) Integer year, + public ResponseEntity createBudget(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month, @RequestParam(value = "amount", required = false) Long budget){ accountBookService.createBudget(year, month, budget); + + return new ResponseEntity<>(HttpStatus.OK); } @PutMapping("/budget") - public void updateBudget(@RequestParam(value = "year", required = false) Integer year, + public ResponseEntity updateBudget(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month, @RequestParam(value = "amount", required = false) Long budget){ accountBookService.updateBudget(year, month, budget); - } - @GetMapping("/category") - public List getTransactionAll(@RequestParam(value = "year", required = false) Integer year, - @RequestParam(value = "month", required = false) Integer month){ - return null; + + return new ResponseEntity<>(HttpStatus.OK); } @GetMapping("/all") - public AccountBookDto.AccountBookResponse getAccountBook(@RequestParam(value = "year", required = false) Integer year, + public ResponseEntity getAccountBook(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month){ - return accountBookService.getAccountBookResponse(year, month); + return ResponseEntity.status(HttpStatus.OK).body(accountBookService.getAccountBookResponse(year, month)); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java index d53509f..b466809 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java @@ -3,6 +3,8 @@ import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; import com.umc.DongnaeFriend.domain.account.book.service.MemoService; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -18,26 +20,32 @@ public class MemoController { * 유저 권한 확인 필요 */ @GetMapping - public MemoDto.MemoListResponse getMemoList(@RequestParam(value = "year", required = false) Integer year, - @RequestParam(value = "month", required = false) Integer month){ - return memoService.getMemoList(year, month); + public ResponseEntity getMemoList(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return ResponseEntity.status(HttpStatus.OK).body(memoService.getMemoList(year, month)); } @PostMapping - public void createMemo(@RequestParam(value = "year", required = false) Integer year, + public ResponseEntity createMemo(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month, @RequestBody MemoDto.MemoRequest requestDto){ memoService.createMemo(requestDto, year,month); + + return new ResponseEntity<>(HttpStatus.OK); } @PutMapping - public void updateMemo(@RequestParam(value = "id", required = false) Long id, + public ResponseEntity updateMemo(@RequestParam(value = "id", required = false) Long id, @RequestBody MemoDto.MemoRequest requestDto){ memoService.updateMemo(requestDto, id); + + return new ResponseEntity<>(HttpStatus.OK); } @DeleteMapping - public void deleteMemo(@RequestParam(value = "id", required = false) Long id){ + public ResponseEntity deleteMemo(@RequestParam(value = "id", required = false) Long id){ memoService.deleteMemo(id); + + return new ResponseEntity<>(HttpStatus.OK); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java index eb475fc..e5a517e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java @@ -5,6 +5,8 @@ import com.umc.DongnaeFriend.domain.account.book.service.TransactionService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.transaction.Transactional; @@ -17,25 +19,30 @@ public class TransactionController { private final TransactionService transactionService; @PostMapping - public void createTransaction(@RequestBody TransactionDto.TransactionRequest request){ + public ResponseEntity createTransaction(@RequestBody TransactionDto.TransactionRequest request){ transactionService.createTransaction(request); + + return new ResponseEntity<>(HttpStatus.OK); + } @GetMapping - public TransactionDto.TransactionListResponse getTransaction(@RequestParam(value = "year", required = false) Integer year, + public ResponseEntity getTransaction(@RequestParam(value = "year", required = false) Integer year, @RequestParam(value = "month", required = false) Integer month, @RequestParam(value = "day", required = false) Integer day, Pageable pageable){ - return transactionService.getTransactions(year, month, day, pageable); + return ResponseEntity.status(HttpStatus.OK).body(transactionService.getTransactions(year, month, day, pageable)); } @PutMapping - public void updateTransaction(@RequestBody TransactionDto.TransactionRequest requestDto, + public ResponseEntity updateTransaction(@RequestBody TransactionDto.TransactionRequest requestDto, @RequestParam(value = "id", required = false) Long id){ transactionService.updateTransaction(requestDto, id); + return new ResponseEntity<>(HttpStatus.OK); } @DeleteMapping - public void deleteTransaction(@RequestParam(value = "id", required = false) Long id){ + public ResponseEntity deleteTransaction(@RequestParam(value = "id", required = false) Long id){ transactionService.deleteTransaction(id); + return new ResponseEntity<>(HttpStatus.OK); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java index 89ee471..ba3a0d0 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java @@ -5,6 +5,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -19,8 +21,8 @@ public class AccountBookProfileController { // 동네정보 프로필 조회 @GetMapping({"/api/my/account-books", "/api/{userId}/account-books"}) - public AccountBookProfileDto.AccountBookProfileResponse getProfile(@PathVariable(value = "userId", required = false) Long userId, - @RequestParam int category, Pageable pageable){ - return accountBookProfileService.getAbSharing(userId, category, pageable); + public ResponseEntity getProfile(@PathVariable(value = "userId", required = false) Long userId, + @RequestParam int category, Pageable pageable){ + return ResponseEntity.status(HttpStatus.OK).body(accountBookProfileService.getAbSharing(userId, category, pageable)); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java index 7b01050..9847446 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java @@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Pageable; import org.springframework.data.repository.query.Param; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -24,9 +26,9 @@ public class DongnaeProfileController { // 동네정보 프로필 조회 @GetMapping({"/api/my/town", "/api/{userId}/town"}) - public DongnaeProfileDto.DongnaeProfileResponse getProfile(@PathVariable(value = "userId", required = false) Long userId, - @RequestParam int category, Pageable pageable){ - return dongnaeProfileService.getDongnaeProfile(userId, category, pageable); + public ResponseEntity getProfile(@PathVariable(value = "userId", required = false) Long userId, + @RequestParam int category, Pageable pageable){ + return ResponseEntity.status(HttpStatus.OK).body(dongnaeProfileService.getDongnaeProfile(userId, category, pageable)); } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java index 06a5527..627edd6 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java @@ -5,6 +5,8 @@ import com.umc.DongnaeFriend.domain.profile.service.MyPageService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -16,15 +18,17 @@ public class MyPageController { private final MyPageService myPageService; @GetMapping("/api/user") - public MyPageDto.MyPageResponseDto getMyPage(){ - return myPageService.getMyPage(); + public ResponseEntity getMyPage(){ + return ResponseEntity.status(HttpStatus.OK).body(myPageService.getMyPage()); } @PutMapping("/api/user") - public void updateMyPage(@RequestPart(value = "request", required = false) MyPageDto.MyPageRequestDto myPageRequest, + public ResponseEntity updateMyPage(@RequestPart(value = "request", required = false) MyPageDto.MyPageRequestDto myPageRequest, @RequestPart(value = "image", required = false) MultipartFile image){ log.info("updateMyPage - 프로필 사진 변경"); myPageService.updateMyPage(myPageRequest, image); + + return new ResponseEntity<>(HttpStatus.OK); } } From 93d315225727448b8d75c6631d2886d6db8ceb74 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 28 Jul 2023 12:08:35 +0900 Subject: [PATCH 49/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FFeat=20#39:=20[?= =?UTF-8?q?=EC=9E=84=EC=8B=9C]=20=ED=86=A0=ED=81=B0=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes build.gradle | 3 + src/.DS_Store | Bin 0 -> 6148 bytes src/main/.DS_Store | Bin 0 -> 6148 bytes .../DongnaeFriend/KakaoTokenController.java | 79 ++++++++++++++++++ .../DongnaeFriend/config/SecurityConfig.java | 2 + .../global/security/JwtTokenFilter.java | 4 - .../global/util/JwtTokenProvider.java | 1 + src/main/resources/.DS_Store | Bin 0 -> 6148 bytes src/main/resources/application.yml | 6 +- src/main/resources/templates/.DS_Store | Bin 0 -> 6148 bytes src/main/resources/templates/html/.DS_Store | Bin 0 -> 6148 bytes src/main/resources/templates/html/index.html | 15 ++++ .../templates/html/kakao_login_large_wide.png | Bin 0 -> 7213 bytes src/main/resources/templates/html/token.html | 10 +++ 15 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 .DS_Store create mode 100644 src/.DS_Store create mode 100644 src/main/.DS_Store create mode 100644 src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java create mode 100644 src/main/resources/.DS_Store create mode 100644 src/main/resources/templates/.DS_Store create mode 100644 src/main/resources/templates/html/.DS_Store create mode 100644 src/main/resources/templates/html/index.html create mode 100644 src/main/resources/templates/html/kakao_login_large_wide.png create mode 100644 src/main/resources/templates/html/token.html diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bb91921a2a3efe497257c3ef774e64fe6753649b GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8Z7D(y3VK`cS}?65h?fxS3mDOZN=;1BV9b^zHHT2hU0=u-@p+ut z-GIfMMeGdhe)GGV{UH0p7~}3D95H4w#(K~YIVuf;?#58dBqMShBbx`Y48Zyb<|g*n z0l&S?GM2K3p!oj%ag^n@{mEPH&cEWzNHq1WLE`sT%Znlj=@SJj)Hzw4oDXP MMF@4oz%MZH1znO!ssI20 literal 0 HcmV?d00001 diff --git a/build.gradle b/build.gradle index fa99fb7..9e6c099 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,9 @@ dependencies { //jwt implementation 'io.jsonwebtoken:jjwt:0.9.1' + //thymeleaf + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + } diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0f989cbe2913e7d5fb88216aaadf3f6e53190448 GIT binary patch literal 6148 zcmeHK!AiqG5S?wKZ7D(y3VI88Etpmj#7n642aM=Jr6#0kFwIJnnnNk%u0Q0D_&v_- zZi}_`DpF@)_RY@DB+N_L-2nj69Y<{d8vyF4gp~#kD}>fbm!x7m7NVeMghlooCNjkN z`%*MJ{vreP?JO8V05POrzhC&A#98jTAEHvVHa2T0&Dx#+C<{Li@^RJ;MmIFOlrjlt zb`W00gQ9P5pUE^2;&d=l32`*QklX7xjbzc4<21@tuCEswD1CcxGHG{Qx8)pl+-b|1 zoOH-OJf2P)^_~5L(~JI7GEC*GW>Me|r)10E4BpU~7xdzf(nO{Y=%aWGau`4c`T7)U z3i?*)j0{F*fEi#0Rx@C>(0X(AGJBZ;X5b$)K>LG(O6VCZHL9%x2h{=~(lt^E+SE%> zj$_a>SZc%-6rocQb*eBehS2HgcTAjTu+*s2L73)4m^Ta4p$PSMe7>W?L3kQ@WCoal zMFy&RYSa0D{&WAon8Y(?fEidT287k~dtEHaoUKd6(OK)D-lLLGT&Z!Mf`&SZF_wS5Z-O8Z74zx3VI88Etpmj#7l_v1&ruHr6wk5FlI}B?4cBL*BA0dd>&_Z zH)3f8Pa<{(X203_$+F*u{b7u8w+#D?nT)XxC}P8aW{F@NbwL{1gUIDKN|v!Z7O^~- zEM$}8FEW5@XTYk#nlZt?tY1D35)nZ3Ef^ur#3`^I|^6R+@#GI#y# z3VY{5BtdQa!9^TRM&{;;NDDtsqf8dWVFW4HmvI`3i7U!9%w?^o0tU#)+?h`M1KaLd z2LpT7v!+J_wD%8ZGo!P$yLWsxdQ6^D@uK+T@asw0&{)GO7)z%1>}6>p(tC*3m30Ln zF+dCu11rLS-u^n>6`3zhlNcZde$D{y4;Cn*qp?ybw+?9V`iSusA_~~}mO!*LIvOj5 z5CP$;6i}6N{lws^9Q>Bfb2L^8RXO8wWcZFAnd=t{m!pHr6wHD|tC<^9P3O`H0kVi4(;!(T}Dh2!& X8i0<*N+Eba=prC#poSRuRR%r)veZq@ literal 0 HcmV?d00001 diff --git a/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java b/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java new file mode 100644 index 0000000..4998903 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java @@ -0,0 +1,79 @@ +package com.umc.DongnaeFriend; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.umc.DongnaeFriend.domain.user.dto.UserDto; +import com.umc.DongnaeFriend.domain.user.service.KakaoService; +import com.umc.DongnaeFriend.domain.user.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Controller +@RequestMapping("") +public class KakaoTokenController { + + @Autowired + private UserService userService; + + @Autowired + private KakaoService kakaoService; + + @GetMapping("/kakao") + public String kakologin(Model model, HttpServletResponse response) { + response.setContentType(MediaType.TEXT_HTML_VALUE); + + return "html/index"; + } + + @GetMapping("/callback") + public String callback(Model model, @RequestParam("code") String code) throws IOException { + + //------kakao POST 요청------ + String reqURL = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=8427ba9114a5ecb09621710469748441&code=" + code; + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = ""; + String result = ""; + + while ((line = br.readLine()) != null) { + result += line; + } + + ObjectMapper objectMapper = new ObjectMapper(); + Map jsonMap = objectMapper.readValue(result, new TypeReference>() { + }); + + String accessToken = (String) jsonMap.get("access_token"); + + //-------------------------------------------------서버 로그인---------------------------------------------------- + + HashMap userInfo = kakaoService.getUserInfo(accessToken); + UserDto.Response response = userService.userValidation(userInfo); + + model.addAttribute("token","Bearer "+ response.getAccessToken()); + + return "html/token"; + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java index 865fbbf..0f9a562 100644 --- a/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java +++ b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java @@ -25,6 +25,8 @@ protected void configure(HttpSecurity http) throws Exception { .authorizeRequests() .antMatchers("/user/login").permitAll() // 인증 없이 접근 허용하는 URL .antMatchers("/user/reissuance").permitAll() // 인증 없이 접근 허용하는 URL + .antMatchers("/kakao").permitAll() // 카카오 토큰 추출(임시) + .antMatchers("/callback").permitAll() // 카카오 토큰 추출(임시) .anyRequest().authenticated(); // 그 외의 URL은 인증 필요 http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class); } diff --git a/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java index 6c0cb55..edb3311 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java +++ b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java @@ -31,10 +31,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse log.info("JwtTokenFilter 진입"); - if (request.getServletPath().contains("/user/login")) { - log.info("/user/login 진입"); - } - // Request Header에서 JWT 토큰 가져오기 String authorizationHeader = request.getHeader("Authorization"); log.info("authorizationHeader : {}",authorizationHeader); diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java index 344ba00..af5c405 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java @@ -43,6 +43,7 @@ public String createAccessToken(Long userId) { // claims.put("userId", user.getId()); // 사용자 아이디 // claims.put("email", user.getEmail()); // 사용자 이메일 + return Jwts.builder() .signWith(SignatureAlgorithm.HS512, String.valueOf(jwtConfig.SECRET_KEY)) .claim("userId", userId) diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..aec35509dbea9e4a7c70c78b4e01f0508d1b1406 GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8Z74zx3VK`cS}?65h?fxS3mDOZN=-=6V45vWY7eE5yS|Vw;`2DO zyAew(coMNQF#FBUPnP{Q>m-Zh)RU7e%2lne0~W}@-kZ(3J;&*Y zqn;a-xWmQ2) z3=jjvz?v{%w!c<;P3B9}BnF6qpEH2_g8)Tz4VD_!)&UJ(A2HrQL;)M$5{SZ}Yp~P^ z5fH9R0d*-iPYkZh!7ognYp~R)%NbWA!*|Tc+`Le@8Xf#Xr8Dkoq?Q;U1{N8p>#mLG z|M~at|HUHe5d*})zhZzl`hMSoDVei%X>xeh3ebB{6wE6%ewKitj$+8gqj(oo3HSvX WfUdz(BX~gQBA{rXh8Xx&20j4UZcVHJ literal 0 HcmV?d00001 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6b69a6d..a2271fb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,8 +8,8 @@ logging: spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: Tnqls9004^^ + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update @@ -17,6 +17,8 @@ spring: hibernate: format_sql: true show_sql: true + thymeleaf: + cache: false jwt: secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 diff --git a/src/main/resources/templates/.DS_Store b/src/main/resources/templates/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3c68b2bad4ea102ea75153b162be0fe2ac66caf6 GIT binary patch literal 6148 zcmeHK%}T>S5Z-O0Z7D(y3VK`cS}?65h?kJo7cim+m70)ZgK4%jsX3HF?)pN$h|lB9 z?nW%utB9R}-EV$(vma!C7-QU?B1dJ7pnGkoW|9#(ju95wG)!a&_M3_Q zb--`8*qG&P!jiAwA5N1v%N^&P*Xq{Rb_1l{xcA4h@be&_XI?P7Me9n+B&_rxypBi3 z(BAFKG!No*G*bm}G=h}7n>dYR;mLU#WvbTKffmTnK3FWeJ;&*Ylb*Beh{ahC_2bj! zven!>JUYJ|J|&Y>zGy}{5Uym$U_fH@MH z?TuxC7ETNh13xi<`-6an=o&0Fs;vV$ygp;xLPP-_-x7$zplh(y2oVsjO96E$H%|<% z%fT;9o@=nwsLL5wGs8G$=IZgn)$HIGDxGmxBlW}pF|f)&U7I$Z{}=GftbOFKmXJjZ z5Ci{=0d5Wafd`8+XY04+;aMx7JwQXjyb=`<&{r-2VBkKouYx)*P=`F%V5t#DLBA>o Pq>F$eggRp27Z~^eH1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 + + + My Page + + +

+ + diff --git a/src/main/resources/templates/html/kakao_login_large_wide.png b/src/main/resources/templates/html/kakao_login_large_wide.png new file mode 100644 index 0000000000000000000000000000000000000000..c0c1856129a03c5e5812854c7b7a1a6134f0f5c0 GIT binary patch literal 7213 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/html/token.html b/src/main/resources/templates/html/token.html new file mode 100644 index 0000000..10b3429 --- /dev/null +++ b/src/main/resources/templates/html/token.html @@ -0,0 +1,10 @@ + + + + + Access Token + + +

ERROR...

+ + \ No newline at end of file From d9991a17e979a6d3d5b0b413b593ab6df199d80c Mon Sep 17 00:00:00 2001 From: Limwngur Date: Fri, 28 Jul 2023 18:53:58 +0900 Subject: [PATCH 50/58] =?UTF-8?q?=E2=9A=BDFEAT=20#41:=20=EC=84=B1=EB=B3=84?= =?UTF-8?q?=20=EB=B0=8F=20=EB=82=98=EC=9D=B4=EB=8C=80=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DongnaeFriend/KakaoTokenController.java | 46 +++++++++++-------- .../umc/DongnaeFriend/domain/type/Age.java | 10 ++++ .../umc/DongnaeFriend/domain/type/Gender.java | 10 ++++ .../domain/user/service/UserService.java | 35 ++++---------- src/main/resources/application.yml | 4 +- src/main/resources/templates/html/index.html | 2 +- 6 files changed, 58 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java b/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java index 4998903..d9668b9 100644 --- a/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java +++ b/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java @@ -44,36 +44,42 @@ public String kakologin(Model model, HttpServletResponse response) { @GetMapping("/callback") public String callback(Model model, @RequestParam("code") String code) throws IOException { - //------kakao POST 요청------ - String reqURL = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=8427ba9114a5ecb09621710469748441&code=" + code; - URL url = new URL(reqURL); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); + try { +//------kakao POST 요청------ + String reqURL = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=1ad317e194df665ca44dcb82d11a7093&code=" + code; + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); - BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line = ""; - String result = ""; + String line = ""; + String result = ""; - while ((line = br.readLine()) != null) { - result += line; - } + while ((line = br.readLine()) != null) { + result += line; + } + + ObjectMapper objectMapper = new ObjectMapper(); + Map jsonMap = objectMapper.readValue(result, new TypeReference>() { + }); - ObjectMapper objectMapper = new ObjectMapper(); - Map jsonMap = objectMapper.readValue(result, new TypeReference>() { - }); + String accessToken = (String) jsonMap.get("access_token"); - String accessToken = (String) jsonMap.get("access_token"); + //-------------------------------------------------서버 로그인---------------------------------------------------- - //-------------------------------------------------서버 로그인---------------------------------------------------- + HashMap userInfo = kakaoService.getUserInfo(accessToken); + UserDto.Response response = userService.userValidation(userInfo); - HashMap userInfo = kakaoService.getUserInfo(accessToken); - UserDto.Response response = userService.userValidation(userInfo); + model.addAttribute("token","Bearer "+ response.getAccessToken()); - model.addAttribute("token","Bearer "+ response.getAccessToken()); + return "html/token"; + } catch (Exception e) { + e.printStackTrace(); + } + return null; - return "html/token"; } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java index 0228124..f88afbc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java @@ -22,4 +22,14 @@ public enum Age { public String getAge() { return this.age; } + + public static Age fromString(String strAge) { + + for(Age age : Age.values()){ + if(age.getAge().equals(strAge)){ + return age; + } + } + throw new IllegalArgumentException("No matching type for [" + strAge + "]"); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java index 64f11eb..816f5cf 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java @@ -17,4 +17,14 @@ public enum Gender { public String getGender() { return this.gender; } + + public static Gender fromString(String strGender) { + + for(Gender gender : Gender.values()){ + if(gender.getGender().equals(strGender)){ + return gender; + } + } + throw new IllegalArgumentException("No matching type for [" + strGender + "]"); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java index 40e600c..1aa3b78 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -60,22 +60,13 @@ public User userRegister(HashMap userInfo) { Long kakaoId = (Long) userInfo.get("id"); -// Optional gender = Optional.ofNullable(userInfo.get("gender").toString()); -// String strGender = ""; -// log.info("Gender : {}", gender.get()); -// if(gender.get()=="F"){ -// strGender="여성"; -// }else { -// strGender = "남성"; -// } -// log.info("strGender : {}", strGender); -// -// -// Optional age = Optional.ofNullable(userInfo.get("age").toString()); -// String[] ageRange = age.get().split("-"); -// -// -// // refreshToken userId를 claim 으로 생성 뒤, User의 필드에 넣고 User를 저장 + String strGender = userInfo.getOrDefault("gender", null).toString(); + String strAge = userInfo.getOrDefault("age", null).toString(); + + Gender gender = Gender.fromString(strGender); + Age age = Age.fromString(strAge); + + String refresh_Token = jwtTokenProvider.createRefreshToken((Long) userInfo.get("id")); return userRepository.save( @@ -85,16 +76,8 @@ public User userRegister(HashMap userInfo) { // // ) .email(email) - //TODO : Gender 결정[O] - .gender( -// Gender.valueOf(strGender) - Gender.MALE - ) - //TODO : Age 결정[O] - .age( -// Age.valueOf(ageRange[0]+"대") - Age.AGE20 - ) + .gender(gender) + .age(age) .townCert(YesNo.NO) .townCertCnt(0) .infoCert(YesNo.NO) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a2271fb..57b5933 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,9 +7,9 @@ logging: # Settings for local spring: datasource: - url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false + url: jdbc:mysql://localhost:3306/security?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false username: root - password: qwe335577! + password: Wngurdl1! driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update diff --git a/src/main/resources/templates/html/index.html b/src/main/resources/templates/html/index.html index 26d4b25..39a3ed4 100644 --- a/src/main/resources/templates/html/index.html +++ b/src/main/resources/templates/html/index.html @@ -6,7 +6,7 @@

동네친구 카카오 로그인

- + kakoLogin From c2ff8282343d82b925db217ee7d4635d50a3a982 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 28 Jul 2023 21:43:54 +0900 Subject: [PATCH 51/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FReafactor=20#28:=20?= =?UTF-8?q?=EB=8F=99=EB=84=A4=EC=A0=95=EB=B3=B4=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20Paging=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/SharingBoardRepository.java | 4 +-- .../AccountBookSharingServiceImpl.java | 2 +- .../controller/DongnaeBoardController.java | 14 +++-------- .../respository/DongnaeBoardRepository.java | 13 +++++----- .../dongnae/service/DongnaeBoardService.java | 4 +-- .../service/DongnaeBoardServiceImpl.java | 25 +++---------------- 6 files changed, 17 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java index 54bc584..f99d1f3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -1,8 +1,6 @@ package com.umc.DongnaeFriend.domain.account.sharing.repository; -import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; -import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -36,7 +34,7 @@ public interface SharingBoardRepository extends JpaRepository "LEFT JOIN sharing_sympathy ON sharing_board.sharing_board_id = sharing_sympathy.sharing_board_id\n" + "WHERE (sharing_board.title LIKE %:keyword% OR sharing_board.content LIKE %:keyword%)\n" + "AND sharing_board.category = :category GROUP BY sharing_board.sharing_board_id ", nativeQuery = true) - List findByKeywordOrderByLikes(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); + List findByKeyword(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index 6687692..e741567 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -55,7 +55,7 @@ public class AccountBookSharingServiceImpl implements AccountBookSharingService @Override public List searchByKeyword(String keyword, int category, Pageable pageable) { //TODO : 전체 카테고리 처리 - List sharingBoards = sharingBoardRepository.findByKeywordOrderByLikes(keyword, SharingCategory.valueOf(category).name(), pageable); + List sharingBoards = sharingBoardRepository.findByKeyword(keyword, SharingCategory.valueOf(category).name(), pageable); if (sharingBoards.isEmpty()) { throw new CustomException(ErrorCode.NO_CONTENT_FOUND); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java index 51c4fe2..ec1ea11 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -5,6 +5,7 @@ import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; @@ -26,15 +27,6 @@ public class DongnaeBoardController { @Autowired DongnaeBoardService dongnaeBoardService; - /* - * [동네정보] 홈 화면 - */ - //TODO : 파라미터 다시 확인해보기 - @GetMapping("/home") - public ResponseEntity home(@RequestParam("category") int category, - @RequestParam("sortBy") int sort) { - return ResponseEntity.ok(dongnaeBoardService.home(category)); - } /* * [동네정보] 사용자 위치 정보 @@ -54,11 +46,11 @@ public ResponseEntity getLocation() { @GetMapping("/search") public ResponseEntity getBoards(@RequestParam("keyword") String keyword, @RequestParam("category") int category, - @RequestParam("sortBy") int sort) { + Pageable pageable) { log.info("User Id: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); - return ResponseEntity.ok(dongnaeBoardService.searchByKeyword(keyword, category, sort)); + return ResponseEntity.ok(dongnaeBoardService.searchByKeyword(keyword, category, pageable)); } /* diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java index eaded3e..54cd3d4 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -1,6 +1,8 @@ package com.umc.DongnaeFriend.domain.dongnae.respository; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -13,14 +15,11 @@ @Repository public interface DongnaeBoardRepository extends JpaRepository { - @Query(value = "select * from dongnae_board where title like %?1% or content like %?1% and category = ?2 ORDER BY created_at DESC;", nativeQuery = true) - List findByKeywordOrderByCreatedAt(String keyword, String category); - - @Query(value = "SELECT dongnae_board.*, COUNT(dongnae_sympathy.dongnae_board_id) AS cnt FROM dongnae_board\n" + + @Query(value = "SELECT dongnae_board.*, COUNT(dongnae_sympathy.dongnae_board_id) AS likes FROM dongnae_board\n" + "LEFT JOIN dongnae_sympathy ON dongnae_board.dongnae_board_id = dongnae_sympathy.dongnae_board_id\n" + - "WHERE (dongnae_board.title LIKE %?1% OR dongnae_board.content LIKE %?2%)\n" + - "AND dongnae_board.category = ?2 GROUP BY dongnae_board.dongnae_board_id ORDER BY cnt DESC ;", nativeQuery = true) - List findByKeywordOrderByLikes(String keyword, String category); + "WHERE (dongnae_board.title LIKE %:keyword% OR dongnae_board.content LIKE %:keyword%)\n" + + "AND dongnae_board.category = :category GROUP BY dongnae_board.dongnae_board_id ", nativeQuery = true) + List findByKeyword(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); @Query(value = "select * from dongnae_board ORDER BY created_at DESC;", nativeQuery = true) List findAllOrderByCreatedAt(); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java index 8f1c978..02c6e4d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -2,19 +2,19 @@ import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import org.springframework.data.domain.Pageable; import javax.naming.AuthenticationException; import java.util.List; public interface DongnaeBoardService { - List searchByKeyword(String keyword, int category, int sort); + List searchByKeyword(String keyword, int category, Pageable pageable); List searchAll(int sort); void createBoard(DongnaeBoardDto.Request req); - List home(int category); UserLocationDto getUserLocation(); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 5d127bc..a0554b0 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -14,6 +14,7 @@ import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -55,19 +56,6 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { @Autowired private DongnaeRepository dongnaeRepository; - /* - * [동네정보] 홈 화면 - * 카테고리 별 게시글 2개씩 반환 - * @param sort - */ - @Override - public List home(int category) { - String category_String = DongnaeBoardCategory.valueOf(category).name(); - //TODO : 동네 인증 여부 확인하기 - (User 필요) - String category_ = "RESTAURANT"; - List dongnaeBoardList = dongnaeBoardRepository.findTwoByCategoryOrderByCreatedAt(category_); - return getListResponses(dongnaeBoardList); - } /* * [동네정보] 사용자 위치 정보 @@ -87,16 +75,10 @@ public UserLocationDto getUserLocation() { @Override // @Transactional(propagation = Propagation.REQUIRED) - public List searchByKeyword(String keyword, int category, int sort) { + public List searchByKeyword(String keyword, int category, Pageable pageable) { String categoryName = DongnaeBoardCategory.valueOf(category).name(); - - List dongnaeBoardList; - if (sort == 0) { - dongnaeBoardList = dongnaeBoardRepository.findByKeywordOrderByCreatedAt(keyword, categoryName); - } else { - dongnaeBoardList = dongnaeBoardRepository.findByKeywordOrderByLikes(keyword, categoryName); - } + List dongnaeBoardList = dongnaeBoardRepository.findByKeyword(keyword, categoryName, pageable); return getListResponses(dongnaeBoardList); } @@ -134,6 +116,7 @@ public void createBoard(DongnaeBoardDto.Request req) { } + /* * [동네정보] 게시글 상세 조회 */ From e94933204f6a08ed0707d6fcd01e578ad608f460 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 28 Jul 2023 22:03:46 +0900 Subject: [PATCH 52/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FRefactor=20#27:=20[?= =?UTF-8?q?=EB=8F=99=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/sharing/dto/SharingDto.java | 7 +++++ .../AccountBookSharingServiceImpl.java | 12 +++++++-- .../domain/dongnae/dto/DongnaeBoardDto.java | 9 +++++++ .../service/DongnaeBoardServiceImpl.java | 26 +++++++++---------- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java index 7825ef8..01bb153 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -10,7 +10,9 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.springframework.lang.Nullable; +import javax.validation.constraints.NotNull; import java.util.List; public class SharingDto { @@ -20,12 +22,17 @@ public class SharingDto { @AllArgsConstructor @NoArgsConstructor public static class Request { + + @NotNull(message = "카테고리는 필수입니다.") private int category; + @NotNull(message = "제목은 필수입니다.") private String title; + @NotNull(message = "내용은 필수입니다.") private String content; + private List images; public SharingBoard toEntity(User user) { diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index e741567..87338b3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -59,7 +59,6 @@ public List searchByKeyword(String keyword, int categor if (sharingBoards.isEmpty()) { throw new CustomException(ErrorCode.NO_CONTENT_FOUND); } - log.info("board found" + sharingBoards.get(0).getId()); return getListResponses(sharingBoards); } @@ -118,7 +117,7 @@ public SharingDto.Response getBoard(long board_id) { @Override public void updateBoard(long board_id, SharingDto.Request req) { SharingBoard board = sharingBoardRepository.findById(board_id).orElseThrow( - () -> new CustomException(ErrorCode.INVALID_VALUE)); + () -> new CustomException(ErrorCode.NO_CONTENT_FOUND)); board.updateBoard(req); sharingBoardRepository.save(board); @@ -132,6 +131,15 @@ public void updateBoard(long board_id, SharingDto.Request req) { */ @Override public void deleteBoard(long board_id) { + Optional sharingBoard = sharingBoardRepository.findById(board_id); + if (sharingBoard.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + + if (!Objects.equals(sharingBoard.get().getUser().getId(), user.getId())) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } + sharingBoardRepository.deleteById(board_id); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java index 6489bcf..59ff18d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -11,6 +11,8 @@ import com.umc.DongnaeFriend.domain.user.entity.User; import lombok.*; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.stream.Collectors; @@ -21,12 +23,19 @@ public class DongnaeBoardDto { @AllArgsConstructor @NoArgsConstructor public static class Request { + @NotNull(message = "카테고리는 필수입니다.") private int category; + + @NotNull(message = "제목은 필수입니다.") private String title; + @NotNull(message = "내응은 필수입니다.") private String content; private List images; + + @NotNull(message = "장소는 필수입니다.") private String place; + @NotNull(message = "자세한 장소는 필수입니다.") private String placeLocation; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index a0554b0..97d4ef9 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -12,6 +12,8 @@ import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; @@ -80,11 +82,15 @@ public List searchByKeyword(String keyword, int ca List dongnaeBoardList = dongnaeBoardRepository.findByKeyword(keyword, categoryName, pageable); + if (dongnaeBoardList.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + return getListResponses(dongnaeBoardList); } /* - * [동네정보] 게시글 목록 조회 + * [동네정보] 게시글 목록 조회 DLETED * @param sort */ @Override @@ -106,12 +112,6 @@ public List searchAll(int sort) { @Override public void createBoard(DongnaeBoardDto.Request req) { //TODO : User Mapping UserRepository 필요. - - Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); - - dongnaeRepository.save(dongnae); - userRepository.save(user); dongnaeBoardRepository.save(req.toEntity(user, dongnae)); } @@ -126,7 +126,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { //TODO : User 식별자 필요. Optional board = dongnaeBoardRepository.findById(board_id); if (board.isEmpty()) { - throw new RuntimeException(); + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); } //Get Images @@ -165,17 +165,17 @@ public DongnaeBoardDto.Response getBoard(long board_id) { * [동네정보] 게시글 수정 */ @Override - public void updateBoard(long board_id, DongnaeBoardDto.Request request) throws AuthenticationException { + public void updateBoard(long board_id, DongnaeBoardDto.Request request) { Optional board = dongnaeBoardRepository.findById(board_id); if (board.isPresent()) { //User Validaiton if (!Objects.equals(board.get().getUser().getId(), user.getId())) { - throw new AuthenticationException(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); } board.get().updateBoard(request); dongnaeBoardRepository.save(board.get()); } else { - throw new EntityNotFoundException(); + throw new CustomException(ErrorCode.INVALID_VALUE); } } @@ -183,10 +183,10 @@ public void updateBoard(long board_id, DongnaeBoardDto.Request request) throws A public void deleteBoard(long board_id) throws AuthenticationException { Optional board = dongnaeBoardRepository.findById(board_id); - if (board.isEmpty()) throw new EntityNotFoundException(); + if (board.isEmpty()) throw new CustomException(ErrorCode.NO_CONTENT_FOUND); //User Validation if (!Objects.equals(board.get().getUser().getId(), user.getId())) { - throw new AuthenticationException(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); } else { dongnaeBoardRepository.deleteById(board_id); } From 02646197670cac88da8b742d86a32b1afff5e776 Mon Sep 17 00:00:00 2001 From: soogoori Date: Sat, 29 Jul 2023 10:00:07 +0900 Subject: [PATCH 53/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20Feat=20#36=20:=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=94=84=EB=A1=9C=ED=95=84=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/book/dto/TransactionDto.java | 19 --------------- .../book/service/AccountBookService.java | 3 --- .../book/service/TransactionService.java | 5 ---- .../service/AccountBookProfileService.java | 23 +++++++++++-------- .../service/DongnaeProfileService.java | 16 +++++++------ .../domain/profile/service/MyPageService.java | 1 - .../global/security/JwtTokenFilter.java | 2 -- src/main/resources/application.yml | 2 +- 8 files changed, 24 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java index 7587d89..40070dc 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java @@ -86,23 +86,4 @@ public static TransactionListResponse of(List transactionList){ return new TransactionListResponse(transactionResponses); } } - - - @Getter - @NoArgsConstructor - public static class TransactionByCategory{ - private TransactionCategory transactionCategory; - private Long price; - private Long expenditure; - private Long income; - private Long budget; - - public TransactionByCategory(TransactionCategory transactionCategory, Long price, Long expenditure, Long income, Long budget) { - this.transactionCategory = transactionCategory; - this.price = price; - this.expenditure = expenditure; - this.income = income; - this.budget = budget; - } - } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java index d932ecc..2c5c95f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -23,9 +23,6 @@ public class AccountBookService { // 가계부 예산 설정 (한달) @Transactional public void createBudget(Integer year, Integer month, Long budget){ - /*this.accountBookRepository.findByYearAndMonth(year, month) - .ifPresent(ab->{throw new IllegalStateException("이미 예산이 설정되어있습니다."); - });*/ accountBookRepository.save(AccountBookDto.BudgetRequest.toEntity(year, month, budget)); } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java index c492a7f..a15cc8f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java @@ -18,11 +18,6 @@ @RequiredArgsConstructor public class TransactionService { - /** - * 월별 가계부 지출 및 수입 업데이트 시 지출(예산) 총액이 0보다 작아지면 예외 발생하게 만들기 - * 유저 권한 확인 필요 - */ - private final TransactionRepository transactionRepository; private final AccountBookRepository accountBookRepository; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java index aef7669..e226e7d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java @@ -14,6 +14,7 @@ import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import java.util.List; @@ -21,6 +22,9 @@ import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; +/** + * TODO : 공감, 스크랩 게시물 조회 필요 + */ @Service @RequiredArgsConstructor public class AccountBookProfileService { @@ -35,8 +39,7 @@ public class AccountBookProfileService { private User checkUser(Long userId){ User user; if(userId==null){ // 유저아이디가 없으면 본인 - user = userRepository.findById(userId/*본인인증 필요*/) - .orElseThrow(); + user = findUser(); }else{ user = userRepository.findById(userId) .orElseThrow(); @@ -51,10 +54,9 @@ public AccountBookProfileDto.AccountBookProfileResponse getAbSharing(Long userId User user = checkUser(userId); // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 - return AccountBookProfileDto.AccountBookProfileResponse.builder() - .userId(userId==null ? user.getId() /*본인인증 필요*/ : userId) - .isMine(userId.equals(user.getId() /*본인인증 필오*/)) + .userId(userId==null ? findUser().getId() : userId) + .isMine(user.getId().equals(findUser().getId())) .postTotalCount(sharingBoardRepository.countAllByUserId(user.getId())) .commentTotalCount(sharingCommentRepository.countAllByUserId(user.getId())) .likedTotalCount(sharingSympathyRepository.countAllByUserId(user.getId())) @@ -62,6 +64,7 @@ public AccountBookProfileDto.AccountBookProfileResponse getAbSharing(Long userId .content(getWrittenContent(user.getId(), category, pageable)) .build(); } + /** * 가계부 공유 - 작성한 글 , 작성한 댓글의 게시글 조회 */ @@ -78,10 +81,6 @@ public List getWrittenContent(Long us return getProfileListResponse(sharingBoardList); } - /** - * TODO : 공감, 스크랩 게시물 조회 필요 - */ - //ListResponse 변환 private List getProfileListResponse(List sharingBoardList){ @@ -98,4 +97,10 @@ private List getProfileListResponse(L .build()) .collect(Collectors.toList()); } + + public User findUser() { + Object userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById((Long) userId) + .orElseThrow(); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java index 07a4bc3..c305809 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java @@ -22,6 +22,9 @@ import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; +/** + * TODO : 공감, 스크랩 게시물 조회 필요 + */ @Service @RequiredArgsConstructor public class DongnaeProfileService { @@ -36,8 +39,7 @@ public class DongnaeProfileService { private User checkUser(Long userId){ User user; if(userId==null){ // 유저아이디가 없으면 본인 - user = userRepository.findById(userId/*본인인증 필요*/) - .orElseThrow(); + user = findUser(); }else{ user = userRepository.findById(userId) .orElseThrow(); @@ -49,13 +51,12 @@ private User checkUser(Long userId){ * 동네 정보 프로필 조회 */ public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, int category, Pageable pageable){ - User user = checkUser(userId); - // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 + User user = checkUser(userId); return DongnaeProfileDto.DongnaeProfileResponse.builder() - .userId(userId==null ? user.getId() /*본인인증 필요*/ : userId) - .isMine(userId.equals(user.getId() /*본인인증 필오*/)) + .userId(userId==null ? findUser().getId() : userId) + .isMine(user.getId().equals(findUser().getId())) .postTotalCount(dongnaeBoardRepository.countAllByUserId(user.getId())) .commentTotalCount(commentRepository.countAllByUserId(user.getId())) .likedTotalCount(dongnaeSympathyRepository.countAllByUserId(user.getId())) @@ -63,9 +64,9 @@ public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, i .content(getWrittenContent(user.getId(), category, pageable)) .build(); } + /** * 동네정보 - 작성한 글 , 작성한 댓글의 게시글 조회 - * TODO : 공감, 스크랩 게시물 조회 필요 */ public List getWrittenContent(Long userId, int category, Pageable pageable) { User user = checkUser(userId); @@ -79,6 +80,7 @@ public List getWrittenContent(Long u } return getProfileListResponse(dongnaeBoardList); } + //ListResponse 변환 private List getProfileListResponse(List dongnaeBoardList){ return dongnaeBoardList.stream() diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java index 17e3d82..73fea1e 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java @@ -58,7 +58,6 @@ public void updateMyPage(MyPageDto.MyPageRequestDto myPageRequest, MultipartFile user.updateProfileImage(fileName); log.info("프로필 이미지 업데이트완료"); user.updateProfile(myPageRequest.toEntity()); - log.info("프로필 업데이트 완료"); log.info("유저 닉네임 : " + user.getNickname()); log.info("유저 프로필 : " + user.getProfileImage()); diff --git a/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java index edb3311..ae2d9b5 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java +++ b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java @@ -52,7 +52,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse new UsernamePasswordAuthenticationToken( userId,null, null); // SecurityContextHolder에 인증 객체 저장 - SecurityContextHolder.getContext().setAuthentication(authenticationToken); filterChain.doFilter(request, response); @@ -69,6 +68,5 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse log.info("Header None"); filterChain.doFilter(request, response); } - } } \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 67434f0..b4076c7 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -12,7 +12,7 @@ spring: password: Tnqls9004^^ driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: update + hibernate.ddl-auto: create properties: hibernate: format_sql: true From fa8f9f13f2c63f6864ff139584c3b8f0710250bd Mon Sep 17 00:00:00 2001 From: Limwngur Date: Sat, 29 Jul 2023 11:09:29 +0900 Subject: [PATCH 54/58] =?UTF-8?q?=E2=9A=BDFeat=20#41:=20=EC=97=B0=EB=A0=B9?= =?UTF-8?q?=EB=8C=80=20=EB=B0=8F=20=EC=84=B1=EB=B3=84=20stringToEnum=20?= =?UTF-8?q?=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umc/DongnaeFriend/domain/type/Age.java | 4 +- .../umc/DongnaeFriend/domain/type/Gender.java | 8 ++-- .../domain/user/service/KakaoServiceimpl.java | 5 ++- .../domain/user/service/UserService.java | 38 ++++++++++++++++++- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java index f88afbc..ddc50e3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java @@ -26,10 +26,10 @@ public String getAge() { public static Age fromString(String strAge) { for(Age age : Age.values()){ - if(age.getAge().equals(strAge)){ + if((age.getAge().charAt(0))==(strAge.charAt(0))){ return age; } } - throw new IllegalArgumentException("No matching type for [" + strAge + "]"); + return null; } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java index 816f5cf..e5f1c83 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java @@ -3,9 +3,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Getter @RequiredArgsConstructor +@Slf4j public enum Gender { MALE(0, "남성"), FEMALE(1, "여성"); @@ -21,10 +23,10 @@ public String getGender() { public static Gender fromString(String strGender) { for(Gender gender : Gender.values()){ - if(gender.getGender().equals(strGender)){ - return gender; + if(gender.toString().equalsIgnoreCase(strGender)){ + return strGender.equals("male")? Gender.MALE : Gender.FEMALE; } } - throw new IllegalArgumentException("No matching type for [" + strGender + "]"); + return null; } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java index 6c147f5..2d2114b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java @@ -68,12 +68,15 @@ public HashMap getUserInfo(String access_Token) throws IOExcepti String nickname = properties.get("nickname").toString(); String profileImage = properties.get("profile_image").toString(); String email = kakao_account.get("email").toString(); + String gender = kakao_account.get("gender").toString(); + String age = kakao_account.get("age_range").toString(); userInfo.put("id", id); userInfo.put("nickname", nickname); userInfo.put("profileImage", profileImage); userInfo.put("email", email); - + userInfo.put("age", age); + userInfo.put("gender", gender); return userInfo; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java index 1aa3b78..85a6f40 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -1,5 +1,6 @@ package com.umc.DongnaeFriend.domain.user.service; +import com.fasterxml.jackson.databind.ObjectMapper; import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.Gender; import com.umc.DongnaeFriend.domain.type.YesNo; @@ -14,6 +15,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.HashMap; import java.util.Optional; @@ -60,8 +65,8 @@ public User userRegister(HashMap userInfo) { Long kakaoId = (Long) userInfo.get("id"); - String strGender = userInfo.getOrDefault("gender", null).toString(); - String strAge = userInfo.getOrDefault("age", null).toString(); + String strGender = userInfo.getOrDefault("gender", "").toString(); + String strAge = userInfo.getOrDefault("age", "").toString(); Gender gender = Gender.fromString(strGender); Age age = Age.fromString(strAge); @@ -103,5 +108,34 @@ public String createAccessTokenFromRefreshToken(String refreshToken) { return accessToken; } + public String kakaoGetCode() { + + try { + String reqURL= "https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=1ad317e194df665ca44dcb82d11a7093&redirect_uri=http://localhost:8080/callback"; + + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = ""; + String result = ""; + + while ((line = br.readLine()) != null) { + result += line; + } + + ObjectMapper objectMapper = new ObjectMapper(); + HashMap jsonMap = objectMapper.readValue(result, HashMap.class); + + log.info(jsonMap.toString()); + return ""; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } } From 8d8a44b5f6fe1cbabff428169174c243a5de9f02 Mon Sep 17 00:00:00 2001 From: Limwngur Date: Sat, 29 Jul 2023 11:26:18 +0900 Subject: [PATCH 55/58] =?UTF-8?q?=E2=9A=BDRefactor=20#41:=20=EC=84=B1?= =?UTF-8?q?=EB=B3=84=20=EB=B0=8F=20=EC=97=B0=EB=A0=B9=EB=8C=80=EB=B3=80?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/umc/DongnaeFriend/domain/type/Age.java | 3 +++ .../DongnaeFriend/domain/user/service/KakaoServiceimpl.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java index ddc50e3..e55b91f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java @@ -24,6 +24,9 @@ public String getAge() { } public static Age fromString(String strAge) { + if(strAge==""){ + return null; + } for(Age age : Age.values()){ if((age.getAge().charAt(0))==(strAge.charAt(0))){ diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java index 2d2114b..047549b 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java @@ -68,8 +68,8 @@ public HashMap getUserInfo(String access_Token) throws IOExcepti String nickname = properties.get("nickname").toString(); String profileImage = properties.get("profile_image").toString(); String email = kakao_account.get("email").toString(); - String gender = kakao_account.get("gender").toString(); - String age = kakao_account.get("age_range").toString(); + String gender = kakao_account.getOrDefault("gender","").toString(); + String age = kakao_account.getOrDefault("age_range","").toString(); userInfo.put("id", id); userInfo.put("nickname", nickname); From ad8ca244392d7794d1199a0eeaabb642b1b82a10 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 29 Jul 2023 16:13:29 +0900 Subject: [PATCH 56/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FRefactor=20#45:=20[?= =?UTF-8?q?=EB=8F=99=EB=84=A4=EC=A0=95=EB=B3=B4]=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/dongnae/dto/UserLocationDto.java | 3 + .../respository/DongnaeRepository.java | 3 + .../service/DongnaeBoardServiceImpl.java | 63 +++++++++---------- src/main/resources/application.yml | 6 +- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java index cb2906d..d85af96 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java @@ -3,8 +3,11 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import javax.validation.constraints.NotNull; + @Getter @AllArgsConstructor public class UserLocationDto { + @NotNull(message = "동네 정보가 없습니다.") private String town; } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java index b242442..a350433 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java @@ -2,6 +2,9 @@ import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface DongnaeRepository extends JpaRepository { + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java index 97d4ef9..f7e2e47 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -2,14 +2,10 @@ import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; -import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; import com.umc.DongnaeFriend.domain.dongnae.respository.*; -import com.umc.DongnaeFriend.domain.type.Age; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; -import com.umc.DongnaeFriend.domain.type.Gender; -import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import com.umc.DongnaeFriend.global.exception.CustomException; @@ -17,13 +13,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import javax.naming.AuthenticationException; -import javax.persistence.EntityNotFoundException; - import java.util.List; import java.util.Objects; import java.util.Optional; @@ -35,10 +29,6 @@ @Service public class DongnaeBoardServiceImpl implements DongnaeBoardService { - //임시 유저 - Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); - @Autowired private DongnaeBoardRepository dongnaeBoardRepository; @@ -64,9 +54,7 @@ public class DongnaeBoardServiceImpl implements DongnaeBoardService { */ @Override public UserLocationDto getUserLocation() { - //TODO : 사용자 식별자 가져오기 - (User 필요) - long user_id = 1; - return new UserLocationDto("서울도시"); + return new UserLocationDto(getCurUser().getDongnae().getTownName()); } @@ -90,7 +78,7 @@ public List searchByKeyword(String keyword, int ca } /* - * [동네정보] 게시글 목록 조회 DLETED + * [동네정보] 게시글 목록 조회 DELETED * @param sort */ @Override @@ -111,8 +99,8 @@ public List searchAll(int sort) { */ @Override public void createBoard(DongnaeBoardDto.Request req) { - //TODO : User Mapping UserRepository 필요. - dongnaeBoardRepository.save(req.toEntity(user, dongnae)); + User user = getCurUser(); + dongnaeBoardRepository.save(req.toEntity(user,user.getDongnae())); } @@ -123,17 +111,16 @@ public void createBoard(DongnaeBoardDto.Request req) { @Override @Transactional(propagation = Propagation.REQUIRED) public DongnaeBoardDto.Response getBoard(long board_id) { - //TODO : User 식별자 필요. - Optional board = dongnaeBoardRepository.findById(board_id); - if (board.isEmpty()) { - throw new CustomException(ErrorCode.NO_CONTENT_FOUND); - } + User user = getCurUser(); + DongnaeBoard board = dongnaeBoardRepository.findById(board_id).orElseThrow(() -> + new CustomException(ErrorCode.NO_CONTENT_FOUND)); + //Get Images List images = dongnaeImgRepository.findAllByDongnaeBoard_Id(board_id); //Writer인지 검사 - boolean isWriter = Objects.equals(board.get().getUser().getId(), user.getId()); + boolean isWriter = Objects.equals(board.getUser().getId(), user.getId()); //LikeOrNot 검사 boolean likeOrNot = !dongnaeSympathyRepository.findByUser_Id(user.getId()).isEmpty(); @@ -144,20 +131,20 @@ public DongnaeBoardDto.Response getBoard(long board_id) { return DongnaeBoardDto.Response.builder() - .profileImage(user.getProfileImage()) - .nickname(user.getNickname()) - .category(board.get().getCategory().getValue()) - .title(board.get().getTitle()) - .content(board.get().getContent()) + .profileImage(board.getUser().getProfileImage()) + .nickname(board.getUser().getNickname()) + .category(board.getCategory().getValue()) + .title(board.getTitle()) + .content(board.getContent()) .images(images.stream().map(DongnaeImg::getImageUrl).collect(Collectors.toList())) - .place(board.get().getPlace()) - .placeLocation(board.get().getPlaceLocation()) - .createdAt(getTime(board.get().getCreatedAt())) + .place(board.getPlace()) + .placeLocation(board.getPlaceLocation()) + .createdAt(getTime(board.getCreatedAt())) .townCertification(user.getTownCertCnt()) .isWriter(isWriter) .likeOrNot(likeOrNot) .scrapOrNot(scrapOrNot) - .view(board.get().getView()).build(); + .view(board.getView()).build(); } @@ -166,6 +153,7 @@ public DongnaeBoardDto.Response getBoard(long board_id) { */ @Override public void updateBoard(long board_id, DongnaeBoardDto.Request request) { + User user = getCurUser(); Optional board = dongnaeBoardRepository.findById(board_id); if (board.isPresent()) { //User Validaiton @@ -180,7 +168,8 @@ public void updateBoard(long board_id, DongnaeBoardDto.Request request) { } @Override - public void deleteBoard(long board_id) throws AuthenticationException { + public void deleteBoard(long board_id) { + User user = getCurUser(); Optional board = dongnaeBoardRepository.findById(board_id); if (board.isEmpty()) throw new CustomException(ErrorCode.NO_CONTENT_FOUND); @@ -219,6 +208,14 @@ private List getListResponses(List d .build()) .collect(Collectors.toList()); } + + + private User getCurUser() { + Long user_id = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById(user_id).orElseThrow(() -> + new CustomException(ErrorCode.UNAUTHORIZED_MEMBER) + ); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6826cbf..f108bf4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,11 +9,11 @@ spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: - password: + username: root + password: qwe335577! driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create + hibernate.ddl-auto: update properties: hibernate: format_sql: true From ac0c9cf8ec89c9b382b218a198f7d3181e12066a Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 29 Jul 2023 16:34:33 +0900 Subject: [PATCH 57/58] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8FReafactor=20#45:=20[?= =?UTF-8?q?=EA=B0=80=EA=B3=84=EB=B6=80=20=EA=B3=B5=EC=9C=A0]=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AccountBookSharingServiceImpl.java | 62 ++++++++++++------- .../respository/DongnaeImgRepository.java | 2 + 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java index 87338b3..ff68779 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -13,11 +13,14 @@ import com.umc.DongnaeFriend.domain.type.SharingCategory; import com.umc.DongnaeFriend.domain.type.YesNo; import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; import com.umc.DongnaeFriend.global.exception.CustomException; import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.FileUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import java.util.List; @@ -31,11 +34,6 @@ @Service public class AccountBookSharingServiceImpl implements AccountBookSharingService { - - //임시 유저 - Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); - User user = User.builder().profileImage("profileImage").id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); - @Autowired private SharingBoardRepository sharingBoardRepository; @@ -48,6 +46,9 @@ public class AccountBookSharingServiceImpl implements AccountBookSharingService @Autowired private SharingSympathyRepository sharingSympathyRepository; + @Autowired + private UserRepository userRepository; + /* * [가계부 공유] 게시글 검색 @@ -67,7 +68,7 @@ public List searchByKeyword(String keyword, int categor */ @Override public void createPost(SharingDto.Request req) { - + User user = getCurUser(); sharingBoardRepository.save(req.toEntity(user)); //TODO : Img 파일 업로드 } @@ -78,17 +79,16 @@ public void createPost(SharingDto.Request req) { */ @Override public SharingDto.Response getBoard(long board_id) { - //TODO : User 식별자 필요. - Optional board = sharingBoardRepository.findById(board_id); - if (board.isEmpty()) { - throw new CustomException(ErrorCode.NO_CONTENT_FOUND); - } + SharingBoard board = sharingBoardRepository.findById(board_id).orElseThrow(() -> + new CustomException(ErrorCode.NO_CONTENT_FOUND)); + + User user = getCurUser(); //Get Images List images = sharingImgRepository.findAllBySharingBoard_Id(board_id); //Writer인지 검사 - boolean isWriter = Objects.equals(board.get().getUser().getId(), user.getId()); + boolean isWriter = Objects.equals(board.getUser().getId(), user.getId()); //LikeOrNot 검사 boolean likeOrNot = !sharingSympathyRepository.findByUser_Id(user.getId()).isEmpty(); @@ -98,17 +98,17 @@ public SharingDto.Response getBoard(long board_id) { boolean scrapOrNot = false; return SharingDto.Response.builder() - .profileImage(user.getProfileImage()) - .nickname(user.getNickname()) - .category(board.get().getCategory().getValue()) - .title(board.get().getTitle()) - .content(board.get().getContent()) + .profileImage(board.getUser().getProfileImage()) + .nickname(board.getUser().getNickname()) + .category(board.getCategory().getValue()) + .title(board.getTitle()) + .content(board.getContent()) .images(images.stream().map(SharingImg::getImageUrl).collect(Collectors.toList())) - .createdAt(getTime(board.get().getCreatedAt())) + .createdAt(getTime(board.getCreatedAt())) .isWriter(isWriter) .likeOrNot(likeOrNot) .scrapOrNot(scrapOrNot) - .view(board.get().getView()).build(); + .view(board.getView()).build(); } /* @@ -116,21 +116,27 @@ public SharingDto.Response getBoard(long board_id) { */ @Override public void updateBoard(long board_id, SharingDto.Request req) { + SharingBoard board = sharingBoardRepository.findById(board_id).orElseThrow( () -> new CustomException(ErrorCode.NO_CONTENT_FOUND)); + //권한 검사 + if (!board.getUser().getId().equals(getCurUser().getId())) throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + board.updateBoard(req); sharingBoardRepository.save(board); - sharingImgRepository.deleteAllById(board_id); - //TODO: Img Upload + sharingImgRepository.findAllBySharingBoard_Id(board_id); + + //TODO: File Upload } /* - * [가계부 공유] 게시글 수정 + * [가계부 공유] 게시글 삭제 */ @Override public void deleteBoard(long board_id) { + User user = getCurUser(); Optional sharingBoard = sharingBoardRepository.findById(board_id); if (sharingBoard.isEmpty()) { throw new CustomException(ErrorCode.NO_CONTENT_FOUND); @@ -140,7 +146,11 @@ public void deleteBoard(long board_id) { throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); } + + //게시글 삭제 sharingBoardRepository.deleteById(board_id); + //이미지 삭제 + sharingImgRepository.findAllBySharingBoard_Id(board_id); } @@ -170,4 +180,12 @@ private List getListResponses(List sharin .build()) .collect(Collectors.toList()); } + + + private User getCurUser() { + Long user_id = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById(user_id).orElseThrow(() -> + new CustomException(ErrorCode.UNAUTHORIZED_MEMBER) + ); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java index 8a20d65..d4de701 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java @@ -15,4 +15,6 @@ public interface DongnaeImgRepository extends JpaRepository { Optional findFirst(long dongnae_board_id); List findAllByDongnaeBoard_Id(long id); + + void deleteAllByDongnaeBoard_Id(Long board_id); } From 44aea1d1f1d80113a9c88cbb9dc6b3f1bbf88ccd Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Sun, 30 Jul 2023 10:12:41 +0900 Subject: [PATCH 58/58] =?UTF-8?q?:sparkles:=20Feat=20#37:=20=EC=8B=A0?= =?UTF-8?q?=EA=B3=A0=ED=95=98=EA=B8=B0=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 - .../report/controller/ReportController.java | 25 ++++++ .../domain/report/dto/ReportDto.java | 41 +++++++++ .../domain/report/entity/Report.java | 61 +++++++++++++ .../report/repository/ReportRepository.java | 8 ++ .../repository/ReportRepositoryCustom.java | 10 +++ .../repository/ReportRepositoryImpl.java | 59 +++++++++++++ .../domain/report/service/ReportService.java | 88 +++++++++++++++++++ .../global/exception/ErrorCode.java | 7 +- .../report/controller/ReportController.java | 16 ---- src/main/resources/application.yml | 14 +-- 11 files changed, 305 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java create mode 100644 src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java delete mode 100644 src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java diff --git a/build.gradle b/build.gradle index fa99fb7..2aa0023 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,6 @@ dependencies { //jwt implementation 'io.jsonwebtoken:jjwt:0.9.1' - } tasks.named('test') { diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java b/src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java new file mode 100644 index 0000000..55ba2c5 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java @@ -0,0 +1,25 @@ +package com.umc.DongnaeFriend.domain.report.controller; + +import com.umc.DongnaeFriend.domain.report.dto.ReportDto; +import com.umc.DongnaeFriend.domain.report.service.ReportService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/report") +public class ReportController { + + private final ReportService reportService; + + @PostMapping + public ResponseEntity reportBoard(@RequestBody ReportDto.ReportRequest request) { + reportService.report(request); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java b/src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java new file mode 100644 index 0000000..f5c3166 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java @@ -0,0 +1,41 @@ +package com.umc.DongnaeFriend.domain.report.dto; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import com.umc.DongnaeFriend.domain.user.entity.User; +import javax.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class ReportDto { + + @Getter + @NoArgsConstructor + public static class ReportRequest { + + private Long reportUserId; + private Long sharingBoardId; + private Long dongnaeBoardId; + private Long sharingCommentId; + private Long dongnaeCommentId; + + @NotBlank(message = "신고사유는 필수 값입니다.") + private String content; + + public Report toEntity(User user, User reportUser, DongnaeBoard db, SharingBoard sb, + DongnaeComment dc, SharingComment sc, String content) { + return Report.builder() + .user(user) + .reportUser(reportUser) + .dongnaeBoard(db) + .sharingBoard(sb) + .dongnaeComment(dc) + .sharingComment(sc) + .content(content) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java b/src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java new file mode 100644 index 0000000..429259f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java @@ -0,0 +1,61 @@ +package com.umc.DongnaeFriend.domain.report.entity; + +import static javax.persistence.FetchType.LAZY; +import static javax.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.user.entity.User; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor(access = PROTECTED) +@AllArgsConstructor(access = PRIVATE) +@Entity +public class Report { + @Id + @GeneratedValue(strategy = IDENTITY) + @Column(name = "report_id") + private Long id; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "report_user_id") + private User reportUser; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "dongnae_board_id") + private DongnaeBoard dongnaeBoard; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "sharing_board_id") + private SharingBoard sharingBoard; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "dongnae_comment_id") + private DongnaeComment dongnaeComment; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "sharing_comment_id") + private SharingComment sharingComment; + + @Column(columnDefinition = "MEDIUMTEXT", nullable = false) + private String content; //신고사유 +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java new file mode 100644 index 0000000..612b6e3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java @@ -0,0 +1,8 @@ +package com.umc.DongnaeFriend.domain.report.repository; + +import com.umc.DongnaeFriend.domain.report.entity.Report; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReportRepository extends JpaRepository, ReportRepositoryCustom { + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java new file mode 100644 index 0000000..284f95a --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.umc.DongnaeFriend.domain.report.repository; + +import com.umc.DongnaeFriend.domain.report.dto.ReportDto.ReportRequest; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import java.util.Optional; + +public interface ReportRepositoryCustom { + + Optional findByUserAndPost(Long userId, ReportRequest request); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java new file mode 100644 index 0000000..58d5ca7 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java @@ -0,0 +1,59 @@ +package com.umc.DongnaeFriend.domain.report.repository; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import static com.umc.DongnaeFriend.domain.report.entity.QReport.report; + +import com.umc.DongnaeFriend.domain.report.dto.ReportDto.ReportRequest; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import java.util.Optional; +import javax.persistence.EntityManager; + +public class ReportRepositoryImpl implements ReportRepositoryCustom { + + private final JPAQueryFactory queryFactory; + private final EntityManager em; + + public ReportRepositoryImpl(EntityManager em) { + this.em = em; + this.queryFactory = new JPAQueryFactory(em); + } + + @Override + public Optional findByUserAndPost(Long userId, ReportRequest request) { + + Report result = queryFactory + .selectFrom(report) + .where( + userEq(userId), + dongnaeBoardEq(request.getDongnaeBoardId()), + sharingBoardEq(request.getSharingBoardId()), + dongnaeCommentEq(request.getDongnaeCommentId()), + sharingCommentEq(request.getSharingCommentId()) + ) + .fetchOne(); + return Optional.ofNullable(result); + } + + private BooleanExpression userEq(Long userId) { + return report.user.id.eq(userId); + } + + private BooleanExpression dongnaeBoardEq(Long dongnaeBoardId) { + return dongnaeBoardId == null ? null : report.dongnaeBoard.id.eq(dongnaeBoardId); + } + + private BooleanExpression sharingBoardEq(Long sharingBoardId) { + return sharingBoardId == null ? null : report.sharingBoard.id.eq(sharingBoardId); + } + + private BooleanExpression dongnaeCommentEq(Long dongnaeCommentId) { + return dongnaeCommentId == null ? null : report.dongnaeComment.id.eq(dongnaeCommentId); + } + + private BooleanExpression sharingCommentEq(Long sharingCommentId) { + return sharingCommentId == null ? null : report.sharingComment.id.eq(sharingCommentId); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java b/src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java new file mode 100644 index 0000000..f598059 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java @@ -0,0 +1,88 @@ +package com.umc.DongnaeFriend.domain.report.service; + +import static com.umc.DongnaeFriend.global.exception.ErrorCode.COMMENT_NOT_EXISTS; +import static com.umc.DongnaeFriend.global.exception.ErrorCode.POST_NOT_EXISTS; +import static com.umc.DongnaeFriend.global.exception.ErrorCode.REPORT_ALREADY_EXISTS; +import static com.umc.DongnaeFriend.global.exception.ErrorCode.USER_NOT_FOUND; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.QSharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingCommentRepository; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; +import com.umc.DongnaeFriend.domain.report.dto.ReportDto; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import com.umc.DongnaeFriend.domain.report.repository.ReportRepository; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class ReportService { + + private final UserRepository userRepository; + private final ReportRepository reportRepository; + private final DongnaeBoardRepository dongnaeBoardRepository; + private final DongnaeCommentRepository dongnaeCommentRepository; + private final SharingBoardRepository sharingBoardRepository; + private final SharingCommentRepository sharingCommentRepository; + + public void report(ReportDto.ReportRequest request) { + User user = userRepository.findById(getId()) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + + reportDuplicateCheck(user.getId(), request); + + request.toString(); + + User reportUser = null; + DongnaeBoard db = null; + SharingBoard sb = null; + DongnaeComment dc = null; + SharingComment sc = null; + + if (request.getReportUserId() != null) { + reportUser = userRepository.findById(request.getReportUserId()) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + } else if (request.getDongnaeBoardId() != null) { + db = dongnaeBoardRepository.findById(request.getDongnaeBoardId()) + .orElseThrow(() -> new CustomException(POST_NOT_EXISTS)); + } else if (request.getSharingBoardId() != null) { + sb = sharingBoardRepository.findById(request.getSharingBoardId()) + .orElseThrow(() -> new CustomException(POST_NOT_EXISTS)); + } else if (request.getDongnaeCommentId() != null) { + dc = dongnaeCommentRepository.findById(request.getDongnaeCommentId()) + .orElseThrow(() -> new CustomException(COMMENT_NOT_EXISTS)); + } else { + sc = sharingCommentRepository.findById(request.getSharingCommentId()) + .orElseThrow(() -> new CustomException(COMMENT_NOT_EXISTS)); + } + + Report report = request.toEntity(user, reportUser, db, sb, dc, sc, request.getContent()); + reportRepository.save(report); + } + + public Long getId() { + return (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + + /** + * 신고 중복체크 + */ + public void reportDuplicateCheck(Long userId, ReportDto.ReportRequest request) { + reportRepository.findByUserAndPost(userId, request).ifPresent(report -> + { + throw new CustomException(REPORT_ALREADY_EXISTS); + }); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java index a3a73e9..1befb4b 100644 --- a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java @@ -12,9 +12,14 @@ public enum ErrorCode { /* 10* 가계부 */ /* 20* 동네정보 */ + POST_NOT_EXISTS(BAD_REQUEST, 200, "없는 게시글입니다."), + COMMENT_NOT_EXISTS(BAD_REQUEST, 201, "없는 댓글입니다."), /* 50* 스크랩 */ + /* 60* 신고 */ + REPORT_ALREADY_EXISTS(BAD_REQUEST, 600, "이미 신고 처리가 되었습니다."), + /* 200 NO_CONTENT : 자료를 찾을 수 없음 */ NO_CONTENT_FOUND(NO_CONTENT, 204, "요청된 자료를 찾을 수 없습니다."), @@ -30,7 +35,7 @@ public enum ErrorCode { UNAUTHORIZED_MEMBER(UNAUTHORIZED,401, "현재 내 계정 정보가 존재하지 않습니다"), /* 404 NOT_FOUND : Resource 를 찾을 수 없음 */ - MEMBER_NOT_FOUND(NOT_FOUND,404, "해당 유저 정보를 찾을 수 없습니다"), + USER_NOT_FOUND(NOT_FOUND,404, "해당 유저 정보를 찾을 수 없습니다"), REFRESH_TOKEN_NOT_FOUND(NOT_FOUND, 404,"로그아웃 된 사용자입니다"), NOT_FOLLOW(NOT_FOUND,404, "팔로우 중이지 않습니다"), diff --git a/src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java b/src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java deleted file mode 100644 index cda1bf4..0000000 --- a/src/main/java/com/umc/DongnaeFriend/global/report/controller/ReportController.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.umc.DongnaeFriend.global.report.controller; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/accuse") -public class ReportController { - - public ResponseEntity reportBoard(@RequestBody int id) { - return new ResponseEntity<>(HttpStatus.OK); - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6b69a6d..3839dc3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,20 +3,20 @@ logging: com.example.carrotmarket: debug org.hibernate.SQL: debug +spring: + jpa: + properties: + hibernate: + format_sql: true --- # Settings for local spring: datasource: url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false username: dongnae - password: Tnqls9004^^ + password: df1234 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate.ddl-auto: update - properties: - hibernate: - format_sql: true - show_sql: true - jwt: - secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 + secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 \ No newline at end of file