From 7d982063037b487abdf6fd114406950929a44e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 21 Jan 2023 20:58:52 +0900 Subject: [PATCH 01/44] Create README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb7e1c1 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Spring-JPA-study +D-Coding 백엔드 스터디 + +1주차 과제 제출(23-01-21) From 810b9460ac37e5932ec877e8a5fe460a65cbbea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 21 Jan 2023 21:01:15 +0900 Subject: [PATCH 02/44] Create submission --- submission | 1 + 1 file changed, 1 insertion(+) create mode 100644 submission diff --git a/submission b/submission new file mode 100644 index 0000000..8695b2c --- /dev/null +++ b/submission @@ -0,0 +1 @@ +23-01-21 과제제출 From 0d6316fa2340bfe0132499a84447e82be48c8fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 21 Jan 2023 21:02:08 +0900 Subject: [PATCH 03/44] Delete submission --- submission | 1 - 1 file changed, 1 deletion(-) delete mode 100644 submission diff --git a/submission b/submission deleted file mode 100644 index 8695b2c..0000000 --- a/submission +++ /dev/null @@ -1 +0,0 @@ -23-01-21 과제제출 From 9d9d768cb557af21f0f4bc764b1213d44e6e7bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Thu, 26 Jan 2023 20:07:33 +0900 Subject: [PATCH 04/44] Update README.md --- README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eb7e1c1..1f3a19c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,25 @@ # Spring-JPA-study D-Coding 백엔드 스터디 -1주차 과제 제출(23-01-21) +## 1주차 과제 제출(23-01-21) +스프링 입문 강의 정리 + +## 2~4주차 과제 +- 간단한 ‘당근마켓’ 벡엔드 구현해보기 +### 요구 사항 + +- 회원가입/로그인 기능 +- 상품등록 기능 +- 상품페이지 기능 +- 마이 페이지(나의 당근 페이지) 기능 + +### 제한 사항 + +- Spring 또는 Spring Boot Framework를 사용해야합니다. +- JPA를 사용해야합니다. (Spring data jpa 활용 가능) +- 인증/인가 방식은 JWT & Spring Security 를 활용해야합니다. + +### 2주차 + +- 요구사항대로 당근마켓 ERD 그려보기 +- 요구사항 API 구현 (가능한 만큼) From 6dd36f30e5c4633941e90f68819ca9c3bc0d855d Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sat, 28 Jan 2023 10:01:57 +0900 Subject: [PATCH 05/44] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=94=84=EB=A7=81?= =?UTF-8?q?=EB=B6=80=ED=8A=B8,=20=EC=9E=90=EB=B0=94=20=EB=B2=84=EC=A0=84?= =?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 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 15b77ef..9fa1e35 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.8' id 'io.spring.dependency-management' version '1.1.0' } group = 'com.dku' version = '0.0.1-SNAPSHOT' -sourceCompatibility = '17' +sourceCompatibility = '11' configurations { compileOnly { From 919d5d3152588a740909d980dafbd77c6c98cbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sat, 28 Jan 2023 12:27:51 +0900 Subject: [PATCH 06/44] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1f3a19c..29c13e0 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,6 @@ D-Coding 백엔드 스터디 - 요구사항대로 당근마켓 ERD 그려보기 - 요구사항 API 구현 (가능한 만큼) + +![dcoding-erd](https://user-images.githubusercontent.com/85729858/215239770-a2ac0b3a-cd5b-443d-b7a3-d026ce9ae5c5.png) + From a1a16c37b6e5aee35ab99f81bb860dad566a980f Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:28:23 +0900 Subject: [PATCH 07/44] =?UTF-8?q?refactor:=20yml=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/resources/{application.properties => application.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{application.properties => application.yml} (100%) diff --git a/src/main/resources/application.properties b/src/main/resources/application.yml similarity index 100% rename from src/main/resources/application.properties rename to src/main/resources/application.yml From 73f98e95d67f47ef676d8f4c898027114307d9e7 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:05:58 +0900 Subject: [PATCH 08/44] =?UTF-8?q?feat:=20jwt=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 --- build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.gradle b/build.gradle index 9fa1e35..db355ca 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,13 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + runtimeOnly 'com.h2database:h2' + //implementation 'com.auth0:java-jwt:3.18.2' + // jwt + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' } tasks.named('test') { From d8c32ae2964fcfa3ea7eff411ead10f9c348cd1a Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:06:57 +0900 Subject: [PATCH 09/44] =?UTF-8?q?feat:=20DB,=20jpa,=20jwt=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8b13789..c822a97 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1 +1,20 @@ +spring: + datasource: + url: jdbc:h2:tcp://localhost/~/test + username: sa + password: + driver-class-name: org.h2.Driver + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + #show_sql: true + format_sql: true +logging.level: + org.hibernate.SQL: debug + org.hibernate.type: trace + +jwt: + secret: VlwEyVBsYt9V7zq57TejMnVUyzblYcfPQye08f7MGVA9XkHa From dedd7215c7491808e826edb1c765f15ec823a741 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:08:06 +0900 Subject: [PATCH 10/44] =?UTF-8?q?feat:=20erd=EB=B0=94=ED=83=95=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/category/Category.java | 20 ++++++++++ .../com/dku/springstudy/domain/like/like.java | 4 ++ .../springstudy/domain/product/Product.java | 33 +++++++++++++++++ .../com/dku/springstudy/domain/user/Role.java | 5 +++ .../com/dku/springstudy/domain/user/User.java | 37 +++++++++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/category/Category.java create mode 100644 src/main/java/com/dku/springstudy/domain/like/like.java create mode 100644 src/main/java/com/dku/springstudy/domain/product/Product.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/Role.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/User.java diff --git a/src/main/java/com/dku/springstudy/domain/category/Category.java b/src/main/java/com/dku/springstudy/domain/category/Category.java new file mode 100644 index 0000000..d976b4d --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/category/Category.java @@ -0,0 +1,20 @@ +package com.dku.springstudy.domain.category; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Category { + @Id + @GeneratedValue + private Long id; + + private String categoryName; +} diff --git a/src/main/java/com/dku/springstudy/domain/like/like.java b/src/main/java/com/dku/springstudy/domain/like/like.java new file mode 100644 index 0000000..47f557b --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/like/like.java @@ -0,0 +1,4 @@ +package com.dku.springstudy.domain.like; + +public class like { +} diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java new file mode 100644 index 0000000..e6466a6 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -0,0 +1,33 @@ +package com.dku.springstudy.domain.product; + +import com.dku.springstudy.domain.category.Category; +import com.dku.springstudy.domain.user.User; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Product { + @Id + @GeneratedValue + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private Category category; + + private String productName; + private String productImgUrl; + private Integer cost; + private String contents; + + +} diff --git a/src/main/java/com/dku/springstudy/domain/user/Role.java b/src/main/java/com/dku/springstudy/domain/user/Role.java new file mode 100644 index 0000000..9f20574 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/Role.java @@ -0,0 +1,5 @@ +package com.dku.springstudy.domain.user; + +public enum Role { + ROLE_USER, ROLE_ADMIN +} diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java new file mode 100644 index 0000000..dd4ce3f --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -0,0 +1,37 @@ +package com.dku.springstudy.domain.user; + +import com.dku.springstudy.domain.product.Product; +import lombok.*; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class User { + + @Id + @GeneratedValue + private Long id; + + @OneToMany(mappedBy = "user") + private List products = new ArrayList<>(); + + private String email; + private String password; + private String username; + private String phoneNumber; + private String nickname; + private String profileImgUrl; + + @Enumerated(EnumType.STRING) + private Role role; + + @Builder + public User(String email, String password) { + this.email = email; + this.password = password; + } +} From c6d6bdafef721a6a17b51df1633ab11802872823 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:10:41 +0900 Subject: [PATCH 11/44] =?UTF-8?q?feat:=20jwt=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/config/SecurityConfig.java | 44 +++++++ .../springstudy/domain/user/SecurityUser.java | 76 ++++++++++++ .../user/controller/UserController.java | 26 +++++ .../domain/user/dto/LoginRequestDto.java | 9 ++ .../repository/SecurityUserRepository.java | 12 ++ .../service/CustomUserDetailsService.java | 41 +++++++ .../user/service/SecurityUserService.java | 34 ++++++ .../jwt/JwtAuthenticationFilter.java | 42 +++++++ .../dku/springstudy/jwt/JwtTokenProvider.java | 110 ++++++++++++++++++ .../com/dku/springstudy/jwt/TokenDto.java | 15 +++ 10 files changed, 409 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/config/SecurityConfig.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/SecurityUser.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/controller/UserController.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java create mode 100644 src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java create mode 100644 src/main/java/com/dku/springstudy/jwt/TokenDto.java diff --git a/src/main/java/com/dku/springstudy/config/SecurityConfig.java b/src/main/java/com/dku/springstudy/config/SecurityConfig.java new file mode 100644 index 0000000..5614060 --- /dev/null +++ b/src/main/java/com/dku/springstudy/config/SecurityConfig.java @@ -0,0 +1,44 @@ +package com.dku.springstudy.config; + +import com.dku.springstudy.jwt.JwtAuthenticationFilter; +import com.dku.springstudy.jwt.JwtTokenProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; + +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + private final JwtTokenProvider jwtTokenProvider; + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .httpBasic().disable() + .csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/api/v1/**").permitAll() + //.antMatchers("/api/v1/").hasRole("USER") + .anyRequest().authenticated() + .and() + .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java b/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java new file mode 100644 index 0000000..6f73b77 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java @@ -0,0 +1,76 @@ +package com.dku.springstudy.domain.user; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class SecurityUser implements UserDetails { + + @Id + @Column(updatable = false, unique = true, nullable = false) + private String email; + @Column(nullable = false) + private String password; + + @ElementCollection(fetch = FetchType.EAGER) + @Builder.Default + private List roles = new ArrayList<>(); + +/* public SecurityUser(User user) { + id = user.getId(); + email = user.getEmail(); + password = user.getPassword(); + }*/ + + @Override + public Collection getAuthorities() { + return this.roles.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + @Override + public String getUsername() { + return email; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java new file mode 100644 index 0000000..e1ab6ca --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java @@ -0,0 +1,26 @@ +package com.dku.springstudy.domain.user.controller; + + +import com.dku.springstudy.domain.user.dto.LoginRequestDto; +import com.dku.springstudy.domain.user.service.SecurityUserService; +import com.dku.springstudy.jwt.TokenDto; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class UserController { + private final SecurityUserService securityUserService; + + @PostMapping("/login") + public TokenDto login(@RequestBody LoginRequestDto loginRequestDto) { + String email = loginRequestDto.getEmail(); + String password = loginRequestDto.getPassword(); + TokenDto tokenDto = securityUserService.login(email, password); + return tokenDto; + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java b/src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java new file mode 100644 index 0000000..2a5b8ec --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/dto/LoginRequestDto.java @@ -0,0 +1,9 @@ +package com.dku.springstudy.domain.user.dto; + +import lombok.Data; + +@Data +public class LoginRequestDto { + private String email; + private String password; +} diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java new file mode 100644 index 0000000..d5b6fd3 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java @@ -0,0 +1,12 @@ +package com.dku.springstudy.domain.user.repository; + +import com.dku.springstudy.domain.user.SecurityUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface SecurityUserRepository extends JpaRepository { + Optional findByEmail(String email); +} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java new file mode 100644 index 0000000..b3cc67f --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java @@ -0,0 +1,41 @@ +package com.dku.springstudy.domain.user.service; + +import com.dku.springstudy.domain.user.SecurityUser; +import com.dku.springstudy.domain.user.repository.SecurityUserRepository; +import com.dku.springstudy.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CustomUserDetailsService implements UserDetailsService { + private final SecurityUserRepository securityUserRepository; + private final PasswordEncoder passwordEncoder; + + /*@Override + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + User user = userRepository.findByEmail(email) + .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); + return new SecurityUser(user); + }*/ + + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + return securityUserRepository.findByEmail(email) + .map(this::createUserDetails) + .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); + } + + // 해당하는 User 의 데이터가 존재한다면 UserDetails 객체로 만들어서 리턴 + private UserDetails createUserDetails(SecurityUser securityUser) { + return User.builder() + .username(securityUser.getUsername()) + .password(passwordEncoder.encode(securityUser.getPassword())) + .roles(securityUser.getRoles().toArray(new String[0])) + .build(); + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java b/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java new file mode 100644 index 0000000..7fdef30 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java @@ -0,0 +1,34 @@ +package com.dku.springstudy.domain.user.service; + +import com.dku.springstudy.jwt.JwtTokenProvider; +import com.dku.springstudy.jwt.TokenDto; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class SecurityUserService { + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final JwtTokenProvider jwtTokenProvider; + + @Transactional + public TokenDto login(String email, String password) { + // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 + // 이때 authentication 는 인증 여부를 확인하는 authenticated 값이 false + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); + + // 2. 실제 검증 (사용자 비밀번호 체크)이 이루어지는 부분 + // authenticate 매서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드가 실행 + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + + // 3. 인증 정보를 기반으로 JWT 토큰 생성 + TokenDto tokenDto = jwtTokenProvider.generateToken(authentication); + + return tokenDto; + } +} diff --git a/src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java b/src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java new file mode 100644 index 0000000..9942825 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/JwtAuthenticationFilter.java @@ -0,0 +1,42 @@ +package com.dku.springstudy.jwt; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends GenericFilterBean { + private final JwtTokenProvider jwtTokenProvider; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + // 1. Request Header 에서 JWT 토큰 추출 + String token = resolveToken((HttpServletRequest) request); + + // 2. validateToken 으로 토큰 유효성 검사 + if (token != null && jwtTokenProvider.validateToken(token)) { + // 토큰이 유효할 경우 토큰에서 Authentication 객체를 가지고 와서 SecurityContext 에 저장 + Authentication authentication = jwtTokenProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + chain.doFilter(request, response); + } + // Request Header 에서 토큰 정보 추출 + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java b/src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java new file mode 100644 index 0000000..16f4a44 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/JwtTokenProvider.java @@ -0,0 +1,110 @@ +package com.dku.springstudy.jwt; + + +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + + +@Slf4j +@Component +public class JwtTokenProvider { + + private final Key key; + + public JwtTokenProvider(@Value("${jwt.secret}") String secretKey) { + byte[] keyBytes = Decoders.BASE64.decode(secretKey); + this.key = Keys.hmacShaKeyFor(keyBytes); + } + + public TokenDto generateToken(Authentication authentication) { + // 권한 가져오기 + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + // Access Token 생성 + Date accessTokenExpiresIn = new Date(now + 86400000); + String accessToken = Jwts.builder() + .setSubject(authentication.getName()) + .claim("auth", authorities) + .setExpiration(accessTokenExpiresIn) + .signWith(key, SignatureAlgorithm.HS256) + .compact(); + + // Refresh Token 생성 + //1일: 24 * 60 * 60 * 1000 = 86400000 + String refreshToken = Jwts.builder() + .setExpiration(new Date(now + 86400000)) + .signWith(key, SignatureAlgorithm.HS256) + .compact(); + + return TokenDto.builder() + .grantType("Bearer") + .accessToken(accessToken) + .refreshToken(refreshToken) + .build(); + } + + // JWT 토큰을 복호화하여 토큰에 들어있는 정보를 꺼내는 메서드 + public Authentication getAuthentication(String accessToken) { + // 토큰 복호화 + Claims claims = parseClaims(accessToken); + + if (claims.get("auth") == null) { + throw new RuntimeException("권한 정보가 없는 토큰입니다."); + } + + // 클레임에서 권한 정보 가져오기 + Collection authorities = + Arrays.stream(claims.get("auth").toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + // UserDetails 객체를 만들어서 Authentication 리턴 + UserDetails principal = new User(claims.getSubject(), "", authorities); + return new UsernamePasswordAuthenticationToken(principal, "", authorities); + } + + // 토큰 정보를 검증하는 메서드 + public boolean validateToken(String token) { + try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + log.info("Invalid JWT Token", e); + } catch (ExpiredJwtException e) { + log.info("Expired JWT Token", e); + } catch (UnsupportedJwtException e) { + log.info("Unsupported JWT Token", e); + } catch (IllegalArgumentException e) { + log.info("JWT claims string is empty.", e); + } + return false; + } + + private Claims parseClaims(String accessToken) { + try { + return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(accessToken).getBody(); + } catch (ExpiredJwtException e) { + return e.getClaims(); + } + } +} diff --git a/src/main/java/com/dku/springstudy/jwt/TokenDto.java b/src/main/java/com/dku/springstudy/jwt/TokenDto.java new file mode 100644 index 0000000..0737d70 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/TokenDto.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.jwt; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +@AllArgsConstructor +public class TokenDto { + //grantType은 JWT 대한 인증 타입 + private String grantType; + private String accessToken; + private String refreshToken; +} From fa545ff70e40ed085845c934a9e207befb806f41 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:12:07 +0900 Subject: [PATCH 12/44] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=84=9C=EB=B9=84=EC=8A=A4,=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/repository/UserRepository.java | 10 ++++++ .../domain/user/service/UserService.java | 36 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/service/UserService.java diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java new file mode 100644 index 0000000..0e3e396 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.domain.user.repository; + +import com.dku.springstudy.domain.user.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + +} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java new file mode 100644 index 0000000..fc84aab --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java @@ -0,0 +1,36 @@ +package com.dku.springstudy.domain.user.service; + +import com.dku.springstudy.domain.exception.UsernameAlreadyExistException; +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.dto.UserRequestDTO; +import com.dku.springstudy.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserService { +/* private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public void create(UserRequestDTO userRequestDTO) throws IllegalArgumentException, UsernameAlreadyExistException { + validate(userRequestDTO); + User user = userRequestDTO.toEntity(); + user.(passwordEncoder.encode(user.getPassword())); + + userRepository.save(user); + } + + private void validate(UserRequestDTO userDTO) throws IllegalArgumentException, UsernameAlreadyExistException { + if (userDTO.getUsername().isBlank() || userDTO.getPassword().isBlank()) { + throw new IllegalArgumentException(); + } + if (userRepository.findByUsername(userDTO.getUsername()).isPresent()) { + throw new UsernameAlreadyExistException(); + } + }*/ +} From 82138942ce02f43131a4a03eeb980186fd143400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Wed, 1 Feb 2023 23:34:12 +0900 Subject: [PATCH 13/44] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 29c13e0..82b574c 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,8 @@ D-Coding 백엔드 스터디 ![dcoding-erd](https://user-images.githubusercontent.com/85729858/215239770-a2ac0b3a-cd5b-443d-b7a3-d026ce9ae5c5.png) + +### 3주차 + +- 피드백 반영하여 카테고리를 enum으로 처리하도록 하고, createdDate와 updatedDate추가 +![image](https://user-images.githubusercontent.com/85729858/216071539-42dc3af6-452e-464f-9a68-c52364c5fc3f.png) From 9de73e4f11287989a5e0f41d74cd6331529fd98b Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 21:57:56 +0900 Subject: [PATCH 14/44] =?UTF-8?q?feat:=20=EC=83=9D=EC=84=B1=EC=8B=9C?= =?UTF-8?q?=EA=B0=84,=20=EC=88=98=EC=A0=95=EC=8B=9C=EA=B0=84=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20=EC=9C=84=ED=95=9C=20BaseTimeEntity=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/BaseTimeEntity.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java diff --git a/src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java b/src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java new file mode 100644 index 0000000..673b74c --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/BaseTimeEntity.java @@ -0,0 +1,23 @@ +package com.dku.springstudy.domain; + +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; + +@EntityListeners(AuditingEntityListener.class) +@MappedSuperclass +@Getter +public class BaseTimeEntity { + @CreatedDate + @Column(updatable = false) + private LocalDateTime createdDate; + + @LastModifiedDate + private LocalDateTime lastModifiedDate; +} From be9261ac6b43934f982c588168e6a55d20bc2023 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 21:59:23 +0900 Subject: [PATCH 15/44] =?UTF-8?q?refactor:=20validation=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=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 --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index db355ca..ee53417 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,8 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + + implementation 'org.springframework.boot:spring-boot-starter-validation' } tasks.named('test') { From 9f19d077538b5712f208c6c2a9f9bd4a9d3ddd5e Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:00:06 +0900 Subject: [PATCH 16/44] =?UTF-8?q?refactor:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20enum=EC=9C=BC=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 --- .../springstudy/domain/category/Category.java | 20 ----------- .../springstudy/domain/product/Category.java | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/com/dku/springstudy/domain/category/Category.java create mode 100644 src/main/java/com/dku/springstudy/domain/product/Category.java diff --git a/src/main/java/com/dku/springstudy/domain/category/Category.java b/src/main/java/com/dku/springstudy/domain/category/Category.java deleted file mode 100644 index d976b4d..0000000 --- a/src/main/java/com/dku/springstudy/domain/category/Category.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.dku.springstudy.domain.category; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Category { - @Id - @GeneratedValue - private Long id; - - private String categoryName; -} diff --git a/src/main/java/com/dku/springstudy/domain/product/Category.java b/src/main/java/com/dku/springstudy/domain/product/Category.java new file mode 100644 index 0000000..7d1abcd --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/Category.java @@ -0,0 +1,36 @@ +package com.dku.springstudy.domain.product; + +import lombok.Getter; + +@Getter +public enum Category { + /* + ‘디지털기기’, ‘생활가전’, ‘가구/인테리어’, ‘유아동’, ‘생활/가공식품’, + ‘유아도서’, ‘스포츠/레저’, ‘여성잡화’, ‘여성의류’, ‘남성패션/잡화’, + ‘게임/취미’, ‘뷰티/미용’, ‘반려동물용품’, ‘도서/티켓/음반’, ‘식물’, + ‘기타 중고물품’, ‘중고차’ + */ + DIGITAL_DEVICE("디지털기기"), + HOME_ELECTRONIC("생활가전"), + FURNITURE_INTERIOR("가구/인테리어"), + CHILD("유아동"), + LIVING_PROCESSED_FOODS("생활/가공식품"), + CHILD_BOOK("유아도서"), + SPORTS_LEISURE("스포츠/레저"), + WOMAN_GOODS("여성잡화"), + WOMAN_CLOTHES("여성의류"), + MAN_FASHION_GOODS("남성패션/잡화"), + GAME_HOBBY("게임/취미"), + BEAUTY("뷰티/미용"), + PET_GOODS("반려동물용품"), + BOOK_TICKET_RECORD("도서/티켓/음반"), + PLANT("식물"), + USED_ETC("기타 중고물품"), + USED_CAR("중고차"); + + private final String korCategory; + + Category(String korCategory) { + this.korCategory = korCategory; + } +} From a2365fc8cce0ed9b255693bc2e9a69bd01faae10 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:01:09 +0900 Subject: [PATCH 17/44] =?UTF-8?q?refactor:=20role=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=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/domain/user/Role.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/dku/springstudy/domain/user/Role.java b/src/main/java/com/dku/springstudy/domain/user/Role.java index 9f20574..a7c98a7 100644 --- a/src/main/java/com/dku/springstudy/domain/user/Role.java +++ b/src/main/java/com/dku/springstudy/domain/user/Role.java @@ -1,5 +1,5 @@ package com.dku.springstudy.domain.user; public enum Role { - ROLE_USER, ROLE_ADMIN + USER, ADMIN } From f23049c44f7e46d4e02efb755841c1e57efc4443 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:06:23 +0900 Subject: [PATCH 18/44] =?UTF-8?q?refactor:=20login=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81,=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/SpringStudyApplication.java | 2 + .../springstudy/config/SecurityConfig.java | 4 +- .../springstudy/domain/user/SecurityUser.java | 76 ------------------- .../com/dku/springstudy/domain/user/User.java | 10 ++- .../user/controller/UserController.java | 21 +++-- .../domain/user/dto/SignUpRequestDTO.java | 31 ++++++++ .../repository/SecurityUserRepository.java | 12 --- .../user/repository/UserRepository.java | 6 +- .../service/CustomUserDetailsService.java | 28 ++----- .../user/service/SecurityUserService.java | 34 --------- .../domain/user/service/UserService.java | 48 +++++++----- .../springstudy/jwt/SecurityUserDetails.java | 62 +++++++++++++++ 12 files changed, 162 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/com/dku/springstudy/domain/user/SecurityUser.java create mode 100644 src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java delete mode 100644 src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java delete mode 100644 src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java create mode 100644 src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java diff --git a/src/main/java/com/dku/springstudy/SpringStudyApplication.java b/src/main/java/com/dku/springstudy/SpringStudyApplication.java index ef164c9..1bef475 100644 --- a/src/main/java/com/dku/springstudy/SpringStudyApplication.java +++ b/src/main/java/com/dku/springstudy/SpringStudyApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class SpringStudyApplication { diff --git a/src/main/java/com/dku/springstudy/config/SecurityConfig.java b/src/main/java/com/dku/springstudy/config/SecurityConfig.java index 5614060..65e9db0 100644 --- a/src/main/java/com/dku/springstudy/config/SecurityConfig.java +++ b/src/main/java/com/dku/springstudy/config/SecurityConfig.java @@ -25,13 +25,15 @@ public class SecurityConfig { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .httpBasic().disable() + .formLogin().disable() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/v1/**").permitAll() //.antMatchers("/api/v1/").hasRole("USER") - .anyRequest().authenticated() + //.anyRequest().authenticated() + .anyRequest().permitAll() .and() .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); return http.build(); diff --git a/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java b/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java deleted file mode 100644 index 6f73b77..0000000 --- a/src/main/java/com/dku/springstudy/domain/user/SecurityUser.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.dku.springstudy.domain.user; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import javax.persistence.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Entity -public class SecurityUser implements UserDetails { - - @Id - @Column(updatable = false, unique = true, nullable = false) - private String email; - @Column(nullable = false) - private String password; - - @ElementCollection(fetch = FetchType.EAGER) - @Builder.Default - private List roles = new ArrayList<>(); - -/* public SecurityUser(User user) { - id = user.getId(); - email = user.getEmail(); - password = user.getPassword(); - }*/ - - @Override - public Collection getAuthorities() { - return this.roles.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - } - - @Override - public String getUsername() { - return email; - } - - @Override - public String getPassword() { - return password; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } -} diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java index dd4ce3f..0869383 100644 --- a/src/main/java/com/dku/springstudy/domain/user/User.java +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -1,5 +1,6 @@ package com.dku.springstudy.domain.user; +import com.dku.springstudy.domain.BaseTimeEntity; import com.dku.springstudy.domain.product.Product; import lombok.*; @@ -10,7 +11,7 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class User { +public class User extends BaseTimeEntity { @Id @GeneratedValue @@ -30,8 +31,13 @@ public class User { private Role role; @Builder - public User(String email, String password) { + public User(String email, String password, String username, String phoneNumber, String nickname, String profileImgUrl) { this.email = email; this.password = password; + this.username = username; + this.phoneNumber = phoneNumber; + this.nickname = nickname; + this.profileImgUrl = profileImgUrl; + this.role = Role.USER; } } diff --git a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java index e1ab6ca..538898a 100644 --- a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java +++ b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java @@ -2,25 +2,36 @@ import com.dku.springstudy.domain.user.dto.LoginRequestDto; -import com.dku.springstudy.domain.user.service.SecurityUserService; +import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; +import com.dku.springstudy.domain.user.service.UserService; import com.dku.springstudy.jwt.TokenDto; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; + @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") public class UserController { - private final SecurityUserService securityUserService; + private final UserService userService; + + @PostMapping("/signup") + public ResponseEntity signUp(@Valid @RequestBody SignUpRequestDTO requestDTO){ + userService.signUp(requestDTO); + + return ResponseEntity.status(HttpStatus.CREATED).body(null); + } @PostMapping("/login") - public TokenDto login(@RequestBody LoginRequestDto loginRequestDto) { + public TokenDto login(@Valid @RequestBody LoginRequestDto loginRequestDto) { String email = loginRequestDto.getEmail(); String password = loginRequestDto.getPassword(); - TokenDto tokenDto = securityUserService.login(email, password); - return tokenDto; + return userService.login(email, password); } } diff --git a/src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java b/src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java new file mode 100644 index 0000000..78c44ba --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/dto/SignUpRequestDTO.java @@ -0,0 +1,31 @@ +package com.dku.springstudy.domain.user.dto; + +import com.dku.springstudy.domain.user.User; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +@Data +@NoArgsConstructor +public class SignUpRequestDTO { + @NonNull + private String email; + @NonNull + private String password; + @NonNull + private String username; + @NonNull + private String phoneNumber; + @NonNull + private String nickname; + + public User toEntity() { + return User.builder() + .email(email) + .password(password) + .username(username) + .phoneNumber(phoneNumber) + .nickname(nickname) + .build(); + } +} diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java deleted file mode 100644 index d5b6fd3..0000000 --- a/src/main/java/com/dku/springstudy/domain/user/repository/SecurityUserRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.dku.springstudy.domain.user.repository; - -import com.dku.springstudy.domain.user.SecurityUser; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface SecurityUserRepository extends JpaRepository { - Optional findByEmail(String email); -} diff --git a/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java index 0e3e396..304784f 100644 --- a/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java +++ b/src/main/java/com/dku/springstudy/domain/user/repository/UserRepository.java @@ -2,9 +2,9 @@ import com.dku.springstudy.domain.user.User; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -@Repository -public interface UserRepository extends JpaRepository { +import java.util.Optional; +public interface UserRepository extends JpaRepository { + Optional findByEmail(String email); } diff --git a/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java index b3cc67f..6cb7d4a 100644 --- a/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java +++ b/src/main/java/com/dku/springstudy/domain/user/service/CustomUserDetailsService.java @@ -1,41 +1,25 @@ package com.dku.springstudy.domain.user.service; -import com.dku.springstudy.domain.user.SecurityUser; -import com.dku.springstudy.domain.user.repository.SecurityUserRepository; +import com.dku.springstudy.jwt.SecurityUserDetails; +import com.dku.springstudy.domain.user.User; + import com.dku.springstudy.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class CustomUserDetailsService implements UserDetailsService { - private final SecurityUserRepository securityUserRepository; - private final PasswordEncoder passwordEncoder; + private final UserRepository userRepository; - /*@Override + @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email) .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); - return new SecurityUser(user); - }*/ - - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - return securityUserRepository.findByEmail(email) - .map(this::createUserDetails) - .orElseThrow(() -> new UsernameNotFoundException("해당하는 유저를 찾을 수 없습니다.")); + return new SecurityUserDetails(user); } - // 해당하는 User 의 데이터가 존재한다면 UserDetails 객체로 만들어서 리턴 - private UserDetails createUserDetails(SecurityUser securityUser) { - return User.builder() - .username(securityUser.getUsername()) - .password(passwordEncoder.encode(securityUser.getPassword())) - .roles(securityUser.getRoles().toArray(new String[0])) - .build(); - } } diff --git a/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java b/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java deleted file mode 100644 index 7fdef30..0000000 --- a/src/main/java/com/dku/springstudy/domain/user/service/SecurityUserService.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.dku.springstudy.domain.user.service; - -import com.dku.springstudy.jwt.JwtTokenProvider; -import com.dku.springstudy.jwt.TokenDto; -import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class SecurityUserService { - private final AuthenticationManagerBuilder authenticationManagerBuilder; - private final JwtTokenProvider jwtTokenProvider; - - @Transactional - public TokenDto login(String email, String password) { - // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 - // 이때 authentication 는 인증 여부를 확인하는 authenticated 값이 false - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); - - // 2. 실제 검증 (사용자 비밀번호 체크)이 이루어지는 부분 - // authenticate 매서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드가 실행 - Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - - // 3. 인증 정보를 기반으로 JWT 토큰 생성 - TokenDto tokenDto = jwtTokenProvider.generateToken(authentication); - - return tokenDto; - } -} diff --git a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java index fc84aab..e356a85 100644 --- a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java +++ b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java @@ -1,36 +1,50 @@ package com.dku.springstudy.domain.user.service; -import com.dku.springstudy.domain.exception.UsernameAlreadyExistException; import com.dku.springstudy.domain.user.User; -import com.dku.springstudy.domain.user.dto.UserRequestDTO; +import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; import com.dku.springstudy.domain.user.repository.UserRepository; +import com.dku.springstudy.jwt.JwtTokenProvider; +import com.dku.springstudy.jwt.TokenDto; import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.validation.Valid; @Service -@RequiredArgsConstructor @Transactional(readOnly = true) +@RequiredArgsConstructor public class UserService { -/* private final UserRepository userRepository; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final JwtTokenProvider jwtTokenProvider; + private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; + @Transactional + public TokenDto login(String email, String password) { + // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 + // 이때 authentication 는 인증 여부를 확인하는 authenticated 값이 false + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); - public void create(UserRequestDTO userRequestDTO) throws IllegalArgumentException, UsernameAlreadyExistException { - validate(userRequestDTO); - User user = userRequestDTO.toEntity(); - user.(passwordEncoder.encode(user.getPassword())); + // 2. 실제 검증 (사용자 비밀번호 체크)이 이루어지는 부분 + // authenticate 매서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드가 실행 + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - userRepository.save(user); + // 3. 인증 정보를 기반으로 JWT 토큰 생성 + + return jwtTokenProvider.generateToken(authentication); } - private void validate(UserRequestDTO userDTO) throws IllegalArgumentException, UsernameAlreadyExistException { - if (userDTO.getUsername().isBlank() || userDTO.getPassword().isBlank()) { - throw new IllegalArgumentException(); - } - if (userRepository.findByUsername(userDTO.getUsername()).isPresent()) { - throw new UsernameAlreadyExistException(); - } - }*/ + @Transactional + public Long signUp(@Valid SignUpRequestDTO requestDTO){ + String bcryptPassword = passwordEncoder.encode(requestDTO.getPassword()); + requestDTO.setPassword(bcryptPassword); + User user = requestDTO.toEntity(); + userRepository.save(user); + + return user.getId(); + } } diff --git a/src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java b/src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java new file mode 100644 index 0000000..6ec4fa7 --- /dev/null +++ b/src/main/java/com/dku/springstudy/jwt/SecurityUserDetails.java @@ -0,0 +1,62 @@ +package com.dku.springstudy.jwt; + + +import com.dku.springstudy.domain.user.User; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.ArrayList; +import java.util.Collection; + + +public class SecurityUserDetails implements UserDetails { + private User user; + + public SecurityUserDetails(User user) { + this.user = user; + } + + public User getUser() { + return user; + } + + @Override + public Collection getAuthorities() { + Collection authorities = new ArrayList<>(); + String roles = user.getRole().toString(); + for (String role : roles.split(",")) { + authorities.add(() -> role); + } + return authorities; + } + + @Override + public String getUsername() { + return user.getEmail(); + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} From af99cdda94a939b8d658146e108df2ad30b330f3 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:07:48 +0900 Subject: [PATCH 19/44] =?UTF-8?q?feat:=20=EC=8B=9C=EA=B0=84=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=B6=94=EA=B0=80,=20=EC=83=81=ED=83=9C,=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dku/springstudy/domain/product/Product.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java index e6466a6..fd9edaa 100644 --- a/src/main/java/com/dku/springstudy/domain/product/Product.java +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -1,6 +1,6 @@ package com.dku.springstudy.domain.product; -import com.dku.springstudy.domain.category.Category; +import com.dku.springstudy.domain.BaseTimeEntity; import com.dku.springstudy.domain.user.User; import lombok.AccessLevel; import lombok.Getter; @@ -11,7 +11,7 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Product { +public class Product extends BaseTimeEntity { @Id @GeneratedValue private Long id; @@ -20,14 +20,16 @@ public class Product { @JoinColumn(name = "user_id") private User user; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "category_id") - private Category category; - private String productName; private String productImgUrl; private Integer cost; private String contents; + @Enumerated(EnumType.STRING) + private ProductStatus status; + + @Enumerated(EnumType.STRING) + private Category category; + } From 98544b9e00108e790fe4746707ce3998a8e83cf7 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:08:15 +0900 Subject: [PATCH 20/44] =?UTF-8?q?feat:=20ProductRepository=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 --- .../domain/product/repository/ProductRepository.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java diff --git a/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java b/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java new file mode 100644 index 0000000..fda69c6 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java @@ -0,0 +1,7 @@ +package com.dku.springstudy.domain.product.repository; + +import com.dku.springstudy.domain.product.Product; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductRepository extends JpaRepository { +} From 9e5c260d49d7c07dc82e985e7ee964c1a15f6a4f Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:08:52 +0900 Subject: [PATCH 21/44] =?UTF-8?q?feat:=20ProductService=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 --- .../domain/product/service/ProductService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/service/ProductService.java diff --git a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java new file mode 100644 index 0000000..decbdb7 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.domain.product.service; + +import com.dku.springstudy.domain.product.repository.ProductRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ProductService { + private final ProductRepository productRepository; +} From 2fd386cab23f190623df920f6199509e292fe08f Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:09:10 +0900 Subject: [PATCH 22/44] =?UTF-8?q?feat:=20ProductStatus=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 --- .../springstudy/domain/product/ProductStatus.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/ProductStatus.java diff --git a/src/main/java/com/dku/springstudy/domain/product/ProductStatus.java b/src/main/java/com/dku/springstudy/domain/product/ProductStatus.java new file mode 100644 index 0000000..81dd814 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/ProductStatus.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.domain.product; + +import lombok.Getter; + +@Getter +public enum ProductStatus { + ON_SALE("판매중"), SOLD_OUT("판매완료"), RESERVED("예약중"); + + private final String korStatus; + + ProductStatus(String korStatus) { + this.korStatus = korStatus; + } + +} From c78c58d880976ac24015e341e744cd8c3392be7b Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:10:26 +0900 Subject: [PATCH 23/44] =?UTF-8?q?feat:=20db=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=EC=9A=A9=20=ED=81=B4=EB=9E=98=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dku/springstudy/testInit.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/testInit.java diff --git a/src/main/java/com/dku/springstudy/testInit.java b/src/main/java/com/dku/springstudy/testInit.java new file mode 100644 index 0000000..1b44c75 --- /dev/null +++ b/src/main/java/com/dku/springstudy/testInit.java @@ -0,0 +1,56 @@ +package com.dku.springstudy; + +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; +import com.dku.springstudy.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import javax.persistence.EntityManager; + +@Component +@RequiredArgsConstructor +public class testInit { + private final InitService initService; + + @PostConstruct + public void init() { + initService.dbInit1(); + + } + + @Component + @Transactional + @RequiredArgsConstructor + static class InitService { + private final UserRepository userRepository; + + private final EntityManager em; + private final PasswordEncoder passwordEncoder; + + public void dbInit1() { + + User user = createUser("qwe", "123", "username", "01012341234", "usernick"); + em.persist(user); + + } + + private User createUser(String email, String password, String username, String phoneNumber, String nickname) { + SignUpRequestDTO requestDTO = new SignUpRequestDTO(); + String bcryptPassword = passwordEncoder.encode(password); + + requestDTO.setEmail(email); + requestDTO.setPassword(bcryptPassword); + requestDTO.setUsername(username); + requestDTO.setPhoneNumber(phoneNumber); + requestDTO.setNickname(nickname); + User user = requestDTO.toEntity(); + + return user; + } + + } +} From ef784f334eb3079304db4b53e0082f9b00c47f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:16:59 +0900 Subject: [PATCH 24/44] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 82b574c..15ac609 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ D-Coding 백엔드 스터디 - 요구사항대로 당근마켓 ERD 그려보기 - 요구사항 API 구현 (가능한 만큼) +- jwt, security 이용하여 로그인, 회원가입 기능 구현 + ![dcoding-erd](https://user-images.githubusercontent.com/85729858/215239770-a2ac0b3a-cd5b-443d-b7a3-d026ce9ae5c5.png) @@ -30,4 +32,9 @@ D-Coding 백엔드 스터디 ### 3주차 - 피드백 반영하여 카테고리를 enum으로 처리하도록 하고, createdDate와 updatedDate추가 +- 로그인 기능 리펙토링 +- 회원가입 기능 추가 +- 상품 관련 엔티티, 레포지토리, 서비스 추가 +- 상태, 카테고리 enum추가 + ![image](https://user-images.githubusercontent.com/85729858/216071539-42dc3af6-452e-464f-9a68-c52364c5fc3f.png) From e142eced10f080b5a7c976d977532de39020efa1 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:42:12 +0900 Subject: [PATCH 25/44] =?UTF-8?q?feat:=20ProductController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java diff --git a/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java b/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java new file mode 100644 index 0000000..ea30d2a --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java @@ -0,0 +1,32 @@ +package com.dku.springstudy.domain.product.controller; + + +import com.dku.springstudy.domain.product.dto.ProductRegisterRequestDTO; +import com.dku.springstudy.domain.product.service.ProductService; +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.service.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/product") +public class ProductController { + private final ProductService productService; + private final UserService userService; + + @PostMapping("/create") + public ResponseEntity create(@Valid @RequestBody ProductRegisterRequestDTO requestDTO, + @AuthenticationPrincipal UserDetails userDetails) { + User findUser = userService.findUser(userDetails.getUsername()); + Long id = productService.save(requestDTO, findUser); + + return ResponseEntity.status(HttpStatus.OK).body(id); + } +} From 0356437155b2eda3fb8948c78f28f7d8bbead3cc Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:44:11 +0900 Subject: [PATCH 26/44] =?UTF-8?q?refactor:=20findUser=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dku/springstudy/domain/user/service/UserService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java index e356a85..48e8c51 100644 --- a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java +++ b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java @@ -9,6 +9,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -47,4 +48,9 @@ public Long signUp(@Valid SignUpRequestDTO requestDTO){ return user.getId(); } + + public User findUser(String email) { + return userRepository.findByEmail(email) + .orElseThrow(() -> new UsernameNotFoundException("No user")); + } } From f934bac5b0aad8ea9147127d9a5d673d05fe0489 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:44:59 +0900 Subject: [PATCH 27/44] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/ProductRegisterRequestDTO.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/dto/ProductRegisterRequestDTO.java diff --git a/src/main/java/com/dku/springstudy/domain/product/dto/ProductRegisterRequestDTO.java b/src/main/java/com/dku/springstudy/domain/product/dto/ProductRegisterRequestDTO.java new file mode 100644 index 0000000..cc9c4d1 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/dto/ProductRegisterRequestDTO.java @@ -0,0 +1,46 @@ +package com.dku.springstudy.domain.product.dto; + +import com.dku.springstudy.domain.product.Category; +import com.dku.springstudy.domain.product.Product; +import com.dku.springstudy.domain.product.ProductStatus; +import com.dku.springstudy.domain.user.User; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +@Data +@NoArgsConstructor +public class ProductRegisterRequestDTO { + @NonNull + private String productName; + @NonNull + private Category category; + @NonNull + private Integer cost; + @NonNull + private String contents; + @NonNull + private String productImgUrl; + + @Builder + public ProductRegisterRequestDTO(String productName, Category category, Integer cost, String contents, String productImgUrl) { + this.productName = productName; + this.category = category; + this.cost = cost; + this.contents = contents; + this.productImgUrl = productImgUrl; + } + + public Product toEntity(User user) { + return Product.builder() + .productName(this.getProductName()) + .category(this.getCategory()) + .cost(this.getCost()) + .contents(this.getContents()) + .productImgUrl(this.getProductImgUrl()) + .productStatus(ProductStatus.ON_SALE) + .user(user) + .build(); + } +} From 048b279bc94b0c40026e9704c27dd277a1e75313 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:45:32 +0900 Subject: [PATCH 28/44] =?UTF-8?q?refactor:=20=EC=83=81=ED=92=88=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/service/ProductService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java index decbdb7..0999e05 100644 --- a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java +++ b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java @@ -1,6 +1,10 @@ package com.dku.springstudy.domain.product.service; +import com.dku.springstudy.domain.product.Product; +import com.dku.springstudy.domain.product.dto.ProductRegisterRequestDTO; import com.dku.springstudy.domain.product.repository.ProductRepository; +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -10,4 +14,13 @@ @RequiredArgsConstructor public class ProductService { private final ProductRepository productRepository; + + @Transactional + public Long save(ProductRegisterRequestDTO requestDTO, User user) { + Product product = requestDTO.toEntity(user); + productRepository.save(product); + + return product.getId(); + } + } From 3e04d6a57b3ca6232958bad34377439eaa4110f2 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:46:02 +0900 Subject: [PATCH 29/44] =?UTF-8?q?refactor:=20builder=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/domain/product/Product.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java index fd9edaa..d3e0714 100644 --- a/src/main/java/com/dku/springstudy/domain/product/Product.java +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -3,6 +3,7 @@ import com.dku.springstudy.domain.BaseTimeEntity; import com.dku.springstudy.domain.user.User; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -31,5 +32,17 @@ public class Product extends BaseTimeEntity { @Enumerated(EnumType.STRING) private Category category; + @Builder + public Product(String productName, Category category, Integer cost, String contents, + String productImgUrl, User user, ProductStatus productStatus) { + this.productName = productName; + this.category = category; + this.cost = cost; + this.contents = contents; + this.productImgUrl = productImgUrl; + this.status = productStatus; + this.user = user; + } + } From a6e26b8d651a92ec472dca7515e260cd3cb6d169 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:52:22 +0900 Subject: [PATCH 30/44] =?UTF-8?q?refactor:=20Like=20=EC=97=B0=EA=B4=80?= =?UTF-8?q?=EA=B4=80=EA=B3=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dku/springstudy/domain/product/Product.java | 6 ++++++ src/main/java/com/dku/springstudy/domain/user/User.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java index d3e0714..f3b7751 100644 --- a/src/main/java/com/dku/springstudy/domain/product/Product.java +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -1,6 +1,7 @@ package com.dku.springstudy.domain.product; import com.dku.springstudy.domain.BaseTimeEntity; +import com.dku.springstudy.domain.like.Like; import com.dku.springstudy.domain.user.User; import lombok.AccessLevel; import lombok.Builder; @@ -8,6 +9,8 @@ import lombok.NoArgsConstructor; import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; @Entity @Getter @@ -32,6 +35,9 @@ public class Product extends BaseTimeEntity { @Enumerated(EnumType.STRING) private Category category; + @OneToMany(mappedBy = "product") + private List likes = new ArrayList<>(); + @Builder public Product(String productName, Category category, Integer cost, String contents, String productImgUrl, User user, ProductStatus productStatus) { diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java index 0869383..8c674e9 100644 --- a/src/main/java/com/dku/springstudy/domain/user/User.java +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -1,6 +1,7 @@ package com.dku.springstudy.domain.user; import com.dku.springstudy.domain.BaseTimeEntity; +import com.dku.springstudy.domain.like.Like; import com.dku.springstudy.domain.product.Product; import lombok.*; @@ -20,6 +21,9 @@ public class User extends BaseTimeEntity { @OneToMany(mappedBy = "user") private List products = new ArrayList<>(); + @OneToMany(mappedBy = "user") + private List likes = new ArrayList<>(); + private String email; private String password; private String username; From 08a0b88dd82544c3218d9e5e141cec6b9738ceea Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 00:30:30 +0900 Subject: [PATCH 31/44] =?UTF-8?q?feat:=20Like=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dku/springstudy/domain/like/Like.java | 27 +++++++++++++++++++ .../com/dku/springstudy/domain/like/like.java | 4 --- 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/domain/like/Like.java delete mode 100644 src/main/java/com/dku/springstudy/domain/like/like.java diff --git a/src/main/java/com/dku/springstudy/domain/like/Like.java b/src/main/java/com/dku/springstudy/domain/like/Like.java new file mode 100644 index 0000000..7f13a4a --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/like/Like.java @@ -0,0 +1,27 @@ +package com.dku.springstudy.domain.like; + +import com.dku.springstudy.domain.BaseTimeEntity; +import com.dku.springstudy.domain.product.Product; +import com.dku.springstudy.domain.user.User; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class Like extends BaseTimeEntity { + @Id @GeneratedValue + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id") + private Product product; + +} diff --git a/src/main/java/com/dku/springstudy/domain/like/like.java b/src/main/java/com/dku/springstudy/domain/like/like.java deleted file mode 100644 index 47f557b..0000000 --- a/src/main/java/com/dku/springstudy/domain/like/like.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.dku.springstudy.domain.like; - -public class like { -} From 19a7163ea35bbfd7578183fc0a81530cb24ec1f7 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 00:31:24 +0900 Subject: [PATCH 32/44] =?UTF-8?q?feat:=20LikeController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/like/controller/LikeController.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java diff --git a/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java b/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java new file mode 100644 index 0000000..bb54318 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.domain.like.controller; + +import com.dku.springstudy.domain.like.service.LikeService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/like") +public class LikeController { + private final LikeService likeService; + + +} From 0f53c109029a5837c0a77cd831fe45179523e00b Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 00:31:35 +0900 Subject: [PATCH 33/44] =?UTF-8?q?feat:=20LikeService=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/like/service/LikeService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/like/service/LikeService.java diff --git a/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java b/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java new file mode 100644 index 0000000..3813b45 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java @@ -0,0 +1,12 @@ +package com.dku.springstudy.domain.like.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class LikeService { + +} From ffea9edc74cb6d6e71e7bc3d5374b7b3699d5e28 Mon Sep 17 00:00:00 2001 From: OneK-2 <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 00:40:12 +0900 Subject: [PATCH 34/44] =?UTF-8?q?refactor:=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=83=81=ED=92=88=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springstudy/domain/product/dto/ProductResponseDTO.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java diff --git a/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java b/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java new file mode 100644 index 0000000..639a474 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java @@ -0,0 +1,4 @@ +package com.dku.springstudy.domain.product.dto; + +public class ProductResponseDTO { +} From 4f72169ac4487385ce3f86703e6c4fff785e83b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:40:46 +0900 Subject: [PATCH 35/44] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/dto/ProductListResponseDTO.java | 15 +++++++++++++ .../product/dto/ProductResponseDTO.java | 22 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/product/dto/ProductListResponseDTO.java diff --git a/src/main/java/com/dku/springstudy/domain/product/dto/ProductListResponseDTO.java b/src/main/java/com/dku/springstudy/domain/product/dto/ProductListResponseDTO.java new file mode 100644 index 0000000..c6dc473 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/product/dto/ProductListResponseDTO.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.domain.product.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class ProductListResponseDTO { + private ProductResponseDTO selectProduct; + private List otherProductList; +} diff --git a/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java b/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java index 639a474..ffdfda7 100644 --- a/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java +++ b/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java @@ -1,4 +1,26 @@ package com.dku.springstudy.domain.product.dto; +import com.dku.springstudy.domain.product.Product; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor public class ProductResponseDTO { + private Long productId; + private String productName; + private Integer cost; + private String contents; + private Long userId; + //like추가 + + public ProductResponseDTO(Product product) { + this.productId = product.getId(); + this.productName = product.getProductName(); + this.cost = product.getCost(); + this.contents = product.getContents(); + this.userId = product.getUser().getId(); + } } From d883f2af58f2cc8bf89b2eae51c1249cb170a7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:41:18 +0900 Subject: [PATCH 36/44] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=9C=84=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/repository/ProductRepository.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java b/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java index fda69c6..c28287e 100644 --- a/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java +++ b/src/main/java/com/dku/springstudy/domain/product/repository/ProductRepository.java @@ -3,5 +3,9 @@ import com.dku.springstudy.domain.product.Product; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; +import java.util.Optional; + public interface ProductRepository extends JpaRepository { + Optional> findProductByUserId(Long userId); } From 2ee851e17943db91085564decc7fe9419c98b955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:45:44 +0900 Subject: [PATCH 37/44] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 14 +++++++++++++ .../product/service/ProductService.java | 21 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java b/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java index ea30d2a..64d3907 100644 --- a/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java +++ b/src/main/java/com/dku/springstudy/domain/product/controller/ProductController.java @@ -1,7 +1,9 @@ package com.dku.springstudy.domain.product.controller; +import com.dku.springstudy.domain.product.dto.ProductListResponseDTO; import com.dku.springstudy.domain.product.dto.ProductRegisterRequestDTO; +import com.dku.springstudy.domain.product.dto.ProductResponseDTO; import com.dku.springstudy.domain.product.service.ProductService; import com.dku.springstudy.domain.user.User; import com.dku.springstudy.domain.user.service.UserService; @@ -13,6 +15,7 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import java.util.List; @RestController @RequiredArgsConstructor @@ -29,4 +32,15 @@ public ResponseEntity create(@Valid @RequestBody ProductRegisterRequestDTO return ResponseEntity.status(HttpStatus.OK).body(id); } + + @GetMapping("{productId}") + public ResponseEntity getProduct(@AuthenticationPrincipal UserDetails userDetails, + @PathVariable("productId") Long productId) { + User loginUser = userService.findUser(userDetails.getUsername()); + ProductResponseDTO view = productService.findByProductId(productId); + List otherList = productService.findByUserId(loginUser.getId()); + + return new ResponseEntity<>(new ProductListResponseDTO(view, otherList), HttpStatus.OK); + } + } diff --git a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java index 0999e05..c1018ba 100644 --- a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java +++ b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java @@ -2,13 +2,17 @@ import com.dku.springstudy.domain.product.Product; import com.dku.springstudy.domain.product.dto.ProductRegisterRequestDTO; +import com.dku.springstudy.domain.product.dto.ProductResponseDTO; import com.dku.springstudy.domain.product.repository.ProductRepository; import com.dku.springstudy.domain.user.User; -import com.dku.springstudy.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -23,4 +27,19 @@ public Long save(ProductRegisterRequestDTO requestDTO, User user) { return product.getId(); } + public ProductResponseDTO findByProductId(Long productId) { + Product product = productRepository.findById(productId).orElseThrow(); + + return new ProductResponseDTO(product); + } + + public List findByUserId(Long userId){ + List products = productRepository.findProductByUserId(userId).orElseGet(ArrayList::new); + + return products.stream() + .map(ProductResponseDTO::new) + .collect(Collectors.toList()); + } + + } From 62a13525b226c8c58b63f0ca9fb027a7ba857631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:13:14 +0900 Subject: [PATCH 38/44] =?UTF-8?q?feat:=20LikeRepository=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/like/repository/LikeRepository.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/like/repository/LikeRepository.java diff --git a/src/main/java/com/dku/springstudy/domain/like/repository/LikeRepository.java b/src/main/java/com/dku/springstudy/domain/like/repository/LikeRepository.java new file mode 100644 index 0000000..b98b17e --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/like/repository/LikeRepository.java @@ -0,0 +1,9 @@ +package com.dku.springstudy.domain.like.repository; + +import com.dku.springstudy.domain.like.Likes; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface LikeRepository extends JpaRepository { + void deleteByProductIdAndUserId(Long productId, Long userId); + // void deleteByProductId(productId); +} From 37328ef2583bd260d0f260ebb4de47201bc39204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:19:53 +0900 Subject: [PATCH 39/44] =?UTF-8?q?feat:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D,=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/like/{Like.java => Likes.java} | 17 +++++++--- .../like/controller/LikeController.java | 34 +++++++++++++++++-- .../domain/like/service/LikeService.java | 13 +++++++ .../springstudy/domain/product/Product.java | 21 ++++++++---- .../product/dto/ProductResponseDTO.java | 2 ++ .../product/service/ProductService.java | 16 ++++++++- 6 files changed, 89 insertions(+), 14 deletions(-) rename src/main/java/com/dku/springstudy/domain/like/{Like.java => Likes.java} (61%) diff --git a/src/main/java/com/dku/springstudy/domain/like/Like.java b/src/main/java/com/dku/springstudy/domain/like/Likes.java similarity index 61% rename from src/main/java/com/dku/springstudy/domain/like/Like.java rename to src/main/java/com/dku/springstudy/domain/like/Likes.java index 7f13a4a..25c4216 100644 --- a/src/main/java/com/dku/springstudy/domain/like/Like.java +++ b/src/main/java/com/dku/springstudy/domain/like/Likes.java @@ -3,18 +3,20 @@ import com.dku.springstudy.domain.BaseTimeEntity; import com.dku.springstudy.domain.product.Product; import com.dku.springstudy.domain.user.User; -import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.*; @Entity -@NoArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor @Getter -public class Like extends BaseTimeEntity { - @Id @GeneratedValue +public class Likes extends BaseTimeEntity { + @Id + @GeneratedValue private Long id; + private Long productInfo; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") @@ -24,4 +26,11 @@ public class Like extends BaseTimeEntity { @JoinColumn(name = "product_id") private Product product; + @Builder + public Likes(Long productInfo, User user, Product product) { + this.productInfo = productInfo; + this.user = user; + this.product = product; + } + } diff --git a/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java b/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java index bb54318..dad9713 100644 --- a/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java +++ b/src/main/java/com/dku/springstudy/domain/like/controller/LikeController.java @@ -1,15 +1,45 @@ package com.dku.springstudy.domain.like.controller; +import com.dku.springstudy.domain.like.Likes; import com.dku.springstudy.domain.like.service.LikeService; +import com.dku.springstudy.domain.product.Product; +import com.dku.springstudy.domain.product.service.ProductService; +import com.dku.springstudy.domain.user.User; +import com.dku.springstudy.domain.user.service.UserService; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/like") public class LikeController { private final LikeService likeService; + private final UserService userService; + private final ProductService productService; + @PostMapping("/{productId}/addLike") + public ResponseEntity addLike(@AuthenticationPrincipal UserDetails userDetails, + @PathVariable("productId") Long productId) { + User user = userService.findUser(userDetails.getUsername()); + Product product = productService.findProduct(productId); + likeService.addLike(new Likes(productId, user, product)); + productService.addLikeCount(product); + + return ResponseEntity.status(HttpStatus.OK).body("success"); + } + + @DeleteMapping("/{productId}/deleteLike") + public ResponseEntity deleteLike(@AuthenticationPrincipal UserDetails userDetails, + @PathVariable("productId") Long productId) { + User user = userService.findUser(userDetails.getUsername()); + likeService.deleteLike(productId, user.getId()); + productService.deleteLikeCount(productService.findProduct(productId)); + + return ResponseEntity.status(HttpStatus.OK).body("success"); + } } diff --git a/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java b/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java index 3813b45..f11c97a 100644 --- a/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java +++ b/src/main/java/com/dku/springstudy/domain/like/service/LikeService.java @@ -1,5 +1,7 @@ package com.dku.springstudy.domain.like.service; +import com.dku.springstudy.domain.like.Likes; +import com.dku.springstudy.domain.like.repository.LikeRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -8,5 +10,16 @@ @Transactional(readOnly = true) @RequiredArgsConstructor public class LikeService { + private final LikeRepository likeRepository; + + @Transactional + public Likes addLike(Likes likes){ + return likeRepository.save(likes); + } + + @Transactional + public void deleteLike(Long productId, Long userId){ + likeRepository.deleteByProductIdAndUserId(productId, userId); + } } diff --git a/src/main/java/com/dku/springstudy/domain/product/Product.java b/src/main/java/com/dku/springstudy/domain/product/Product.java index f3b7751..5ebf9ab 100644 --- a/src/main/java/com/dku/springstudy/domain/product/Product.java +++ b/src/main/java/com/dku/springstudy/domain/product/Product.java @@ -1,20 +1,20 @@ package com.dku.springstudy.domain.product; import com.dku.springstudy.domain.BaseTimeEntity; -import com.dku.springstudy.domain.like.Like; import com.dku.springstudy.domain.user.User; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.DynamicInsert; import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@DynamicInsert public class Product extends BaseTimeEntity { @Id @GeneratedValue @@ -28,6 +28,8 @@ public class Product extends BaseTimeEntity { private String productImgUrl; private Integer cost; private String contents; + @ColumnDefault("0") + private Integer likeCount; @Enumerated(EnumType.STRING) private ProductStatus status; @@ -35,20 +37,25 @@ public class Product extends BaseTimeEntity { @Enumerated(EnumType.STRING) private Category category; - @OneToMany(mappedBy = "product") - private List likes = new ArrayList<>(); - @Builder public Product(String productName, Category category, Integer cost, String contents, - String productImgUrl, User user, ProductStatus productStatus) { + String productImgUrl, User user, ProductStatus productStatus, Integer likeCount) { this.productName = productName; this.category = category; this.cost = cost; this.contents = contents; + this.likeCount = likeCount; this.productImgUrl = productImgUrl; this.status = productStatus; this.user = user; } + public void addLikeCount() { + this.likeCount++; + } + + public void deleteLikeCount() { + this.likeCount--; + } } diff --git a/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java b/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java index ffdfda7..dc0c17b 100644 --- a/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java +++ b/src/main/java/com/dku/springstudy/domain/product/dto/ProductResponseDTO.java @@ -15,6 +15,7 @@ public class ProductResponseDTO { private String contents; private Long userId; //like추가 + private Integer likeCount; public ProductResponseDTO(Product product) { this.productId = product.getId(); @@ -22,5 +23,6 @@ public ProductResponseDTO(Product product) { this.cost = product.getCost(); this.contents = product.getContents(); this.userId = product.getUser().getId(); + this.likeCount = product.getLikeCount(); } } diff --git a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java index c1018ba..eb18f79 100644 --- a/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java +++ b/src/main/java/com/dku/springstudy/domain/product/service/ProductService.java @@ -6,6 +6,7 @@ import com.dku.springstudy.domain.product.repository.ProductRepository; import com.dku.springstudy.domain.user.User; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -33,7 +34,7 @@ public ProductResponseDTO findByProductId(Long productId) { return new ProductResponseDTO(product); } - public List findByUserId(Long userId){ + public List findByUserId(Long userId) { List products = productRepository.findProductByUserId(userId).orElseGet(ArrayList::new); return products.stream() @@ -41,5 +42,18 @@ public List findByUserId(Long userId){ .collect(Collectors.toList()); } + public Product findProduct(Long id) { + return productRepository.findById(id).orElseThrow(() -> new UsernameNotFoundException("no id")); + } + + @Transactional + public void addLikeCount(Product product) { + product.addLikeCount(); + } + + @Transactional + public void deleteLikeCount(Product product) { + product.deleteLikeCount(); + } } From 0e88e81fee4d0ac665edba6621ed56959244e58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:20:39 +0900 Subject: [PATCH 40/44] =?UTF-8?q?refactor:=20Likes=EB=A1=9C=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=EB=AA=85=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/domain/user/User.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java index 8c674e9..bf9da42 100644 --- a/src/main/java/com/dku/springstudy/domain/user/User.java +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -1,7 +1,7 @@ package com.dku.springstudy.domain.user; import com.dku.springstudy.domain.BaseTimeEntity; -import com.dku.springstudy.domain.like.Like; +import com.dku.springstudy.domain.like.Likes; import com.dku.springstudy.domain.product.Product; import lombok.*; @@ -22,7 +22,7 @@ public class User extends BaseTimeEntity { private List products = new ArrayList<>(); @OneToMany(mappedBy = "user") - private List likes = new ArrayList<>(); + private List likes = new ArrayList<>(); private String email; private String password; From e900d2b9d4b4856f0518bb37f9e6975d21fdf2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Thu, 16 Feb 2023 15:52:47 +0900 Subject: [PATCH 41/44] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 15ac609..a9e95b4 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,10 @@ D-Coding 백엔드 스터디 - 상태, 카테고리 enum추가 ![image](https://user-images.githubusercontent.com/85729858/216071539-42dc3af6-452e-464f-9a68-c52364c5fc3f.png) + + +### 4주차 + +- 상품등록 기능 구현 +- 상품조회 기능 구현 +- 좋아요 등록, 삭제 기능 구현 From 0ae9bb536516f6ed42e01f5c96379db021ab6045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Thu, 16 Feb 2023 18:48:08 +0900 Subject: [PATCH 42/44] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EB=B3=80=EA=B2=BD=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?DTO=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/user/dto/UserProfileUpdateRequestDTO.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/domain/user/dto/UserProfileUpdateRequestDTO.java diff --git a/src/main/java/com/dku/springstudy/domain/user/dto/UserProfileUpdateRequestDTO.java b/src/main/java/com/dku/springstudy/domain/user/dto/UserProfileUpdateRequestDTO.java new file mode 100644 index 0000000..0fd9a93 --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/user/dto/UserProfileUpdateRequestDTO.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.domain.user.dto; + +import lombok.Data; + +@Data +public class UserProfileUpdateRequestDTO { + private String nickname; + private String profileImgUrl; + +} From dc7b0116a20c16d98156a7c7a96ee580b0179862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Thu, 16 Feb 2023 18:48:47 +0900 Subject: [PATCH 43/44] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EB=B3=80=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dku/springstudy/domain/user/User.java | 8 ++++++++ .../domain/user/controller/UserController.java | 15 ++++++++++++++- .../domain/user/service/UserService.java | 14 +++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/dku/springstudy/domain/user/User.java b/src/main/java/com/dku/springstudy/domain/user/User.java index bf9da42..73cdba1 100644 --- a/src/main/java/com/dku/springstudy/domain/user/User.java +++ b/src/main/java/com/dku/springstudy/domain/user/User.java @@ -44,4 +44,12 @@ public User(String email, String password, String username, String phoneNumber, this.profileImgUrl = profileImgUrl; this.role = Role.USER; } + + public void updateNickName(String nickname) { + this.nickname = nickname; + } + + public void updateProfileImg(String profileImgUrl) { + this.profileImgUrl = profileImgUrl; + } } diff --git a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java index 538898a..1ef4846 100644 --- a/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java +++ b/src/main/java/com/dku/springstudy/domain/user/controller/UserController.java @@ -1,13 +1,17 @@ package com.dku.springstudy.domain.user.controller; +import com.dku.springstudy.domain.user.User; import com.dku.springstudy.domain.user.dto.LoginRequestDto; import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; +import com.dku.springstudy.domain.user.dto.UserProfileUpdateRequestDTO; import com.dku.springstudy.domain.user.service.UserService; import com.dku.springstudy.jwt.TokenDto; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -22,7 +26,7 @@ public class UserController { private final UserService userService; @PostMapping("/signup") - public ResponseEntity signUp(@Valid @RequestBody SignUpRequestDTO requestDTO){ + public ResponseEntity signUp(@Valid @RequestBody SignUpRequestDTO requestDTO) { userService.signUp(requestDTO); return ResponseEntity.status(HttpStatus.CREATED).body(null); @@ -34,4 +38,13 @@ public TokenDto login(@Valid @RequestBody LoginRequestDto loginRequestDto) { String password = loginRequestDto.getPassword(); return userService.login(email, password); } + + @PostMapping("/profile") + public ResponseEntity updateProfile(@AuthenticationPrincipal UserDetails userDetails, + @Valid @RequestBody UserProfileUpdateRequestDTO requestDTO) { + User loginUser = userService.findUser(userDetails.getUsername()); + Long id = userService.updateProfile(loginUser, requestDTO); + + return ResponseEntity.status(HttpStatus.OK).body(id); + } } diff --git a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java index 48e8c51..cb54434 100644 --- a/src/main/java/com/dku/springstudy/domain/user/service/UserService.java +++ b/src/main/java/com/dku/springstudy/domain/user/service/UserService.java @@ -2,6 +2,7 @@ import com.dku.springstudy.domain.user.User; import com.dku.springstudy.domain.user.dto.SignUpRequestDTO; +import com.dku.springstudy.domain.user.dto.UserProfileUpdateRequestDTO; import com.dku.springstudy.domain.user.repository.UserRepository; import com.dku.springstudy.jwt.JwtTokenProvider; import com.dku.springstudy.jwt.TokenDto; @@ -24,6 +25,7 @@ public class UserService { private final JwtTokenProvider jwtTokenProvider; private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; + @Transactional public TokenDto login(String email, String password) { // 1. Login ID/PW 를 기반으로 Authentication 객체 생성 @@ -40,7 +42,7 @@ public TokenDto login(String email, String password) { } @Transactional - public Long signUp(@Valid SignUpRequestDTO requestDTO){ + public Long signUp(@Valid SignUpRequestDTO requestDTO) { String bcryptPassword = passwordEncoder.encode(requestDTO.getPassword()); requestDTO.setPassword(bcryptPassword); User user = requestDTO.toEntity(); @@ -53,4 +55,14 @@ public User findUser(String email) { return userRepository.findByEmail(email) .orElseThrow(() -> new UsernameNotFoundException("No user")); } + + @Transactional + public Long updateProfile(User user, UserProfileUpdateRequestDTO requestDTO) { + user.updateNickName(requestDTO.getNickname()); + user.updateProfileImg(requestDTO.getProfileImgUrl()); + userRepository.save(user); + + return user.getId(); + } + } From fddefc09f525cfafb0303b6fb1382761524bd711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9B=90=EA=B7=9C?= <85729858+OneK-2@users.noreply.github.com> Date: Thu, 16 Feb 2023 18:50:01 +0900 Subject: [PATCH 44/44] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a9e95b4..f9b0a02 100644 --- a/README.md +++ b/README.md @@ -45,3 +45,4 @@ D-Coding 백엔드 스터디 - 상품등록 기능 구현 - 상품조회 기능 구현 - 좋아요 등록, 삭제 기능 구현 +- 유저 프로필 수정 기능 추가