From 2197c4085aebad6e2d148861a8f73dfa615709a6 Mon Sep 17 00:00:00 2001 From: KanghoLim <49905142+limkangho@users.noreply.github.com> Date: Sun, 22 Jan 2023 23:38:59 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[1=EC=A3=BC=EC=B0=A8=20=EA=B3=BC=EC=A0=9C]?= =?UTF-8?q?=20=EC=9E=84=EA=B0=95=ED=98=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...] \354\236\204\352\260\225\355\230\270.md" | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 "[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" diff --git "a/[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" "b/[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" new file mode 100644 index 0000000..0f8c27f --- /dev/null +++ "b/[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" @@ -0,0 +1,27 @@ +## 이번 주는 어떻게 학습했나요? 아래 질문에 짧게 답변주세요! + +### 이번 주에 학습에 투자한 시간 + +- 8시간 정도 + +### 학습 하면서 좋았던 점과 아쉬웠던 점 + +- 좋았던 점 + + 굉장히 실용적인 프로젝트 실습이었다. 혼자서 frontend를 공부할 때보다 더 유기적이고 실제 DB가 적용되어 실시간으로 데이터를 저장할 수 있는 웹서버를 만들 수 있었다. 실습 진행 중간 중간에 설명도 자세하게, 실무에서는 어떻게 사용하더라, 이건 고전적인 방법이니 알아만 두자, 이건 중요한 내용이다, 이런 단축키가 있으니 사용하면 편할 것이다 등등 강의 자체가 친절하고 자세하게 다가와서 듣기 편했다. + + + +- 아쉬웠던 점 + + 오류가 발생하여 실습 도중 끝까지 진행하지 못했다. + 강의 내역 중 "스프링 DB 접근 기술 - 순수 JDBC" 파트였는데 + import org.springframework.jdbc.datasource.DataSourceUtils; 구문에서 오류가 발생했다. 강의 커뮤니티 게시판에서 관련 오류 내역을 다 찾아보고 시도해봤는데 고쳐지지 않았다. 이거만 해결하면 끝까지 진행할 수 있을 것 같은데 오늘 22일 기준 3시간 가량 붙잡고 시도해봤는도 해결을 못했다. + +### 어려움을 겪는 부분 + +- IntellJ가 무겁고 사용감 불편함을 느껴서 VSCode로 실습 환경을 구성하여 진행해봤는데 "스프링 DB 접근 기술 - 순수 JDBC" 파트 이전까지 막힘없이 잘 진행했는데 저 파트 오류가 IntelliJ에서는 잘 작동한다. 뭐가 어떻게 달라서 VSC에서는 안되고 IntelliJ에서는 되는건지 모르겠다. + +### 스터디 개선되었으면 하는 점 + + From c41cc8aa03bf9da3630b5a3120ca889b3fc056e1 Mon Sep 17 00:00:00 2001 From: Kangho Date: Sun, 29 Jan 2023 22:15:40 +0900 Subject: [PATCH 2/5] =?UTF-8?q?basic=20security=20config=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++ .../com/dku/springstudy/SecurityConfig.java | 7 ++++ .../com/dku/springstudy/SpringConfig.java | 5 +++ .../springstudy/SpringStudyApplication.java | 3 ++ .../controller/HomeController.java | 13 ++++++ .../com/dku/springstudy/domain/Member.java | 22 ++++++++++ .../repository/MemberRepository.java | 13 ++++++ .../repository/MemoryMemberRepository.java | 42 +++++++++++++++++++ .../springstudy/service/MemberService.java | 37 ++++++++++++++++ src/main/resources/application.properties | 11 +++++ src/main/resources/static/index.html | 1 + src/main/resources/templates/home.html | 18 ++++++++ 12 files changed, 175 insertions(+) create mode 100644 src/main/java/com/dku/springstudy/SecurityConfig.java create mode 100644 src/main/java/com/dku/springstudy/SpringConfig.java create mode 100644 src/main/java/com/dku/springstudy/controller/HomeController.java create mode 100644 src/main/java/com/dku/springstudy/domain/Member.java create mode 100644 src/main/java/com/dku/springstudy/repository/MemberRepository.java create mode 100644 src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java create mode 100644 src/main/java/com/dku/springstudy/service/MemberService.java create mode 100644 src/main/resources/static/index.html create mode 100644 src/main/resources/templates/home.html diff --git a/build.gradle b/build.gradle index 15b77ef..d14674e 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,9 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + // compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity5', version: '3.0.4.RELEASE' + } tasks.named('test') { diff --git a/src/main/java/com/dku/springstudy/SecurityConfig.java b/src/main/java/com/dku/springstudy/SecurityConfig.java new file mode 100644 index 0000000..4d83110 --- /dev/null +++ b/src/main/java/com/dku/springstudy/SecurityConfig.java @@ -0,0 +1,7 @@ +package com.dku.springstudy; + +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@EnableWebSecurity +public class SecurityConfig { +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/SpringConfig.java b/src/main/java/com/dku/springstudy/SpringConfig.java new file mode 100644 index 0000000..1edb81e --- /dev/null +++ b/src/main/java/com/dku/springstudy/SpringConfig.java @@ -0,0 +1,5 @@ +package com.dku.springstudy; + +public class SpringConfig { + +} diff --git a/src/main/java/com/dku/springstudy/SpringStudyApplication.java b/src/main/java/com/dku/springstudy/SpringStudyApplication.java index ef164c9..02360d3 100644 --- a/src/main/java/com/dku/springstudy/SpringStudyApplication.java +++ b/src/main/java/com/dku/springstudy/SpringStudyApplication.java @@ -1,9 +1,12 @@ package com.dku.springstudy; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @SpringBootApplication +@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) public class SpringStudyApplication { public static void main(String[] args) { diff --git a/src/main/java/com/dku/springstudy/controller/HomeController.java b/src/main/java/com/dku/springstudy/controller/HomeController.java new file mode 100644 index 0000000..fd881aa --- /dev/null +++ b/src/main/java/com/dku/springstudy/controller/HomeController.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class HomeController { + + @GetMapping("/") + public String home() { + return "home"; + } +} diff --git a/src/main/java/com/dku/springstudy/domain/Member.java b/src/main/java/com/dku/springstudy/domain/Member.java new file mode 100644 index 0000000..835d15a --- /dev/null +++ b/src/main/java/com/dku/springstudy/domain/Member.java @@ -0,0 +1,22 @@ +package com.dku.springstudy.domain; + +public class Member { + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/repository/MemberRepository.java b/src/main/java/com/dku/springstudy/repository/MemberRepository.java new file mode 100644 index 0000000..9c1f548 --- /dev/null +++ b/src/main/java/com/dku/springstudy/repository/MemberRepository.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.repository; + +import java.util.List; +import java.util.Optional; + +import com.dku.springstudy.domain.Member; + +public interface MemberRepository { + Member save(Member member); + Optional findById(Long id); + Optional findByName(String name); + List findAll(); +} diff --git a/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java b/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java new file mode 100644 index 0000000..7b36a09 --- /dev/null +++ b/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java @@ -0,0 +1,42 @@ +package com.dku.springstudy.repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import com.dku.springstudy.domain.Member; + +public class MemoryMemberRepository implements MemberRepository { + + private static Map store = new HashMap<>(); + private static long sequence = 0L; + @Override + + public Member save(Member member) { + member.setId(++sequence); + store.put(member.getId(), member); + + return member; + } + + @Override + public Optional findById(Long id) { + return Optional.ofNullable(store.get(id)); + } + + @Override + public Optional findByName(String name) { + return store.values().stream() + .filter(member -> member.getName().equals(name)) + .findAny(); + } + + @Override + public List findAll() { + return new ArrayList<>(store.values()); + } + + +} diff --git a/src/main/java/com/dku/springstudy/service/MemberService.java b/src/main/java/com/dku/springstudy/service/MemberService.java new file mode 100644 index 0000000..3452ae4 --- /dev/null +++ b/src/main/java/com/dku/springstudy/service/MemberService.java @@ -0,0 +1,37 @@ +package com.dku.springstudy.service; + +import java.util.List; +import java.util.Optional; + +import com.dku.springstudy.domain.Member; +import com.dku.springstudy.repository.MemberRepository; +import com.dku.springstudy.repository.MemoryMemberRepository; + +public class MemberService { + + private final MemberRepository memberRepository = new MemoryMemberRepository(); + + /* 회원 가입 */ + public Long join(Member member) { + validateDuplicateMember(member); + memberRepository.save(member); + + return member.getId(); + } + + private void validateDuplicateMember(Member member) { + memberRepository.findByName(member.getName()) + .ifPresent(m -> { + throw new IllegalThreadStateException("이미 존재하는 회원입니다."); + }); + } + + /* 전체 회원 조회 */ + public List findMembers() { + return memberRepository.findAll(); + } + + public Optional findOne(Long memberId) { + return memberRepository.findById(memberId); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..accb4c0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,12 @@ +# spring: +# output: +# ansi: +# enabled: always + +# logging: +# level: +# '[com.dku.springstudy]': DEBUG + +spring.security.user.name=user +spring.security.user.password=1234 diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html new file mode 100644 index 0000000..0ffeef0 --- /dev/null +++ b/src/main/resources/static/index.html @@ -0,0 +1 @@ +

JPA Study DKU

\ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html new file mode 100644 index 0000000..df3f27c --- /dev/null +++ b/src/main/resources/templates/home.html @@ -0,0 +1,18 @@ + + + + + + + Home + + +
+

Hello Spirng JPA Study

+

+ Join + List +

+
+ + \ No newline at end of file From 15f1f5d71ce87b6ba0ec5ca1f07734d44b006400 Mon Sep 17 00:00:00 2001 From: Kangho Date: Fri, 3 Feb 2023 19:51:57 +0900 Subject: [PATCH 3/5] =?UTF-8?q?test=20=ED=8C=8C=EC=9D=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dku/springstudy/domain/Member.java | 16 +++++++++--- .../repository/MemoryMemberRepository.java | 4 +-- .../SpringDataMemberRepository.java | 13 ++++++++++ src/main/resources/application.properties | 12 --------- src/main/resources/application.yml | 25 +++++++++++++++++++ .../SpringStudyApplicationTests.java | 21 +++++++++++++--- 6 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml diff --git a/src/main/java/com/dku/springstudy/domain/Member.java b/src/main/java/com/dku/springstudy/domain/Member.java index 835d15a..0a5f833 100644 --- a/src/main/java/com/dku/springstudy/domain/Member.java +++ b/src/main/java/com/dku/springstudy/domain/Member.java @@ -1,11 +1,21 @@ package com.dku.springstudy.domain; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity public class Member { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + + // @Column(name = "username") private String name; public Long getId() { - return id; + return this.id; } public void setId(Long id) { @@ -13,10 +23,10 @@ public void setId(Long id) { } public String getName() { - return name; + return this.name; } public void setName(String name) { this.name = name; } -} \ No newline at end of file +} diff --git a/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java b/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java index 7b36a09..b652184 100644 --- a/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java +++ b/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java @@ -12,8 +12,8 @@ public class MemoryMemberRepository implements MemberRepository { private static Map store = new HashMap<>(); private static long sequence = 0L; - @Override + @Override public Member save(Member member) { member.setId(++sequence); store.put(member.getId(), member); @@ -37,6 +37,4 @@ public Optional findByName(String name) { public List findAll() { return new ArrayList<>(store.values()); } - - } diff --git a/src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java b/src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java new file mode 100644 index 0000000..53f54ac --- /dev/null +++ b/src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.dku.springstudy.domain.Member; + +public interface SpringDataMemberRepository extends JpaRepository, MemberRepository{ + + @Override + public Optional findByName(String name); +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index accb4c0..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,12 +0,0 @@ -# spring: -# output: -# ansi: -# enabled: always - -# logging: -# level: -# '[com.dku.springstudy]': DEBUG - -spring.security.user.name=user -spring.security.user.password=1234 - diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..0947453 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,25 @@ +spring: + # DB 연결 + datasource: + # 설치된 H2 DB와 연결 URL + url: jdbc:h2:tcp://localhost/~/test + # 접속을 위한 드라이버 + driver-class-name: org.h2.Driver + # springboot 2.4 부터는 username이 꼭 있어야합니다. 없으면 에러가 발생합니다. + username: sa + jpa: + # JPA가 수행하는 SQL을 볼 수 있다. + show-sql: true + # 객체를 보고 자동으로 테이블 생성 여부. 생성 - create, 비생성 - none + # 테스트이기 때문에 create로 설정하며 + # 실제로는 none 으로 합니다. create이면 기존의 테이블을 전부 밀어버립니다. + hibernate: + ddl-auto: create + # 콘솔 확인 을 위한 always + output: + ansi: + enabled: always +# 파라미터 확인을 위한 trace +logging: + level: + org.hibernate.type: trace \ No newline at end of file diff --git a/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java b/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java index 79d9975..c509e0a 100644 --- a/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java +++ b/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java @@ -1,13 +1,28 @@ package com.dku.springstudy; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import com.dku.springstudy.domain.Member; +import com.dku.springstudy.repository.MemberRepository; +import com.dku.springstudy.repository.MemoryMemberRepository; + @SpringBootTest class SpringStudyApplicationTests { - @Test - void contextLoads() { - } + MemberRepository memberRepository = new MemoryMemberRepository(); + + @Test + void 회원가입() { + // 멤버 저장 + Member member = new Member(); + member.setName("skyepodium"); + memberRepository.save(member); + // 저장한 멤버 아이디로 검색 + Member findMember = memberRepository.findById(member.getId()).get(); + Assertions.assertThat(member.getName()).isEqualTo(findMember.getName()); + } } From 04c43846d85e3cb9bf8fdb33eb6c2af16f131e35 Mon Sep 17 00:00:00 2001 From: Kangho Date: Mon, 13 Feb 2023 02:57:38 +0900 Subject: [PATCH 4/5] =?UTF-8?q?2,=203=EC=A3=BC=EC=B0=A8=20=EA=B3=BC?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...] \354\236\204\352\260\225\355\230\270.md" | 27 ----- build.gradle | 13 ++- .../com/dku/springstudy/SecurityConfig.java | 7 -- .../com/dku/springstudy/SpringConfig.java | 5 - .../springstudy/SpringStudyApplication.java | 3 - .../controller/HomeController.java | 13 --- .../controller/UserController.java | 65 +++++++++++ .../com/dku/springstudy/domain/Member.java | 32 ------ .../dto/common/ErrorResponseDTO.java | 13 +++ .../springstudy/dto/common/ExceptionDTO.java | 25 +++++ .../springstudy/dto/common/ResponseDTO.java | 10 ++ .../dto/common/SuccessResponseDTO.java | 13 +++ .../dto/user/request/LoginRequestDTO.java | 18 ++++ .../dto/user/request/LogoutRequestDTO.java | 11 ++ .../dto/user/request/SignUpRequestDTO.java | 22 ++++ .../dto/user/response/LoginResponseDTO.java | 15 +++ .../dto/user/response/LogoutResponseDTO.java | 21 ++++ .../dto/user/response/SignUpResponseDTO.java | 16 +++ .../dto/user/response/TokenResponseDTO.java | 9 ++ .../exception/CustomException.java | 10 ++ .../dku/springstudy/exception/ErrorCode.java | 20 ++++ .../springstudy/exception/JwtTokenError.java | 12 +++ .../dku/springstudy/exception/Message.java | 9 ++ .../java/com/dku/springstudy/model/User.java | 34 ++++++ .../repository/MemberRepository.java | 13 --- .../repository/MemoryMemberRepository.java | 40 ------- .../SpringDataMemberRepository.java | 13 --- .../repository/UserRepository.java | 50 +++++++++ .../security/CustomUserDetailService.java | 24 +++++ .../security/CustomUserDetails.java | 52 +++++++++ .../dku/springstudy/security/Interceptor.java | 50 +++++++++ .../security/config/InterceptorConfig.java | 18 ++++ .../config/RedisRepositoryConfig.java | 32 ++++++ .../security/config/SecurityConfig.java | 57 ++++++++++ .../security/config/SpringConfig.java | 19 ++++ .../security/jwt/JwtAuthenticationFilter.java | 75 +++++++++++++ .../springstudy/security/jwt/JwtProvider.java | 101 ++++++++++++++++++ .../springstudy/service/MemberService.java | 37 ------- .../dku/springstudy/service/UserService.java | 75 +++++++++++++ src/main/resources/DB/carrot.mv.db | 0 src/main/resources/application.yml | 34 +++--- src/main/resources/static/index.html | 1 - src/main/resources/templates/home.html | 18 ---- .../SpringStudyApplicationTests.java | 21 +--- 44 files changed, 908 insertions(+), 245 deletions(-) delete mode 100644 "[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" delete mode 100644 src/main/java/com/dku/springstudy/SecurityConfig.java delete mode 100644 src/main/java/com/dku/springstudy/SpringConfig.java delete mode 100644 src/main/java/com/dku/springstudy/controller/HomeController.java create mode 100644 src/main/java/com/dku/springstudy/controller/UserController.java delete mode 100644 src/main/java/com/dku/springstudy/domain/Member.java create mode 100644 src/main/java/com/dku/springstudy/dto/common/ErrorResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/common/ExceptionDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/common/ResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/common/SuccessResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/request/LoginRequestDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/request/LogoutRequestDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/request/SignUpRequestDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/response/LoginResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/response/LogoutResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/response/SignUpResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/dto/user/response/TokenResponseDTO.java create mode 100644 src/main/java/com/dku/springstudy/exception/CustomException.java create mode 100644 src/main/java/com/dku/springstudy/exception/ErrorCode.java create mode 100644 src/main/java/com/dku/springstudy/exception/JwtTokenError.java create mode 100644 src/main/java/com/dku/springstudy/exception/Message.java create mode 100644 src/main/java/com/dku/springstudy/model/User.java delete mode 100644 src/main/java/com/dku/springstudy/repository/MemberRepository.java delete mode 100644 src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java delete mode 100644 src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java create mode 100644 src/main/java/com/dku/springstudy/repository/UserRepository.java create mode 100644 src/main/java/com/dku/springstudy/security/CustomUserDetailService.java create mode 100644 src/main/java/com/dku/springstudy/security/CustomUserDetails.java create mode 100644 src/main/java/com/dku/springstudy/security/Interceptor.java create mode 100644 src/main/java/com/dku/springstudy/security/config/InterceptorConfig.java create mode 100644 src/main/java/com/dku/springstudy/security/config/RedisRepositoryConfig.java create mode 100644 src/main/java/com/dku/springstudy/security/config/SecurityConfig.java create mode 100644 src/main/java/com/dku/springstudy/security/config/SpringConfig.java create mode 100644 src/main/java/com/dku/springstudy/security/jwt/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/dku/springstudy/security/jwt/JwtProvider.java delete mode 100644 src/main/java/com/dku/springstudy/service/MemberService.java create mode 100644 src/main/java/com/dku/springstudy/service/UserService.java create mode 100644 src/main/resources/DB/carrot.mv.db delete mode 100644 src/main/resources/static/index.html delete mode 100644 src/main/resources/templates/home.html diff --git "a/[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" "b/[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" deleted file mode 100644 index 0f8c27f..0000000 --- "a/[1\354\243\274\354\260\250 \352\263\274\354\240\234] \354\236\204\352\260\225\355\230\270.md" +++ /dev/null @@ -1,27 +0,0 @@ -## 이번 주는 어떻게 학습했나요? 아래 질문에 짧게 답변주세요! - -### 이번 주에 학습에 투자한 시간 - -- 8시간 정도 - -### 학습 하면서 좋았던 점과 아쉬웠던 점 - -- 좋았던 점 - - 굉장히 실용적인 프로젝트 실습이었다. 혼자서 frontend를 공부할 때보다 더 유기적이고 실제 DB가 적용되어 실시간으로 데이터를 저장할 수 있는 웹서버를 만들 수 있었다. 실습 진행 중간 중간에 설명도 자세하게, 실무에서는 어떻게 사용하더라, 이건 고전적인 방법이니 알아만 두자, 이건 중요한 내용이다, 이런 단축키가 있으니 사용하면 편할 것이다 등등 강의 자체가 친절하고 자세하게 다가와서 듣기 편했다. - - - -- 아쉬웠던 점 - - 오류가 발생하여 실습 도중 끝까지 진행하지 못했다. - 강의 내역 중 "스프링 DB 접근 기술 - 순수 JDBC" 파트였는데 - import org.springframework.jdbc.datasource.DataSourceUtils; 구문에서 오류가 발생했다. 강의 커뮤니티 게시판에서 관련 오류 내역을 다 찾아보고 시도해봤는데 고쳐지지 않았다. 이거만 해결하면 끝까지 진행할 수 있을 것 같은데 오늘 22일 기준 3시간 가량 붙잡고 시도해봤는도 해결을 못했다. - -### 어려움을 겪는 부분 - -- IntellJ가 무겁고 사용감 불편함을 느껴서 VSCode로 실습 환경을 구성하여 진행해봤는데 "스프링 DB 접근 기술 - 순수 JDBC" 파트 이전까지 막힘없이 잘 진행했는데 저 파트 오류가 IntelliJ에서는 잘 작동한다. 뭐가 어떻게 달라서 VSC에서는 안되고 IntelliJ에서는 되는건지 모르겠다. - -### 스터디 개선되었으면 하는 점 - - diff --git a/build.gradle b/build.gradle index d14674e..b70c824 100644 --- a/build.gradle +++ b/build.gradle @@ -22,14 +22,21 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.mysql:mysql-connector-j' + runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2' + implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'io.jsonwebtoken:jjwt:0.9.1' + implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5' + runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5' + runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5' - // compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity5', version: '3.0.4.RELEASE' - + implementation 'org.apache.httpcomponents:httpclient:4.5.7' } tasks.named('test') { diff --git a/src/main/java/com/dku/springstudy/SecurityConfig.java b/src/main/java/com/dku/springstudy/SecurityConfig.java deleted file mode 100644 index 4d83110..0000000 --- a/src/main/java/com/dku/springstudy/SecurityConfig.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.dku.springstudy; - -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; - -@EnableWebSecurity -public class SecurityConfig { -} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/SpringConfig.java b/src/main/java/com/dku/springstudy/SpringConfig.java deleted file mode 100644 index 1edb81e..0000000 --- a/src/main/java/com/dku/springstudy/SpringConfig.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.dku.springstudy; - -public class SpringConfig { - -} diff --git a/src/main/java/com/dku/springstudy/SpringStudyApplication.java b/src/main/java/com/dku/springstudy/SpringStudyApplication.java index 02360d3..ef164c9 100644 --- a/src/main/java/com/dku/springstudy/SpringStudyApplication.java +++ b/src/main/java/com/dku/springstudy/SpringStudyApplication.java @@ -1,12 +1,9 @@ package com.dku.springstudy; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @SpringBootApplication -@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) public class SpringStudyApplication { public static void main(String[] args) { diff --git a/src/main/java/com/dku/springstudy/controller/HomeController.java b/src/main/java/com/dku/springstudy/controller/HomeController.java deleted file mode 100644 index fd881aa..0000000 --- a/src/main/java/com/dku/springstudy/controller/HomeController.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.dku.springstudy.controller; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; - -@Controller -public class HomeController { - - @GetMapping("/") - public String home() { - return "home"; - } -} diff --git a/src/main/java/com/dku/springstudy/controller/UserController.java b/src/main/java/com/dku/springstudy/controller/UserController.java new file mode 100644 index 0000000..580e750 --- /dev/null +++ b/src/main/java/com/dku/springstudy/controller/UserController.java @@ -0,0 +1,65 @@ +package com.dku.springstudy.controller; + + +import java.security.Timestamp; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.dku.springstudy.dto.user.request.LoginRequestDTO; +import com.dku.springstudy.dto.user.request.SignUpRequestDTO; +import com.dku.springstudy.dto.user.response.LoginResponseDTO; +import com.dku.springstudy.dto.user.response.LogoutResponseDTO; +import com.dku.springstudy.dto.user.response.SignUpResponseDTO; +import com.dku.springstudy.model.User; +import com.dku.springstudy.security.CustomUserDetails; +import com.dku.springstudy.security.jwt.JwtProvider; +import com.dku.springstudy.service.UserService; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +public class UserController { + private final UserService userService; + private final JwtProvider jwtProvider; + + // private Long id; + // private String name; + // private String email; + // private String password; + + + // final Long ID = 30L; + // final String NAME = "kangho"; + // final String EMAIL = "kangho@gmail.com"; + // final String PASSWORD = "kangho"; + + // User user = User.builder() + // .id(ID) + // .name(NAME) + // .email(EMAIL) + // .password(PASSWORD) + // .build(); + + @PostMapping("/user/signUpTest") + public SignUpResponseDTO SignUpTest(@Valid @RequestBody SignUpRequestDTO signUpRequestDTO) { + return userService.signUp(signUpRequestDTO); + } + + @PostMapping("/user/login") + public LoginResponseDTO login(@Valid @RequestBody LoginRequestDTO loginRequest) { + return userService.login(loginRequest); + } + + @PostMapping("/user/logout") + public LogoutResponseDTO logout(@AuthenticationPrincipal CustomUserDetails customUserDetails, HttpServletRequest request) { + User user = customUserDetails.getUser(); + String accessToken = jwtProvider.resolveToken(request); + return userService.logout(user, accessToken); + } +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/domain/Member.java b/src/main/java/com/dku/springstudy/domain/Member.java deleted file mode 100644 index 0a5f833..0000000 --- a/src/main/java/com/dku/springstudy/domain/Member.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.dku.springstudy.domain; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; - -@Entity -public class Member { - - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - // @Column(name = "username") - private String name; - - public Long getId() { - return this.id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/main/java/com/dku/springstudy/dto/common/ErrorResponseDTO.java b/src/main/java/com/dku/springstudy/dto/common/ErrorResponseDTO.java new file mode 100644 index 0000000..791f542 --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/common/ErrorResponseDTO.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.dto.common; + +import lombok.Getter; + +@Getter +public class ErrorResponseDTO extends ResponseDTO{ + private final T data; + + public ErrorResponseDTO(T data) { + super(false); + this.data = data; + } +} diff --git a/src/main/java/com/dku/springstudy/dto/common/ExceptionDTO.java b/src/main/java/com/dku/springstudy/dto/common/ExceptionDTO.java new file mode 100644 index 0000000..c26cc2e --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/common/ExceptionDTO.java @@ -0,0 +1,25 @@ +package com.dku.springstudy.dto.common; + +import com.dku.springstudy.exception.CustomException; +import lombok.Getter; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; + +@Getter +public class ExceptionDTO { + private final HttpStatus error; + private final Integer status; + private final String message; + + public ExceptionDTO(CustomException e) { + this.status = e.getErrorCode().getStatus(); + this.error = e.getErrorCode().getError(); + this.message = e.getErrorCode().getMessage(); + } + + public ExceptionDTO(MethodArgumentNotValidException e) { + this.error = (HttpStatus) e.getStatusCode(); + this.status = this.error.value(); + this.message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); + } +} diff --git a/src/main/java/com/dku/springstudy/dto/common/ResponseDTO.java b/src/main/java/com/dku/springstudy/dto/common/ResponseDTO.java new file mode 100644 index 0000000..8c61ae5 --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/common/ResponseDTO.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.dto.common; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class ResponseDTO { + private boolean isSuccessful; +} diff --git a/src/main/java/com/dku/springstudy/dto/common/SuccessResponseDTO.java b/src/main/java/com/dku/springstudy/dto/common/SuccessResponseDTO.java new file mode 100644 index 0000000..35fcbcc --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/common/SuccessResponseDTO.java @@ -0,0 +1,13 @@ +package com.dku.springstudy.dto.common; + +import lombok.Getter; + +@Getter +public class SuccessResponseDTO extends ResponseDTO{ + private final T data; + + public SuccessResponseDTO(T data) { + super(true); + this.data = data; + } +} diff --git a/src/main/java/com/dku/springstudy/dto/user/request/LoginRequestDTO.java b/src/main/java/com/dku/springstudy/dto/user/request/LoginRequestDTO.java new file mode 100644 index 0000000..dc4e5c8 --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/request/LoginRequestDTO.java @@ -0,0 +1,18 @@ +package com.dku.springstudy.dto.user.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Getter +public class LoginRequestDTO { + + @Email(message = "Email format does not match") + @NotBlank(message = "Please input email") + private String email; + + @NotBlank(message = "Please input password") + private String password; +} diff --git a/src/main/java/com/dku/springstudy/dto/user/request/LogoutRequestDTO.java b/src/main/java/com/dku/springstudy/dto/user/request/LogoutRequestDTO.java new file mode 100644 index 0000000..926941f --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/request/LogoutRequestDTO.java @@ -0,0 +1,11 @@ +package com.dku.springstudy.dto.user.request; + +// import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class LogoutRequestDTO { + private String token; +} diff --git a/src/main/java/com/dku/springstudy/dto/user/request/SignUpRequestDTO.java b/src/main/java/com/dku/springstudy/dto/user/request/SignUpRequestDTO.java new file mode 100644 index 0000000..eb96e58 --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/request/SignUpRequestDTO.java @@ -0,0 +1,22 @@ +package com.dku.springstudy.dto.user.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Getter +public class SignUpRequestDTO { + + @Email(message = "Email format does not match") + @NotBlank(message = "Please input email") + private String email; + + @NotBlank(message = "Please input password") + private String password; + + @NotBlank(message = "Please input name") + private String name; + +} diff --git a/src/main/java/com/dku/springstudy/dto/user/response/LoginResponseDTO.java b/src/main/java/com/dku/springstudy/dto/user/response/LoginResponseDTO.java new file mode 100644 index 0000000..7190736 --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/response/LoginResponseDTO.java @@ -0,0 +1,15 @@ +package com.dku.springstudy.dto.user.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class LoginResponseDTO { + private String accessToken; + private String refreshToken; + + public LoginResponseDTO LoginResponse(String accessToken, String refreshToken) { + return new LoginResponseDTO(accessToken,refreshToken); + } +} diff --git a/src/main/java/com/dku/springstudy/dto/user/response/LogoutResponseDTO.java b/src/main/java/com/dku/springstudy/dto/user/response/LogoutResponseDTO.java new file mode 100644 index 0000000..fa53bee --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/response/LogoutResponseDTO.java @@ -0,0 +1,21 @@ +package com.dku.springstudy.dto.user.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class LogoutResponseDTO { + private boolean success; + private String message = ""; + + public LogoutResponseDTO(boolean success){ + this.success = success; + } + + public LogoutResponseDTO(boolean success, String message){ + this.success = success; + this.message = message; + } +} diff --git a/src/main/java/com/dku/springstudy/dto/user/response/SignUpResponseDTO.java b/src/main/java/com/dku/springstudy/dto/user/response/SignUpResponseDTO.java new file mode 100644 index 0000000..c3876e2 --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/response/SignUpResponseDTO.java @@ -0,0 +1,16 @@ +package com.dku.springstudy.dto.user.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class SignUpResponseDTO { + private String accessToken; + private String refreshToken; + + public SignUpResponseDTO LoginResponse(String accessToken, String refreshToken) { + return new SignUpResponseDTO(accessToken,refreshToken); + } + +} diff --git a/src/main/java/com/dku/springstudy/dto/user/response/TokenResponseDTO.java b/src/main/java/com/dku/springstudy/dto/user/response/TokenResponseDTO.java new file mode 100644 index 0000000..9f15aac --- /dev/null +++ b/src/main/java/com/dku/springstudy/dto/user/response/TokenResponseDTO.java @@ -0,0 +1,9 @@ +package com.dku.springstudy.dto.user.response; + +import lombok.Data; + +@Data +public class TokenResponseDTO { + private final String atk; + private final String rtk; +} diff --git a/src/main/java/com/dku/springstudy/exception/CustomException.java b/src/main/java/com/dku/springstudy/exception/CustomException.java new file mode 100644 index 0000000..925a963 --- /dev/null +++ b/src/main/java/com/dku/springstudy/exception/CustomException.java @@ -0,0 +1,10 @@ +package com.dku.springstudy.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class CustomException extends RuntimeException { + ErrorCode errorCode; +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/exception/ErrorCode.java b/src/main/java/com/dku/springstudy/exception/ErrorCode.java new file mode 100644 index 0000000..1c89df9 --- /dev/null +++ b/src/main/java/com/dku/springstudy/exception/ErrorCode.java @@ -0,0 +1,20 @@ +package com.dku.springstudy.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ErrorCode { + USER_NOT_FOUND_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.value(), "User not found"), + USER_ALREADY_EXIST_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.value(), "User already exist"), + USER_PASSWORD_INCORRECT_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.value(), "User password incorrect"), + EXPIRED_TOKEN_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.value(), "Expired JWT token"), + INVALID_TOKEN_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.value(), "Invalid JWT token") + ; + + private final HttpStatus error; + private final Integer status; + private final String message; +} diff --git a/src/main/java/com/dku/springstudy/exception/JwtTokenError.java b/src/main/java/com/dku/springstudy/exception/JwtTokenError.java new file mode 100644 index 0000000..aab80d9 --- /dev/null +++ b/src/main/java/com/dku/springstudy/exception/JwtTokenError.java @@ -0,0 +1,12 @@ +package com.dku.springstudy.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public class JwtTokenError { + private String message; + private HttpStatus status; +} diff --git a/src/main/java/com/dku/springstudy/exception/Message.java b/src/main/java/com/dku/springstudy/exception/Message.java new file mode 100644 index 0000000..adce9b4 --- /dev/null +++ b/src/main/java/com/dku/springstudy/exception/Message.java @@ -0,0 +1,9 @@ +package com.dku.springstudy.exception; + +public class Message { + public static final String JWT_TOKEN_EXPIRED = "만료된 JWT 토큰 만료"; + public static final String JWT_UNSUPPORTED = "미지원하는 JWT 토큰 미지원"; + public static final String JWT_MALFORMED = "올바르지 않은 JWT 토큰"; + public static final String JWT_SIGNATURE = "올바르지 않은 Signature"; + public static final String JWT_ILLEGAL_ARGUMENT = "올바르지 않은 정보"; +} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/model/User.java b/src/main/java/com/dku/springstudy/model/User.java new file mode 100644 index 0000000..8e8c0c2 --- /dev/null +++ b/src/main/java/com/dku/springstudy/model/User.java @@ -0,0 +1,34 @@ +package com.dku.springstudy.model; + +import jakarta.persistence.*; +import lombok.*; + +import java.sql.Timestamp; + +@Entity +@Getter //Lombok +@Setter //Lombok +@ToString //Lombok +@Table(name = "USERS") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class User { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + @Column(name = "Name") + private String name; + @Column(name = "Email") + private String email; + @Column(name = "Password") + private String password; + @Column(name = "Image") + private String imageURL; + @Column(name = "Created") + private Timestamp created; + @Column(name = "Updated") + private Timestamp updated; + @Column(name = "Status") + private String status; +} diff --git a/src/main/java/com/dku/springstudy/repository/MemberRepository.java b/src/main/java/com/dku/springstudy/repository/MemberRepository.java deleted file mode 100644 index 9c1f548..0000000 --- a/src/main/java/com/dku/springstudy/repository/MemberRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.dku.springstudy.repository; - -import java.util.List; -import java.util.Optional; - -import com.dku.springstudy.domain.Member; - -public interface MemberRepository { - Member save(Member member); - Optional findById(Long id); - Optional findByName(String name); - List findAll(); -} diff --git a/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java b/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java deleted file mode 100644 index b652184..0000000 --- a/src/main/java/com/dku/springstudy/repository/MemoryMemberRepository.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.dku.springstudy.repository; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import com.dku.springstudy.domain.Member; - -public class MemoryMemberRepository implements MemberRepository { - - private static Map store = new HashMap<>(); - private static long sequence = 0L; - - @Override - public Member save(Member member) { - member.setId(++sequence); - store.put(member.getId(), member); - - return member; - } - - @Override - public Optional findById(Long id) { - return Optional.ofNullable(store.get(id)); - } - - @Override - public Optional findByName(String name) { - return store.values().stream() - .filter(member -> member.getName().equals(name)) - .findAny(); - } - - @Override - public List findAll() { - return new ArrayList<>(store.values()); - } -} diff --git a/src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java b/src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java deleted file mode 100644 index 53f54ac..0000000 --- a/src/main/java/com/dku/springstudy/repository/SpringDataMemberRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.dku.springstudy.repository; - -import java.util.Optional; - -import org.springframework.data.jpa.repository.JpaRepository; - -import com.dku.springstudy.domain.Member; - -public interface SpringDataMemberRepository extends JpaRepository, MemberRepository{ - - @Override - public Optional findByName(String name); -} \ No newline at end of file diff --git a/src/main/java/com/dku/springstudy/repository/UserRepository.java b/src/main/java/com/dku/springstudy/repository/UserRepository.java new file mode 100644 index 0000000..e6aef26 --- /dev/null +++ b/src/main/java/com/dku/springstudy/repository/UserRepository.java @@ -0,0 +1,50 @@ +package com.dku.springstudy.repository; + +import com.dku.springstudy.model.User; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityTransaction; +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.hibernate.Session; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@RequiredArgsConstructor +@Transactional +public class UserRepository { + private final EntityManager entityManager; + + public void save(User user){ + entityManager.persist(user); + } + + public void remove(User user){ + Session session = entityManager.unwrap(Session.class); + session.remove(entityManager.contains(user) ? user : entityManager.merge(user)); + session.flush(); + entityManager.close(); + } + + public Optional findById(Long id){ + User user = entityManager.find(User.class, id); + + return Optional.ofNullable(user); + } + + public Optional findByName(String name) { + return entityManager. + createQuery("select m from user m where m.name = :name", + User.class) + .setParameter("name", name) + .getResultList().stream().findAny(); + } + + public Optional findByEmail(String email){ + return entityManager. + createQuery("select m from user m where m.email = :email", User.class) + .setParameter("email", email) + .getResultList().stream().findAny(); + } +} diff --git a/src/main/java/com/dku/springstudy/security/CustomUserDetailService.java b/src/main/java/com/dku/springstudy/security/CustomUserDetailService.java new file mode 100644 index 0000000..eb3f7a5 --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/CustomUserDetailService.java @@ -0,0 +1,24 @@ +package com.dku.springstudy.security; + +import com.dku.springstudy.model.User; +import com.dku.springstudy.exception.CustomException; +import com.dku.springstudy.exception.ErrorCode; +import com.dku.springstudy.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class CustomUserDetailService implements UserDetailsService { + + private final UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws CustomException { + User user = userRepository.findByName(username) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND_ERROR)); + return new CustomUserDetails(user); + } +} diff --git a/src/main/java/com/dku/springstudy/security/CustomUserDetails.java b/src/main/java/com/dku/springstudy/security/CustomUserDetails.java new file mode 100644 index 0000000..687bd4b --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/CustomUserDetails.java @@ -0,0 +1,52 @@ +package com.dku.springstudy.security; + +import com.dku.springstudy.model.User; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +@RequiredArgsConstructor +@AllArgsConstructor +@Getter +public class CustomUserDetails implements UserDetails { + private User user; + + @Override + public Collection getAuthorities() { + return null; + } + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public String getUsername() { + return user.getName(); + } + + @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/security/Interceptor.java b/src/main/java/com/dku/springstudy/security/Interceptor.java new file mode 100644 index 0000000..42feb72 --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/Interceptor.java @@ -0,0 +1,50 @@ +package com.dku.springstudy.security; + +import com.dku.springstudy.dto.common.ErrorResponseDTO; +import com.dku.springstudy.dto.common.SuccessResponseDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.util.ContentCachingResponseWrapper; + +@Slf4j +@RequiredArgsConstructor +@Component +public class Interceptor implements HandlerInterceptor { + private final ObjectMapper objectMapper; + + @Override + public void afterCompletion( + HttpServletRequest request, + HttpServletResponse response, + Object object, + Exception ex) throws Exception { + final ContentCachingResponseWrapper cachingResponse = (ContentCachingResponseWrapper) response; + + if (cachingResponse.getContentType() != null + && (cachingResponse.getContentType().contains("application/json"))) { + + if (cachingResponse.getContentAsByteArray().length != 0) { + + String body = new String(cachingResponse.getContentAsByteArray()); + Object data = objectMapper.readValue(body, Object.class); + + if (body.contains("BAD_REQUEST") || !String.valueOf(response.getStatus()).startsWith("2")) { + ErrorResponseDTO errorResponseDto = new ErrorResponseDTO<>(data); + String wrappedBody = objectMapper.writeValueAsString(errorResponseDto); + cachingResponse.resetBuffer(); + cachingResponse.getOutputStream().write(wrappedBody.getBytes(), 0, wrappedBody.getBytes().length); + } else { + SuccessResponseDTO successResponseDto = new SuccessResponseDTO<>(data); + String wrappedBody = objectMapper.writeValueAsString(successResponseDto); + cachingResponse.resetBuffer(); + cachingResponse.getOutputStream().write(wrappedBody.getBytes(), 0, wrappedBody.getBytes().length); + } + } + } + } +} diff --git a/src/main/java/com/dku/springstudy/security/config/InterceptorConfig.java b/src/main/java/com/dku/springstudy/security/config/InterceptorConfig.java new file mode 100644 index 0000000..2a8939c --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/config/InterceptorConfig.java @@ -0,0 +1,18 @@ +package com.dku.springstudy.security.config; + +import com.dku.springstudy.security.Interceptor; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@RequiredArgsConstructor +public class InterceptorConfig implements WebMvcConfigurer { + private final Interceptor interceptor; + @Override + public void addInterceptors(InterceptorRegistry registry){ + registry.addInterceptor(interceptor) + .addPathPatterns("/**"); + } +} diff --git a/src/main/java/com/dku/springstudy/security/config/RedisRepositoryConfig.java b/src/main/java/com/dku/springstudy/security/config/RedisRepositoryConfig.java new file mode 100644 index 0000000..f665396 --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/config/RedisRepositoryConfig.java @@ -0,0 +1,32 @@ +package com.dku.springstudy.security.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@RequiredArgsConstructor +@Configuration +@EnableRedisRepositories +public class RedisRepositoryConfig { + private final RedisProperties redisProperties; + + @Bean + public RedisConnectionFactory redisConnectionFactory(){ + return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort()); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + return redisTemplate; + } +} diff --git a/src/main/java/com/dku/springstudy/security/config/SecurityConfig.java b/src/main/java/com/dku/springstudy/security/config/SecurityConfig.java new file mode 100644 index 0000000..5d7e7cc --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/config/SecurityConfig.java @@ -0,0 +1,57 @@ +package com.dku.springstudy.security.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +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; + +import com.dku.springstudy.security.jwt.JwtAuthenticationFilter; +import com.dku.springstudy.security.jwt.JwtProvider; + +import jakarta.persistence.PersistenceContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtAuthenticationFilter jwtAuthenticationFilter; + + @Bean + public PasswordEncoder passwordEncoder(){ + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) + throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ + return http + .csrf().disable() + .headers().frameOptions().disable().and() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 토큰 기반 인증이므로 세션 역시 사용하지 않습니다. + .and() + .authorizeHttpRequests(authorize -> authorize + // .requestMatchers(PUBLIC_URI).permitAll() // localhost:8080/test -> 이하는 permitALl -> 허용한다 모두 + // .requestMatchers("/**").permitAll() // localhost:8080/test -> 이하는 permitALl -> 허용한다 모두 + // .requestMatchers("/admin/**").hasRole("ADMIN") + // .requestMatchers("/user/**").hasRole("USER") + .anyRequest().authenticated()) + .addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } +} diff --git a/src/main/java/com/dku/springstudy/security/config/SpringConfig.java b/src/main/java/com/dku/springstudy/security/config/SpringConfig.java new file mode 100644 index 0000000..5f0af73 --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/config/SpringConfig.java @@ -0,0 +1,19 @@ +package com.dku.springstudy.security.config; + +import com.dku.springstudy.repository.UserRepository; +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor +public class SpringConfig { + + private final EntityManager entityManager; + + @Bean + public UserRepository userRepository(){ + return new UserRepository(entityManager); + } +} diff --git a/src/main/java/com/dku/springstudy/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/dku/springstudy/security/jwt/JwtAuthenticationFilter.java new file mode 100644 index 0000000..b730e3e --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/jwt/JwtAuthenticationFilter.java @@ -0,0 +1,75 @@ +package com.dku.springstudy.security.jwt; + +import com.dku.springstudy.model.User; +import com.dku.springstudy.dto.common.ExceptionDTO; +import com.dku.springstudy.exception.CustomException; +import com.dku.springstudy.exception.ErrorCode; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.filter.GenericFilterBean; +import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.ContentCachingResponseWrapper; + +import java.io.IOException; +import java.util.Objects; +import java.util.Optional; + +@RequiredArgsConstructor +@Component +@Slf4j +public class JwtAuthenticationFilter extends GenericFilterBean { + + private final JwtProvider jwtProvider; + private final RedisTemplate redisTemplate; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + try { + ContentCachingRequestWrapper wrappingRequest = new ContentCachingRequestWrapper( + (HttpServletRequest) request); + ContentCachingResponseWrapper wrappingResponse = new ContentCachingResponseWrapper( + (HttpServletResponse) response); + + String accessToken = jwtProvider.resolveToken((HttpServletRequest) request); + + if (accessToken != null) { + if (jwtProvider.validateToken(accessToken)) { + + String isLogout = redisTemplate.opsForValue().get(accessToken); + if (ObjectUtils.isEmpty(isLogout)) { + Authentication authentication = jwtProvider.getAuthentication(accessToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + } else { + throw new CustomException(ErrorCode.INVALID_TOKEN_ERROR); + } + + } else { + throw new CustomException(ErrorCode.EXPIRED_TOKEN_ERROR); + } + } + + chain.doFilter(wrappingRequest, wrappingResponse); + wrappingResponse.copyBodyToResponse(); + } catch (CustomException e) { + HttpServletResponse errorResponse = (HttpServletResponse) response; + errorResponse.setStatus(e.getErrorCode().getStatus()); + errorResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); + ExceptionDTO exceptionDto = new ExceptionDTO(e); + ObjectMapper objectMapper = new ObjectMapper(); + String exceptionMessage = objectMapper.writeValueAsString(exceptionDto); + errorResponse.getWriter().write(exceptionMessage); + } + } +} diff --git a/src/main/java/com/dku/springstudy/security/jwt/JwtProvider.java b/src/main/java/com/dku/springstudy/security/jwt/JwtProvider.java new file mode 100644 index 0000000..4c1a3b0 --- /dev/null +++ b/src/main/java/com/dku/springstudy/security/jwt/JwtProvider.java @@ -0,0 +1,101 @@ +package com.dku.springstudy.security.jwt; + +// 토큰을 생성하고 검증하는 클래스 +// 해당 컴포넌트는 필터클래스에서 사전 검증을 거침 + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Base64; +import java.util.Date; + +@Slf4j +@RequiredArgsConstructor +@Component +public class JwtProvider { + + private String secretKey = "kangho"; + private final UserDetailsService userDetailsService; + + private Key getSigninKey(String secretKey) { + byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8); + return Keys.hmacShaKeyFor(keyBytes); + } + + @PostConstruct + protected void init() { + secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); + } + + public String createToken(Claims claims, long expiredDuration) { + Date createdTime = new Date(); + Date ExpiredTime = new Date(createdTime.getTime() + expiredDuration); + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(createdTime) + .setExpiration(ExpiredTime) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); + } + + public String createAccessToken(String userPK) { + Claims claims = Jwts.claims(); + claims.setSubject(userPK); + long accessTokenValidMilliSecond = 60 * 60 * 1000L; + + return createToken(claims, accessTokenValidMilliSecond); + } + + public String createRefreshToken(String userPK) { + Claims claims = Jwts.claims(); + claims.setSubject(userPK); + long refreshTokenValidMilliSecond = 24 * 60 * 60 * 1000L; + + return createToken(claims, refreshTokenValidMilliSecond); + } + + public Authentication getAuthentication(String token) { + UserDetails userDetails = userDetailsService.loadUserByUsername(this.getUserPk(token)); + return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); + } + + public String getUserPk(String token) { + return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); + } + + public String resolveToken(HttpServletRequest request) { + return request.getHeader("X-AUTH-TOKEN"); + } + + public boolean validateToken(String token){ + try { + Jws claimsJws = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); + return !claimsJws.getBody().getExpiration().before(new Date()); + } catch (Exception e) { + return false; + } + } + + public Long getExpiration(String accessToken){ + + Date expiration = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(accessToken) + .getBody().getExpiration(); + long now = new Date().getTime(); + return expiration.getTime() - now; + } + +} diff --git a/src/main/java/com/dku/springstudy/service/MemberService.java b/src/main/java/com/dku/springstudy/service/MemberService.java deleted file mode 100644 index 3452ae4..0000000 --- a/src/main/java/com/dku/springstudy/service/MemberService.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.dku.springstudy.service; - -import java.util.List; -import java.util.Optional; - -import com.dku.springstudy.domain.Member; -import com.dku.springstudy.repository.MemberRepository; -import com.dku.springstudy.repository.MemoryMemberRepository; - -public class MemberService { - - private final MemberRepository memberRepository = new MemoryMemberRepository(); - - /* 회원 가입 */ - public Long join(Member member) { - validateDuplicateMember(member); - memberRepository.save(member); - - return member.getId(); - } - - private void validateDuplicateMember(Member member) { - memberRepository.findByName(member.getName()) - .ifPresent(m -> { - throw new IllegalThreadStateException("이미 존재하는 회원입니다."); - }); - } - - /* 전체 회원 조회 */ - public List findMembers() { - return memberRepository.findAll(); - } - - public Optional findOne(Long memberId) { - return memberRepository.findById(memberId); - } -} diff --git a/src/main/java/com/dku/springstudy/service/UserService.java b/src/main/java/com/dku/springstudy/service/UserService.java new file mode 100644 index 0000000..c4881e4 --- /dev/null +++ b/src/main/java/com/dku/springstudy/service/UserService.java @@ -0,0 +1,75 @@ +package com.dku.springstudy.service; + + +import com.dku.springstudy.dto.user.request.LoginRequestDTO; +import com.dku.springstudy.dto.user.request.SignUpRequestDTO; +import com.dku.springstudy.dto.user.response.LoginResponseDTO; +import com.dku.springstudy.dto.user.response.LogoutResponseDTO; +import com.dku.springstudy.dto.user.response.SignUpResponseDTO; +import com.dku.springstudy.exception.CustomException; +import com.dku.springstudy.exception.ErrorCode; +import com.dku.springstudy.model.User; +import com.dku.springstudy.repository.UserRepository; +import com.dku.springstudy.security.jwt.JwtProvider; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import java.util.concurrent.TimeUnit; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final JwtProvider jwtProvider; + private final RedisTemplate redisTemplate; + + public SignUpResponseDTO signUp(SignUpRequestDTO membershipRequestDTO){ + User user = User.builder() + .email(membershipRequestDTO.getEmail()) + .name(membershipRequestDTO.getName()) + .password(passwordEncoder.encode(membershipRequestDTO.getPassword())) + .build(); + + userRepository.save(user); + + String loginAccessToken = jwtProvider.createAccessToken(user.getName()); + String loginRefreshToken = jwtProvider.createRefreshToken(user.getName()); + + return new SignUpResponseDTO(loginAccessToken, loginRefreshToken); + } + + public LoginResponseDTO login(LoginRequestDTO loginRequestDTO){ + + User user = userRepository.findByEmail(loginRequestDTO.getEmail()) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND_ERROR)); + + if(passwordEncoder.matches(loginRequestDTO.getPassword(), user.getPassword())) { + String accessToken = jwtProvider.createAccessToken(user.getName()); + String refreshToken = jwtProvider.createRefreshToken(user.getName()); + redisTemplate.opsForValue() + .set(user.getEmail(), refreshToken, + jwtProvider.getExpiration(refreshToken), TimeUnit.MILLISECONDS); + + return new LoginResponseDTO(accessToken, refreshToken); + } else { + throw new CustomException(ErrorCode.USER_PASSWORD_INCORRECT_ERROR); + } + + } + + public LogoutResponseDTO logout(User user, String accessToken){ + try { + Long expiration = jwtProvider.getExpiration(accessToken); + redisTemplate.opsForValue().set(accessToken, "logout", expiration, TimeUnit.MILLISECONDS); + redisTemplate.delete(user.getEmail()); + + return new LogoutResponseDTO(true); + }catch (Exception e){ + return new LogoutResponseDTO(false, e.getMessage()); + } + } +} diff --git a/src/main/resources/DB/carrot.mv.db b/src/main/resources/DB/carrot.mv.db new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0947453..4a97bc4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,25 +1,29 @@ +server: + port: 8080 + spring: - # DB 연결 + application: + name: springstudy + datasource: - # 설치된 H2 DB와 연결 URL url: jdbc:h2:tcp://localhost/~/test - # 접속을 위한 드라이버 driver-class-name: org.h2.Driver - # springboot 2.4 부터는 username이 꼭 있어야합니다. 없으면 에러가 발생합니다. username: sa + jpa: - # JPA가 수행하는 SQL을 볼 수 있다. - show-sql: true - # 객체를 보고 자동으로 테이블 생성 여부. 생성 - create, 비생성 - none - # 테스트이기 때문에 create로 설정하며 - # 실제로는 none 으로 합니다. create이면 기존의 테이블을 전부 밀어버립니다. hibernate: ddl-auto: create - # 콘솔 확인 을 위한 always - output: - ansi: - enabled: always -# 파라미터 확인을 위한 trace + properties: + hibernate: + format_sql: true + show_sql: true + logging: level: - org.hibernate.type: trace \ No newline at end of file + com.dku.springstudy: DEBUG + +jwt: + secret-key: kangho + + + diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html deleted file mode 100644 index 0ffeef0..0000000 --- a/src/main/resources/static/index.html +++ /dev/null @@ -1 +0,0 @@ -

JPA Study DKU

\ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html deleted file mode 100644 index df3f27c..0000000 --- a/src/main/resources/templates/home.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - Home - - -
-

Hello Spirng JPA Study

-

- Join - List -

-
- - \ No newline at end of file diff --git a/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java b/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java index c509e0a..79d9975 100644 --- a/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java +++ b/src/test/java/com/dku/springstudy/SpringStudyApplicationTests.java @@ -1,28 +1,13 @@ package com.dku.springstudy; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import com.dku.springstudy.domain.Member; -import com.dku.springstudy.repository.MemberRepository; -import com.dku.springstudy.repository.MemoryMemberRepository; - @SpringBootTest class SpringStudyApplicationTests { - MemberRepository memberRepository = new MemoryMemberRepository(); - - @Test - void 회원가입() { - // 멤버 저장 - Member member = new Member(); - member.setName("skyepodium"); - memberRepository.save(member); + @Test + void contextLoads() { + } - // 저장한 멤버 아이디로 검색 - Member findMember = memberRepository.findById(member.getId()).get(); - Assertions.assertThat(member.getName()).isEqualTo(findMember.getName()); - } } From 93b0d5ba0f3525a6b3de41d32795d8ac7b43ee60 Mon Sep 17 00:00:00 2001 From: Kangho Date: Mon, 13 Feb 2023 03:32:12 +0900 Subject: [PATCH 5/5] ahah --- .../java/com/dku/springstudy/controller/UserController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/dku/springstudy/controller/UserController.java b/src/main/java/com/dku/springstudy/controller/UserController.java index 580e750..d17dc9f 100644 --- a/src/main/java/com/dku/springstudy/controller/UserController.java +++ b/src/main/java/com/dku/springstudy/controller/UserController.java @@ -22,6 +22,8 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +// why not commit + @RestController @RequiredArgsConstructor public class UserController {