From 1625d7ebda579940f06bf2fbf7011aa8bd9e0354 Mon Sep 17 00:00:00 2001 From: dku19jam Date: Sun, 22 Jan 2023 19:53:15 +0900 Subject: [PATCH 01/15] =?UTF-8?q?1=EC=A3=BC=EC=B0=A8=20=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1\354\243\274\354\260\250 \352\263\274\354\240\234.txt" | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 "\354\265\234\354\236\254\353\257\274/1\354\243\274\354\260\250 \352\263\274\354\240\234.txt" diff --git "a/\354\265\234\354\236\254\353\257\274/1\354\243\274\354\260\250 \352\263\274\354\240\234.txt" "b/\354\265\234\354\236\254\353\257\274/1\354\243\274\354\260\250 \352\263\274\354\240\234.txt" new file mode 100644 index 0000000..e69de29 From 525021171636d096e7aa6b870f0b3214f4a91fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Fri, 27 Jan 2023 14:19:45 +0900 Subject: [PATCH 02/15] =?UTF-8?q?Feat:=20=EA=B8=B0=EB=B3=B8=20entity=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 +-- .../springstudy/SpringStudyApplication.java | 5 ++ .../dku/springstudy/global/BaseEntity.java | 29 ++++++++++++ .../dku/springstudy/item/entity/Category.java | 29 ++++++++++++ .../dku/springstudy/item/entity/Image.java | 22 +++++++++ .../com/dku/springstudy/item/entity/Item.java | 46 +++++++++++++++++++ .../dku/springstudy/item/entity/Status.java | 17 +++++++ .../com/dku/springstudy/like/entity/Like.java | 43 +++++++++++++++++ .../dku/springstudy/user/entity/Member.java | 42 +++++++++++++++++ src/main/resources/application.yml | 28 +++++++++++ 10 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/global/BaseEntity.java create mode 100644 src/main/java/com/dku/springstudy/item/entity/Category.java create mode 100644 src/main/java/com/dku/springstudy/item/entity/Image.java create mode 100644 src/main/java/com/dku/springstudy/item/entity/Item.java create mode 100644 src/main/java/com/dku/springstudy/item/entity/Status.java create mode 100644 src/main/java/com/dku/springstudy/like/entity/Like.java create mode 100644 src/main/java/com/dku/springstudy/user/entity/Member.java create mode 100644 src/main/resources/application.yml diff --git a/build.gradle b/build.gradle index 15b77ef..e0f41b0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.0.1' + id 'org.springframework.boot' version '2.7.1' id 'io.spring.dependency-management' version '1.1.0' } group = 'com.dku' version = '0.0.1-SNAPSHOT' -sourceCompatibility = '17' +sourceCompatibility = '11' configurations { compileOnly { @@ -23,10 +23,11 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + runtimeOnly 'org.postgresql:postgresql' } tasks.named('test') { diff --git a/src/main/java/com/dku/springstudy/SpringStudyApplication.java b/src/main/java/com/dku/springstudy/SpringStudyApplication.java index ef164c9..71906bf 100644 --- a/src/main/java/com/dku/springstudy/SpringStudyApplication.java +++ b/src/main/java/com/dku/springstudy/SpringStudyApplication.java @@ -2,8 +2,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +/** + * @author 최재민 + */ @SpringBootApplication +@EnableJpaAuditing public class SpringStudyApplication { public static void main(String[] args) { diff --git a/src/main/java/com/dku/springstudy/global/BaseEntity.java b/src/main/java/com/dku/springstudy/global/BaseEntity.java new file mode 100644 index 0000000..944b86d --- /dev/null +++ b/src/main/java/com/dku/springstudy/global/BaseEntity.java @@ -0,0 +1,29 @@ +package com.dku.springstudy.global; + +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.time.LocalDateTime; + +/** + * @author 최재민 + */ +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +public abstract class BaseEntity { + + @CreatedDate + @Column(updatable = false, name = "created_at") + private LocalDateTime createDate; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updateDate; + +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Category.java b/src/main/java/com/dku/springstudy/item/entity/Category.java new file mode 100644 index 0000000..edd6752 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/entity/Category.java @@ -0,0 +1,29 @@ +package com.dku.springstudy.item.entity; + +/** + * @author 최재민 + */ +public enum Category { + DIGITAL_DEVICE("디지털기기"), + HOUSEHOLD_APPLIANCE("생활가전"), + FURNITURE("가구"), + CHILDREN("유아동"), + PROCESSED_FOOD("생활/가공식품"), + CHILDREN_BOOK("유아도서"), + WOMEN_CLOTHING("여성의류"), + MEN_CLOTHING("남성의류"), + LEISURE("게임/취미"), + BEAUTY("뷰티"), + PET("반려동물용품"), + BOOK("도서/티켓/음반"), + PLANT("식물"), + CAR("중고차"), + OTHERS("기타 중고물품") + ; + + + private String name; + Category(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Image.java b/src/main/java/com/dku/springstudy/item/entity/Image.java new file mode 100644 index 0000000..3119567 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/entity/Image.java @@ -0,0 +1,22 @@ +package com.dku.springstudy.item.entity; + + +import com.dku.springstudy.global.BaseEntity; + +import javax.persistence.*; + +@Entity +public class Image extends BaseEntity { + + @Id + @Column(name = "image_id") + @GeneratedValue + private String id; + + private String fileName; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "item_id") + private Item item; + +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Item.java b/src/main/java/com/dku/springstudy/item/entity/Item.java new file mode 100644 index 0000000..19a7310 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/entity/Item.java @@ -0,0 +1,46 @@ +package com.dku.springstudy.item.entity; + +import com.dku.springstudy.global.BaseEntity; +import com.dku.springstudy.like.entity.Like; +import com.dku.springstudy.user.entity.Member; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.List; + +/** + * @author 최재민 + */ +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Item extends BaseEntity { + + @Id + @GeneratedValue + @Column(name = "item_id") + private Long id; + + private String title; + + private Long price; + + @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) + private List image; + + @ManyToOne + @JoinColumn(name = "member_id") + private Member seller; + + private Category category; + + @Lob + private String content; + + private Status status; + + @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) + private List likes; +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Status.java b/src/main/java/com/dku/springstudy/item/entity/Status.java new file mode 100644 index 0000000..87b7915 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/entity/Status.java @@ -0,0 +1,17 @@ +package com.dku.springstudy.item.entity; + +/** + * @author 최재민 + */ + +public enum Status { + ON_SALE("판매중"), + RESERVED("예약완료"), + SOLD("판매완료"); + + private String name; + + Status(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/dku/springstudy/like/entity/Like.java b/src/main/java/com/dku/springstudy/like/entity/Like.java new file mode 100644 index 0000000..dd051b6 --- /dev/null +++ b/src/main/java/com/dku/springstudy/like/entity/Like.java @@ -0,0 +1,43 @@ +package com.dku.springstudy.like.entity; + +import com.dku.springstudy.global.BaseEntity; +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.user.entity.Member; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; +import java.io.Serializable; + +@Entity +@Getter +@Table(name = "likes") +public class Like extends BaseEntity { + + @EmbeddedId + private LikeId likeId; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("memberId") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("itemId") + private Item item; + + + /** + * composite key 사용 + */ + @Embeddable + @Getter @Setter + @EqualsAndHashCode + public static class LikeId implements Serializable { + @Column(name = "item_id") + private Long itemId; + @Column(name = "member_id") + private String memberId; + } +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/user/entity/Member.java b/src/main/java/com/dku/springstudy/user/entity/Member.java new file mode 100644 index 0000000..e11058f --- /dev/null +++ b/src/main/java/com/dku/springstudy/user/entity/Member.java @@ -0,0 +1,42 @@ +package com.dku.springstudy.user.entity; + +import com.dku.springstudy.global.BaseEntity; +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.like.entity.Like; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.List; + +/** + * @author 최재민 + */ +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Member extends BaseEntity { + + @Id + @Column(name = "member_id") + private String email; + + private String password; + + private String name; + + private String nickname; + + @Column(name = "phone_number") + private String phoneNumber; + + private String profileImageUrl; + + @OneToMany(mappedBy = "seller", cascade = CascadeType.ALL, orphanRemoval = true) + private List products; + + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) + private List likes; + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..d9251ad --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,28 @@ +spring: + sql: + init: + mode: always + servlet: + multipart: + max-file-size: 15MB + max-request-size: 15MB + datasource: + url: jdbc:postgresql://localhost:5432/carrot + username: postgres + password: 32194691 + driver-class-name: org.postgresql.Driver + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + database: postgresql + database-platform: org.hibernate.dialect.PostgreSQLDialect + generate-ddl: true + show-sql: true + mvc: + pathmatch: + matching-strategy: ant_path_matcher + + From 673e33e0b624a180b27253c96f093be8548062e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Fri, 27 Jan 2023 16:54:02 +0900 Subject: [PATCH 03/15] =?UTF-8?q?Chore:=20setting=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20gitignore=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c2065bc..056f822 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ out/ ### VS Code ### .vscode/ + +.yml +.properties \ No newline at end of file From 4fabac1a10390188c8abfc92ccb3a34603800d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Fri, 27 Jan 2023 16:58:07 +0900 Subject: [PATCH 04/15] =?UTF-8?q?Fix:=20member=EC=9D=98=20=ED=82=A4?= =?UTF-8?q?=EB=A5=BC=20email=20->=20generatedId=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/dku/springstudy/like/entity/Like.java | 2 +- src/main/java/com/dku/springstudy/user/entity/Member.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dku/springstudy/like/entity/Like.java b/src/main/java/com/dku/springstudy/like/entity/Like.java index dd051b6..5e0eccd 100644 --- a/src/main/java/com/dku/springstudy/like/entity/Like.java +++ b/src/main/java/com/dku/springstudy/like/entity/Like.java @@ -38,6 +38,6 @@ public static class LikeId implements Serializable { @Column(name = "item_id") private Long itemId; @Column(name = "member_id") - private String memberId; + private Long memberId; } } \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/user/entity/Member.java b/src/main/java/com/dku/springstudy/user/entity/Member.java index e11058f..bffa448 100644 --- a/src/main/java/com/dku/springstudy/user/entity/Member.java +++ b/src/main/java/com/dku/springstudy/user/entity/Member.java @@ -19,7 +19,11 @@ public class Member extends BaseEntity { @Id + @GeneratedValue @Column(name = "member_id") + private Long id; + + @Column(unique = true) private String email; private String password; From f16c3325adaf8a6bf6f77e601601824e7e59cdc6 Mon Sep 17 00:00:00 2001 From: dku19jam <70689205+dku19jam@users.noreply.github.com> Date: Mon, 30 Jan 2023 15:17:15 +0900 Subject: [PATCH 05/15] =?UTF-8?q?Feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + .../Member/controller/MemberController.java | 21 ++++ .../Member/dto/LoginRequestDto.java | 11 ++ .../Member/dto/LoginResponseDto.java | 14 +++ .../Member/dto/SignupRequestDto.java | 19 ++++ .../springstudy/Member/dto/TokenResponse.java | 9 ++ .../{user => Member}/entity/Member.java | 10 +- .../springstudy/Member/entity/MemberROLE.java | 15 +++ .../Member/repository/MemberRepository.java | 11 ++ .../Member/service/MemberDetailService.java | 34 ++++++ .../Member/service/MemberService.java | 58 ++++++++++ .../auth/JwtAuthenticationFilter.java | 53 +++++++++ .../com/dku/springstudy/auth/JwtProvider.java | 103 ++++++++++++++++++ .../dku/springstudy/auth/SecretConfig.java | 26 +++++ .../com/dku/springstudy/auth/SecretKey.java | 17 +++ .../dku/springstudy/auth/UserPrincipal.java | 56 ++++++++++ .../com/dku/springstudy/item/entity/Item.java | 2 +- .../com/dku/springstudy/like/entity/Like.java | 2 +- 18 files changed, 457 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/Member/controller/MemberController.java create mode 100644 src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java create mode 100644 src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java create mode 100644 src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java create mode 100644 src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java rename src/main/java/com/dku/springstudy/{user => Member}/entity/Member.java (86%) create mode 100644 src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java create mode 100644 src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java create mode 100644 src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java create mode 100644 src/main/java/com/dku/springstudy/Member/service/MemberService.java create mode 100644 src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/dku/springstudy/auth/JwtProvider.java create mode 100644 src/main/java/com/dku/springstudy/auth/SecretConfig.java create mode 100644 src/main/java/com/dku/springstudy/auth/SecretKey.java create mode 100644 src/main/java/com/dku/springstudy/auth/UserPrincipal.java diff --git a/build.gradle b/build.gradle index e0f41b0..aaac6d1 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,8 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1' + runtimeOnly 'org.postgresql:postgresql' } diff --git a/src/main/java/com/dku/springstudy/Member/controller/MemberController.java b/src/main/java/com/dku/springstudy/Member/controller/MemberController.java new file mode 100644 index 0000000..c787595 --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/controller/MemberController.java @@ -0,0 +1,21 @@ +package com.dku.springstudy.Member.controller; + +import com.dku.springstudy.Member.dto.SignupRequestDto; +import com.dku.springstudy.Member.service.MemberService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class MemberController { + + private final MemberService memberService; + + @PostMapping + public ResponseEntity signup(SignupRequestDto request) { + memberService.signup(request); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java b/src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java new file mode 100644 index 0000000..5051ced --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java @@ -0,0 +1,11 @@ +package com.dku.springstudy.Member.dto; + +import lombok.Data; + +@Data +public class LoginRequestDto { + + private String email; + + private String password; +} diff --git a/src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java b/src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java new file mode 100644 index 0000000..3af6536 --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java @@ -0,0 +1,14 @@ +package com.dku.springstudy.Member.dto; + +import lombok.Data; + +@Data +public class LoginResponseDto { + private final String accessToken; + private final Long tokenExpireTime; + + public LoginResponseDto(String accessToken, Long tokenExpireTime) { + this.accessToken = accessToken; + this.tokenExpireTime = tokenExpireTime; + } +} diff --git a/src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java b/src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java new file mode 100644 index 0000000..9a976a4 --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java @@ -0,0 +1,19 @@ +package com.dku.springstudy.Member.dto; + +import com.dku.springstudy.Member.entity.MemberROLE; +import lombok.Data; + +@Data +public class SignupRequestDto { + private String email; + + private String password; + + private String name; + + private String nickname; + + private MemberROLE memberRole; + + private String phoneNumber; +} diff --git a/src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java b/src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java new file mode 100644 index 0000000..2d1f961 --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java @@ -0,0 +1,9 @@ +package com.dku.springstudy.Member.dto; + +import lombok.Data; + +@Data +public class TokenResponse { + + private final String accessToken; +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/user/entity/Member.java b/src/main/java/com/dku/springstudy/Member/entity/Member.java similarity index 86% rename from src/main/java/com/dku/springstudy/user/entity/Member.java rename to src/main/java/com/dku/springstudy/Member/entity/Member.java index e11058f..40c79ac 100644 --- a/src/main/java/com/dku/springstudy/user/entity/Member.java +++ b/src/main/java/com/dku/springstudy/Member/entity/Member.java @@ -1,11 +1,9 @@ -package com.dku.springstudy.user.entity; +package com.dku.springstudy.Member.entity; import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.item.entity.Item; import com.dku.springstudy.like.entity.Like; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; +import lombok.*; import javax.persistence.*; import java.util.List; @@ -16,6 +14,8 @@ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor +@Getter +@Builder public class Member extends BaseEntity { @Id @@ -28,6 +28,8 @@ public class Member extends BaseEntity { private String nickname; + private MemberROLE memberRole; + @Column(name = "phone_number") private String phoneNumber; diff --git a/src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java b/src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java new file mode 100644 index 0000000..23aba7a --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.Member.entity; + +public enum MemberROLE { + USER("USER"), + ADMIN("ADMIN"), + ; + + final String role; + + MemberROLE(String role) { + this.role = role; + } + + public String role() { return role; } +} diff --git a/src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java b/src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java new file mode 100644 index 0000000..dcd811f --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java @@ -0,0 +1,11 @@ +package com.dku.springstudy.Member.repository; + +import com.dku.springstudy.Member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface MemberRepository extends JpaRepository { + + Optional findByEmail(String email); +} diff --git a/src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java b/src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java new file mode 100644 index 0000000..8af1334 --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java @@ -0,0 +1,34 @@ +package com.dku.springstudy.Member.service; + +import com.dku.springstudy.Member.entity.Member; +import com.dku.springstudy.Member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class MemberDetailService implements UserDetailsService{ + + private final MemberRepository memberRepository; + + @Override + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + if (email.isBlank()) { +// throw new EmailEmptyException(); + } + + Optional optionalUser = memberRepository.findByEmail(email); + Member member = optionalUser.orElseThrow(); + + Collection authorities = new ArrayList<>(); + return new org.springframework.security.core.userdetails.User(member.getEmail(), member.getPassword(), authorities); + } +} diff --git a/src/main/java/com/dku/springstudy/Member/service/MemberService.java b/src/main/java/com/dku/springstudy/Member/service/MemberService.java new file mode 100644 index 0000000..67c48e0 --- /dev/null +++ b/src/main/java/com/dku/springstudy/Member/service/MemberService.java @@ -0,0 +1,58 @@ +package com.dku.springstudy.Member.service; + + +import com.dku.springstudy.Member.dto.LoginRequestDto; +import com.dku.springstudy.Member.dto.LoginResponseDto; +import com.dku.springstudy.Member.dto.SignupRequestDto; +import com.dku.springstudy.Member.dto.TokenResponse; +import com.dku.springstudy.Member.entity.Member; +import com.dku.springstudy.Member.entity.MemberROLE; +import com.dku.springstudy.Member.repository.MemberRepository; +import com.dku.springstudy.auth.JwtProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MemberService { + + private final AuthenticationManager authenticationManager; + private final MemberRepository memberRepository; + private final JwtProvider jwtProvider; + + public void signup(SignupRequestDto request) { + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + String encodedPassword = encoder.encode(request.getPassword()); + Member member = Member.builder() + .name(request.getName()) + .email(request.getEmail()) + .password(encodedPassword) + .phoneNumber(request.getPhoneNumber()) + .nickname(request.getNickname()) + .memberRole(MemberROLE.USER) + .build(); + + memberRepository.save(member); + } + + + public LoginResponseDto login(LoginRequestDto loginRequest) { + authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword())); + TokenResponse createToken = createTokenReturn(loginRequest); + Long tokenExpireTime = jwtProvider.getTokenExpireTime(createToken.getAccessToken()); + return new LoginResponseDto( + createToken.getAccessToken(), + tokenExpireTime); + } + + private TokenResponse createTokenReturn(LoginRequestDto loginRequest) { + + String accessToken = jwtProvider.createAccessToken(loginRequest.getEmail()); + + return new TokenResponse(accessToken); + } +} diff --git a/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java b/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java new file mode 100644 index 0000000..b155ddc --- /dev/null +++ b/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java @@ -0,0 +1,53 @@ +package com.dku.springstudy.auth; + + +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.SignatureException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +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; + +@Slf4j +@Component +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + private final JwtProvider jwtProvider; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain chain) throws IOException, ServletException { + + String token = jwtProvider.resolveToken(request); + + try { + if (token != null && jwtProvider.validateJwtToken(token)) { + Authentication authentication = jwtProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } catch (ExpiredJwtException err) { + logger.error("token is expired and not valid anymore", err); + throw new JwtException("토큰 기한이 만료되었습니다."); + } catch (IllegalArgumentException err) { + logger.error("an error occurred during getting email from token", err); + throw new JwtException("유효하지 않은 토큰정보 입니다."); + } catch (SignatureException err) { + logger.error("Authentication Failed. Username or Password not valid", err); + throw new JwtException("사용자 인증에 실패하였습니다."); + } catch (BadCredentialsException err) { + logger.error("Incorrect email or password."); + throw new BadCredentialsException("이메일 또는 비밀번호를 다시 확인해주세요."); + } + chain.doFilter(request, response); + } +} diff --git a/src/main/java/com/dku/springstudy/auth/JwtProvider.java b/src/main/java/com/dku/springstudy/auth/JwtProvider.java new file mode 100644 index 0000000..8915955 --- /dev/null +++ b/src/main/java/com/dku/springstudy/auth/JwtProvider.java @@ -0,0 +1,103 @@ +package com.dku.springstudy.auth; + +import com.dku.springstudy.Member.service.MemberDetailService; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.*; + + +@Service +@RequiredArgsConstructor +@Slf4j +public class JwtProvider { + private final MemberDetailService memberDetailService; + private final SecretKey secretKey; + + public String createAccessToken(String payload) { + Claims claims = Jwts.claims().setSubject(payload); + Date now = new Date(); + Date validityTime = new Date(now.getTime() + secretKey.getJwtValidityTime()); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validityTime) + .signWith(SignatureAlgorithm.HS256, secretKey.getJwtSecretKey()) + .compact(); + } + + public Authentication getAuthentication(String token) { + UserDetails userDetails = memberDetailService.loadUserByUsername(this.extractEmail(token)); + return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); + } + + public String extractEmail(String token) { + return (String) Jwts.parser().setSigningKey(secretKey.getJwtSecretKey()).parseClaimsJws(token).getBody().get("email"); + } + + public String resolveToken(HttpServletRequest request) { + String header = request.getHeader("Authorization"); + if (header == null) { + return null; + } + return header.replace("Bearer ", ""); + } + + public boolean validateJwtToken(String token) { + try { + Jws claims = Jwts.parser().setSigningKey(secretKey.getJwtSecretKey()) + .parseClaimsJws(token); + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + throw new IllegalArgumentException("유효하지 않은 토큰 정보입니다."); + } + } + + public Map createRefreshToken(String payload) { + + Claims claims = Jwts.claims().setSubject(payload); + Date now = new Date(); + Date validityTime = new Date(now.getTime() + secretKey.getJwtValidityTime()); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH); + String refreshTokenExpirationAt = simpleDateFormat.format(validityTime); + + String jwt = Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validityTime) + .signWith(SignatureAlgorithm.HS256, secretKey.getJwtSecretKey()) + .compact(); + + Map result = new HashMap<>(); + result.put("refreshToken", jwt); + result.put("refreshTokenExpirationAt", refreshTokenExpirationAt); + return result; + } + + + public Long getTokenExpireTime(String accessToken) { + + Base64.Decoder decoder = Base64.getUrlDecoder(); + String[] parts = accessToken.split("\\."); + ObjectMapper mapper = new ObjectMapper(); + String payload = new String(decoder.decode(parts[1])); + Map exp = null; + + try { + exp = mapper.readValue(payload, Map.class); + return ((Number) exp.get("exp")).longValue(); + } catch (IOException err) { + throw new RuntimeException(err); + } + } +} diff --git a/src/main/java/com/dku/springstudy/auth/SecretConfig.java b/src/main/java/com/dku/springstudy/auth/SecretConfig.java new file mode 100644 index 0000000..ef09e38 --- /dev/null +++ b/src/main/java/com/dku/springstudy/auth/SecretConfig.java @@ -0,0 +1,26 @@ +package com.dku.springstudy.auth; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SecretConfig { + + private final String jwtSecretKey; + private final Long jwtValidityTime; + private final Long refreshValidityTime; + + @Bean + public SecretKey newSecretKey() { + return new SecretKey(jwtSecretKey, jwtValidityTime, refreshValidityTime); + } + + public SecretConfig(@Value("${security.jwt.token.secret-key}") String jwtSecretKey, + @Value("${security.jwt.token.expire-length}")Long jwtValidityTime, + @Value("${security.jwt.token.expire-length-refresh}") Long refreshValidityTime) { + this.jwtSecretKey = jwtSecretKey; + this.jwtValidityTime = jwtValidityTime; + this.refreshValidityTime = refreshValidityTime; + } +} diff --git a/src/main/java/com/dku/springstudy/auth/SecretKey.java b/src/main/java/com/dku/springstudy/auth/SecretKey.java new file mode 100644 index 0000000..103a569 --- /dev/null +++ b/src/main/java/com/dku/springstudy/auth/SecretKey.java @@ -0,0 +1,17 @@ +package com.dku.springstudy.auth; + +import lombok.Getter; + +@Getter +public class SecretKey { + + private final String jwtSecretKey; + private final Long jwtValidityTime; + private final Long refreshValidityTime; + + public SecretKey(String jwtSecretKey, Long jwtValidityTime, Long refreshValidityTime) { + this.jwtSecretKey = jwtSecretKey; + this.jwtValidityTime = jwtValidityTime; + this.refreshValidityTime = refreshValidityTime; + } +} diff --git a/src/main/java/com/dku/springstudy/auth/UserPrincipal.java b/src/main/java/com/dku/springstudy/auth/UserPrincipal.java new file mode 100644 index 0000000..d6babf8 --- /dev/null +++ b/src/main/java/com/dku/springstudy/auth/UserPrincipal.java @@ -0,0 +1,56 @@ +package com.dku.springstudy.auth; + +import com.dku.springstudy.Member.entity.Member; +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.Collections; + + +@Getter +public class UserPrincipal implements UserDetails { + private Member member; + + public UserPrincipal(Member member) { + this.member = member; + } + + @Override + public Collection getAuthorities() { + SimpleGrantedAuthority authority = new SimpleGrantedAuthority(member.getMemberRole().name()); + return Collections.singletonList(authority); + } + + @Override + public String getPassword() { + return member.getPassword(); + } + + @Override + public String getUsername() { + return member.getEmail(); + } + + @Override + public boolean isAccountNonExpired() { + return false; + } + + @Override + public boolean isAccountNonLocked() { + return false; + } + + @Override + public boolean isCredentialsNonExpired() { + return false; + } + + @Override + public boolean isEnabled() { + return false; + } +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Item.java b/src/main/java/com/dku/springstudy/item/entity/Item.java index 19a7310..d9b41aa 100644 --- a/src/main/java/com/dku/springstudy/item/entity/Item.java +++ b/src/main/java/com/dku/springstudy/item/entity/Item.java @@ -2,7 +2,7 @@ import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.like.entity.Like; -import com.dku.springstudy.user.entity.Member; +import com.dku.springstudy.Member.entity.Member; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/dku/springstudy/like/entity/Like.java b/src/main/java/com/dku/springstudy/like/entity/Like.java index dd051b6..a3be4cf 100644 --- a/src/main/java/com/dku/springstudy/like/entity/Like.java +++ b/src/main/java/com/dku/springstudy/like/entity/Like.java @@ -2,7 +2,7 @@ import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.item.entity.Item; -import com.dku.springstudy.user.entity.Member; +import com.dku.springstudy.Member.entity.Member; import lombok.EqualsAndHashCode; import lombok.Getter; From 23cdd656c6b7bb081f285edbf28233a4f3dfe303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Tue, 31 Jan 2023 10:59:20 +0900 Subject: [PATCH 06/15] =?UTF-8?q?Fix:=20SecurityConfig=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=88=84=EB=9D=BD=20=EB=B0=8F=20member=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dku/springstudy/auth/JwtProvider.java | 2 +- .../dku/springstudy/auth/UserPrincipal.java | 2 +- .../springstudy/global/SecurityConfig.java | 72 +++++++++++++++++++ .../com/dku/springstudy/item/entity/Item.java | 2 +- .../com/dku/springstudy/like/entity/Like.java | 2 +- .../dto/LoginRequestDto.java | 2 +- .../dto/LoginResponseDto.java | 2 +- .../dto/SignupRequestDto.java | 6 +- .../{Member => member}/dto/TokenResponse.java | 2 +- .../{Member => member}/entity/Member.java | 2 +- .../{Member => member}/entity/MemberROLE.java | 2 +- .../repository/MemberRepository.java | 4 +- .../service/MemberDetailService.java | 6 +- .../service/MemberService.java | 16 ++--- 14 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/global/SecurityConfig.java rename src/main/java/com/dku/springstudy/{Member => member}/dto/LoginRequestDto.java (74%) rename src/main/java/com/dku/springstudy/{Member => member}/dto/LoginResponseDto.java (88%) rename src/main/java/com/dku/springstudy/{Member => member}/dto/SignupRequestDto.java (61%) rename src/main/java/com/dku/springstudy/{Member => member}/dto/TokenResponse.java (70%) rename src/main/java/com/dku/springstudy/{Member => member}/entity/Member.java (95%) rename src/main/java/com/dku/springstudy/{Member => member}/entity/MemberROLE.java (82%) rename src/main/java/com/dku/springstudy/{Member => member}/repository/MemberRepository.java (69%) rename src/main/java/com/dku/springstudy/{Member => member}/service/MemberDetailService.java (88%) rename src/main/java/com/dku/springstudy/{Member => member}/service/MemberService.java (81%) diff --git a/src/main/java/com/dku/springstudy/auth/JwtProvider.java b/src/main/java/com/dku/springstudy/auth/JwtProvider.java index 8915955..678ac8a 100644 --- a/src/main/java/com/dku/springstudy/auth/JwtProvider.java +++ b/src/main/java/com/dku/springstudy/auth/JwtProvider.java @@ -1,6 +1,6 @@ package com.dku.springstudy.auth; -import com.dku.springstudy.Member.service.MemberDetailService; +import com.dku.springstudy.member.service.MemberDetailService; import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.*; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/dku/springstudy/auth/UserPrincipal.java b/src/main/java/com/dku/springstudy/auth/UserPrincipal.java index d6babf8..fa876a4 100644 --- a/src/main/java/com/dku/springstudy/auth/UserPrincipal.java +++ b/src/main/java/com/dku/springstudy/auth/UserPrincipal.java @@ -1,6 +1,6 @@ package com.dku.springstudy.auth; -import com.dku.springstudy.Member.entity.Member; +import com.dku.springstudy.member.entity.Member; import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; diff --git a/src/main/java/com/dku/springstudy/global/SecurityConfig.java b/src/main/java/com/dku/springstudy/global/SecurityConfig.java new file mode 100644 index 0000000..aa85810 --- /dev/null +++ b/src/main/java/com/dku/springstudy/global/SecurityConfig.java @@ -0,0 +1,72 @@ +package com.dku.springstudy.global; + +import com.dku.springstudy.auth.JwtAuthenticationFilter; +import com.dku.springstudy.auth.JwtProvider; +import com.dku.springstudy.member.repository.MemberRepository; +import com.dku.springstudy.member.service.MemberDetailService; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.BeanIds; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + + +@RequiredArgsConstructor +@EnableWebSecurity +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final MemberDetailService memberDetailService; + + private final JwtProvider jwtProvider; + + @Override + public void configure(HttpSecurity httpSecurity) throws Exception { + httpSecurity.csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .headers().frameOptions().disable() + .and() + .authorizeRequests() + .antMatchers("/login", "/signup","/").permitAll() + .anyRequest().authenticated() + .and() + .exceptionHandling() + .and() + .addFilterBefore(new JwtAuthenticationFilter(jwtProvider), UsernamePasswordAuthenticationFilter.class); + + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(memberDetailService) + .passwordEncoder(new BCryptPasswordEncoder()); + } + + @Bean(name = BeanIds.AUTHENTICATION_MANAGER) + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Override + public void configure(WebSecurity web) { + web.ignoring().antMatchers( + // -- Static resources + "/css/**", "/images/**", "/js/**" + // -- Swagger UI v2 + , "/v2/api-docs", "/swagger-resources/**" + , "/swagger-ui.html", "/webjars/**", "/swagger/**" + // -- Swagger UI v3 (Open API) + , "/v3/api-docs/**", "/swagger-ui/**" + ); } +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Item.java b/src/main/java/com/dku/springstudy/item/entity/Item.java index d9b41aa..ba51056 100644 --- a/src/main/java/com/dku/springstudy/item/entity/Item.java +++ b/src/main/java/com/dku/springstudy/item/entity/Item.java @@ -2,7 +2,7 @@ import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.like.entity.Like; -import com.dku.springstudy.Member.entity.Member; +import com.dku.springstudy.member.entity.Member; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/dku/springstudy/like/entity/Like.java b/src/main/java/com/dku/springstudy/like/entity/Like.java index 4ee5377..3df16e5 100644 --- a/src/main/java/com/dku/springstudy/like/entity/Like.java +++ b/src/main/java/com/dku/springstudy/like/entity/Like.java @@ -2,7 +2,7 @@ import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.item.entity.Item; -import com.dku.springstudy.Member.entity.Member; +import com.dku.springstudy.member.entity.Member; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java b/src/main/java/com/dku/springstudy/member/dto/LoginRequestDto.java similarity index 74% rename from src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java rename to src/main/java/com/dku/springstudy/member/dto/LoginRequestDto.java index 5051ced..838c45d 100644 --- a/src/main/java/com/dku/springstudy/Member/dto/LoginRequestDto.java +++ b/src/main/java/com/dku/springstudy/member/dto/LoginRequestDto.java @@ -1,4 +1,4 @@ -package com.dku.springstudy.Member.dto; +package com.dku.springstudy.member.dto; import lombok.Data; diff --git a/src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java b/src/main/java/com/dku/springstudy/member/dto/LoginResponseDto.java similarity index 88% rename from src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java rename to src/main/java/com/dku/springstudy/member/dto/LoginResponseDto.java index 3af6536..a8ab8f6 100644 --- a/src/main/java/com/dku/springstudy/Member/dto/LoginResponseDto.java +++ b/src/main/java/com/dku/springstudy/member/dto/LoginResponseDto.java @@ -1,4 +1,4 @@ -package com.dku.springstudy.Member.dto; +package com.dku.springstudy.member.dto; import lombok.Data; diff --git a/src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java b/src/main/java/com/dku/springstudy/member/dto/SignupRequestDto.java similarity index 61% rename from src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java rename to src/main/java/com/dku/springstudy/member/dto/SignupRequestDto.java index 9a976a4..0c60026 100644 --- a/src/main/java/com/dku/springstudy/Member/dto/SignupRequestDto.java +++ b/src/main/java/com/dku/springstudy/member/dto/SignupRequestDto.java @@ -1,6 +1,6 @@ -package com.dku.springstudy.Member.dto; +package com.dku.springstudy.member.dto; -import com.dku.springstudy.Member.entity.MemberROLE; +import com.dku.springstudy.member.entity.MemberROLE; import lombok.Data; @Data @@ -13,7 +13,5 @@ public class SignupRequestDto { private String nickname; - private MemberROLE memberRole; - private String phoneNumber; } diff --git a/src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java b/src/main/java/com/dku/springstudy/member/dto/TokenResponse.java similarity index 70% rename from src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java rename to src/main/java/com/dku/springstudy/member/dto/TokenResponse.java index 2d1f961..ad4843e 100644 --- a/src/main/java/com/dku/springstudy/Member/dto/TokenResponse.java +++ b/src/main/java/com/dku/springstudy/member/dto/TokenResponse.java @@ -1,4 +1,4 @@ -package com.dku.springstudy.Member.dto; +package com.dku.springstudy.member.dto; import lombok.Data; diff --git a/src/main/java/com/dku/springstudy/Member/entity/Member.java b/src/main/java/com/dku/springstudy/member/entity/Member.java similarity index 95% rename from src/main/java/com/dku/springstudy/Member/entity/Member.java rename to src/main/java/com/dku/springstudy/member/entity/Member.java index 02ecade..d6b1b75 100644 --- a/src/main/java/com/dku/springstudy/Member/entity/Member.java +++ b/src/main/java/com/dku/springstudy/member/entity/Member.java @@ -1,4 +1,4 @@ -package com.dku.springstudy.Member.entity; +package com.dku.springstudy.member.entity; import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.item.entity.Item; diff --git a/src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java b/src/main/java/com/dku/springstudy/member/entity/MemberROLE.java similarity index 82% rename from src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java rename to src/main/java/com/dku/springstudy/member/entity/MemberROLE.java index 23aba7a..83b27a0 100644 --- a/src/main/java/com/dku/springstudy/Member/entity/MemberROLE.java +++ b/src/main/java/com/dku/springstudy/member/entity/MemberROLE.java @@ -1,4 +1,4 @@ -package com.dku.springstudy.Member.entity; +package com.dku.springstudy.member.entity; public enum MemberROLE { USER("USER"), diff --git a/src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java b/src/main/java/com/dku/springstudy/member/repository/MemberRepository.java similarity index 69% rename from src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java rename to src/main/java/com/dku/springstudy/member/repository/MemberRepository.java index dcd811f..672fa9c 100644 --- a/src/main/java/com/dku/springstudy/Member/repository/MemberRepository.java +++ b/src/main/java/com/dku/springstudy/member/repository/MemberRepository.java @@ -1,6 +1,6 @@ -package com.dku.springstudy.Member.repository; +package com.dku.springstudy.member.repository; -import com.dku.springstudy.Member.entity.Member; +import com.dku.springstudy.member.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; diff --git a/src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java b/src/main/java/com/dku/springstudy/member/service/MemberDetailService.java similarity index 88% rename from src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java rename to src/main/java/com/dku/springstudy/member/service/MemberDetailService.java index 8af1334..902225c 100644 --- a/src/main/java/com/dku/springstudy/Member/service/MemberDetailService.java +++ b/src/main/java/com/dku/springstudy/member/service/MemberDetailService.java @@ -1,7 +1,7 @@ -package com.dku.springstudy.Member.service; +package com.dku.springstudy.member.service; -import com.dku.springstudy.Member.entity.Member; -import com.dku.springstudy.Member.repository.MemberRepository; +import com.dku.springstudy.member.entity.Member; +import com.dku.springstudy.member.repository.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; diff --git a/src/main/java/com/dku/springstudy/Member/service/MemberService.java b/src/main/java/com/dku/springstudy/member/service/MemberService.java similarity index 81% rename from src/main/java/com/dku/springstudy/Member/service/MemberService.java rename to src/main/java/com/dku/springstudy/member/service/MemberService.java index 67c48e0..9231d80 100644 --- a/src/main/java/com/dku/springstudy/Member/service/MemberService.java +++ b/src/main/java/com/dku/springstudy/member/service/MemberService.java @@ -1,13 +1,13 @@ -package com.dku.springstudy.Member.service; +package com.dku.springstudy.member.service; -import com.dku.springstudy.Member.dto.LoginRequestDto; -import com.dku.springstudy.Member.dto.LoginResponseDto; -import com.dku.springstudy.Member.dto.SignupRequestDto; -import com.dku.springstudy.Member.dto.TokenResponse; -import com.dku.springstudy.Member.entity.Member; -import com.dku.springstudy.Member.entity.MemberROLE; -import com.dku.springstudy.Member.repository.MemberRepository; +import com.dku.springstudy.member.dto.LoginRequestDto; +import com.dku.springstudy.member.dto.LoginResponseDto; +import com.dku.springstudy.member.dto.SignupRequestDto; +import com.dku.springstudy.member.dto.TokenResponse; +import com.dku.springstudy.member.entity.Member; +import com.dku.springstudy.member.entity.MemberROLE; +import com.dku.springstudy.member.repository.MemberRepository; import com.dku.springstudy.auth.JwtProvider; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.AuthenticationManager; From 9b8ae8afc55ff9c28dfd07539cdba68beb5d056d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Tue, 31 Jan 2023 10:59:38 +0900 Subject: [PATCH 07/15] =?UTF-8?q?Feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Member/controller/MemberController.java | 21 ------------- .../member/controller/MemberController.java | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 21 deletions(-) delete mode 100644 src/main/java/com/dku/springstudy/Member/controller/MemberController.java create mode 100644 src/main/java/com/dku/springstudy/member/controller/MemberController.java diff --git a/src/main/java/com/dku/springstudy/Member/controller/MemberController.java b/src/main/java/com/dku/springstudy/Member/controller/MemberController.java deleted file mode 100644 index c787595..0000000 --- a/src/main/java/com/dku/springstudy/Member/controller/MemberController.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.dku.springstudy.Member.controller; - -import com.dku.springstudy.Member.dto.SignupRequestDto; -import com.dku.springstudy.Member.service.MemberService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -public class MemberController { - - private final MemberService memberService; - - @PostMapping - public ResponseEntity signup(SignupRequestDto request) { - memberService.signup(request); - return ResponseEntity.ok().build(); - } -} diff --git a/src/main/java/com/dku/springstudy/member/controller/MemberController.java b/src/main/java/com/dku/springstudy/member/controller/MemberController.java new file mode 100644 index 0000000..19326c6 --- /dev/null +++ b/src/main/java/com/dku/springstudy/member/controller/MemberController.java @@ -0,0 +1,30 @@ +package com.dku.springstudy.member.controller; + +import com.dku.springstudy.member.dto.LoginRequestDto; +import com.dku.springstudy.member.dto.LoginResponseDto; +import com.dku.springstudy.member.dto.SignupRequestDto; +import com.dku.springstudy.member.service.MemberService; +import lombok.RequiredArgsConstructor; +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.RestController; + +@RestController +@RequiredArgsConstructor +public class MemberController { + + private final MemberService memberService; + + @PostMapping("/signup") + public ResponseEntity signup(@RequestBody SignupRequestDto request) { + memberService.signup(request); + return ResponseEntity.ok().body("회원가입에 성공하셨습니다."); + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody LoginRequestDto request) { + LoginResponseDto member = memberService.login(request); + return ResponseEntity.ok().body(member); + } +} From 0ad646111dc52d050fe384b0d5a4a0c81b7e1f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Fri, 3 Feb 2023 15:19:39 +0900 Subject: [PATCH 08/15] =?UTF-8?q?Fix:=20=EA=B6=8C=ED=95=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B3=80=EA=B2=BD=20(USER=20->=20ROLE=5FUSER,=20AD?= =?UTF-8?q?MIN=20->=20ROLE=5FADMIN)=20securityConfig=EC=97=90=20=EC=B0=A8?= =?UTF-8?q?=EB=8B=A8=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=ED=95=9C=20=EC=9D=B4=EB=A6=84=EC=9D=B4=20USER=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20ROLE=5FUSER=EC=99=80=20=EC=9D=BC=EC=B9=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=A8,,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/dku/springstudy/item/entity/Item.java | 1 + .../java/com/dku/springstudy/member/entity/Member.java | 1 + .../java/com/dku/springstudy/member/entity/MemberROLE.java | 5 +++-- .../com/dku/springstudy/member/service/MemberService.java | 7 ++++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/dku/springstudy/item/entity/Item.java b/src/main/java/com/dku/springstudy/item/entity/Item.java index ba51056..5d92bf8 100644 --- a/src/main/java/com/dku/springstudy/item/entity/Item.java +++ b/src/main/java/com/dku/springstudy/item/entity/Item.java @@ -34,6 +34,7 @@ public class Item extends BaseEntity { @JoinColumn(name = "member_id") private Member seller; + @Enumerated(EnumType.STRING) private Category category; @Lob diff --git a/src/main/java/com/dku/springstudy/member/entity/Member.java b/src/main/java/com/dku/springstudy/member/entity/Member.java index d6b1b75..5c8a3ae 100644 --- a/src/main/java/com/dku/springstudy/member/entity/Member.java +++ b/src/main/java/com/dku/springstudy/member/entity/Member.java @@ -32,6 +32,7 @@ public class Member extends BaseEntity { private String nickname; + @Enumerated(EnumType.STRING) private MemberROLE memberRole; @Column(name = "phone_number") diff --git a/src/main/java/com/dku/springstudy/member/entity/MemberROLE.java b/src/main/java/com/dku/springstudy/member/entity/MemberROLE.java index 83b27a0..5ec7271 100644 --- a/src/main/java/com/dku/springstudy/member/entity/MemberROLE.java +++ b/src/main/java/com/dku/springstudy/member/entity/MemberROLE.java @@ -1,8 +1,9 @@ package com.dku.springstudy.member.entity; public enum MemberROLE { - USER("USER"), - ADMIN("ADMIN"), + //Config에서 검사 시 ROLE + config에 등록한 이름으로 검사함... + ROLE_USER("USER"), + ROLE_ADMIN("ADMIN"), ; final String role; diff --git a/src/main/java/com/dku/springstudy/member/service/MemberService.java b/src/main/java/com/dku/springstudy/member/service/MemberService.java index 9231d80..3502d52 100644 --- a/src/main/java/com/dku/springstudy/member/service/MemberService.java +++ b/src/main/java/com/dku/springstudy/member/service/MemberService.java @@ -14,9 +14,14 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +/** + * @author 최재민 + */ @Service @RequiredArgsConstructor +@Transactional public class MemberService { private final AuthenticationManager authenticationManager; @@ -32,7 +37,7 @@ public void signup(SignupRequestDto request) { .password(encodedPassword) .phoneNumber(request.getPhoneNumber()) .nickname(request.getNickname()) - .memberRole(MemberROLE.USER) + .memberRole(MemberROLE.ROLE_USER) .build(); memberRepository.save(member); From 1df1c4e2550bce2361dd05412fcb891d8ec9c68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Tue, 7 Feb 2023 15:20:35 +0900 Subject: [PATCH 09/15] =?UTF-8?q?Feat:=20Item=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 30 +++++++++++ .../dku/springstudy/global/PageResponse.java | 36 +++++++++++++ .../item/controller/ItemController.java | 50 +++++++++++++++++++ .../springstudy/item/dto/CreateItemDto.java | 18 +++++++ .../springstudy/item/dto/ItemResponseDto.java | 39 +++++++++++++++ .../com/dku/springstudy/item/entity/Item.java | 6 +-- .../item/repository/ItemRepository.java | 7 +++ .../item/repository/ItemRepositoryCustom.java | 10 ++++ .../item/repository/ItemRepositoryImpl.java | 49 ++++++++++++++++++ .../springstudy/item/service/ItemService.java | 48 ++++++++++++++++++ 10 files changed, 290 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/global/PageResponse.java create mode 100644 src/main/java/com/dku/springstudy/item/controller/ItemController.java create mode 100644 src/main/java/com/dku/springstudy/item/dto/CreateItemDto.java create mode 100644 src/main/java/com/dku/springstudy/item/dto/ItemResponseDto.java create mode 100644 src/main/java/com/dku/springstudy/item/repository/ItemRepository.java create mode 100644 src/main/java/com/dku/springstudy/item/repository/ItemRepositoryCustom.java create mode 100644 src/main/java/com/dku/springstudy/item/repository/ItemRepositoryImpl.java create mode 100644 src/main/java/com/dku/springstudy/item/service/ItemService.java diff --git a/build.gradle b/build.gradle index aaac6d1..8a39299 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,14 @@ +buildscript { + ext { + queryDslVersion = "5.0.0" + } +} + plugins { id 'java' id 'org.springframework.boot' version '2.7.1' id 'io.spring.dependency-management' version '1.1.0' + id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } group = 'com.dku' @@ -12,6 +19,8 @@ configurations { compileOnly { extendsFrom annotationProcessor } + querydsl.extendsFrom compileClasspath + } repositories { @@ -22,6 +31,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-redis:2.3.1.RELEASE' + compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' @@ -30,8 +41,27 @@ dependencies { implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1' runtimeOnly 'org.postgresql:postgresql' + + implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" + annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" } tasks.named('test') { useJUnitPlatform() } + + +def querydslDir = "$buildDir/generated/querydsl" +querydsl { + jpa = true + querydslSourcesDir = querydslDir +} +sourceSets { + main.java.srcDir querydslDir +} +configurations { + querydsl.extendsFrom compileClasspath +} +compileQuerydsl { + options.annotationProcessorPath = configurations.querydsl +} diff --git a/src/main/java/com/dku/springstudy/global/PageResponse.java b/src/main/java/com/dku/springstudy/global/PageResponse.java new file mode 100644 index 0000000..5bb9143 --- /dev/null +++ b/src/main/java/com/dku/springstudy/global/PageResponse.java @@ -0,0 +1,36 @@ +package com.dku.springstudy.global; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import java.io.Serializable; +import java.util.List; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class PageResponse implements Serializable { + + private List content; + private boolean hasNext; + private int totalPages; + private long totalElements; + private int page; + private int size; + private boolean first; + private boolean last; + + public PageResponse(List content, Pageable pageable, long totalCount){ + final PageImpl page = new PageImpl<>(content, pageable, totalCount); + this.content = content; + this.hasNext = page.hasNext(); + this.totalPages = page.getTotalPages(); + this.totalElements = page.getTotalElements(); + this.page = page.getNumber()+1; + this.size = page.getSize(); + this.first = page.isFirst(); + this.last = page.isLast(); + } +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/item/controller/ItemController.java b/src/main/java/com/dku/springstudy/item/controller/ItemController.java new file mode 100644 index 0000000..60ded41 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/controller/ItemController.java @@ -0,0 +1,50 @@ +package com.dku.springstudy.item.controller; + +import com.dku.springstudy.auth.JwtProvider; +import com.dku.springstudy.global.PageResponse; +import com.dku.springstudy.item.dto.CreateItemDto; +import com.dku.springstudy.item.dto.ItemResponseDto; +import com.dku.springstudy.item.service.ItemService; +import com.dku.springstudy.member.entity.Member; +import com.dku.springstudy.member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequiredArgsConstructor +public class ItemController { + + private final ItemService itemService; + private final JwtProvider jwtProvider; + private final MemberRepository memberRepository; + + @PostMapping + public ResponseEntity createItem(HttpServletRequest request, + @RequestBody CreateItemDto dto) { + String token = jwtProvider.resolveToken(request); + Member member = memberRepository.findByEmail(jwtProvider.extractEmail(token)).orElseThrow(); + Long item = itemService.createItem(member, dto); + + return ResponseEntity.ok().body(item); + } + + @GetMapping("/{id}") + public ResponseEntity getOneItem(@RequestBody Long itemId) { + ItemResponseDto item = itemService.getItemById(itemId); + + return ResponseEntity.ok().body(item); + } + + @GetMapping + public PageResponse getAllItem(@RequestParam(value = "query") String query, + @RequestParam(value = "category") String category, + Pageable pageable) { + Page items = itemService.getItemByParam(query, category, pageable); + return new PageResponse<>(items.getContent(), items.getPageable(), items.getTotalElements()); + } +} diff --git a/src/main/java/com/dku/springstudy/item/dto/CreateItemDto.java b/src/main/java/com/dku/springstudy/item/dto/CreateItemDto.java new file mode 100644 index 0000000..454b0f1 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/dto/CreateItemDto.java @@ -0,0 +1,18 @@ +package com.dku.springstudy.item.dto; + +import com.dku.springstudy.item.entity.Category; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class CreateItemDto { + private String title; + private Long price; + private Category category; + private String content; + + private List files = new ArrayList<>(); +} diff --git a/src/main/java/com/dku/springstudy/item/dto/ItemResponseDto.java b/src/main/java/com/dku/springstudy/item/dto/ItemResponseDto.java new file mode 100644 index 0000000..6ed0e83 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/dto/ItemResponseDto.java @@ -0,0 +1,39 @@ +package com.dku.springstudy.item.dto; + +import com.dku.springstudy.item.entity.Category; +import com.dku.springstudy.item.entity.Image; +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.item.entity.Status; +import com.dku.springstudy.like.entity.Like; +import com.dku.springstudy.member.entity.Member; + +import javax.persistence.*; +import java.util.List; + +public class ItemResponseDto { + private String title; + + private Long price; + + private List image; + + private String seller; + + private Category category; + + private String content; + + private Status status; + + private int likeCount; + + public ItemResponseDto(Item item) { + this.title = item.getTitle(); + this.content = item.getContent(); + this.image = item.getImage(); + this.seller = item.getSeller().getName(); + this.category = item.getCategory(); + this.status = item.getStatus(); + this.likeCount = item.getLikes().size(); + } +} diff --git a/src/main/java/com/dku/springstudy/item/entity/Item.java b/src/main/java/com/dku/springstudy/item/entity/Item.java index 5d92bf8..ab17cba 100644 --- a/src/main/java/com/dku/springstudy/item/entity/Item.java +++ b/src/main/java/com/dku/springstudy/item/entity/Item.java @@ -3,9 +3,7 @@ import com.dku.springstudy.global.BaseEntity; import com.dku.springstudy.like.entity.Like; import com.dku.springstudy.member.entity.Member; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; +import lombok.*; import javax.persistence.*; import java.util.List; @@ -16,6 +14,8 @@ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor +@Builder +@Getter public class Item extends BaseEntity { @Id diff --git a/src/main/java/com/dku/springstudy/item/repository/ItemRepository.java b/src/main/java/com/dku/springstudy/item/repository/ItemRepository.java new file mode 100644 index 0000000..aaafce3 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/repository/ItemRepository.java @@ -0,0 +1,7 @@ +package com.dku.springstudy.item.repository; + +import com.dku.springstudy.item.entity.Item; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ItemRepository extends JpaRepository, ItemRepositoryCustom{ +} diff --git a/src/main/java/com/dku/springstudy/item/repository/ItemRepositoryCustom.java b/src/main/java/com/dku/springstudy/item/repository/ItemRepositoryCustom.java new file mode 100644 index 0000000..9db812b --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/repository/ItemRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.item.repository; + +import com.dku.springstudy.item.entity.Category; +import com.dku.springstudy.item.entity.Item; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface ItemRepositoryCustom { + Page findItemByParam(String query, String category, Pageable pageable); +} diff --git a/src/main/java/com/dku/springstudy/item/repository/ItemRepositoryImpl.java b/src/main/java/com/dku/springstudy/item/repository/ItemRepositoryImpl.java new file mode 100644 index 0000000..e36ce22 --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/repository/ItemRepositoryImpl.java @@ -0,0 +1,49 @@ +package com.dku.springstudy.item.repository; + +import com.dku.springstudy.item.entity.Category; +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.item.entity.Status; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.jpa.impl.JPAQuery; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; + +import javax.persistence.EntityManager; + +import java.util.List; + +import static com.dku.springstudy.item.entity.QItem.item; + +public class ItemRepositoryImpl implements ItemRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + public ItemRepositoryImpl(EntityManager entityManager) { + this.queryFactory = new JPAQueryFactory(entityManager); + } + @Override + public Page findItemByParam(String query, String category, Pageable pageable) { + BooleanBuilder builder = new BooleanBuilder(item.category.eq(Category.valueOf(category))) + .and(item.status.ne(Status.SOLD)); + + if (query != null) { + builder.and(item.title.contains(query)); + } + + List items = queryFactory + .selectFrom(item) + .where(builder) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + JPAQuery countQuery = queryFactory + .selectFrom(item) + .where(builder); + + return PageableExecutionUtils.getPage(items, pageable, () -> countQuery.fetch().size()); + + } +} diff --git a/src/main/java/com/dku/springstudy/item/service/ItemService.java b/src/main/java/com/dku/springstudy/item/service/ItemService.java new file mode 100644 index 0000000..95c111f --- /dev/null +++ b/src/main/java/com/dku/springstudy/item/service/ItemService.java @@ -0,0 +1,48 @@ +package com.dku.springstudy.item.service; + +import com.dku.springstudy.item.dto.ItemResponseDto; +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.item.entity.Status; +import com.dku.springstudy.item.repository.ItemRepository; +import com.dku.springstudy.item.dto.CreateItemDto; +import com.dku.springstudy.member.entity.Member; +import com.dku.springstudy.member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class ItemService { + private final ItemRepository itemRepository; + private final MemberRepository memberRepository; + + public Long createItem(Member member, CreateItemDto dto) { + Item item = Item.builder() + .title(dto.getTitle()) + .price(dto.getPrice()) + .category(dto.getCategory()) + .content(dto.getContent()) + .seller(member) + .status(Status.ON_SALE) +// .image() 이미지 저장 시 추가 + .build(); + + Item save = itemRepository.save(item); + return save.getId(); + } + + public ItemResponseDto getItemById(Long itemId) { + Item item = itemRepository.findById(itemId).orElseThrow(); + return new ItemResponseDto(item); + } + + public Page getItemByParam(String query, String category, Pageable pageable) { + Page itemByParam = itemRepository.findItemByParam(query, category, pageable); + return itemByParam + .map(ItemResponseDto::new); + } +} From b918cb1470c3cfd6a111e2d83fba7ddae36e5314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Tue, 7 Feb 2023 15:49:07 +0900 Subject: [PATCH 10/15] =?UTF-8?q?Feat:=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=EC=9D=98=20=EC=A0=91=EA=B7=BC=20=EA=B6=8C=ED=95=9C?= =?UTF-8?q?=EC=9D=84=20USER=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/dku/springstudy/global/SecurityConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dku/springstudy/global/SecurityConfig.java b/src/main/java/com/dku/springstudy/global/SecurityConfig.java index aa85810..75f0723 100644 --- a/src/main/java/com/dku/springstudy/global/SecurityConfig.java +++ b/src/main/java/com/dku/springstudy/global/SecurityConfig.java @@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -37,7 +38,8 @@ public void configure(HttpSecurity httpSecurity) throws Exception { .headers().frameOptions().disable() .and() .authorizeRequests() - .antMatchers("/login", "/signup","/").permitAll() + .antMatchers("/login", "/signup", "/").permitAll() + .antMatchers(HttpMethod.POST, "/item").hasRole("USER") .anyRequest().authenticated() .and() .exceptionHandling() From 404dbe7a5a0f7c2b49baf3027c69c92b37f8db58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Tue, 7 Feb 2023 17:22:43 +0900 Subject: [PATCH 11/15] =?UTF-8?q?Feat:=20exception=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?base=20ApplicationException=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 + .../error/ApplicationException.java | 19 +++++ .../error/ApplicationExceptionHandler.java | 18 +++++ .../com/dku/springstudy/error/ErrorCode.java | 18 +++++ .../dku/springstudy/error/ErrorResponse.java | 76 +++++++++++++++++++ 5 files changed, 135 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/error/ApplicationException.java create mode 100644 src/main/java/com/dku/springstudy/error/ApplicationExceptionHandler.java create mode 100644 src/main/java/com/dku/springstudy/error/ErrorCode.java create mode 100644 src/main/java/com/dku/springstudy/error/ErrorResponse.java diff --git a/build.gradle b/build.gradle index 8a39299..3a60e1c 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,10 @@ dependencies { implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" + + // Swagger + implementation 'io.springfox:springfox-boot-starter:3.0.0' + implementation 'io.springfox:springfox-swagger-ui:3.0.0' } tasks.named('test') { diff --git a/src/main/java/com/dku/springstudy/error/ApplicationException.java b/src/main/java/com/dku/springstudy/error/ApplicationException.java new file mode 100644 index 0000000..bb67040 --- /dev/null +++ b/src/main/java/com/dku/springstudy/error/ApplicationException.java @@ -0,0 +1,19 @@ +package com.dku.springstudy.error; + +import lombok.Getter; + +@Getter +public class ApplicationException extends RuntimeException { + + private final ErrorCode errorCode; + + public ApplicationException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + protected ApplicationException(String message, ErrorCode errorCode) { + super(message); + this.errorCode = errorCode; + } +} diff --git a/src/main/java/com/dku/springstudy/error/ApplicationExceptionHandler.java b/src/main/java/com/dku/springstudy/error/ApplicationExceptionHandler.java new file mode 100644 index 0000000..f1eb2c7 --- /dev/null +++ b/src/main/java/com/dku/springstudy/error/ApplicationExceptionHandler.java @@ -0,0 +1,18 @@ +package com.dku.springstudy.error; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@Slf4j +public class ApplicationExceptionHandler { + + @ExceptionHandler + protected ResponseEntity handleApplicationException(final ApplicationException exception) { + log.error("handleApplicationException", exception); + final ErrorCode errorCode = exception.getErrorCode(); + final ErrorResponse response = ErrorResponse.from(errorCode); + return new ResponseEntity<>(response, HttpStatus.valueOf(errorCode.getHttpStatus())); + } +} diff --git a/src/main/java/com/dku/springstudy/error/ErrorCode.java b/src/main/java/com/dku/springstudy/error/ErrorCode.java new file mode 100644 index 0000000..ae135d7 --- /dev/null +++ b/src/main/java/com/dku/springstudy/error/ErrorCode.java @@ -0,0 +1,18 @@ +package com.dku.springstudy.error; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Getter; + +@JsonFormat(shape = JsonFormat.Shape.OBJECT) +@Getter +public class ErrorCode { + + private final int httpStatus; + private final String code; + private final String message; + ErrorCode(final int httpStatus, final String code, final String message) { + this.httpStatus = httpStatus; + this.code = code; + this.message = message; + } +} diff --git a/src/main/java/com/dku/springstudy/error/ErrorResponse.java b/src/main/java/com/dku/springstudy/error/ErrorResponse.java new file mode 100644 index 0000000..0e6f825 --- /dev/null +++ b/src/main/java/com/dku/springstudy/error/ErrorResponse.java @@ -0,0 +1,76 @@ +package com.dku.springstudy.error; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.validation.BindingResult; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ErrorResponse { + + private int httpStatus; + private String code; + private String message; + private List errors; + + private ErrorResponse(final ErrorCode errorcode) { + this.httpStatus = errorcode.getHttpStatus(); + this.code = errorcode.getCode(); + this.message = errorcode.getMessage(); + this.errors = new ArrayList<>(); + } + + private ErrorResponse(final ErrorCode errorCode, final List errors) { + this.httpStatus = errorCode.getHttpStatus(); + this.code = errorCode.getCode(); + this.message = errorCode.getMessage(); + this.errors = errors; + } + + public static ErrorResponse from(final ErrorCode errorCode) { + return new ErrorResponse(errorCode); + } + + public static ErrorResponse of(final ErrorCode errorCode, final List errors) { + return new ErrorResponse(errorCode, errors); + } + + public void changeMessage(String message) { + this.message = message; + } + + @Getter + @NoArgsConstructor(access = AccessLevel.PROTECTED) + public static class FieldError { + private String field; + private String value; + private String reason; + + public FieldError(String field, String value,String reason) { + this.field = field; + this.value = value; + this.reason = reason; + } + + public static List of(final String field, final String value, final String reason) { + List fieldErrors = new ArrayList<>(); + fieldErrors.add(new FieldError(field, value, reason)); + return fieldErrors; + } + + private static List of(final BindingResult bindingResult) { + final List fieldErrors = bindingResult.getFieldErrors(); + return fieldErrors.stream() + .map(error -> new FieldError( + error.getField(), + error.getRejectedValue() == null ? "" : error.getRejectedValue().toString(), + error.getDefaultMessage())) + .collect(Collectors.toList()); + } + } +} \ No newline at end of file From dcc645d4847c8f54e00637f8499ca9b705c8a650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Tue, 7 Feb 2023 17:23:29 +0900 Subject: [PATCH 12/15] =?UTF-8?q?Docs:=20swagger=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dku/springstudy/global/SwaggerConfig.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/global/SwaggerConfig.java diff --git a/src/main/java/com/dku/springstudy/global/SwaggerConfig.java b/src/main/java/com/dku/springstudy/global/SwaggerConfig.java new file mode 100644 index 0000000..03b06f4 --- /dev/null +++ b/src/main/java/com/dku/springstudy/global/SwaggerConfig.java @@ -0,0 +1,50 @@ +package com.dku.springstudy.global; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +@Configuration +public class SwaggerConfig implements WebMvcConfigurer { + + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/swagger-ui.html") + .addResourceLocations("classpath:/META-INF/resources/"); + + registry.addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + // -- Static resources + registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); + registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css"); + registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/"); + registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/"); + } + + @Bean + public Docket api() { + return new Docket(DocumentationType.OAS_30) + .useDefaultResponseMessages(false) + .select() + .apis(RequestHandlerSelectors.basePackage("com.dku.springstudy")) + .paths(PathSelectors.any()) + .build() + .apiInfo(apiInfo()); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("단국대 스프링 스터디") + .description("당근마켓 클론 REST API") + .contact(new Contact("dku19jam","https://www.github.com/dku19jam","panzzang518@gmail.com")) + .version("1.0") + .build(); + } +} \ No newline at end of file From f60eb5f5983c6749d4734e74cf2c27813bb998f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Wed, 8 Feb 2023 10:00:31 +0900 Subject: [PATCH 13/15] =?UTF-8?q?Feat:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dku/springstudy/item/entity/Item.java | 9 ++- .../like/controller/LikeController.java | 56 +++++++++++++++++++ .../springstudy/like/dto/CreateLikeDto.java | 13 +++++ .../com/dku/springstudy/like/entity/Like.java | 23 +++++++- .../like/repository/LikeRepository.java | 8 +++ .../springstudy/like/service/LikeService.java | 38 +++++++++++++ .../dku/springstudy/member/entity/Member.java | 8 ++- 7 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/like/controller/LikeController.java create mode 100644 src/main/java/com/dku/springstudy/like/dto/CreateLikeDto.java create mode 100644 src/main/java/com/dku/springstudy/like/repository/LikeRepository.java create mode 100644 src/main/java/com/dku/springstudy/like/service/LikeService.java diff --git a/src/main/java/com/dku/springstudy/item/entity/Item.java b/src/main/java/com/dku/springstudy/item/entity/Item.java index ab17cba..dd3cbda 100644 --- a/src/main/java/com/dku/springstudy/item/entity/Item.java +++ b/src/main/java/com/dku/springstudy/item/entity/Item.java @@ -6,6 +6,7 @@ import lombok.*; import javax.persistence.*; +import java.util.ArrayList; import java.util.List; /** @@ -28,7 +29,7 @@ public class Item extends BaseEntity { private Long price; @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) - private List image; + private List image = new ArrayList<>(); @ManyToOne @JoinColumn(name = "member_id") @@ -43,5 +44,9 @@ public class Item extends BaseEntity { private Status status; @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) - private List likes; + private List likes = new ArrayList<>(); + + public void addLike(Like like) { + this.likes.add(like); + } } diff --git a/src/main/java/com/dku/springstudy/like/controller/LikeController.java b/src/main/java/com/dku/springstudy/like/controller/LikeController.java new file mode 100644 index 0000000..3fbb9c2 --- /dev/null +++ b/src/main/java/com/dku/springstudy/like/controller/LikeController.java @@ -0,0 +1,56 @@ +package com.dku.springstudy.like.controller; + +import com.dku.springstudy.auth.JwtProvider; +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.item.repository.ItemRepository; +import com.dku.springstudy.like.dto.CreateLikeDto; +import com.dku.springstudy.like.entity.Like; +import com.dku.springstudy.like.repository.LikeRepository; +import com.dku.springstudy.like.service.LikeService; +import com.dku.springstudy.member.entity.Member; +import com.dku.springstudy.member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/like") +public class LikeController { + + private final LikeService likeService; + private final ItemRepository itemRepository; + private final JwtProvider jwtProvider; + private final MemberRepository memberRepository; + private final LikeRepository likeRepository; + + @PostMapping + public ResponseEntity likeItem(@RequestBody CreateLikeDto dto, + HttpServletRequest request) { + String token = jwtProvider.resolveToken(request); + Member member = memberRepository.findByEmail(jwtProvider.extractEmail(token)).orElseThrow(); + Item item = itemRepository.findById(dto.getItemId()).orElseThrow(); + Like like = likeService.createLike(member, item); + Like save = likeRepository.save(like); + + return ResponseEntity.ok().body(save.getLikeId()); + } + + @PostMapping("/unCheck") + public ResponseEntity unCheckLike(@RequestBody CreateLikeDto dto, + HttpServletRequest request) { + String token = jwtProvider.resolveToken(request); + Member member = memberRepository.findByEmail(jwtProvider.extractEmail(token)).orElseThrow(); + Item item = itemRepository.findById(dto.getItemId()).orElseThrow(); + Like.LikeId likeId = new Like.LikeId(member.getId(), item.getId()); + Like like = likeRepository.findById(likeId).orElseThrow(); + like.unCheckLike(); + + return ResponseEntity.ok().body("성공!"); + } +} diff --git a/src/main/java/com/dku/springstudy/like/dto/CreateLikeDto.java b/src/main/java/com/dku/springstudy/like/dto/CreateLikeDto.java new file mode 100644 index 0000000..8d804bb --- /dev/null +++ b/src/main/java/com/dku/springstudy/like/dto/CreateLikeDto.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.like.dto; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class CreateLikeDto { + private Long itemId; +} diff --git a/src/main/java/com/dku/springstudy/like/entity/Like.java b/src/main/java/com/dku/springstudy/like/entity/Like.java index 3df16e5..04cb293 100644 --- a/src/main/java/com/dku/springstudy/like/entity/Like.java +++ b/src/main/java/com/dku/springstudy/like/entity/Like.java @@ -4,9 +4,7 @@ import com.dku.springstudy.item.entity.Item; import com.dku.springstudy.member.entity.Member; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; +import lombok.*; import javax.persistence.*; import java.io.Serializable; @@ -14,6 +12,7 @@ @Entity @Getter @Table(name = "likes") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Like extends BaseEntity { @EmbeddedId @@ -27,6 +26,8 @@ public class Like extends BaseEntity { @MapsId("itemId") private Item item; + private boolean checked; + /** * composite key 사용 @@ -34,10 +35,26 @@ public class Like extends BaseEntity { @Embeddable @Getter @Setter @EqualsAndHashCode + @AllArgsConstructor + @NoArgsConstructor(access = AccessLevel.PROTECTED) public static class LikeId implements Serializable { @Column(name = "item_id") private Long itemId; @Column(name = "member_id") private Long memberId; } + + public Like(Member member, Item item) { + this.member = member; + this.item = item; + this.checked = true; + } + + public void unCheckLike() { + this.checked = false; + } + + public void checkLike() { + this.checked = true; + } } \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/like/repository/LikeRepository.java b/src/main/java/com/dku/springstudy/like/repository/LikeRepository.java new file mode 100644 index 0000000..61b4e0a --- /dev/null +++ b/src/main/java/com/dku/springstudy/like/repository/LikeRepository.java @@ -0,0 +1,8 @@ +package com.dku.springstudy.like.repository; + +import com.dku.springstudy.like.entity.Like; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface LikeRepository extends JpaRepository { + +} diff --git a/src/main/java/com/dku/springstudy/like/service/LikeService.java b/src/main/java/com/dku/springstudy/like/service/LikeService.java new file mode 100644 index 0000000..05c2c41 --- /dev/null +++ b/src/main/java/com/dku/springstudy/like/service/LikeService.java @@ -0,0 +1,38 @@ +package com.dku.springstudy.like.service; + +import com.dku.springstudy.item.entity.Item; +import com.dku.springstudy.like.entity.Like; +import com.dku.springstudy.like.repository.LikeRepository; +import com.dku.springstudy.member.entity.Member; +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Transactional +@RequiredArgsConstructor +public class LikeService { + + private final LikeRepository likeRepository; + + public Like createLike(Member member, Item item) { + Like.LikeId likeId = new Like.LikeId(member.getId(), item.getId()); + Like like; + Optional byId = likeRepository.findById(likeId); + if (byId.isPresent()) { + like = byId.get(); + like.checkLike(); + }else { + like = new Like(member, item); + member.addLike(like); + item.addLike(like); + likeRepository.save(like); + } + return like; + } + + public void unCheckLike(Like.LikeId likeId) { + Like like = likeRepository.findById(likeId).orElseThrow(); + like.unCheckLike(); + } +} diff --git a/src/main/java/com/dku/springstudy/member/entity/Member.java b/src/main/java/com/dku/springstudy/member/entity/Member.java index 5c8a3ae..0b2a428 100644 --- a/src/main/java/com/dku/springstudy/member/entity/Member.java +++ b/src/main/java/com/dku/springstudy/member/entity/Member.java @@ -6,6 +6,7 @@ import lombok.*; import javax.persistence.*; +import java.util.ArrayList; import java.util.List; /** @@ -41,9 +42,12 @@ public class Member extends BaseEntity { private String profileImageUrl; @OneToMany(mappedBy = "seller", cascade = CascadeType.ALL, orphanRemoval = true) - private List products; + private List products = new ArrayList<>(); @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) - private List likes; + private List likes = new ArrayList<>(); + public void addLike(Like like) { + this.likes.add(like); + } } From 1a5a39ffdd914cd293e40b7f32fed6e208f2b327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Wed, 8 Feb 2023 10:01:09 +0900 Subject: [PATCH 14/15] =?UTF-8?q?Fix:=20ErrorCode=20enum=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/dku/springstudy/error/ErrorCode.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dku/springstudy/error/ErrorCode.java b/src/main/java/com/dku/springstudy/error/ErrorCode.java index ae135d7..5ff916c 100644 --- a/src/main/java/com/dku/springstudy/error/ErrorCode.java +++ b/src/main/java/com/dku/springstudy/error/ErrorCode.java @@ -5,7 +5,9 @@ @JsonFormat(shape = JsonFormat.Shape.OBJECT) @Getter -public class ErrorCode { +public enum ErrorCode { + ALREADY_EXIST(400, "G001", "이미 존재합니다"), + NOT_EXIST(400, "G002", "존재하지 않습니다"); private final int httpStatus; private final String code; From 702b7c0d1141d56ab83d3a040507d74940a03cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=9E=AC=EB=AF=BC?= Date: Wed, 8 Feb 2023 10:30:16 +0900 Subject: [PATCH 15/15] =?UTF-8?q?Fix:=20filter=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=EA=B0=92=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/JwtAuthenticationFilter.java | 31 +++++++++---------- .../auth/exception/TokenException.java | 10 ++++++ .../com/dku/springstudy/error/ErrorCode.java | 3 +- 3 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/auth/exception/TokenException.java diff --git a/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java b/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java index b155ddc..508d6df 100644 --- a/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java +++ b/src/main/java/com/dku/springstudy/auth/JwtAuthenticationFilter.java @@ -1,12 +1,13 @@ package com.dku.springstudy.auth; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.SignatureException; +import com.dku.springstudy.auth.exception.TokenException; +import com.dku.springstudy.error.ErrorResponse; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; @@ -35,18 +36,16 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse Authentication authentication = jwtProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } - } catch (ExpiredJwtException err) { - logger.error("token is expired and not valid anymore", err); - throw new JwtException("토큰 기한이 만료되었습니다."); - } catch (IllegalArgumentException err) { - logger.error("an error occurred during getting email from token", err); - throw new JwtException("유효하지 않은 토큰정보 입니다."); - } catch (SignatureException err) { - logger.error("Authentication Failed. Username or Password not valid", err); - throw new JwtException("사용자 인증에 실패하였습니다."); - } catch (BadCredentialsException err) { - logger.error("Incorrect email or password."); - throw new BadCredentialsException("이메일 또는 비밀번호를 다시 확인해주세요."); + } catch (TokenException e) { + HttpServletResponse errorResponse = (HttpServletResponse) response; + errorResponse.setStatus(e.getErrorCode().getHttpStatus()); + errorResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); + ResponseEntity exceptionDto = ResponseEntity.status(e.getErrorCode().getHttpStatus()).body(ErrorResponse.from(e.getErrorCode())); + + ObjectMapper objectMapper = new ObjectMapper(); + String exceptionMessage = objectMapper.writeValueAsString(exceptionDto); + + errorResponse.getWriter().write(exceptionMessage); } chain.doFilter(request, response); } diff --git a/src/main/java/com/dku/springstudy/auth/exception/TokenException.java b/src/main/java/com/dku/springstudy/auth/exception/TokenException.java new file mode 100644 index 0000000..46281a3 --- /dev/null +++ b/src/main/java/com/dku/springstudy/auth/exception/TokenException.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.auth.exception; + +import com.dku.springstudy.error.ApplicationException; +import com.dku.springstudy.error.ErrorCode; + +public class TokenException extends ApplicationException { + public TokenException(ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/com/dku/springstudy/error/ErrorCode.java b/src/main/java/com/dku/springstudy/error/ErrorCode.java index 5ff916c..f7dd428 100644 --- a/src/main/java/com/dku/springstudy/error/ErrorCode.java +++ b/src/main/java/com/dku/springstudy/error/ErrorCode.java @@ -7,7 +7,8 @@ @Getter public enum ErrorCode { ALREADY_EXIST(400, "G001", "이미 존재합니다"), - NOT_EXIST(400, "G002", "존재하지 않습니다"); + NOT_EXIST(400, "G002", "존재하지 않습니다"), + TOKEN_VALIDATE_FAILED(400, "A001", "인증 토큰이 잘못되었습니다"); private final int httpStatus; private final String code;