From 8b2d854203ee5e17dc5368c1c7312a6a14122bd8 Mon Sep 17 00:00:00 2001 From: jiyun Date: Mon, 6 May 2024 10:54:55 +0900 Subject: [PATCH 01/13] [Remove] Removing some file --- .idea/misc.xml | 1 - .../todoListAPI/hyeonseung/.idea/.gitignore | 8 - .../todoListAPI/hyeonseung/.idea/compiler.xml | 16 -- .../hyeonseung/.idea/encodings.xml | 4 - .../todoListAPI/hyeonseung/.idea/gradle.xml | 16 -- .../hyeonseung/.idea/hyeonseung.iml | 9 - .../hyeonseung/.idea/jarRepositories.xml | 20 -- .../todoListAPI/hyeonseung/.idea/misc.xml | 10 - .../todoListAPI/hyeonseung/.idea/modules.xml | 9 - .../.idea/modules/todolist.main.iml | 8 - contents/todoListAPI/hyeonseung/.idea/vcs.xml | 6 - .../hyeonseung/todolist/.gitignore | 37 --- .../todoListAPI/hyeonseung/todolist/ERD.png | Bin 168212 -> 0 bytes .../hyeonseung/todolist/build.gradle | 40 --- .../gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../todoListAPI/hyeonseung/todolist/gradlew | 249 ------------------ .../hyeonseung/todolist/gradlew.bat | 92 ------- .../hyeonseung/todolist/settings.gradle | 1 - .../todolist/TodolistApplication.java | 16 -- .../todolist/config/SwaggerConfig.java | 25 -- .../todolist/controller/MemberController.java | 65 ----- .../todolist/controller/TodoController.java | 58 ---- .../todolist/todolist/domain/BaseEntity.java | 34 --- .../com/todolist/todolist/domain/Member.java | 44 ---- .../com/todolist/todolist/domain/Todo.java | 63 ----- .../todolist/todolist/dto/EntityMapper.java | 6 - .../todolist/dto/member/MemberMapper.java | 26 -- .../todolist/dto/member/MemberRequestDto.java | 32 --- .../dto/member/MemberResponseDto.java | 22 -- .../todolist/dto/todo/TodoMapper.java | 28 -- .../todolist/dto/todo/TodoRequestDto.java | 20 -- .../todolist/dto/todo/TodoResponseDto.java | 21 -- .../todolist/repository/MemberRepository.java | 15 -- .../todolist/repository/TodoRepository.java | 17 -- .../todolist/service/MemberService.java | 91 ------- .../todolist/service/TodoService.java | 110 -------- .../src/main/resources/application.properties | 21 -- .../todolist/TodolistApplicationTests.java | 13 - contents/todoListAPI/kangwook/README.md | 4 - .../todoListAPI/kangwook/practice/.gitignore | 39 --- .../kangwook/practice/build.gradle | 63 ----- .../gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../todoListAPI/kangwook/practice/gradlew | 249 ------------------ .../todoListAPI/kangwook/practice/gradlew.bat | 92 ------- .../kangwook/practice/settings.gradle | 1 - .../practice/domain/QBaseEntity.java | 39 --- .../appcenter/practice/domain/QComment.java | 63 ----- .../appcenter/practice/domain/QMember.java | 56 ---- .../com/appcenter/practice/domain/QTodo.java | 65 ----- .../practice/PracticeApplication.java | 16 -- .../practice/config/QueryDslConfig.java | 19 -- .../controller/CommentController.java | 51 ---- .../practice/controller/MemberController.java | 27 -- .../practice/controller/TodoController.java | 56 ---- .../appcenter/practice/domain/BaseEntity.java | 23 -- .../appcenter/practice/domain/Comment.java | 40 --- .../com/appcenter/practice/domain/Member.java | 51 ---- .../com/appcenter/practice/domain/Role.java | 5 - .../com/appcenter/practice/domain/Todo.java | 50 ---- .../dto/reqeust/comment/AddCommentReq.java | 19 -- .../dto/reqeust/comment/UpdateCommentReq.java | 9 - .../dto/reqeust/member/SignupMemberReq.java | 21 -- .../practice/dto/reqeust/todo/AddTodoReq.java | 19 -- .../dto/reqeust/todo/UpdateTodoReq.java | 9 - .../practice/dto/response/CommonResponse.java | 25 -- .../dto/response/comment/ReadCommentRes.java | 22 -- .../dto/response/todo/ReadTodoRes.java | 23 -- .../repository/CommentRepository.java | 7 - .../practice/repository/MemberRepository.java | 11 - .../practice/repository/TodoRepository.java | 7 - .../practice/service/CommentService.java | 60 ----- .../practice/service/MemberService.java | 24 -- .../practice/service/TodoService.java | 67 ----- .../src/main/resources/application.properties | 19 -- .../practice/PracticeApplicationTests.java | 13 - contents/todoListAPI/seungseop/README.md | 6 - .../todoListAPI/seungseop/todolist/.gitignore | 37 --- .../seungseop/todolist/build.gradle | 81 ------ .../gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../todoListAPI/seungseop/todolist/gradlew | 249 ------------------ .../seungseop/todolist/gradlew.bat | 92 ------- .../seungseop/todolist/settings.gradle | 1 - .../todolist/TodolistApplication.java | 14 - .../todolist/config/QueryDslConfig.java | 23 -- .../todolist/config/SwaggerConfig.java | 25 -- .../todolist/controller/FolderController.java | 56 ---- .../todolist/controller/TodoController.java | 73 ----- .../todolist/controller/UserController.java | 63 ----- .../serverstudy/todolist/domain/Folder.java | 35 --- .../serverstudy/todolist/domain/Priority.java | 26 -- .../serverstudy/todolist/domain/Progress.java | 21 -- .../com/serverstudy/todolist/domain/Role.java | 14 - .../com/serverstudy/todolist/domain/Todo.java | 83 ------ .../com/serverstudy/todolist/domain/User.java | 61 ----- .../todolist/dto/request/FolderReq.java | 33 --- .../todolist/dto/request/TodoReq.java | 103 -------- .../todolist/dto/request/UserReq.java | 45 ---- .../todolist/dto/response/FolderRes.java | 21 -- .../todolist/dto/response/TodoRes.java | 44 ---- .../todolist/dto/response/UserRes.java | 21 -- .../todolist/repository/FolderRepository.java | 13 - .../repository/TodoCustomRepository.java | 12 - .../repository/TodoCustomRepositoryImpl.java | 43 --- .../todolist/repository/TodoRepository.java | 18 -- .../todolist/repository/UserRepository.java | 8 - .../todolist/service/FolderService.java | 77 ------ .../todolist/service/TodoService.java | 163 ------------ .../todolist/service/UserService.java | 85 ------ .../src/main/resources/application.properties | 31 --- 112 files changed, 4315 deletions(-) delete mode 100644 contents/todoListAPI/hyeonseung/.idea/.gitignore delete mode 100644 contents/todoListAPI/hyeonseung/.idea/compiler.xml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/encodings.xml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/gradle.xml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/hyeonseung.iml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/jarRepositories.xml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/misc.xml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/modules.xml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/modules/todolist.main.iml delete mode 100644 contents/todoListAPI/hyeonseung/.idea/vcs.xml delete mode 100644 contents/todoListAPI/hyeonseung/todolist/.gitignore delete mode 100644 contents/todoListAPI/hyeonseung/todolist/ERD.png delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build.gradle delete mode 100644 contents/todoListAPI/hyeonseung/todolist/gradle/wrapper/gradle-wrapper.jar delete mode 100644 contents/todoListAPI/hyeonseung/todolist/gradle/wrapper/gradle-wrapper.properties delete mode 100755 contents/todoListAPI/hyeonseung/todolist/gradlew delete mode 100644 contents/todoListAPI/hyeonseung/todolist/gradlew.bat delete mode 100644 contents/todoListAPI/hyeonseung/todolist/settings.gradle delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/resources/application.properties delete mode 100644 contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/TodolistApplicationTests.java delete mode 100644 contents/todoListAPI/kangwook/README.md delete mode 100644 contents/todoListAPI/kangwook/practice/.gitignore delete mode 100644 contents/todoListAPI/kangwook/practice/build.gradle delete mode 100644 contents/todoListAPI/kangwook/practice/gradle/wrapper/gradle-wrapper.jar delete mode 100644 contents/todoListAPI/kangwook/practice/gradle/wrapper/gradle-wrapper.properties delete mode 100644 contents/todoListAPI/kangwook/practice/gradlew delete mode 100644 contents/todoListAPI/kangwook/practice/gradlew.bat delete mode 100644 contents/todoListAPI/kangwook/practice/settings.gradle delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QBaseEntity.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QComment.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QMember.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QTodo.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/PracticeApplication.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/config/QueryDslConfig.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/CommentController.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/MemberController.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/TodoController.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/BaseEntity.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Comment.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Member.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Role.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Todo.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/AddCommentReq.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/UpdateCommentReq.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/member/SignupMemberReq.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/AddTodoReq.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/UpdateTodoReq.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/CommonResponse.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/comment/ReadCommentRes.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/todo/ReadTodoRes.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/CommentRepository.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/MemberRepository.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/TodoRepository.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/CommentService.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/MemberService.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/TodoService.java delete mode 100644 contents/todoListAPI/kangwook/practice/src/main/resources/application.properties delete mode 100644 contents/todoListAPI/kangwook/practice/src/test/java/com/appcenter/practice/PracticeApplicationTests.java delete mode 100644 contents/todoListAPI/seungseop/README.md delete mode 100644 contents/todoListAPI/seungseop/todolist/.gitignore delete mode 100644 contents/todoListAPI/seungseop/todolist/build.gradle delete mode 100644 contents/todoListAPI/seungseop/todolist/gradle/wrapper/gradle-wrapper.jar delete mode 100644 contents/todoListAPI/seungseop/todolist/gradle/wrapper/gradle-wrapper.properties delete mode 100644 contents/todoListAPI/seungseop/todolist/gradlew delete mode 100644 contents/todoListAPI/seungseop/todolist/gradlew.bat delete mode 100644 contents/todoListAPI/seungseop/todolist/settings.gradle delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/TodolistApplication.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/QueryDslConfig.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/SwaggerConfig.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/FolderController.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/TodoController.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/UserController.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Folder.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Priority.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Progress.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Role.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Todo.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/User.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/FolderReq.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/TodoReq.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/UserReq.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/FolderRes.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/TodoRes.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/UserRes.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/FolderRepository.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepository.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepositoryImpl.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoRepository.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/UserRepository.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/FolderService.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/TodoService.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/UserService.java delete mode 100644 contents/todoListAPI/seungseop/todolist/src/main/resources/application.properties diff --git a/.idea/misc.xml b/.idea/misc.xml index 639900d..6e86672 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/contents/todoListAPI/hyeonseung/.idea/.gitignore b/contents/todoListAPI/hyeonseung/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/contents/todoListAPI/hyeonseung/.idea/compiler.xml b/contents/todoListAPI/hyeonseung/.idea/compiler.xml deleted file mode 100644 index b10d681..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/compiler.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/encodings.xml b/contents/todoListAPI/hyeonseung/.idea/encodings.xml deleted file mode 100644 index da0415a..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/gradle.xml b/contents/todoListAPI/hyeonseung/.idea/gradle.xml deleted file mode 100644 index ab9768a..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/gradle.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/hyeonseung.iml b/contents/todoListAPI/hyeonseung/.idea/hyeonseung.iml deleted file mode 100644 index d6ebd48..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/hyeonseung.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/jarRepositories.xml b/contents/todoListAPI/hyeonseung/.idea/jarRepositories.xml deleted file mode 100644 index fdc392f..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/jarRepositories.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/misc.xml b/contents/todoListAPI/hyeonseung/.idea/misc.xml deleted file mode 100644 index a11d17e..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/modules.xml b/contents/todoListAPI/hyeonseung/.idea/modules.xml deleted file mode 100644 index a62df77..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/modules/todolist.main.iml b/contents/todoListAPI/hyeonseung/.idea/modules/todolist.main.iml deleted file mode 100644 index 5019b9d..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/modules/todolist.main.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/.idea/vcs.xml b/contents/todoListAPI/hyeonseung/.idea/vcs.xml deleted file mode 100644 index c2365ab..0000000 --- a/contents/todoListAPI/hyeonseung/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/.gitignore b/contents/todoListAPI/hyeonseung/todolist/.gitignore deleted file mode 100644 index c2065bc..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ diff --git a/contents/todoListAPI/hyeonseung/todolist/ERD.png b/contents/todoListAPI/hyeonseung/todolist/ERD.png deleted file mode 100644 index 591d49af1d1738614c77b49b8224507f36bf0cd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168212 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/contents/todoListAPI/hyeonseung/todolist/gradlew.bat b/contents/todoListAPI/hyeonseung/todolist/gradlew.bat deleted file mode 100644 index 7101f8e..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/contents/todoListAPI/hyeonseung/todolist/settings.gradle b/contents/todoListAPI/hyeonseung/todolist/settings.gradle deleted file mode 100644 index 59357f0..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'todolist' diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java deleted file mode 100644 index 9793ac7..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.todolist.todolist; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; - - -@SpringBootApplication -@EnableJpaAuditing -public class TodolistApplication { - - public static void main(String[] args) { - SpringApplication.run(TodolistApplication.class, args); - } - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java deleted file mode 100644 index 5027e64..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.todolist.todolist.config; - - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SwaggerConfig { - @Bean - public OpenAPI openAPI() { - return new OpenAPI() - .components(new Components()) - .info(apiInfo()); - } - - private Info apiInfo() { - return new Info() - .title("Swagger API Test") - .description("Springdoc을 사용한 Swagger Api test") - .version("1.0.0"); - } -} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java deleted file mode 100644 index b6acede..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.todolist.todolist.controller; - -import com.todolist.todolist.dto.member.MemberResponseDto; -import com.todolist.todolist.dto.member.MemberRequestDto; -import com.todolist.todolist.service.MemberService; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.Errors; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RequestMapping("api/members") -@RestController -@RequiredArgsConstructor -public class MemberController { - private final MemberService memberService; - - // 회원가입 - @PostMapping - public ResponseEntity createMember(@Valid @RequestBody MemberRequestDto request, Errors errors) { - - if(errors.hasErrors()){ - System.out.println("에러"); - } - MemberResponseDto responseDto = memberService.create(request); - - return new ResponseEntity(responseDto,HttpStatus.CREATED); - } - - // 회원 정보 수정 - @PutMapping("/{memberId}") - public ResponseEntity updateMember(@Valid @RequestBody MemberRequestDto request, @PathVariable Long memberId){ - MemberResponseDto responseDto = memberService.update(memberId, request); - - return new ResponseEntity<>(responseDto,HttpStatus.OK); - } - - // 회원 검색 - 단일조회 - @GetMapping("/{memberId}") - public ResponseEntity readOneMember(@PathVariable Long memberId){ - MemberResponseDto responseDto = memberService.searchId(memberId); - - return new ResponseEntity(responseDto,HttpStatus.OK); - } - - // 회원 검색 - 전체 - @GetMapping - public ResponseEntity> readAllMember(){ - List responseDto = memberService.searchAll(); - - return new ResponseEntity<>(responseDto,HttpStatus.OK); - } - - // 회원 삭제 - @DeleteMapping("/{memberId}") - public ResponseEntity delete(@PathVariable Long memberId){ - memberService.delete(memberId); - return ResponseEntity.noContent().build(); - } - - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java deleted file mode 100644 index 7ec8078..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.todolist.todolist.controller; - -import com.todolist.todolist.dto.todo.TodoRequestDto; -import com.todolist.todolist.dto.todo.TodoResponseDto; -import com.todolist.todolist.service.TodoService; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RequestMapping("/todo") -@RestController -@RequiredArgsConstructor -public class TodoController { - private final TodoService todoService; - - // 회원에 따른 Todo 추가 - @PostMapping("/{memberId}") - public ResponseEntity addTodo(@Valid @PathVariable Long memberId, @RequestBody TodoRequestDto request){ - TodoResponseDto responseDto = todoService.add(memberId, request); - - return new ResponseEntity(responseDto, HttpStatus.CREATED); - } - - // Todo 전체 목록 조회 - @GetMapping - public ResponseEntity> readAll(){ - List responseDto = todoService.searchAll(); - - return new ResponseEntity<>(responseDto,HttpStatus.OK); - // return new ResponseEntity(responseDto_list,HttpStatus.OK); - } - - // 회원-> Todo 목록 조회 - @GetMapping("/{memberId}") - public ResponseEntity> readMemberTodo (@PathVariable Long memberId){ - List responseDto = todoService.searchById(memberId); - return new ResponseEntity<>(responseDto, HttpStatus.CREATED); - } - - // Todo 수정 - @PutMapping("/{memberId}/{todoId}") - public ResponseEntity update(@Valid @PathVariable Long memberId, @PathVariable Long todoId, @RequestBody TodoRequestDto request){ - TodoResponseDto responseDto = todoService.update(memberId,todoId,request); - - return ResponseEntity.status(200).body(responseDto); - } - - // Todo 단일 삭제 - @DeleteMapping("/{todoId}") - public ResponseEntity deleteOne(@PathVariable Long todoId){ - todoService.delete(todoId); - return ResponseEntity.noContent().build(); - } -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java deleted file mode 100644 index e370c0e..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.todolist.todolist.domain; - -import jakarta.persistence.Column; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.MappedSuperclass; -import lombok.Getter; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedBy; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import java.time.LocalDateTime; - -/* -생성시간, 수정시간 공통 항목 엔티티 - */ -@MappedSuperclass -@EntityListeners(AuditingEntityListener.class) -@Getter -// 추상클래스 -> 이를 추상클래스로 상속할 때, @CreatedDate, @ModifiedDate 등을 컬럼으로 인식 -public abstract class BaseEntity { - - @CreatedDate - @Column(updatable = false) - private LocalDateTime createdAt; - - @LastModifiedBy - @Column(insertable = false) - private LocalDateTime modifiedAt; - - @Column(insertable = false) - private LocalDateTime deletedAt; - - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java deleted file mode 100644 index 93ac840..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.todolist.todolist.domain; - -import jakarta.persistence.*; -import lombok.*; - -import java.util.*; - -@Entity -@Getter -@Builder // Builder & AllArgs -> Mapper 에서 id 를 찾아야 함.. -@AllArgsConstructor -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Member extends BaseEntity{ - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "member_id") - private Long id; - - @Column(nullable = false) - private String name; - - @Column(nullable = false) - private String loginId; - - @Column(nullable = false) - private String password; - - @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) - // 1:N ] N쪽이 FK가진 연관관계의 주인 - private List todoList = new ArrayList<>(); - - public void updateLoginId(String loginId){ - this.loginId = loginId; - } - - public void updatePassword(String Password){ - this.password = password; - } - - public void updateName(String name){ - this.name = name; - } -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java deleted file mode 100644 index 317a63c..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.todolist.todolist.domain; - -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -@Entity -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Getter -public class Todo extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private String title; - - private String contents; - - private Boolean isCompleted; - - private LocalDateTime dueAt; - - // 할일을 작성한 멤버 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; - - @Builder - protected Todo(String title, String contents, Boolean isCompleted, LocalDateTime dueAt, Member member) { - this.title = title; - this.contents = contents; - this.isCompleted = isCompleted; - this.dueAt = dueAt; - this.member = member; - } - - public void matchMember(Member member){ - this.member = member; - } - - public void updateTitle(String title) { - if(title != null) this.title = title; - } - - public void updateContents(String contents) { - if(contents != null) this.contents = contents; - } - - public void updateIsCompleted(Boolean isCompleted) { - if(isCompleted != null) this.isCompleted = isCompleted; - } - - public void updateDueAt(LocalDateTime dueAt) { - if(dueAt != null) this.dueAt = dueAt; - } - -} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java deleted file mode 100644 index e7e192b..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.todolist.todolist.dto; - -public interface EntityMapper { - ENTITY toEntity(final REQUEST request); - RESPONSE toDto(final ENTITY entity); -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java deleted file mode 100644 index 171e45b..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.todolist.todolist.dto.member; - -import com.todolist.todolist.domain.Member; -import com.todolist.todolist.dto.EntityMapper; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - - -/* Mapper 사용 -Service와 Controller 의 목적을 정확히 구분하고, -이들 사이에서 Entity <-> DTO 간의 객체 mapping을 편하게 도와주기 위해 - */ -@Mapper -public interface MemberMapper extends EntityMapper { - // 해당하는 INSTANCE가 MemberMapper을 상속받아, MemberMapperImpl로 구현하게 될것. - MemberMapper INSTANCE = Mappers.getMapper(MemberMapper.class); - - @Override - @Mapping(target = "id", ignore = true) - @Mapping(target = "todoList",ignore = true) // Member 엔티티가 @Builder 이다 보니. 제거 대상 - Member toEntity(final MemberRequestDto requestDto); - @Override - MemberResponseDto toDto(final Member member); - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java deleted file mode 100644 index 6e6272e..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.todolist.todolist.dto.member; - -import com.todolist.todolist.domain.Member; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@AllArgsConstructor -@NoArgsConstructor -public class MemberRequestDto { - - @NotBlank (message = "이름은 필수 입력값입니다.") - @Pattern(message = "잘못된 이름 형식입니다.", - regexp = "^(?:[가-힣]{3,6}|[A-Za-z]{3,12})$") - private String name; - - @NotBlank(message = "아이디는 필수 입력값입니다.") - @Pattern(message = "잘못된 아이디 형식입니다.", - regexp = "^[a-z0-9]{3,12}" ) - private String loginId; - - @NotBlank(message = "비밀번호는 필수 입력값입니다.") - @Pattern(message = "비밀번호는 영문 대,소문자와 숫자, 특수기호가 적어도 1개 이상씩 포함된 8자 ~ 15자의 비밀번호여야 합니다.", - regexp = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%*#?&])[A-Za-z[0-9]$@$!%*#?&]{8,15}") - private String password; - - - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java deleted file mode 100644 index 2d43e44..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.todolist.todolist.dto.member; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Builder -public class MemberResponseDto { - - private Long id; - private String name; - private String loginId; - private LocalDateTime createdAt; - private LocalDateTime modifiedAt; - - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java deleted file mode 100644 index 5aa4fda..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.todolist.todolist.dto.todo; - -import com.todolist.todolist.domain.Member; -import com.todolist.todolist.domain.Todo; -import com.todolist.todolist.dto.EntityMapper; -import jakarta.persistence.Column; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - -import java.time.LocalDateTime; - -@Mapper -public interface TodoMapper extends EntityMapper { - - TodoMapper INSTANCE = Mappers.getMapper(TodoMapper.class); - - @Override - @Mapping(target = "member", ignore = true) - Todo toEntity(final TodoRequestDto todoRequestDto); - - @Override - @Mapping(target = "member", ignore = true) - TodoResponseDto toDto(final Todo todo); -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java deleted file mode 100644 index 463a304..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.todolist.todolist.dto.todo; - -import com.todolist.todolist.domain.Member; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Builder -public class TodoRequestDto { - private String title; - private String contents; - private boolean isCompleted; - private LocalDateTime dueAt; -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java deleted file mode 100644 index d626b6d..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.todolist.todolist.dto.todo; - -import com.todolist.todolist.domain.Member; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class TodoResponseDto { - private Long id; - private String title; - private String contents; - private boolean isCompleted; - private LocalDateTime dueAt; - private Member member; -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java deleted file mode 100644 index 31cf469..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.todolist.todolist.repository; - -import com.todolist.todolist.domain.Member; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; -import java.util.Optional; - -public interface MemberRepository extends JpaRepository { - - Optional findByLoginId(String loginId); - Optional findById(Long id); - - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java deleted file mode 100644 index 577ab36..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.todolist.todolist.repository; - -import com.todolist.todolist.domain.Member; -import com.todolist.todolist.domain.Todo; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; -import java.util.Optional; - -public interface TodoRepository extends JpaRepository { - - List findAll (); - Optional findById(Long id); - - List findByMember(Member member); - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java deleted file mode 100644 index 33d1f1c..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.todolist.todolist.service; - -import com.todolist.todolist.domain.Member; -import com.todolist.todolist.dto.member.MemberMapper; -import com.todolist.todolist.dto.member.MemberRequestDto; -import com.todolist.todolist.dto.member.MemberResponseDto; -import com.todolist.todolist.repository.MemberRepository; - -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -public class MemberService { - - private final MemberRepository memberRepository; - - /* - 1. 가입 - 2. 로그인 - 3. 회원조회 - 4. 회원전체조회 - 4. 수정 - 5. 삭제 - */ - - // 1. 회원가입 - public MemberResponseDto create(MemberRequestDto request) { - Member member = MemberMapper.INSTANCE.toEntity(request); - memberRepository.save(member); - - return MemberMapper.INSTANCE.toDto(member); - - } - - // 2. 로그인 - public boolean signIn(MemberRequestDto request){ - Member member = memberRepository.findByLoginId(request.getLoginId()) - .orElseThrow(()-> new ResponseStatusException(HttpStatus.NOT_FOUND)); - return member.getPassword().equals(request.getPassword()); - } - - // 3. 회원 검색 - public MemberResponseDto searchId(Long id){ - Member member = memberRepository.findById(id) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - - return MemberMapper.INSTANCE.toDto(member); - } - - // 4. 회원 전체 검색 - public List searchAll(){ - List members = memberRepository.findAll(); - List memberList = new ArrayList<>(); - - return members.stream() - .map(MemberMapper.INSTANCE::toDto) - .collect(Collectors.toList()); - -// for (Member member : members){ -// MemberResponseDto responseDto = MemberMapper.INSTANCE.toDto(member); -// memberList.add(responseDto); -// } -// return memberList; - } - - // 5. 정보수정 - public MemberResponseDto update(Long id, MemberRequestDto request){ - Member member = memberRepository.findById(id) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - member.updateLoginId(request.getLoginId()); ; - member.updatePassword(request.getPassword()); - member.updateName(request.getName()); - memberRepository.save(member); - - return MemberMapper.INSTANCE.toDto(member); - } - - // 6. 회원 삭제 - public void delete(Long id){ - memberRepository.deleteById(id); - - } - -} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java deleted file mode 100644 index da387f2..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.todolist.todolist.service; - -import com.todolist.todolist.domain.Member; -import com.todolist.todolist.domain.Todo; -import com.todolist.todolist.dto.todo.TodoMapper; -import com.todolist.todolist.dto.todo.TodoRequestDto; -import com.todolist.todolist.dto.todo.TodoResponseDto; -import com.todolist.todolist.repository.MemberRepository; -import com.todolist.todolist.repository.TodoRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -public class TodoService { - - private final TodoRepository todoRepository; - private final MemberRepository memberRepository; - - /* - 1. Todo 추가 - 2. Todo 수정 - 3. Todo 전체 조회 - 4. Todo 리스트 조회 (memberId로 조회) - 5. Todo 삭제 - 6. Todo 전체 삭제 - */ - - // 1. Todo 추가 - public TodoResponseDto add(Long id,TodoRequestDto requestDto) { - Todo todo = TodoMapper.INSTANCE.toEntity(requestDto); - Member member = memberRepository.findById(id) - .orElseThrow( ()-> new ResponseStatusException(HttpStatus.NOT_FOUND)); - todo.matchMember(member); - - todoRepository.save(todo); - - return TodoMapper.INSTANCE.toDto(todo); - } - - // 2. Todo 수정 - public TodoResponseDto update(Long memberId,Long todoId, TodoRequestDto requestDto) { - Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,"존재하는 회원이 없습니다.")); - // 회원과 할일 간에 -> 관계가 매핑되어 있지 않음 - List todos = todoRepository.findByMember(member); - - Todo targetTodo = todos.stream() - .filter(todo-> todo.getId().equals(todoId)) - .findFirst() - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,"회원과 일치하는 TodoList가 없습니다.")); - - targetTodo.updateTitle(requestDto.getTitle()); - targetTodo.updateContents(requestDto.getContents()); - targetTodo.updateIsCompleted(requestDto.isCompleted()); - targetTodo.updateDueAt(requestDto.getDueAt()); - todoRepository.save(targetTodo); - - return TodoMapper.INSTANCE.toDto(targetTodo); - } - - // 3. Todo 전체 조회 - public List searchAll() { - List todos = todoRepository.findAll(); - - return todos.stream() - .map(TodoMapper.INSTANCE::toDto) - .collect(Collectors.toList()); - -// List todoList = new ArrayList<>(); -// for (Todo todo : todos){ -// TodoResponseDto responseDto = TodoMapper.INSTANCE.toDto(todo); -// todoList.add(responseDto); -// } -// return todoList; - } - - // 4. Todo 리스트 조회 (memberId로 조회) - public List searchById(Long id){ - // 회원찾기 - Member member = memberRepository.findById(id) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - // 회원으로 - List todo = todoRepository.findByMember(member); - - List todoList = new ArrayList<>(); - for(Todo todo_one : todo){ - TodoResponseDto responseDto = TodoMapper.INSTANCE.toDto(todo_one); - todoList.add(responseDto); - } - - return todoList; - } - - // 5. Todo 삭제 - public void delete(Long id){ - todoRepository.deleteById(id); - } - -// // 6. Todo 전체 삭제 -// public void deleteAll(){ -// todoRepository.deleteAll(); -// } -} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/resources/application.properties b/contents/todoListAPI/hyeonseung/todolist/src/main/resources/application.properties deleted file mode 100644 index 7bdc760..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/resources/application.properties +++ /dev/null @@ -1,21 +0,0 @@ -spring.application.name=todolist - -## DB 설정 - -# MySQL -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver - -# DB Source URL -spring.datasource.url=jdbc:mysql://localhost:3306/todolist? -#characterEncoding=UTF-8&serverTimezone=UTC -spring.datasource.username=root -spring.datasource.password=root - -# DDL(create,alter,drop) -spring.jpa.hibernate.ddl-auto=update - -#sql 보여주기 -spring.jpa.show-sql=true - -spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect -spring.jpa.properties.hibernate.format_sql=true diff --git a/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/TodolistApplicationTests.java b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/TodolistApplicationTests.java deleted file mode 100644 index 14b6547..0000000 --- a/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/TodolistApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.todolist.todolist; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class TodolistApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/contents/todoListAPI/kangwook/README.md b/contents/todoListAPI/kangwook/README.md deleted file mode 100644 index ea697f1..0000000 --- a/contents/todoListAPI/kangwook/README.md +++ /dev/null @@ -1,4 +0,0 @@ -https://www.erdcloud.com/d/ZkorMacqBtstiZJmS - -![image](https://github.com/inu-appcenter/server-study-16th/assets/62889359/6db09618-2429-4cf1-9432-52b8214fc198) - diff --git a/contents/todoListAPI/kangwook/practice/.gitignore b/contents/todoListAPI/kangwook/practice/.gitignore deleted file mode 100644 index f90c65c..0000000 --- a/contents/todoListAPI/kangwook/practice/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -application.properties - -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ diff --git a/contents/todoListAPI/kangwook/practice/build.gradle b/contents/todoListAPI/kangwook/practice/build.gradle deleted file mode 100644 index 4f8ee2e..0000000 --- a/contents/todoListAPI/kangwook/practice/build.gradle +++ /dev/null @@ -1,63 +0,0 @@ -plugins { - id 'java' - id 'org.springframework.boot' version '3.2.4' - id 'io.spring.dependency-management' version '1.1.4' -} - -group = 'com.appcenter' -version = '0.0.1-SNAPSHOT' - -java { - sourceCompatibility = '17' -} - -configurations { - compileOnly { - extendsFrom annotationProcessor - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-data-redis' - implementation 'org.springframework.boot:spring-boot-starter-mail' - implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-web' - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.h2database:h2' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.springframework.security:spring-security-test' - //querydsl dependencies 추가(스프링부트 3.0이상) - implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' - annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" - annotationProcessor "jakarta.annotation:jakarta.annotation-api" - annotationProcessor "jakarta.persistence:jakarta.persistence-api" -} - -tasks.named('test') { - useJUnitPlatform() -} -// Querydsl 설정부 -def generated = 'src/main/generated' - -// querydsl QClass 파일 생성 위치를 지정 -tasks.withType(JavaCompile) { - options.getGeneratedSourceOutputDirectory().set(file(generated)) -} - -// java source set 에 querydsl QClass 위치 추가 -sourceSets { - main.java.srcDirs += [ generated ] -} - -// gradle clean 시에 QClass 디렉토리 삭제 -clean { - delete file(generated) -} \ No newline at end of file diff --git a/contents/todoListAPI/kangwook/practice/gradle/wrapper/gradle-wrapper.jar b/contents/todoListAPI/kangwook/practice/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136f3d4ba8a0da8d277868979cfbc8ad796..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c z&{(nX_ht=QbJ%DzAya}!&uNu!4V0xI)QE$SY__m)SAKcN0P(&JcoK*Lxr@P zY&P=}&B3*UWNlc|&$Oh{BEqwK2+N2U$4WB7Fd|aIal`FGANUa9E-O)!gV`((ZGCc$ zBJA|FFrlg~9OBp#f7aHodCe{6= zay$6vN~zj1ddMZ9gQ4p32(7wD?(dE>KA2;SOzXRmPBiBc6g`eOsy+pVcHu=;Yd8@{ zSGgXf@%sKKQz~;!J;|2fC@emm#^_rnO0esEn^QxXgJYd`#FPWOUU5b;9eMAF zZhfiZb|gk8aJIw*YLp4!*(=3l8Cp{(%p?ho22*vN9+5NLV0TTazNY$B5L6UKUrd$n zjbX%#m7&F#U?QNOBXkiiWB*_tk+H?N3`vg;1F-I+83{M2!8<^nydGr5XX}tC!10&e z7D36bLaB56WrjL&HiiMVtpff|K%|*{t*ltt^5ood{FOG0<>k&1h95qPio)2`eL${YAGIx(b4VN*~nKn6E~SIQUuRH zQ+5zP6jfnP$S0iJ@~t!Ai3o`X7biohli;E zT#yXyl{bojG@-TGZzpdVDXhbmF%F9+-^YSIv|MT1l3j zrxOFq>gd2%U}?6}8mIj?M zc077Zc9fq(-)4+gXv?Az26IO6eV`RAJz8e3)SC7~>%rlzDwySVx*q$ygTR5kW2ds- z!HBgcq0KON9*8Ff$X0wOq$`T7ml(@TF)VeoF}x1OttjuVHn3~sHrMB++}f7f9H%@f z=|kP_?#+fve@{0MlbkC9tyvQ_R?lRdRJ@$qcB(8*jyMyeME5ns6ypVI1Xm*Zr{DuS zZ!1)rQfa89c~;l~VkCiHI|PCBd`S*2RLNQM8!g9L6?n`^evQNEwfO@&JJRme+uopQX0%Jo zgd5G&#&{nX{o?TQwQvF1<^Cg3?2co;_06=~Hcb6~4XWpNFL!WU{+CK;>gH%|BLOh7@!hsa(>pNDAmpcuVO-?;Bic17R}^|6@8DahH)G z!EmhsfunLL|3b=M0MeK2vqZ|OqUqS8npxwge$w-4pFVXFq$_EKrZY?BuP@Az@(k`L z`ViQBSk`y+YwRT;&W| z2e3UfkCo^uTA4}Qmmtqs+nk#gNr2W4 zTH%hhErhB)pkXR{B!q5P3-OM+M;qu~f>}IjtF%>w{~K-0*jPVLl?Chz&zIdxp}bjx zStp&Iufr58FTQ36AHU)0+CmvaOpKF;W@sMTFpJ`j;3d)J_$tNQI^c<^1o<49Z(~K> z;EZTBaVT%14(bFw2ob@?JLQ2@(1pCdg3S%E4*dJ}dA*v}_a4_P(a`cHnBFJxNobAv zf&Zl-Yt*lhn-wjZsq<9v-IsXxAxMZ58C@e0!rzhJ+D@9^3~?~yllY^s$?&oNwyH!#~6x4gUrfxplCvK#!f z$viuszW>MFEcFL?>ux*((!L$;R?xc*myjRIjgnQX79@UPD$6Dz0jutM@7h_pq z0Zr)#O<^y_K6jfY^X%A-ip>P%3saX{!v;fxT-*0C_j4=UMH+Xth(XVkVGiiKE#f)q z%Jp=JT)uy{&}Iq2E*xr4YsJ5>w^=#-mRZ4vPXpI6q~1aFwi+lQcimO45V-JXP;>(Q zo={U`{=_JF`EQj87Wf}{Qy35s8r1*9Mxg({CvOt}?Vh9d&(}iI-quvs-rm~P;eRA@ zG5?1HO}puruc@S{YNAF3vmUc2B4!k*yi))<5BQmvd3tr}cIs#9)*AX>t`=~{f#Uz0 z0&Nk!7sSZwJe}=)-R^$0{yeS!V`Dh7w{w5rZ9ir!Z7Cd7dwZcK;BT#V0bzTt>;@Cl z#|#A!-IL6CZ@eHH!CG>OO8!%G8&8t4)Ro@}USB*k>oEUo0LsljsJ-%5Mo^MJF2I8- z#v7a5VdJ-Cd%(a+y6QwTmi+?f8Nxtm{g-+WGL>t;s#epv7ug>inqimZCVm!uT5Pf6 ziEgQt7^%xJf#!aPWbuC_3Nxfb&CFbQy!(8ANpkWLI4oSnH?Q3f?0k1t$3d+lkQs{~(>06l&v|MpcFsyAv zin6N!-;pggosR*vV=DO(#+}4ps|5$`udE%Kdmp?G7B#y%H`R|i8skKOd9Xzx8xgR$>Zo2R2Ytktq^w#ul4uicxW#{ zFjG_RNlBroV_n;a7U(KIpcp*{M~e~@>Q#Av90Jc5v%0c>egEdY4v3%|K1XvB{O_8G zkTWLC>OZKf;XguMH2-Pw{BKbFzaY;4v2seZV0>^7Q~d4O=AwaPhP3h|!hw5aqOtT@ z!SNz}$of**Bl3TK209@F=Tn1+mgZa8yh(Png%Zd6Mt}^NSjy)etQrF zme*llAW=N_8R*O~d2!apJnF%(JcN??=`$qs3Y+~xs>L9x`0^NIn!8mMRFA_tg`etw z3k{9JAjnl@ygIiJcNHTy02GMAvBVqEss&t2<2mnw!; zU`J)0>lWiqVqo|ex7!+@0i>B~BSU1A_0w#Ee+2pJx0BFiZ7RDHEvE*ptc9md(B{&+ zKE>TM)+Pd>HEmdJao7U@S>nL(qq*A)#eLOuIfAS@j`_sK0UEY6OAJJ-kOrHG zjHx`g!9j*_jRcJ%>CE9K2MVf?BUZKFHY?EpV6ai7sET-tqk=nDFh-(65rhjtlKEY% z@G&cQ<5BKatfdA1FKuB=i>CCC5(|9TMW%K~GbA4}80I5%B}(gck#Wlq@$nO3%@QP_ z8nvPkJFa|znk>V92cA!K1rKtr)skHEJD;k8P|R8RkCq1Rh^&}Evwa4BUJz2f!2=MH zo4j8Y$YL2313}H~F7@J7mh>u%556Hw0VUOz-Un@ZASCL)y8}4XXS`t1AC*^>PLwIc zUQok5PFS=*#)Z!3JZN&eZ6ZDP^-c@StY*t20JhCnbMxXf=LK#;`4KHEqMZ-Ly9KsS zI2VUJGY&PmdbM+iT)zek)#Qc#_i4uH43 z@T5SZBrhNCiK~~esjsO9!qBpaWK<`>!-`b71Y5ReXQ4AJU~T2Njri1CEp5oKw;Lnm)-Y@Z3sEY}XIgSy%xo=uek(kAAH5MsV$V3uTUsoTzxp_rF=tx zV07vlJNKtJhCu`b}*#m&5LV4TAE&%KtHViDAdv#c^x`J7bg z&N;#I2GkF@SIGht6p-V}`!F_~lCXjl1BdTLIjD2hH$J^YFN`7f{Q?OHPFEM$65^!u zNwkelo*5+$ZT|oQ%o%;rBX$+?xhvjb)SHgNHE_yP%wYkkvXHS{Bf$OiKJ5d1gI0j< zF6N}Aq=(WDo(J{e-uOecxPD>XZ@|u-tgTR<972`q8;&ZD!cep^@B5CaqFz|oU!iFj zU0;6fQX&~15E53EW&w1s9gQQ~Zk16X%6 zjG`j0yq}4deX2?Tr(03kg>C(!7a|b9qFI?jcE^Y>-VhudI@&LI6Qa}WQ>4H_!UVyF z((cm&!3gmq@;BD#5P~0;_2qgZhtJS|>WdtjY=q zLnHH~Fm!cxw|Z?Vw8*~?I$g#9j&uvgm7vPr#&iZgPP~v~BI4jOv;*OQ?jYJtzO<^y z7-#C={r7CO810!^s(MT!@@Vz_SVU)7VBi(e1%1rvS!?PTa}Uv`J!EP3s6Y!xUgM^8 z4f!fq<3Wer_#;u!5ECZ|^c1{|q_lh3m^9|nsMR1#Qm|?4Yp5~|er2?W^7~cl;_r4WSme_o68J9p03~Hc%X#VcX!xAu%1`R!dfGJCp zV*&m47>s^%Ib0~-2f$6oSgn3jg8m%UA;ArcdcRyM5;}|r;)?a^D*lel5C`V5G=c~k zy*w_&BfySOxE!(~PI$*dwG><+-%KT5p?whOUMA*k<9*gi#T{h3DAxzAPxN&Xws8o9Cp*`PA5>d9*Z-ynV# z9yY*1WR^D8|C%I@vo+d8r^pjJ$>eo|j>XiLWvTWLl(^;JHCsoPgem6PvegHb-OTf| zvTgsHSa;BkbG=(NgPO|CZu9gUCGr$8*EoH2_Z#^BnxF0yM~t`|9ws_xZ8X8iZYqh! zAh;HXJ)3P&)Q0(&F>!LN0g#bdbis-cQxyGn9Qgh`q+~49Fqd2epikEUw9caM%V6WgP)532RMRW}8gNS%V%Hx7apSz}tn@bQy!<=lbhmAH=FsMD?leawbnP5BWM0 z5{)@EEIYMu5;u)!+HQWhQ;D3_Cm_NADNeb-f56}<{41aYq8p4=93d=-=q0Yx#knGYfXVt z+kMxlus}t2T5FEyCN~!}90O_X@@PQpuy;kuGz@bWft%diBTx?d)_xWd_-(!LmVrh**oKg!1CNF&LX4{*j|) zIvjCR0I2UUuuEXh<9}oT_zT#jOrJAHNLFT~Ilh9hGJPI1<5`C-WA{tUYlyMeoy!+U zhA#=p!u1R7DNg9u4|QfED-2TuKI}>p#2P9--z;Bbf4Op*;Q9LCbO&aL2i<0O$ByoI z!9;Ght733FC>Pz>$_mw(F`zU?`m@>gE`9_p*=7o=7av`-&ifU(^)UU`Kg3Kw`h9-1 z6`e6+im=|m2v`pN(2dE%%n8YyQz;#3Q-|x`91z?gj68cMrHl}C25|6(_dIGk*8cA3 zRHB|Nwv{@sP4W+YZM)VKI>RlB`n=Oj~Rzx~M+Khz$N$45rLn6k1nvvD^&HtsMA4`s=MmuOJID@$s8Ph4E zAmSV^+s-z8cfv~Yd(40Sh4JG#F~aB>WFoX7ykaOr3JaJ&Lb49=B8Vk-SQT9%7TYhv z?-Pprt{|=Y5ZQ1?od|A<_IJU93|l4oAfBm?3-wk{O<8ea+`}u%(kub(LFo2zFtd?4 zwpN|2mBNywv+d^y_8#<$r>*5+$wRTCygFLcrwT(qc^n&@9r+}Kd_u@Ithz(6Qb4}A zWo_HdBj#V$VE#l6pD0a=NfB0l^6W^g`vm^sta>Tly?$E&{F?TTX~DsKF~poFfmN%2 z4x`Dc{u{Lkqz&y!33;X}weD}&;7p>xiI&ZUb1H9iD25a(gI|`|;G^NwJPv=1S5e)j z;U;`?n}jnY6rA{V^ zxTd{bK)Gi^odL3l989DQlN+Zs39Xe&otGeY(b5>rlIqfc7Ap4}EC?j<{M=hlH{1+d zw|c}}yx88_xQr`{98Z!d^FNH77=u(p-L{W6RvIn40f-BldeF-YD>p6#)(Qzf)lfZj z?3wAMtPPp>vMehkT`3gToPd%|D8~4`5WK{`#+}{L{jRUMt zrFz+O$C7y8$M&E4@+p+oV5c%uYzbqd2Y%SSgYy#xh4G3hQv>V*BnuKQhBa#=oZB~w{azUB+q%bRe_R^ z>fHBilnRTUfaJ201czL8^~Ix#+qOHSO)A|xWLqOxB$dT2W~)e-r9;bm=;p;RjYahB z*1hegN(VKK+ztr~h1}YP@6cfj{e#|sS`;3tJhIJK=tVJ-*h-5y9n*&cYCSdg#EHE# zSIx=r#qOaLJoVVf6v;(okg6?*L_55atl^W(gm^yjR?$GplNP>BZsBYEf_>wM0Lc;T zhf&gpzOWNxS>m+mN92N0{;4uw`P+9^*|-1~$uXpggj4- z^SFc4`uzj2OwdEVT@}Q`(^EcQ_5(ZtXTql*yGzdS&vrS_w>~~ra|Nb5abwf}Y!uq6R5f&6g2ge~2p(%c< z@O)cz%%rr4*cRJ5f`n@lvHNk@lE1a*96Kw6lJ~B-XfJW%?&-y?;E&?1AacU@`N`!O z6}V>8^%RZ7SQnZ-z$(jsX`amu*5Fj8g!3RTRwK^`2_QHe;_2y_n|6gSaGyPmI#kA0sYV<_qOZc#-2BO%hX)f$s-Z3xlI!ub z^;3ru11DA`4heAu%}HIXo&ctujzE2!6DIGE{?Zs>2}J+p&C$rc7gJC35gxhflorvsb%sGOxpuWhF)dL_&7&Z99=5M0b~Qa;Mo!j&Ti_kXW!86N%n= zSC@6Lw>UQ__F&+&Rzv?gscwAz8IP!n63>SP)^62(HK98nGjLY2*e^OwOq`3O|C92? z;TVhZ2SK%9AGW4ZavTB9?)mUbOoF`V7S=XM;#3EUpR+^oHtdV!GK^nXzCu>tpR|89 zdD{fnvCaN^^LL%amZ^}-E+214g&^56rpdc@yv0b<3}Ys?)f|fXN4oHf$six)-@<;W&&_kj z-B}M5U*1sb4)77aR=@%I?|Wkn-QJVuA96an25;~!gq(g1@O-5VGo7y&E_srxL6ZfS z*R%$gR}dyONgju*D&?geiSj7SZ@ftyA|}(*Y4KbvU!YLsi1EDQQCnb+-cM=K1io78o!v*);o<XwjaQH%)uIP&Zm?)Nfbfn;jIr z)d#!$gOe3QHp}2NBak@yYv3m(CPKkwI|{;d=gi552u?xj9ObCU^DJFQp4t4e1tPzM zvsRIGZ6VF+{6PvqsplMZWhz10YwS={?`~O0Ec$`-!klNUYtzWA^f9m7tkEzCy<_nS z=&<(awFeZvt51>@o_~>PLs05CY)$;}Oo$VDO)?l-{CS1Co=nxjqben*O1BR>#9`0^ zkwk^k-wcLCLGh|XLjdWv0_Hg54B&OzCE^3NCP}~OajK-LuRW53CkV~Su0U>zN%yQP zH8UH#W5P3-!ToO-2k&)}nFe`t+mdqCxxAHgcifup^gKpMObbox9LFK;LP3}0dP-UW z?Zo*^nrQ6*$FtZ(>kLCc2LY*|{!dUn$^RW~m9leoF|@Jy|M5p-G~j%+P0_#orRKf8 zvuu5<*XO!B?1E}-*SY~MOa$6c%2cM+xa8}_8x*aVn~57v&W(0mqN1W`5a7*VN{SUH zXz98DDyCnX2EPl-`Lesf`=AQT%YSDb`$%;(jUTrNen$NPJrlpPDP}prI>Ml!r6bCT;mjsg@X^#&<}CGf0JtR{Ecwd&)2zuhr#nqdgHj+g2n}GK9CHuwO zk>oZxy{vcOL)$8-}L^iVfJHAGfwN$prHjYV0ju}8%jWquw>}_W6j~m<}Jf!G?~r5&Rx)!9JNX!ts#SGe2HzobV5); zpj@&`cNcO&q+%*<%D7za|?m5qlmFK$=MJ_iv{aRs+BGVrs)98BlN^nMr{V_fcl_;jkzRju+c-y?gqBC_@J0dFLq-D9@VN&-`R9U;nv$Hg?>$oe4N&Ht$V_(JR3TG^! zzJsbQbi zFE6-{#9{G{+Z}ww!ycl*7rRdmU#_&|DqPfX3CR1I{Kk;bHwF6jh0opI`UV2W{*|nn zf_Y@%wW6APb&9RrbEN=PQRBEpM(N1w`81s=(xQj6 z-eO0k9=Al|>Ej|Mw&G`%q8e$2xVz1v4DXAi8G};R$y)ww638Y=9y$ZYFDM$}vzusg zUf+~BPX>(SjA|tgaFZr_e0{)+z9i6G#lgt=F_n$d=beAt0Sa0a7>z-?vcjl3e+W}+ z1&9=|vC=$co}-Zh*%3588G?v&U7%N1Qf-wNWJ)(v`iO5KHSkC5&g7CrKu8V}uQGcfcz zmBz#Lbqwqy#Z~UzHgOQ;Q-rPxrRNvl(&u6ts4~0=KkeS;zqURz%!-ERppmd%0v>iRlEf+H$yl{_8TMJzo0 z>n)`On|7=WQdsqhXI?#V{>+~}qt-cQbokEbgwV3QvSP7&hK4R{Z{aGHVS3;+h{|Hz z6$Js}_AJr383c_+6sNR|$qu6dqHXQTc6?(XWPCVZv=)D#6_;D_8P-=zOGEN5&?~8S zl5jQ?NL$c%O)*bOohdNwGIKM#jSAC?BVY={@A#c9GmX0=T(0G}xs`-%f3r=m6-cpK z!%waekyAvm9C3%>sixdZj+I(wQlbB4wv9xKI*T13DYG^T%}zZYJ|0$Oj^YtY+d$V$ zAVudSc-)FMl|54n=N{BnZTM|!>=bhaja?o7s+v1*U$!v!qQ%`T-6fBvmdPbVmro&d zk07TOp*KuxRUSTLRrBj{mjsnF8`d}rMViY8j`jo~Hp$fkv9F_g(jUo#Arp;Xw0M$~ zRIN!B22~$kx;QYmOkos@%|5k)!QypDMVe}1M9tZfkpXKGOxvKXB!=lo`p?|R1l=tA zp(1}c6T3Fwj_CPJwVsYtgeRKg?9?}%oRq0F+r+kdB=bFUdVDRPa;E~~>2$w}>O>v=?|e>#(-Lyx?nbg=ckJ#5U6;RT zNvHhXk$P}m9wSvFyU3}=7!y?Y z=fg$PbV8d7g25&-jOcs{%}wTDKm>!Vk);&rr;O1nvO0VrU&Q?TtYVU=ir`te8SLlS zKSNmV=+vF|ATGg`4$N1uS|n??f}C_4Sz!f|4Ly8#yTW-FBfvS48Tef|-46C(wEO_%pPhUC5$-~Y?!0vFZ^Gu`x=m7X99_?C-`|h zfmMM&Y@zdfitA@KPw4Mc(YHcY1)3*1xvW9V-r4n-9ZuBpFcf{yz+SR{ zo$ZSU_|fgwF~aakGr(9Be`~A|3)B=9`$M-TWKipq-NqRDRQc}ABo*s_5kV%doIX7LRLRau_gd@Rd_aLFXGSU+U?uAqh z8qusWWcvgQ&wu{|sRXmv?sl=xc<$6AR$+cl& zFNh5q1~kffG{3lDUdvEZu5c(aAG~+64FxdlfwY^*;JSS|m~CJusvi-!$XR`6@XtY2 znDHSz7}_Bx7zGq-^5{stTRy|I@N=>*y$zz>m^}^{d&~h;0kYiq8<^Wq7Dz0w31ShO^~LUfW6rfitR0(=3;Uue`Y%y@ex#eKPOW zO~V?)M#AeHB2kovn1v=n^D?2{2jhIQd9t|_Q+c|ZFaWt+r&#yrOu-!4pXAJuxM+Cx z*H&>eZ0v8Y`t}8{TV6smOj=__gFC=eah)mZt9gwz>>W$!>b3O;Rm^Ig*POZP8Rl0f zT~o=Nu1J|lO>}xX&#P58%Yl z83`HRs5#32Qm9mdCrMlV|NKNC+Z~ z9OB8xk5HJ>gBLi+m@(pvpw)1(OaVJKs*$Ou#@Knd#bk+V@y;YXT?)4eP9E5{J%KGtYinNYJUH9PU3A}66c>Xn zZ{Bn0<;8$WCOAL$^NqTjwM?5d=RHgw3!72WRo0c;+houoUA@HWLZM;^U$&sycWrFd zE7ekt9;kb0`lps{>R(}YnXlyGY}5pPd9zBpgXeJTY_jwaJGSJQC#-KJqmh-;ad&F- z-Y)E>!&`Rz!HtCz>%yOJ|v(u7P*I$jqEY3}(Z-orn4 zlI?CYKNl`6I){#2P1h)y(6?i;^z`N3bxTV%wNvQW+eu|x=kbj~s8rhCR*0H=iGkSj zk23lr9kr|p7#qKL=UjgO`@UnvzU)`&fI>1Qs7ubq{@+lK{hH* zvl6eSb9%yngRn^T<;jG1SVa)eA>T^XX=yUS@NCKpk?ovCW1D@!=@kn;l_BrG;hOTC z6K&H{<8K#dI(A+zw-MWxS+~{g$tI7|SfP$EYKxA}LlVO^sT#Oby^grkdZ^^lA}uEF zBSj$weBJG{+Bh@Yffzsw=HyChS(dtLE3i*}Zj@~!_T-Ay7z=B)+*~3|?w`Zd)Co2t zC&4DyB!o&YgSw+fJn6`sn$e)29`kUwAc+1MND7YjV%lO;H2}fNy>hD#=gT ze+-aFNpyKIoXY~Vq-}OWPBe?Rfu^{ps8>Xy%42r@RV#*QV~P83jdlFNgkPN=T|Kt7 zV*M`Rh*30&AWlb$;ae130e@}Tqi3zx2^JQHpM>j$6x`#{mu%tZlwx9Gj@Hc92IuY* zarmT|*d0E~vt6<+r?W^UW0&#U&)8B6+1+;k^2|FWBRP9?C4Rk)HAh&=AS8FS|NQaZ z2j!iZ)nbEyg4ZTp-zHwVlfLC~tXIrv(xrP8PAtR{*c;T24ycA-;auWsya-!kF~CWZ zw_uZ|%urXgUbc@x=L=_g@QJ@m#5beS@6W195Hn7>_}z@Xt{DIEA`A&V82bc^#!q8$ zFh?z_Vn|ozJ;NPd^5uu(9tspo8t%&-U9Ckay-s@DnM*R5rtu|4)~e)`z0P-sy?)kc zs_k&J@0&0!q4~%cKL)2l;N*T&0;mqX5T{Qy60%JtKTQZ-xb%KOcgqwJmb%MOOKk7N zgq})R_6**{8A|6H?fO+2`#QU)p$Ei2&nbj6TpLSIT^D$|`TcSeh+)}VMb}LmvZ{O| ze*1IdCt3+yhdYVxcM)Q_V0bIXLgr6~%JS<<&dxIgfL=Vnx4YHuU@I34JXA|+$_S3~ zy~X#gO_X!cSs^XM{yzDGNM>?v(+sF#<0;AH^YrE8smx<36bUsHbN#y57K8WEu(`qHvQ6cAZPo=J5C(lSmUCZ57Rj6cx!e^rfaI5%w}unz}4 zoX=nt)FVNV%QDJH`o!u9olLD4O5fl)xp+#RloZlaA92o3x4->?rB4`gS$;WO{R;Z3>cG3IgFX2EA?PK^M}@%1%A;?f6}s&CV$cIyEr#q5;yHdNZ9h{| z-=dX+a5elJoDo?Eq&Og!nN6A)5yYpnGEp}?=!C-V)(*~z-+?kY1Q7qs#Rsy%hu_60rdbB+QQNr?S1 z?;xtjUv|*E3}HmuNyB9aFL5H~3Ho0UsmuMZELp1a#CA1g`P{-mT?BchuLEtK}!QZ=3AWakRu~?f9V~3F;TV`5%9Pcs_$gq&CcU}r8gOO zC2&SWPsSG{&o-LIGTBqp6SLQZPvYKp$$7L4WRRZ0BR$Kf0I0SCFkqveCp@f)o8W)! z$%7D1R`&j7W9Q9CGus_)b%+B#J2G;l*FLz#s$hw{BHS~WNLODV#(!u_2Pe&tMsq={ zdm7>_WecWF#D=?eMjLj=-_z`aHMZ=3_-&E8;ibPmM}61i6J3is*=dKf%HC>=xbj4$ zS|Q-hWQ8T5mWde6h@;mS+?k=89?1FU<%qH9B(l&O>k|u_aD|DY*@~(`_pb|B#rJ&g zR0(~(68fpUPz6TdS@4JT5MOPrqDh5_H(eX1$P2SQrkvN8sTxwV>l0)Qq z0pzTuvtEAKRDkKGhhv^jk%|HQ1DdF%5oKq5BS>szk-CIke{%js?~%@$uaN3^Uz6Wf z_iyx{bZ(;9y4X&>LPV=L=d+A}7I4GkK0c1Xts{rrW1Q7apHf-))`BgC^0^F(>At1* za@e7{lq%yAkn*NH8Q1{@{lKhRg*^TfGvv!Sn*ed*x@6>M%aaqySxR|oNadYt1mpUZ z6H(rupHYf&Z z29$5g#|0MX#aR6TZ$@eGxxABRKakDYtD%5BmKp;HbG_ZbT+=81E&=XRk6m_3t9PvD zr5Cqy(v?gHcYvYvXkNH@S#Po~q(_7MOuCAB8G$a9BC##gw^5mW16cML=T=ERL7wsk zzNEayTG?mtB=x*wc@ifBCJ|irFVMOvH)AFRW8WE~U()QT=HBCe@s$dA9O!@`zAAT) zaOZ7l6vyR+Nk_OOF!ZlZmjoImKh)dxFbbR~z(cMhfeX1l7S_`;h|v3gI}n9$sSQ>+3@AFAy9=B_y$)q;Wdl|C-X|VV3w8 z2S#>|5dGA8^9%Bu&fhmVRrTX>Z7{~3V&0UpJNEl0=N32euvDGCJ>#6dUSi&PxFW*s zS`}TB>?}H(T2lxBJ!V#2taV;q%zd6fOr=SGHpoSG*4PDaiG0pdb5`jelVipkEk%FV zThLc@Hc_AL1#D&T4D=w@UezYNJ%0=f3iVRuVL5H?eeZM}4W*bomebEU@e2d`M<~uW zf#Bugwf`VezG|^Qbt6R_=U0}|=k;mIIakz99*>FrsQR{0aQRP6ko?5<7bkDN8evZ& zB@_KqQG?ErKL=1*ZM9_5?Pq%lcS4uLSzN(Mr5=t6xHLS~Ym`UgM@D&VNu8e?_=nSFtF$u@hpPSmI4Vo_t&v?>$~K4y(O~Rb*(MFy_igM7 z*~yYUyR6yQgzWnWMUgDov!!g=lInM+=lOmOk4L`O?{i&qxy&D*_qorRbDwj6?)!ef z#JLd7F6Z2I$S0iYI={rZNk*<{HtIl^mx=h>Cim*04K4+Z4IJtd*-)%6XV2(MCscPiw_a+y*?BKbTS@BZ3AUao^%Zi#PhoY9Vib4N>SE%4>=Jco0v zH_Miey{E;FkdlZSq)e<{`+S3W=*ttvD#hB8w=|2aV*D=yOV}(&p%0LbEWH$&@$X3x~CiF-?ejQ*N+-M zc8zT@3iwkdRT2t(XS`d7`tJQAjRmKAhiw{WOqpuvFp`i@Q@!KMhwKgsA}%@sw8Xo5Y=F zhRJZg)O4uqNWj?V&&vth*H#je6T}}p_<>!Dr#89q@uSjWv~JuW(>FqoJ5^ho0%K?E z9?x_Q;kmcsQ@5=}z@tdljMSt9-Z3xn$k)kEjK|qXS>EfuDmu(Z8|(W?gY6-l z@R_#M8=vxKMAoi&PwnaIYw2COJM@atcgfr=zK1bvjW?9B`-+Voe$Q+H$j!1$Tjn+* z&LY<%)L@;zhnJlB^Og6I&BOR-m?{IW;tyYC%FZ!&Z>kGjHJ6cqM-F z&19n+e1=9AH1VrVeHrIzqlC`w9=*zfmrerF?JMzO&|Mmv;!4DKc(sp+jy^Dx?(8>1 zH&yS_4yL7m&GWX~mdfgH*AB4{CKo;+egw=PrvkTaoBU+P-4u?E|&!c z)DKc;>$$B6u*Zr1SjUh2)FeuWLWHl5TH(UHWkf zLs>7px!c5n;rbe^lO@qlYLzlDVp(z?6rPZel=YB)Uv&n!2{+Mb$-vQl=xKw( zve&>xYx+jW_NJh!FV||r?;hdP*jOXYcLCp>DOtJ?2S^)DkM{{Eb zS$!L$e_o0(^}n3tA1R3-$SNvgBq;DOEo}fNc|tB%%#g4RA3{|euq)p+xd3I8^4E&m zFrD%}nvG^HUAIKe9_{tXB;tl|G<%>yk6R;8L2)KUJw4yHJXUOPM>(-+jxq4R;z8H#>rnJy*)8N+$wA$^F zN+H*3t)eFEgxLw+Nw3};4WV$qj&_D`%ADV2%r zJCPCo%{=z7;`F98(us5JnT(G@sKTZ^;2FVitXyLe-S5(hV&Ium+1pIUB(CZ#h|g)u zSLJJ<@HgrDiA-}V_6B^x1>c9B6%~847JkQ!^KLZ2skm;q*edo;UA)~?SghG8;QbHh z_6M;ouo_1rq9=x$<`Y@EA{C%6-pEV}B(1#sDoe_e1s3^Y>n#1Sw;N|}8D|s|VPd+g z-_$QhCz`vLxxrVMx3ape1xu3*wjx=yKSlM~nFgkNWb4?DDr*!?U)L_VeffF<+!j|b zZ$Wn2$TDv3C3V@BHpSgv3JUif8%hk%OsGZ=OxH@8&4`bbf$`aAMchl^qN>Eyu3JH} z9-S!x8-s4fE=lad%Pkp8hAs~u?|uRnL48O|;*DEU! zuS0{cpk%1E0nc__2%;apFsTm0bKtd&A0~S3Cj^?72-*Owk3V!ZG*PswDfS~}2<8le z5+W^`Y(&R)yVF*tU_s!XMcJS`;(Tr`J0%>p=Z&InR%D3@KEzzI+-2)HK zuoNZ&o=wUC&+*?ofPb0a(E6(<2Amd6%uSu_^-<1?hsxs~0K5^f(LsGqgEF^+0_H=uNk9S0bb!|O8d?m5gQjUKevPaO+*VfSn^2892K~%crWM8+6 z25@V?Y@J<9w%@NXh-2!}SK_(X)O4AM1-WTg>sj1{lj5@=q&dxE^9xng1_z9w9DK>| z6Iybcd0e zyi;Ew!KBRIfGPGytQ6}z}MeXCfLY0?9%RiyagSp_D1?N&c{ zyo>VbJ4Gy`@Fv+5cKgUgs~na$>BV{*em7PU3%lloy_aEovR+J7TfQKh8BJXyL6|P8un-Jnq(ghd!_HEOh$zlv2$~y3krgeH;9zC}V3f`uDtW(%mT#944DQa~^8ZI+zAUu4U(j0YcDfKR$bK#gvn_{JZ>|gZ5+)u?T$w7Q%F^;!Wk?G z(le7r!ufT*cxS}PR6hIVtXa)i`d$-_1KkyBU>qmgz-=T};uxx&sKgv48akIWQ89F{ z0XiY?WM^~;|T8zBOr zs#zuOONzH?svv*jokd5SK8wG>+yMC)LYL|vLqm^PMHcT=`}V$=nIRHe2?h)8WQa6O zPAU}d`1y(>kZiP~Gr=mtJLMu`i<2CspL|q2DqAgAD^7*$xzM`PU4^ga`ilE134XBQ z99P(LhHU@7qvl9Yzg$M`+dlS=x^(m-_3t|h>S}E0bcFMn=C|KamQ)=w2^e)35p`zY zRV8X?d;s^>Cof2SPR&nP3E+-LCkS0J$H!eh8~k0qo$}00b=7!H_I2O+Ro@3O$nPdm ztmbOO^B+IHzQ5w>@@@J4cKw5&^_w6s!s=H%&byAbUtczPQ7}wfTqxxtQNfn*u73Qw zGuWsrky_ajPx-5`R<)6xHf>C(oqGf_Fw|-U*GfS?xLML$kv;h_pZ@Kk$y0X(S+K80 z6^|z)*`5VUkawg}=z`S;VhZhxyDfrE0$(PMurAxl~<>lfZa>JZ288ULK7D` zl9|#L^JL}Y$j*j`0-K6kH#?bRmg#5L3iB4Z)%iF@SqT+Lp|{i`m%R-|ZE94Np7Pa5 zCqC^V3}B(FR340pmF*qaa}M}+h6}mqE~7Sh!9bDv9YRT|>vBNAqv09zXHMlcuhKD| zcjjA(b*XCIwJ33?CB!+;{)vX@9xns_b-VO{i0y?}{!sdXj1GM8+$#v>W7nw;+O_9B z_{4L;C6ol?(?W0<6taGEn1^uG=?Q3i29sE`RfYCaV$3DKc_;?HsL?D_fSYg}SuO5U zOB_f4^vZ_x%o`5|C@9C5+o=mFy@au{s)sKw!UgC&L35aH(sgDxRE2De%(%OT=VUdN ziVLEmdOvJ&5*tCMKRyXctCwQu_RH%;m*$YK&m;jtbdH#Ak~13T1^f89tn`A%QEHWs~jnY~E}p_Z$XC z=?YXLCkzVSK+Id`xZYTegb@W8_baLt-Fq`Tv|=)JPbFsKRm)4UW;yT+J`<)%#ue9DPOkje)YF2fsCilK9MIIK>p*`fkoD5nGfmLwt)!KOT+> zOFq*VZktDDyM3P5UOg`~XL#cbzC}eL%qMB=Q5$d89MKuN#$6|4gx_Jt0Gfn8w&q}%lq4QU%6#jT*MRT% zrLz~C8FYKHawn-EQWN1B75O&quS+Z81(zN)G>~vN8VwC+e+y(`>HcxC{MrJ;H1Z4k zZWuv$w_F0-Ub%MVcpIc){4PGL^I7M{>;hS?;eH!;gmcOE66z3;Z1Phqo(t zVP(Hg6q#0gIKgsg7L7WE!{Y#1nI(45tx2{$34dDd#!Z0NIyrm)HOn5W#7;f4pQci# zDW!FI(g4e668kI9{2+mLwB+=#9bfqgX%!B34V-$wwSN(_cm*^{y0jQtv*4}eO^sOV z*9xoNvX)c9isB}Tgx&ZRjp3kwhTVK?r9;n!x>^XYT z@Q^7zp{rkIs{2mUSE^2!Gf6$6;j~&4=-0cSJJDizZp6LTe8b45;{AKM%v99}{{FfC zz709%u0mC=1KXTo(=TqmZQ;c?$M3z(!xah>aywrj40sc2y3rKFw4jCq+Y+u=CH@_V zxz|qeTwa>+<|H%8Dz5u>ZI5MmjTFwXS-Fv!TDd*`>3{krWoNVx$<133`(ftS?ZPyY z&4@ah^3^i`vL$BZa>O|Nt?ucewzsF)0zX3qmM^|waXr=T0pfIb0*$AwU=?Ipl|1Y; z*Pk6{C-p4MY;j@IJ|DW>QHZQJcp;Z~?8(Q+Kk3^0qJ}SCk^*n4W zu9ZFwLHUx-$6xvaQ)SUQcYd6fF8&x)V`1bIuX@>{mE$b|Yd(qomn3;bPwnDUc0F=; zh*6_((%bqAYQWQ~odER?h>1mkL4kpb3s7`0m@rDKGU*oyF)$j~Ffd4fXV$?`f~rHf zB%Y)@5SXZvfwm10RY5X?TEo)PK_`L6qgBp=#>fO49$D zDq8Ozj0q6213tV5Qq=;fZ0$|KroY{Dz=l@lU^J)?Ko@ti20TRplXzphBi>XGx4bou zEWrkNjz0t5j!_ke{g5I#PUlEU$Km8g8TE|XK=MkU@PT4T><2OVamoK;wJ}3X0L$vX zgd7gNa359*nc)R-0!`2X@FOTB`+oETOPc=ubp5R)VQgY+5BTZZJ2?9QwnO=dnulIUF3gFn;BODC2)65)HeVd%t86sL7Rv^Y+nbn+&l z6BAJY(ETvwI)Ts$aiE8rht4KD*qNyE{8{x6R|%akbTBzw;2+6Echkt+W+`u^XX z_z&x%n '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/contents/todoListAPI/kangwook/practice/gradlew.bat b/contents/todoListAPI/kangwook/practice/gradlew.bat deleted file mode 100644 index 25da30d..0000000 --- a/contents/todoListAPI/kangwook/practice/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/contents/todoListAPI/kangwook/practice/settings.gradle b/contents/todoListAPI/kangwook/practice/settings.gradle deleted file mode 100644 index e8a2b01..0000000 --- a/contents/todoListAPI/kangwook/practice/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'practice' diff --git a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QBaseEntity.java b/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QBaseEntity.java deleted file mode 100644 index 6cb32b7..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QBaseEntity.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.appcenter.practice.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; - - -/** - * QBaseEntity is a Querydsl query type for BaseEntity - */ -@Generated("com.querydsl.codegen.DefaultSupertypeSerializer") -public class QBaseEntity extends EntityPathBase { - - private static final long serialVersionUID = 1538631472L; - - public static final QBaseEntity baseEntity = new QBaseEntity("baseEntity"); - - public final DateTimePath createdDate = createDateTime("createdDate", java.time.LocalDateTime.class); - - public final DateTimePath modifiedDate = createDateTime("modifiedDate", java.time.LocalDateTime.class); - - public QBaseEntity(String variable) { - super(BaseEntity.class, forVariable(variable)); - } - - public QBaseEntity(Path path) { - super(path.getType(), path.getMetadata()); - } - - public QBaseEntity(PathMetadata metadata) { - super(BaseEntity.class, metadata); - } - -} - diff --git a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QComment.java b/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QComment.java deleted file mode 100644 index de079a1..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QComment.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.appcenter.practice.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QComment is a Querydsl query type for Comment - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QComment extends EntityPathBase { - - private static final long serialVersionUID = 1970926275L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QComment comment = new QComment("comment"); - - public final QBaseEntity _super = new QBaseEntity(this); - - public final StringPath content = createString("content"); - - //inherited - public final DateTimePath createdDate = _super.createdDate; - - public final BooleanPath deleted = createBoolean("deleted"); - - public final NumberPath id = createNumber("id", Long.class); - - //inherited - public final DateTimePath modifiedDate = _super.modifiedDate; - - public final QTodo toDo; - - public QComment(String variable) { - this(Comment.class, forVariable(variable), INITS); - } - - public QComment(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QComment(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QComment(PathMetadata metadata, PathInits inits) { - this(Comment.class, metadata, inits); - } - - public QComment(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.toDo = inits.isInitialized("toDo") ? new QTodo(forProperty("toDo"), inits.get("toDo")) : null; - } - -} - diff --git a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QMember.java b/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QMember.java deleted file mode 100644 index 552a720..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QMember.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.appcenter.practice.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QMember is a Querydsl query type for Member - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QMember extends EntityPathBase { - - private static final long serialVersionUID = -2014680650L; - - public static final QMember member = new QMember("member1"); - - public final QBaseEntity _super = new QBaseEntity(this); - - //inherited - public final DateTimePath createdDate = _super.createdDate; - - public final StringPath email = createString("email"); - - public final NumberPath id = createNumber("id", Long.class); - - //inherited - public final DateTimePath modifiedDate = _super.modifiedDate; - - public final StringPath nickname = createString("nickname"); - - public final StringPath password = createString("password"); - - public final EnumPath role = createEnum("role", Role.class); - - public final ListPath todoList = this.createList("todoList", Todo.class, QTodo.class, PathInits.DIRECT2); - - public QMember(String variable) { - super(Member.class, forVariable(variable)); - } - - public QMember(Path path) { - super(path.getType(), path.getMetadata()); - } - - public QMember(PathMetadata metadata) { - super(Member.class, metadata); - } - -} - diff --git a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QTodo.java b/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QTodo.java deleted file mode 100644 index 7c98449..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/generated/com/appcenter/practice/domain/QTodo.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.appcenter.practice.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QTodo is a Querydsl query type for Todo - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QTodo extends EntityPathBase { - - private static final long serialVersionUID = 2009292386L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QTodo todo = new QTodo("todo"); - - public final QBaseEntity _super = new QBaseEntity(this); - - public final ListPath commentList = this.createList("commentList", Comment.class, QComment.class, PathInits.DIRECT2); - - public final BooleanPath completed = createBoolean("completed"); - - public final StringPath content = createString("content"); - - //inherited - public final DateTimePath createdDate = _super.createdDate; - - public final NumberPath id = createNumber("id", Long.class); - - public final QMember member; - - //inherited - public final DateTimePath modifiedDate = _super.modifiedDate; - - public QTodo(String variable) { - this(Todo.class, forVariable(variable), INITS); - } - - public QTodo(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QTodo(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QTodo(PathMetadata metadata, PathInits inits) { - this(Todo.class, metadata, inits); - } - - public QTodo(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.member = inits.isInitialized("member") ? new QMember(forProperty("member")) : null; - } - -} - diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/PracticeApplication.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/PracticeApplication.java deleted file mode 100644 index d631f5a..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/PracticeApplication.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.appcenter.practice; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; - - -@EnableJpaAuditing -@SpringBootApplication -public class PracticeApplication { - - public static void main(String[] args) { - SpringApplication.run(PracticeApplication.class, args); - } - -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/config/QueryDslConfig.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/config/QueryDslConfig.java deleted file mode 100644 index f50f08d..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/config/QueryDslConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.appcenter.practice.config; - -import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -@RequiredArgsConstructor -public class QueryDslConfig { - //Spring Boot에서는 EntityManager 를 @PersistenceContext 가 아닌 @Autowired를 통해 인젝션할 수 있게 해준다. - private final EntityManager em; - - @Bean - public JPAQueryFactory jpaQueryFactory(EntityManager em){ - return new JPAQueryFactory(em); - } -} \ No newline at end of file diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/CommentController.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/CommentController.java deleted file mode 100644 index 2a1d917..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/CommentController.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.appcenter.practice.controller; - - -import com.appcenter.practice.dto.reqeust.comment.AddCommentReq; -import com.appcenter.practice.dto.reqeust.comment.UpdateCommentReq; -import com.appcenter.practice.dto.response.CommonResponse; -import com.appcenter.practice.dto.response.comment.ReadCommentRes; -import com.appcenter.practice.service.CommentService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequiredArgsConstructor -public class CommentController { - private final CommentService commentService; - - @GetMapping(value = "/comments") - public ResponseEntity>>getCommentList(){ - return ResponseEntity - .ok(CommonResponse.of("Ok","댓글리스트 조회 성공",commentService.getCommentList())); - } - - @GetMapping(value = "/comments/{id}") - public ResponseEntity>getComment(@PathVariable Long id){ - return ResponseEntity - .ok(CommonResponse.of("Ok","댓글 조회 성공",commentService.getComment(id))); - } - - - @PostMapping(value = "/todos/{id}/comments") - public ResponseEntity> addComment(@PathVariable("id") Long todoId, @RequestBody AddCommentReq reqDto){ - return ResponseEntity - .status(201) - .body(CommonResponse.of("Created","댓글 생성 성공",commentService.saveComment(todoId,reqDto))); - } - - @PatchMapping(value = "/comments/{id}") - public ResponseEntity> updateComment(@PathVariable Long id, @RequestBody UpdateCommentReq reqDto){ - return ResponseEntity - .ok(CommonResponse.of("Ok","댓글 수정 성공",commentService.updateComment(id,reqDto))); - } - - @DeleteMapping(value = "/comments/{id}") - public ResponseEntity> deleteComment(@PathVariable Long id){ - return ResponseEntity - .ok(CommonResponse.of("Ok","댓글 삭제 성공",commentService.deleteComment(id))); - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/MemberController.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/MemberController.java deleted file mode 100644 index 0fef0c1..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/MemberController.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.appcenter.practice.controller; - -import com.appcenter.practice.dto.reqeust.member.SignupMemberReq; -import com.appcenter.practice.dto.response.CommonResponse; -import com.appcenter.practice.service.MemberService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/members") -public class MemberController { - private final MemberService memberService; - - - @PostMapping - public ResponseEntity> signup(@RequestBody SignupMemberReq reqDto){ - return ResponseEntity - .status(201) - .body(CommonResponse.of("Created","member 생성 성공",memberService.signup(reqDto))); - } - -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/TodoController.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/TodoController.java deleted file mode 100644 index cac76e5..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/controller/TodoController.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.appcenter.practice.controller; - - -import com.appcenter.practice.dto.reqeust.todo.AddTodoReq; -import com.appcenter.practice.dto.reqeust.todo.UpdateTodoReq; -import com.appcenter.practice.dto.response.CommonResponse; -import com.appcenter.practice.dto.response.todo.ReadTodoRes; -import com.appcenter.practice.service.TodoService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/todos") -public class TodoController { - private final TodoService todoService; - - @GetMapping - public ResponseEntity>> getTodoList(){ - return ResponseEntity.ok(CommonResponse.of("Ok","TodoList 조회 성공",todoService.getTodoList())); - } - - @GetMapping(value = "/{id}") - public ResponseEntity> getTodo(@PathVariable Long id){ - return ResponseEntity.ok(CommonResponse.of("Ok","Todo 조회 성공",todoService.getTodo(id))); - } - - @PostMapping - public ResponseEntity> addTodo(@RequestBody AddTodoReq reqDto){ - return ResponseEntity - .status(201) - .body(CommonResponse.of("Created","Todo가 생성 성공.",todoService.saveTodo(reqDto))); - } - - @PatchMapping(value = "/{id}") - public ResponseEntity> updateTodo(@PathVariable Long id, @RequestBody UpdateTodoReq reqDto){ - return ResponseEntity - .ok(CommonResponse.of("Ok","Todo 수정 성공",todoService.updateTodo(id,reqDto))); - } - - @PatchMapping(value = "/{id}/complete") - public ResponseEntity> completeTodo(@PathVariable Long id){ - return ResponseEntity - .ok(CommonResponse.of("Ok","Todo 완료 성공",todoService.completeTodo(id))); - } - - @DeleteMapping(value = "/{id}") - public ResponseEntity> deleteTodo(@PathVariable Long id){ - return ResponseEntity - .ok(CommonResponse.of("Ok","Todo 삭제 성공",todoService.deleteTodo(id))); - } - -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/BaseEntity.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/BaseEntity.java deleted file mode 100644 index 0d2e936..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/BaseEntity.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.appcenter.practice.domain; - -import jakarta.persistence.Column; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.MappedSuperclass; -import lombok.Getter; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import java.time.LocalDateTime; - -@MappedSuperclass// 매핑 정보만 상속한다. -@EntityListeners(AuditingEntityListener.class) -public class BaseEntity { - @CreatedDate - @Column(name = "created_date",nullable = false, updatable = false) - private LocalDateTime createdDate; - - @LastModifiedDate - @Column(name = "modificated_date",nullable = false) - private LocalDateTime modifiedDate; -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Comment.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Comment.java deleted file mode 100644 index 2e2b549..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Comment.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.appcenter.practice.domain; - - -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Comment extends BaseEntity{ - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private String content; - - //삭제 여부에 따라 "삭제된 댓글입니다." 작성 - private Boolean deleted; - - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "toDo_Id",nullable = false) - private Todo toDo; - - - @Builder - private Comment(String content,Boolean deleted, Todo toDo) { - this.content = content; - this.deleted = deleted; - this.toDo = toDo; - } - - public void changeDeleted(Boolean deleted){ this.deleted=deleted;} - public void changeContent(String content){ this.content=content; } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Member.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Member.java deleted file mode 100644 index c88ea29..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Member.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.appcenter.practice.domain; - -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Member extends BaseEntity{ - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false,unique = true) - private String email; - - @Column(nullable = false) - private String password; - - @Column(nullable = false,unique = true) - private String nickname; - - @Column(nullable = false) - @Enumerated(EnumType.STRING) - private Role role; - - @OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE, fetch = FetchType.LAZY) - private List todoList =new ArrayList<>(); - - @Builder - private Member(String email, String password, String nickname) { - this.email = email; - this.password = password; - this.nickname = nickname; - } - - public void changePassword(String password){ - this.password=password; - } - public void changeNickname(String nickname){ this.nickname=nickname;} - public void addUserAuthority(){ - this.role=Role.ROLE_USER; - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Role.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Role.java deleted file mode 100644 index 2f68e92..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Role.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.appcenter.practice.domain; - -public enum Role { - ROLE_USER,ROLE_ADMIN -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Todo.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Todo.java deleted file mode 100644 index 4e67a23..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/domain/Todo.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.appcenter.practice.domain; - - -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Todo extends BaseEntity{ - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private String content; - - // boolean은 null값을 가질 수 없다. 기본적으로 false값을 가진다. Boolean 클래스 객체는 null값을 가질 수 있다. - private Boolean completed; - - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id",nullable = false) - private Member member; - - @OneToMany(mappedBy = "toDo",cascade = CascadeType.REMOVE, fetch = FetchType.LAZY) - private List commentList= new ArrayList<>(); - - @Builder - private Todo(String content,Boolean completed, Member member) { - this.content = content; - this.completed = completed; - this.member = member; - } - - public void changeCompleted(Boolean completed){ - this.completed = completed; - } - public void changeContent(String content){ - this.content= content; - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/AddCommentReq.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/AddCommentReq.java deleted file mode 100644 index 145e819..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/AddCommentReq.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.appcenter.practice.dto.reqeust.comment; - - -import com.appcenter.practice.domain.Comment; -import com.appcenter.practice.domain.Todo; -import lombok.Getter; - -@Getter -public class AddCommentReq { - private String content; - - public Comment toEntity(Todo todo){ - return Comment.builder() - .content(content) - .deleted(false) - .toDo(todo) - .build(); - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/UpdateCommentReq.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/UpdateCommentReq.java deleted file mode 100644 index 291b921..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/comment/UpdateCommentReq.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.appcenter.practice.dto.reqeust.comment; - - -import lombok.Getter; - -@Getter -public class UpdateCommentReq { - String content; -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/member/SignupMemberReq.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/member/SignupMemberReq.java deleted file mode 100644 index 37e150d..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/member/SignupMemberReq.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.appcenter.practice.dto.reqeust.member; - - -import com.appcenter.practice.domain.Member; -import lombok.Getter; - -@Getter -public class SignupMemberReq { - private String email; - private String password; - private String nickname; - - - public Member toEntity(){ - return Member.builder() - .email(email) - .password(password) - .nickname(nickname) - .build(); - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/AddTodoReq.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/AddTodoReq.java deleted file mode 100644 index d15529b..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/AddTodoReq.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.appcenter.practice.dto.reqeust.todo; - -import com.appcenter.practice.domain.Member; -import com.appcenter.practice.domain.Todo; -import lombok.Getter; - -@Getter -public class AddTodoReq { - private String email; - private String content; - - public Todo toEntity(Member member){ - return Todo.builder() - .content(content) - .completed(false) - .member(member) - .build(); - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/UpdateTodoReq.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/UpdateTodoReq.java deleted file mode 100644 index af639de..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/reqeust/todo/UpdateTodoReq.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.appcenter.practice.dto.reqeust.todo; - -import lombok.Getter; - -@Getter -public class UpdateTodoReq { - String content; - -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/CommonResponse.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/CommonResponse.java deleted file mode 100644 index 6867de5..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/CommonResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.appcenter.practice.dto.response; - -import lombok.Getter; - -@Getter -//@RequiredArgsConstructor(staticName = "of") -public class CommonResponse{ - private final String statusCode; - private final String message; - private final T dto; - - private CommonResponse(String statusCode, String message, T dto) { - this.statusCode = statusCode; - this.message = message; - this.dto = dto; - } - - //<제네릭 타입> 반환타입 메소드이름() - //클래스에 있는 T와 메소드의 T는 다른 타입이다. - //이를 통해 메소드 호출 시 원하는 타입의 객체를 생성할 수 있다. - public static CommonResponse of(String statusCode,String message, T dto){ - return new CommonResponse(statusCode,message,dto); - - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/comment/ReadCommentRes.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/comment/ReadCommentRes.java deleted file mode 100644 index 5eaf068..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/comment/ReadCommentRes.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.appcenter.practice.dto.response.comment; - - -import com.appcenter.practice.domain.Comment; -import lombok.Getter; - -@Getter -public class ReadCommentRes { - private Long id; - private String content; - private Boolean deleted; - - private ReadCommentRes(Long id, String content, Boolean deleted) { - this.id = id; - this.content = content; - this.deleted = deleted; - } - - public static ReadCommentRes from(Comment comment){ - return new ReadCommentRes(comment.getId(),comment.getContent(),comment.getDeleted()); - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/todo/ReadTodoRes.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/todo/ReadTodoRes.java deleted file mode 100644 index 48ee411..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/dto/response/todo/ReadTodoRes.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.appcenter.practice.dto.response.todo; - -import com.appcenter.practice.domain.Todo; -import lombok.Getter; - -@Getter -public class ReadTodoRes { - private Long id; - private String content; - private Boolean completed; - - - private ReadTodoRes(Long id, String content, Boolean completed) { - this.id = id; - this.content = content; - this.completed = completed; - } - - public static ReadTodoRes from(Todo todo){ - return new ReadTodoRes(todo.getId(),todo.getContent(),todo.getCompleted()); - } - -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/CommentRepository.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/CommentRepository.java deleted file mode 100644 index 17d2c68..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/CommentRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.appcenter.practice.repository; - -import com.appcenter.practice.domain.Comment; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface CommentRepository extends JpaRepository { -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/MemberRepository.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/MemberRepository.java deleted file mode 100644 index d41d736..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/MemberRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.appcenter.practice.repository; - -import com.appcenter.practice.domain.Member; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.Optional; - -public interface MemberRepository extends JpaRepository { - Optional findByEmail(String email); - boolean existsByEmail(String email); -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/TodoRepository.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/TodoRepository.java deleted file mode 100644 index b4e3135..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/repository/TodoRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.appcenter.practice.repository; - -import com.appcenter.practice.domain.Todo; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface TodoRepository extends JpaRepository { -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/CommentService.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/CommentService.java deleted file mode 100644 index ba0e6e7..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/CommentService.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.appcenter.practice.service; - - -import com.appcenter.practice.domain.Comment; -import com.appcenter.practice.domain.Todo; -import com.appcenter.practice.dto.reqeust.comment.AddCommentReq; -import com.appcenter.practice.dto.reqeust.comment.UpdateCommentReq; -import com.appcenter.practice.dto.response.comment.ReadCommentRes; -import com.appcenter.practice.repository.CommentRepository; -import com.appcenter.practice.repository.TodoRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.stream.Collectors; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class CommentService { - private final CommentRepository commentRepository; - private final TodoRepository todoRepository; - - - public List getCommentList(){ - return commentRepository.findAll().stream() - .map(comment-> ReadCommentRes.from(comment)) - .collect(Collectors.toList()); - } - - public ReadCommentRes getComment(Long id){ - Comment comment=commentRepository.findById(id) - .orElseThrow(()-> new IllegalArgumentException("존재하지 않는 comment입니다.")); - return ReadCommentRes.from(comment); - } - - @Transactional - public Long saveComment(Long todoId, AddCommentReq reqDto){ - Todo todo= todoRepository.findById(todoId) - .orElseThrow(()-> new IllegalArgumentException("존재하지 않는 todo입니다.")); - return commentRepository.save(reqDto.toEntity(todo)).getId(); - } - - @Transactional - public Long updateComment(Long id, UpdateCommentReq reqDto){ - Comment comment= commentRepository.findById(id) - .orElseThrow(()-> new IllegalArgumentException("존재하지 않는 comment입니다.")); - comment.changeContent(reqDto.getContent()); - return id; - } - - @Transactional - public Long deleteComment(Long id){ - Comment comment=commentRepository.findById(id) - .orElseThrow(()->new IllegalArgumentException("존재하지 않는 comment입니다.")); - comment.changeDeleted(true); - return id; - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/MemberService.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/MemberService.java deleted file mode 100644 index 2bb2567..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/MemberService.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.appcenter.practice.service; - - -import com.appcenter.practice.domain.Member; -import com.appcenter.practice.dto.reqeust.member.SignupMemberReq; -import com.appcenter.practice.repository.MemberRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class MemberService { - private final MemberRepository memberRepository; - - @Transactional - public Long signup(SignupMemberReq reqDto){ - if(memberRepository.existsByEmail(reqDto.getEmail())) - throw new IllegalArgumentException("이미 존재하는 member입니다."); - Member member=reqDto.toEntity(); - return memberRepository.save(member).getId(); - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/TodoService.java b/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/TodoService.java deleted file mode 100644 index 6164a54..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/java/com/appcenter/practice/service/TodoService.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.appcenter.practice.service; - - -import com.appcenter.practice.domain.Member; -import com.appcenter.practice.domain.Todo; -import com.appcenter.practice.dto.reqeust.todo.AddTodoReq; -import com.appcenter.practice.dto.reqeust.todo.UpdateTodoReq; -import com.appcenter.practice.dto.response.todo.ReadTodoRes; -import com.appcenter.practice.repository.MemberRepository; -import com.appcenter.practice.repository.TodoRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.stream.Collectors; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class TodoService { - private final TodoRepository todoRepository; - private final MemberRepository memberRepository; - - - public List getTodoList(){ - return todoRepository.findAll().stream() - .map(todo-> ReadTodoRes.from(todo)) - .collect(Collectors.toList()); - } - - public ReadTodoRes getTodo(Long id){ - Todo todo=todoRepository.findById(id) - .orElseThrow(()-> new IllegalArgumentException("존재하지 않는 todo입니다.")); - return ReadTodoRes.from(todo); - } - - - @Transactional - public Long saveTodo(AddTodoReq reqDto){ - Member member=memberRepository.findByEmail(reqDto.getEmail()) - .orElseThrow(()->new IllegalArgumentException("존재하지 않는 member입니다.")); - return todoRepository.save(reqDto.toEntity(member)).getId(); - } - - @Transactional - public Long updateTodo(Long id,UpdateTodoReq reqDto){ - Todo todo=todoRepository.findById(id) - .orElseThrow(()->new IllegalArgumentException("존재하지 않는 todo입니다.")); - todo.changeContent(reqDto.getContent()); - return id; - } - - @Transactional - public Long completeTodo(Long id){ - Todo todo=todoRepository.findById(id) - .orElseThrow(()->new IllegalArgumentException("존재하지 않는 todo입니다.")); - todo.changeCompleted(true); - return id; - } - - @Transactional - public Long deleteTodo(Long id){ - todoRepository.deleteById(id); - return id; - } -} diff --git a/contents/todoListAPI/kangwook/practice/src/main/resources/application.properties b/contents/todoListAPI/kangwook/practice/src/main/resources/application.properties deleted file mode 100644 index 8bd613c..0000000 --- a/contents/todoListAPI/kangwook/practice/src/main/resources/application.properties +++ /dev/null @@ -1,19 +0,0 @@ -#setting h2 -spring.h2.console.enabled=true -spring.h2.console.path=/h2-console - -#setting h2 db -# in-memory ?? -spring.datasource.url=jdbc:h2:mem:test -spring.datasource.driver-class-name=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password= -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect - -#show sql -spring.jpa.properties.hibernate.show_sql=true -spring.jpa.properties.hibernate.format_sql=true - -#ddl auto, jpa ??? ?? ?? -spring.jpa.hibernate.ddl-auto=update \ No newline at end of file diff --git a/contents/todoListAPI/kangwook/practice/src/test/java/com/appcenter/practice/PracticeApplicationTests.java b/contents/todoListAPI/kangwook/practice/src/test/java/com/appcenter/practice/PracticeApplicationTests.java deleted file mode 100644 index bbfef6a..0000000 --- a/contents/todoListAPI/kangwook/practice/src/test/java/com/appcenter/practice/PracticeApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.appcenter.practice; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class PracticeApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/contents/todoListAPI/seungseop/README.md b/contents/todoListAPI/seungseop/README.md deleted file mode 100644 index 5fd8a83..0000000 --- a/contents/todoListAPI/seungseop/README.md +++ /dev/null @@ -1,6 +0,0 @@ -### ERD 다이어그램 - -![TodoList](https://github.com/inu-appcenter/server-study-16th/assets/86196038/a5434842-ab73-4103-9058-40333c8a3a8b) - ->https://dbdiagram.io/d/TodoList-660ff41403593b6b61480732 -> \ No newline at end of file diff --git a/contents/todoListAPI/seungseop/todolist/.gitignore b/contents/todoListAPI/seungseop/todolist/.gitignore deleted file mode 100644 index c2065bc..0000000 --- a/contents/todoListAPI/seungseop/todolist/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ diff --git a/contents/todoListAPI/seungseop/todolist/build.gradle b/contents/todoListAPI/seungseop/todolist/build.gradle deleted file mode 100644 index cd5cc39..0000000 --- a/contents/todoListAPI/seungseop/todolist/build.gradle +++ /dev/null @@ -1,81 +0,0 @@ -// querydsl 설정 -buildscript { - ext { - queryDslVersion = "5.0.0" - } -} - -plugins { - id 'java' - id 'org.springframework.boot' version '3.2.4' - id 'io.spring.dependency-management' version '1.1.4' -} - -group = 'com.serverstudy' -version = '0.0.1-SNAPSHOT' - -java { - sourceCompatibility = '17' -} - -// lombok 설정 -configurations { - compileOnly { - extendsFrom annotationProcessor - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - - // lombok 설정 - compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' - - // validation 설정 - implementation 'org.springframework.boot:spring-boot-starter-validation' - - // h2 설정 - runtimeOnly 'com.h2database:h2' // h2 : runtimeOnly -// implementation 'org.springframework.boot:spring-boot-starter-jdbc' // Jdbc, Driver -> JPA에 포함됨 - - - // swagger 설정 - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' // 접속 url: localhost:8080/swagger-ui/index.html - - // querydsl 설정 - implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" - annotationProcessor( - "jakarta.persistence:jakarta.persistence-api", - "jakarta.annotation:jakarta.annotation-api", - "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta") - - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -tasks.named('test') { - useJUnitPlatform() -} - -// Querydsl 설정부 -def generated = 'src/main/generated' - -// querydsl QClass 파일 생성 위치를 지정 -tasks.withType(JavaCompile) { - options.getGeneratedSourceOutputDirectory().set(file(generated)) -} - -// java source set 에 querydsl QClass 위치 추가 -sourceSets { - main.java.srcDirs += [ generated ] -} - -// gradle clean 시에 QClass 디렉토리 삭제 -clean { - delete file(generated) -} diff --git a/contents/todoListAPI/seungseop/todolist/gradle/wrapper/gradle-wrapper.jar b/contents/todoListAPI/seungseop/todolist/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136f3d4ba8a0da8d277868979cfbc8ad796..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/contents/todoListAPI/seungseop/todolist/gradlew.bat b/contents/todoListAPI/seungseop/todolist/gradlew.bat deleted file mode 100644 index 25da30d..0000000 --- a/contents/todoListAPI/seungseop/todolist/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/contents/todoListAPI/seungseop/todolist/settings.gradle b/contents/todoListAPI/seungseop/todolist/settings.gradle deleted file mode 100644 index 59357f0..0000000 --- a/contents/todoListAPI/seungseop/todolist/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'todolist' diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/TodolistApplication.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/TodolistApplication.java deleted file mode 100644 index 8767754..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/TodolistApplication.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.serverstudy.todolist; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; - -@SpringBootApplication -public class TodolistApplication { - - public static void main(String[] args) { - SpringApplication.run(TodolistApplication.class, args); - } - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/QueryDslConfig.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/QueryDslConfig.java deleted file mode 100644 index 8a22d0a..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/QueryDslConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.serverstudy.todolist.config; - -import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class QueryDslConfig { - - private final EntityManager em; - - @Autowired - public QueryDslConfig(EntityManager em) { - this.em = em; - } - - @Bean - public JPAQueryFactory jpaQueryFactory() { - return new JPAQueryFactory(em); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/SwaggerConfig.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/SwaggerConfig.java deleted file mode 100644 index c229f0d..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/config/SwaggerConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.serverstudy.todolist.config; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SwaggerConfig { - - @Bean - public OpenAPI openAPI() { - return new OpenAPI() - .components(new Components()) - .info(apiInfo()); - } - - private Info apiInfo() { - return new Info() - .title("TodoList API") // API의 제목 - .description("앱센터 서버스터디 TodoList 프로젝트 API 입니다.") // API에 대한 설명 - .version("1.0.0"); // API의 버전 - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/FolderController.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/FolderController.java deleted file mode 100644 index 038404d..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/FolderController.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.serverstudy.todolist.controller; - -import com.serverstudy.todolist.dto.request.FolderReq.FolderPatch; -import com.serverstudy.todolist.dto.request.FolderReq.FolderPost; -import com.serverstudy.todolist.dto.response.FolderRes; -import com.serverstudy.todolist.service.FolderService; -import io.swagger.v3.oas.annotations.Operation; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/api/folder") -@CrossOrigin(origins = "*") -@RequiredArgsConstructor -public class FolderController { - - private final FolderService folderService; - - @Operation - @PostMapping - public ResponseEntity postFolder (@Valid @RequestBody FolderPost folderPost, Long userId) { - - long folderId = folderService.create(folderPost, userId); - - return ResponseEntity.status(HttpStatus.CREATED).body(folderId); - } - - @GetMapping - public ResponseEntity getFoldersByUser(Long userId) { - - List responseList = folderService.getAllWithTodoCount(userId); - - return ResponseEntity.ok(responseList); - } - - @PatchMapping("/{folderId}") - public ResponseEntity patchFolder(@Valid @RequestBody FolderPatch folderPatch, @PathVariable Long folderId) { - - long modifiedFolderId = folderService.modify(folderPatch, folderId); - - return ResponseEntity.ok(modifiedFolderId); - } - - @DeleteMapping("/{folderId}") - public ResponseEntity deleteFolder(@PathVariable Long folderId) { - - folderService.delete(folderId); - - return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/TodoController.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/TodoController.java deleted file mode 100644 index 2b2df03..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/TodoController.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.serverstudy.todolist.controller; - -import com.serverstudy.todolist.dto.request.TodoReq.TodoGet; -import com.serverstudy.todolist.dto.request.TodoReq.TodoPost; -import com.serverstudy.todolist.dto.response.TodoRes; -import com.serverstudy.todolist.service.TodoService; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static com.serverstudy.todolist.dto.request.TodoReq.TodoFolderPatch; -import static com.serverstudy.todolist.dto.request.TodoReq.TodoPut; - -@RestController -@RequestMapping("/api/todo") -@CrossOrigin(origins = "*") -@RequiredArgsConstructor -public class TodoController { - - private final TodoService todoService; - - @PostMapping - public ResponseEntity postTodo(@Valid @RequestBody TodoPost todoPost, Long userId) { - - long todoId = todoService.create(todoPost, userId); - - return ResponseEntity.status(HttpStatus.CREATED).body(todoId); - } - - @GetMapping - public ResponseEntity getTodosByRequirements(@Valid @ModelAttribute TodoGet todoGet, Long userId) { - - List responseList = todoService.findAllByConditions(todoGet, userId); - - return ResponseEntity.ok(responseList); - } - - @PutMapping("/{todoId}") - public ResponseEntity putTodo(@Valid @RequestBody TodoPut todoPut, @PathVariable Long todoId, Long userId) { - - long updatedTodoId = todoService.update(todoPut, todoId, userId); - - return ResponseEntity.ok(updatedTodoId); - } - - @PatchMapping("/{todoId}/progress") - public ResponseEntity switchTodoProgress(@PathVariable Long todoId, Long userId) { - - long switchedTodoId = todoService.switchProgress(todoId, userId); - - return ResponseEntity.ok(switchedTodoId); - } - - @PatchMapping("/{todoId}/folder") - public ResponseEntity patchTodoFolder(@RequestBody TodoFolderPatch todoFolderPatch, @PathVariable Long todoId, Long userId) { - - long movedTodoId = todoService.moveFolder(todoFolderPatch.getFolderId(), todoId, userId); - - return ResponseEntity.ok(movedTodoId); - } - - @DeleteMapping("/{todoId}") - public ResponseEntity deleteTodo(@PathVariable Long todoId, Boolean restore, Long userId) { - - Long result = todoService.delete(todoId, restore, userId); - - return ResponseEntity.status(HttpStatus.OK).body(result); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/UserController.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/UserController.java deleted file mode 100644 index 8585a0e..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/controller/UserController.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.serverstudy.todolist.controller; - -import com.serverstudy.todolist.dto.request.UserReq.UserPost; -import com.serverstudy.todolist.dto.request.UserReq.UserPut; -import com.serverstudy.todolist.dto.response.UserRes; -import com.serverstudy.todolist.service.UserService; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Email; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/user") -@CrossOrigin(origins = "*") -@RequiredArgsConstructor -public class UserController { - - private final UserService userService; - - @PostMapping - public ResponseEntity postUser(@Valid @RequestBody UserPost userPost) { - - long userId = userService.join(userPost); - - return ResponseEntity.status(HttpStatus.CREATED).body(userId); - } - - @GetMapping("/check-email") - public ResponseEntity checkUserEmail(@RequestParam @Email String email) { - - boolean checked = userService.checkEmail(email); - - return ResponseEntity.ok(checked); - } - - @GetMapping - public ResponseEntity getUser(Long userId) { - - UserRes response = userService.get(userId); - - return ResponseEntity.ok(response); - } - - @PutMapping - public ResponseEntity putUser(@Valid @RequestBody UserPut UserPut, Long userId) { - - long modifiedUserId = userService.modify(UserPut, userId); - - return ResponseEntity.ok(modifiedUserId); - } - - - @DeleteMapping - public ResponseEntity deleteUser(Long userId) { - - userService.delete(userId); - - return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); - } - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Folder.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Folder.java deleted file mode 100644 index 4fd71f7..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Folder.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.serverstudy.todolist.domain; - -import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "folder_tb") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Getter -public class Folder { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column - @NotNull - private String name; // TODO 사용자별 폴더명 중복 검사는 로직에서 - - private Long userId; - - @Builder - private Folder(String name, long userId) { - this.name = name; - this.userId = userId; - } - - public void changeName(String name) { - this.name = name; - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Priority.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Priority.java deleted file mode 100644 index 6e850aa..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Priority.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.serverstudy.todolist.domain; - -import lombok.Getter; - -import java.util.Arrays; - -@Getter -public enum Priority { - - PRIMARY(1), - SECONDARY(2), - TERTIARY(3); - - private final int number; - - Priority (int number) { - this.number = number; - } - - public static Priority getPriority(int inputNumber) { - return Arrays.stream(Priority.values()) - .filter(priority -> priority.number == inputNumber) - .findAny() - .orElseThrow(() -> new IllegalArgumentException("해당하는 이름의 Priority를 찾을 수 없습니다")); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Progress.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Progress.java deleted file mode 100644 index 4cd582b..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Progress.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.serverstudy.todolist.domain; - -import lombok.Getter; - -@Getter -public enum Progress { - Todo, Doing, Done; - - public static Progress getProgress(String progress) { - - if (progress == null) { - throw new IllegalArgumentException("progrss가 null 값이면 안됩니다."); - } - - try { - return Progress.valueOf(progress); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("부적절한 progress 값: " + progress); - } - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Role.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Role.java deleted file mode 100644 index 0d2cb6f..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Role.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.serverstudy.todolist.domain; - -import lombok.Getter; - -@Getter -public enum Role { - USER("ROLE_USER"), ADMIN("ROLE_ADMIN"); - - private final String role; - - Role(String role) { - this.role = role; - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Todo.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Todo.java deleted file mode 100644 index 2e518ec..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/Todo.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.serverstudy.todolist.domain; - -import com.serverstudy.todolist.dto.request.TodoReq.TodoPut; -import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -@Entity -@Table(name = "todo_tb") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Getter -public class Todo { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String title; - - @Column(columnDefinition="text") - private String description; - - private LocalDateTime deadline; - - @Enumerated(EnumType.ORDINAL) - private Priority priority; - - @Enumerated(EnumType.STRING) - @NotNull - private Progress progress; - - private Boolean isDeleted; - - private LocalDateTime deletedTime; - - private Long userId; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "folder_id") - private Folder folder; - - @Builder - private Todo(String title, String description, LocalDateTime deadline, Priority priority, Progress progress, long userId, Folder folder) { - this.title = title; - this.description = description; - this.deadline = deadline; - this.priority = priority; - this.progress = progress; - this.isDeleted = false; - this.userId = userId; - this.folder = folder; - } - - public void switchProgress() { - if (this.progress.equals(Progress.Todo)) this.progress = Progress.Doing; - else if (this.progress.equals(Progress.Doing)) this.progress = Progress.Done; - else this.progress = Progress.Todo; - } - - public long moveToTrash() { - this.isDeleted = true; - this.deletedTime = LocalDateTime.now(); - - return this.id; - } - - public void changeFolder(Folder folder) { - this.folder = folder; - } - - public void updateTodo(TodoPut todoPut, Folder folder) { - this.title = todoPut.getTitle(); - this.description = todoPut.getDescription(); - this.deadline = todoPut.getDeadline(); - this.priority = todoPut.getPriority(); - this.progress = todoPut.getProgress(); - changeFolder(folder); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/User.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/User.java deleted file mode 100644 index 67e1e4e..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/domain/User.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.serverstudy.todolist.domain; - -import jakarta.persistence.*; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.HashSet; -import java.util.Set; - -@Entity -@Table(name = "user_tb") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Getter -public class User { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(unique = true) - @NotNull - @Email(message = "이메일 형식이 아닙니다.") - private String email; - - @Column - @NotNull - private String password; - - @Column - @NotNull - private String nickname; - - @ElementCollection(fetch = FetchType.EAGER) - private Set roles; - - @Builder - private User(String email, String password, String nickname) { - this.email = email; - this.password = password; - this.nickname = nickname; - this.roles = new HashSet<>(); - addRole(Role.USER); - } - - public void changePassword(String password) { - this.password = password; - } - - public void changeNickname(String nickname) { - this.nickname = nickname; - } - - public void addRole(Role role) { - this.roles.add(role); - } - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/FolderReq.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/FolderReq.java deleted file mode 100644 index 01339cc..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/FolderReq.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.serverstudy.todolist.dto.request; - -import com.serverstudy.todolist.domain.Folder; -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -public interface FolderReq { - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class FolderPost { - - @NotNull - private String name; - - public Folder toEntity(long userId) { - return Folder.builder() - .name(name) - .userId(userId) - .build(); - } - } - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class FolderPatch { - - @NotNull - private String name; - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/TodoReq.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/TodoReq.java deleted file mode 100644 index 98f755f..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/TodoReq.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.serverstudy.todolist.dto.request; - -import com.serverstudy.todolist.domain.Folder; -import com.serverstudy.todolist.domain.Priority; -import com.serverstudy.todolist.domain.Progress; -import com.serverstudy.todolist.domain.Todo; -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.time.LocalDateTime; - -public interface TodoReq { - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class TodoPost { - - private String title; - - private String description; - - private LocalDateTime deadline; - - private Integer priority; - - @NotNull - private Progress progress; - - private Long folderId; - - public Todo toEntity(long userId, Folder folder) { - return Todo.builder() - .title(title == null ? "" : title) - .description(description == null ? "" : description) - .deadline(deadline) - .priority(priority == null ? null : Priority.getPriority(priority)) - .progress(Progress.getProgress(progress.name())) - .userId(userId) - .folder(folder) - .build(); - } - - } - - @Getter - @Setter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class TodoGet { - - private Integer priority; - - private Progress progress; - - private Boolean isDeleted; - - private Long folderId; - } - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class TodoPut { - - private String title; - - private String description; - - private LocalDateTime deadline; - - private Integer priority; - - @NotNull - private Progress progress; - - private Long folderId; - - public String getTitle() { - return title == null ? "" : title; - } - - public String getDescription() { - return description == null ? "" : description; - } - - public Priority getPriority() { - return priority == null ? null : Priority.getPriority(priority); - } - - public Progress getProgress() { - return Progress.getProgress(progress.name()); - } - } - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class TodoFolderPatch { - - private Long folderId; - } - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/UserReq.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/UserReq.java deleted file mode 100644 index 4e758c0..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/request/UserReq.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.serverstudy.todolist.dto.request; - -import com.serverstudy.todolist.domain.User; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -public interface UserReq { - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class UserPost { - - @NotNull - @Email(message = "이메일 형식이 아닙니다.") - private String email; - - @NotNull - private String password; - - @NotNull - private String nickname; - - public User toEntity() { - return User.builder() - .email(email) - .password(password) - .nickname(nickname) - .build(); - } - } - - @Getter - @NoArgsConstructor(access = AccessLevel.PRIVATE) - class UserPut { - - private String password; - - private String nickname; - } - - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/FolderRes.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/FolderRes.java deleted file mode 100644 index 0452e35..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/FolderRes.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.serverstudy.todolist.dto.response; - -import lombok.Builder; -import lombok.Getter; - -@Getter -public class FolderRes { - - private final long folderId; - - private final String name; - - private final int todoCount; - - @Builder - private FolderRes(long folderId, String name, int todoCount) { - this.folderId = folderId; - this.name = name; - this.todoCount = todoCount; - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/TodoRes.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/TodoRes.java deleted file mode 100644 index c681ec6..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/TodoRes.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.serverstudy.todolist.dto.response; - -import lombok.Builder; -import lombok.Getter; - -import java.time.LocalDateTime; - -@Getter -public class TodoRes { - - private final Long id; - - private final String title; - - private final String description; - - private final LocalDateTime deadline; - - private final Integer priority; - - private final String progress; - - private final boolean isDeleted; - - private final Integer dateFromDelete; - - private final Long folderId; - - private final String folderName; - - @Builder - private TodoRes(Long id, String title, String description, LocalDateTime deadline, Integer priority, String progress, boolean isDeleted, Integer dateFromDelete, Long folderId, String folderName) { - this.id = id; - this.title = title; - this.description = description; - this.deadline = deadline; - this.priority = priority; - this.progress = progress; - this.isDeleted = isDeleted; - this.dateFromDelete = dateFromDelete; - this.folderId = folderId; - this.folderName = folderName; - } -} \ No newline at end of file diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/UserRes.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/UserRes.java deleted file mode 100644 index 26cad1f..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/dto/response/UserRes.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.serverstudy.todolist.dto.response; - -import lombok.Builder; -import lombok.Getter; - -@Getter -public class UserRes { - - private final long id; - - private final String email; - - private final String nickname; - - @Builder - private UserRes(long id, String email, String nickname) { - this.id = id; - this.email = email; - this.nickname = nickname; - } -} \ No newline at end of file diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/FolderRepository.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/FolderRepository.java deleted file mode 100644 index 6fb1bf9..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/FolderRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.serverstudy.todolist.repository; - -import com.serverstudy.todolist.domain.Folder; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; - -public interface FolderRepository extends JpaRepository { - - List findAllByUserIdOrderByNameAsc(long userId); - List findAllByUserId(long userId); - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepository.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepository.java deleted file mode 100644 index 2e12c08..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.serverstudy.todolist.repository; - -import com.serverstudy.todolist.domain.Priority; -import com.serverstudy.todolist.domain.Progress; -import com.serverstudy.todolist.domain.Todo; - -import java.util.List; - -public interface TodoCustomRepository { - - List findAllByConditions(Long folderId, Long userId, Priority priority, Progress progress, boolean isDeleted); -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepositoryImpl.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepositoryImpl.java deleted file mode 100644 index 685beea..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoCustomRepositoryImpl.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.serverstudy.todolist.repository; - -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQueryFactory; -import com.serverstudy.todolist.domain.Priority; -import com.serverstudy.todolist.domain.Progress; -import com.serverstudy.todolist.domain.QTodo; -import com.serverstudy.todolist.domain.Todo; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -@RequiredArgsConstructor -public class TodoCustomRepositoryImpl implements TodoCustomRepository { - - private final JPAQueryFactory queryFactory; - - @Override - public List findAllByConditions(Long folderId, Long userId, Priority priority, Progress progress, boolean isDeleted) { - - QTodo todo = QTodo.todo; - BooleanExpression booleanExpression; - - if (folderId != null) - booleanExpression = todo.folder.id.eq(folderId); - else - booleanExpression = todo.userId.eq(userId); - - if (priority != null) - booleanExpression = booleanExpression.and(todo.priority.eq(priority)); - if (progress != null) - booleanExpression = booleanExpression.and(todo.progress.eq(progress)); - - booleanExpression = booleanExpression.and(todo.isDeleted.eq(isDeleted)); - - return queryFactory.selectFrom(todo) - .where(booleanExpression) - .orderBy(todo.deadline.asc(), todo.priority.asc()) - .fetch(); - } -} \ No newline at end of file diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoRepository.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoRepository.java deleted file mode 100644 index 73f964f..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/TodoRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.serverstudy.todolist.repository; - -import com.serverstudy.todolist.domain.Folder; -import com.serverstudy.todolist.domain.Todo; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; - -public interface TodoRepository extends JpaRepository, TodoCustomRepository { - - int countByFolder(Folder folder); - - List findAllByIsDeletedOrderByDeletedTimeAsc (boolean isDeleted); - - List findAllByFolder(Folder folder); - - List findAllByUserId(long userId); -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/UserRepository.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/UserRepository.java deleted file mode 100644 index 94b7289..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/repository/UserRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.serverstudy.todolist.repository; - -import com.serverstudy.todolist.domain.User; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface UserRepository extends JpaRepository { - boolean existsByEmail(String email); -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/FolderService.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/FolderService.java deleted file mode 100644 index 61ca1d2..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/FolderService.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.serverstudy.todolist.service; - -import com.serverstudy.todolist.domain.Folder; -import com.serverstudy.todolist.domain.Todo; -import com.serverstudy.todolist.dto.request.FolderReq; -import com.serverstudy.todolist.dto.request.FolderReq.FolderPatch; -import com.serverstudy.todolist.dto.response.FolderRes; -import com.serverstudy.todolist.repository.FolderRepository; -import com.serverstudy.todolist.repository.TodoRepository; -import com.serverstudy.todolist.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.NoSuchElementException; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class FolderService { - - private final FolderRepository folderRepository; - - private final UserRepository userRepository; - - private final TodoRepository todoRepository; - - @Transactional - public long create(FolderReq.FolderPost folderPost, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - if (!userRepository.existsById(userId)) throw new NoSuchElementException("해당하는 유저가 존재하지 않습니다."); - - Folder folder = folderPost.toEntity(userId); - - return folderRepository.save(folder).getId(); - } - - public List getAllWithTodoCount(Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - - List folderList = folderRepository.findAllByUserIdOrderByNameAsc(userId); - - return folderList.stream().map(folder -> { - int todoCount = todoRepository.countByFolder(folder); - return FolderRes.builder() - .folderId(folder.getId()) - .name(folder.getName()) - .todoCount(todoCount) - .build(); - }).toList(); - } - - @Transactional - public long modify(FolderPatch folderPatch, long folderId) { - - Folder folder = folderRepository.findById(folderId).orElseThrow(() -> new NoSuchElementException("해당하는 폴더가 존재하지 않습니다.")); - - folder.changeName(folderPatch.getName()); - - return folder.getId(); - } - - @Transactional - public void delete(long folderId) { - - Folder folder = folderRepository.findById(folderId).orElseThrow(() -> new NoSuchElementException("해당하는 폴더가 존재하지 않습니다.")); - - // 투두 리스트에서 폴더 null 값으로 변경 - List todoList = todoRepository.findAllByFolder(folder); - todoList.forEach(todo -> todo.changeFolder(null)); - - folderRepository.delete(folder); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/TodoService.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/TodoService.java deleted file mode 100644 index 9671913..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/TodoService.java +++ /dev/null @@ -1,163 +0,0 @@ -package com.serverstudy.todolist.service; - -import com.serverstudy.todolist.domain.Folder; -import com.serverstudy.todolist.domain.Priority; -import com.serverstudy.todolist.domain.Progress; -import com.serverstudy.todolist.domain.Todo; -import com.serverstudy.todolist.dto.request.TodoReq.TodoGet; -import com.serverstudy.todolist.dto.request.TodoReq.TodoPost; -import com.serverstudy.todolist.dto.request.TodoReq.TodoPut; -import com.serverstudy.todolist.dto.response.TodoRes; -import com.serverstudy.todolist.repository.FolderRepository; -import com.serverstudy.todolist.repository.TodoRepository; -import com.serverstudy.todolist.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.NoSuchElementException; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class TodoService { - - private final TodoRepository todoRepository; - private final UserRepository userRepository; - private final FolderRepository folderRepository; - - public long create(TodoPost todoPost, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다"); - if (!userRepository.existsById(userId)) throw new NoSuchElementException("해당하는 유저가 존재하지 않습니다."); - - Folder folder = null; - - if (todoPost.getFolderId() != null) - folder = folderRepository.findById(todoPost.getFolderId()).orElse(null); - - Todo todo = todoPost.toEntity(userId, folder); - - return todoRepository.save(todo).getId(); - } - - public List findAllByConditions(TodoGet todoGet, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다"); - - Long folderId = todoGet.getFolderId(); - Priority priority = todoGet.getPriority() == null ? null : Priority.getPriority(0); - Progress progress = todoGet.getProgress() == null ? null : Progress.getProgress(todoGet.getProgress().name()); - boolean isDeleted = todoGet.getIsDeleted() != null && todoGet.getIsDeleted(); - - List todoList = todoRepository.findAllByConditions(folderId, userId, priority, progress, isDeleted); - - return todoList.stream().map(todo -> { - Integer dateFromDelete; - if (todo.getIsDeleted()) - dateFromDelete = (int) ChronoUnit.DAYS.between(todo.getDeletedTime(), LocalDateTime.now()); - else - dateFromDelete = null; - - Long foundFolderId; - String folderName; - if (todo.getFolder() != null){ - foundFolderId = todo.getFolder().getId(); - folderName = todo.getFolder().getName(); - } - else { - foundFolderId = null; - folderName = null; - } - - return TodoRes.builder() - .id(todo.getId()) - .title(todo.getTitle()) - .description(todo.getDescription()) - .deadline(todo.getDeadline()) - .priority(todo.getPriority().getNumber()) - .progress(todo.getProgress().name()) - .isDeleted(todo.getIsDeleted()) - .dateFromDelete(dateFromDelete) - .folderId(foundFolderId) - .folderName(folderName) - .build(); - }).toList(); - } - - @Transactional - public long update(TodoPut todoPut, long todoId, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - Todo todo = todoRepository.findById(todoId).orElseThrow(() -> new NoSuchElementException("해당하는 todo가 존재하지 않습니다.")); - - Folder folder = null; - - if (todoPut.getFolderId() != null) - folder = folderRepository.findById(todoPut.getFolderId()).orElseThrow(() -> new NoSuchElementException("해당하는 folder가 존재하지 않습니다.")); - - todo.updateTodo(todoPut, folder); - - return todo.getId(); - } - - @Transactional - public long switchProgress(long todoId, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다"); - Todo todo = todoRepository.findById(todoId).orElseThrow(() -> new NoSuchElementException("해당하는 todo가 존재하지 않습니다.")); - - todo.switchProgress(); - - return todo.getId(); - } - - @Transactional - public long moveFolder(Long folderId, long todoId, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - Todo todo = todoRepository.findById(todoId).orElseThrow(() -> new NoSuchElementException("해당하는 todo가 존재하지 않습니다.")); - - Folder folder = folderRepository.findById(folderId).orElseThrow(() -> new NoSuchElementException("해당하는 folder가 존재하지 않습니다.")); - - todo.changeFolder(folder); - - return todo.getId(); - } - - @Transactional - public Long delete(long todoId, Boolean restore, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - if (restore == null) throw new IllegalArgumentException("restore 값이 비어있습니다."); - Todo todo = todoRepository.findById(todoId).orElseThrow(() -> new NoSuchElementException("해당하는 todo가 존재하지 않습니다.")); - - Long result = null; - if (restore) - result = todo.moveToTrash(); - else - todoRepository.delete(todo); - - return result; - } - - // 일정 주기로 실행할 스케줄링 메서드 - @Scheduled(cron = "0 0 0 * * ?") // 매일 자정에 실행 - @Transactional - public void deleteInTrash() { - - List todoList = todoRepository.findAllByIsDeletedOrderByDeletedTimeAsc(true); - - for (Todo todo : todoList) { - int dateFromDelete = (int) ChronoUnit.DAYS.between(todo.getDeletedTime(), LocalDateTime.now()); - - if (dateFromDelete < 30) break; - todoRepository.delete(todo); - } - } - -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/UserService.java b/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/UserService.java deleted file mode 100644 index aa365ef..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/java/com/serverstudy/todolist/service/UserService.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.serverstudy.todolist.service; - -import com.serverstudy.todolist.domain.User; -import com.serverstudy.todolist.dto.request.UserReq.UserPost; -import com.serverstudy.todolist.dto.request.UserReq.UserPut; -import com.serverstudy.todolist.dto.response.UserRes; -import com.serverstudy.todolist.repository.FolderRepository; -import com.serverstudy.todolist.repository.TodoRepository; -import com.serverstudy.todolist.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.NoSuchElementException; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class UserService { - - private final UserRepository userRepository; - private final TodoRepository todoRepository; - private final FolderRepository folderRepository; - - @Transactional - public long join(UserPost userPost) { - - String email = userPost.getEmail(); - - if (userRepository.existsByEmail(email)) - throw new IllegalArgumentException("해당하는 이메일이 이미 존재합니다."); - - User user = userPost.toEntity(); - - return userRepository.save(user).getId(); - } - - public boolean checkEmail(String email) { - return userRepository.existsByEmail(email); - } - - public UserRes get(Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - User user = userRepository.findById(userId).orElseThrow(() -> new NoSuchElementException("해당하는 유저가 존재하지 않습니다.")); - - return UserRes.builder() - .id(user.getId()) - .email(user.getEmail()) - .nickname(user.getNickname()) - .build(); - } - - @Transactional - public long modify(UserPut userPut, Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - User user = userRepository.findById(userId).orElseThrow(() -> new NoSuchElementException("해당하는 유저가 존재하지 않습니다.")); - - String password = userPut.getPassword(); - String nickname = userPut.getNickname(); - - if (password != null) { - user.changePassword(password); - } - if (nickname != null) { - user.changeNickname(nickname); - } - - return user.getId(); - } - - @Transactional - public void delete(Long userId) { - - if (userId == null) throw new IllegalArgumentException("userId 값이 비어있습니다."); - User user = userRepository.findById(userId).orElseThrow(() -> new NoSuchElementException("해당하는 유저가 존재하지 않습니다.")); - - // 투두 리스트와 폴더 삭제 - todoRepository.deleteAll(todoRepository.findAllByUserId(userId)); - folderRepository.deleteAll(folderRepository.findAllByUserId(userId)); - - userRepository.delete(user); - } -} diff --git a/contents/todoListAPI/seungseop/todolist/src/main/resources/application.properties b/contents/todoListAPI/seungseop/todolist/src/main/resources/application.properties deleted file mode 100644 index d0a2562..0000000 --- a/contents/todoListAPI/seungseop/todolist/src/main/resources/application.properties +++ /dev/null @@ -1,31 +0,0 @@ -spring.application.name=todolist - -# h2 database view in web -spring.h2.console.enabled=true -spring.h2.console.path=/h2-console - -# spring - h2 connect driver -spring.datasource.driverClassName=org.h2.Driver - -# DB connect JDBC URL -# embedded Mode -#spring.datasource.url=jdbc:h2:~/todolist -# In-Memory mode -spring.datasource.url=jdbc:h2:mem:testdb - -spring.datasource.username=sa -spring.datasource.password= - -# JPA -# Database Engine Type -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect - -# spring.jpa.hibernate.ddl-auto setting -spring.jpa.hibernate.ddl-auto=update - -# Verifying queries executed on the console (for test) -spring.jpa.properties.hibernate.format_sql=true -spring.jpa.properties.hibernate.show_sql=true - -# make swagger verifying duplicated method name in inner class -springdoc.use-fqn=true \ No newline at end of file From 81be58d2d6ad2705f33ec306538b302115eccb83 Mon Sep 17 00:00:00 2001 From: jiyun Date: Thu, 9 May 2024 17:55:10 +0900 Subject: [PATCH 02/13] =?UTF-8?q?[Refactor]=20MySQL=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20-#34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/jiyunio/todolist/category/Category.java | 2 ++ .../java/com/jiyunio/todolist/member/MemberService.java | 7 ++++--- .../dto/{ChangeUserPwDto.java => ChangeUserPwDTO.java} | 0 .../todolist/member/dto/{SignInDto.java => SignInDTO.java} | 0 .../todolist/member/dto/{SignUpDto.java => SignUpDTO.java} | 0 .../todo/dto/{CreateTodoDto.java => CreateTodoDTO.java} | 0 .../todo/dto/{UpdateTodoDto.java => UpdateTodoDTO.java} | 0 7 files changed, 6 insertions(+), 3 deletions(-) rename contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/{ChangeUserPwDto.java => ChangeUserPwDTO.java} (100%) rename contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/{SignInDto.java => SignInDTO.java} (100%) rename contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/{SignUpDto.java => SignUpDTO.java} (100%) rename contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/{CreateTodoDto.java => CreateTodoDTO.java} (100%) rename contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/{UpdateTodoDto.java => UpdateTodoDTO.java} (100%) diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java index a2ae2ed..684d2a0 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java @@ -32,3 +32,5 @@ protected void updateCategory(String category) { this.category = category; } } + + diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java index 2492d83..d4ced74 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java @@ -5,6 +5,7 @@ import com.jiyunio.todolist.member.dto.ChangeUserPwDTO; import com.jiyunio.todolist.member.dto.SignInDTO; import com.jiyunio.todolist.member.dto.SignUpDTO; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -14,7 +15,7 @@ public class MemberService { private final MemberRepository memberRepository; - public String signUp(SignUpDTO signUpDto) { + public String signUp(@Valid SignUpDTO signUpDto) { if (memberRepository.existsByUserEmail(signUpDto.getUserEmail())) { // 이미 존재하는 이메일 throw new CustomException(HttpStatus.BAD_REQUEST, ErrorCode.EXIST_EMAIL); @@ -39,7 +40,7 @@ public String signUp(SignUpDTO signUpDto) { throw new CustomException(HttpStatus.BAD_REQUEST, ErrorCode.NOT_SAME_CONFIRM_PASSWORD); } - public String signIn(SignInDTO signInDto) { + public String signIn(@Valid SignInDTO signInDto) { if (memberRepository.existsByUserId(signInDto.getUserId())) { Member member = memberRepository.findByUserId(signInDto.getUserId()).get(); if (member.getUserPw().equals(signInDto.getUserPw())) { @@ -53,7 +54,7 @@ public String signIn(SignInDTO signInDto) { throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.NOT_EXIST_USERID); } - public void updateUserPw(Long id, ChangeUserPwDTO changeUserPwDto) { + public void updateUserPw(Long id, @Valid ChangeUserPwDTO changeUserPwDto) { Member member = memberRepository.findById(id).get(); if (member.getUserPw().equals(changeUserPwDto.getUserPw())) { // 회원 비밀번호 확인 if (changeUserPwDto.getChangePw().equals(changeUserPwDto.getConfirmChangePw())) { diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDto.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDTO.java similarity index 100% rename from contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDto.java rename to contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDTO.java diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDto.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDTO.java similarity index 100% rename from contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDto.java rename to contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDTO.java diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDto.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDTO.java similarity index 100% rename from contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDto.java rename to contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDTO.java diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDto.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDTO.java similarity index 100% rename from contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDto.java rename to contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDTO.java diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDto.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDTO.java similarity index 100% rename from contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDto.java rename to contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDTO.java From 11766382968c311eac7c0cbf635a7d20534bfaba Mon Sep 17 00:00:00 2001 From: jiyun Date: Fri, 10 May 2024 22:33:44 +0900 Subject: [PATCH 03/13] =?UTF-8?q?[Refactor]=20MySQL=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20-#34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contents/todoListAPI/jiyun/todolist/build.gradle | 3 +-- .../src/main/resources/application.properties | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/contents/todoListAPI/jiyun/todolist/build.gradle b/contents/todoListAPI/jiyun/todolist/build.gradle index a22ed3f..cffae05 100644 --- a/contents/todoListAPI/jiyun/todolist/build.gradle +++ b/contents/todoListAPI/jiyun/todolist/build.gradle @@ -20,12 +20,11 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - runtimeOnly 'com.h2database:h2' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' - + runtimeOnly 'com.mysql:mysql-connector-j' } tasks.named('test') { diff --git a/contents/todoListAPI/jiyun/todolist/src/main/resources/application.properties b/contents/todoListAPI/jiyun/todolist/src/main/resources/application.properties index 7b5e10d..86d9fa4 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/resources/application.properties +++ b/contents/todoListAPI/jiyun/todolist/src/main/resources/application.properties @@ -1,15 +1,14 @@ spring.application.name=todolist #DB +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.h2.console.enabled=true -spring.h2.console.path=/h2-console -spring.datasource.url=jdbc:h2:~/todolist -spring.datasource.driver-class-name=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password= +spring.datasource.url=jdbc:mysql://localhost:3306/todolist +spring.datasource.username=jiyun +spring.datasource.password=1234 #JPA -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect +spring.jpa.database=mysql spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.show_sql=true spring.jpa.hibernate.ddl-auto=update From 959c936b23562e4cbad02515d97d01f02b3893c5 Mon Sep 17 00:00:00 2001 From: jiyun Date: Mon, 13 May 2024 01:54:00 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[Docs]=204=EC=A3=BC=EC=B0=A8=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=B6=94=EA=B0=80=20-#35?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../concepts/Img/week4/validationPosition.png | Bin 0 -> 68973 bytes contents/concepts/week1/seungseop.md | 424 --------- contents/concepts/week2/seungseop.md | 874 ------------------ contents/concepts/week3/kangwook.md | 81 -- contents/concepts/week3/seungseop.md | 622 ------------- contents/concepts/week4/hyeonseung.md | 187 ---- contents/concepts/week4/jiyun.md | 48 +- 7 files changed, 47 insertions(+), 2189 deletions(-) create mode 100644 contents/concepts/Img/week4/validationPosition.png delete mode 100644 contents/concepts/week1/seungseop.md delete mode 100644 contents/concepts/week2/seungseop.md delete mode 100644 contents/concepts/week3/kangwook.md delete mode 100644 contents/concepts/week3/seungseop.md delete mode 100644 contents/concepts/week4/hyeonseung.md diff --git a/contents/concepts/Img/week4/validationPosition.png b/contents/concepts/Img/week4/validationPosition.png new file mode 100644 index 0000000000000000000000000000000000000000..2197c19da7d4ea3f8a1444e2e8858845f0b02a53 GIT binary patch literal 68973 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 W)!SgsM*^3|x*>NvhA literal 0 HcmV?d00001 diff --git a/contents/concepts/week1/seungseop.md b/contents/concepts/week1/seungseop.md deleted file mode 100644 index a19f4c7..0000000 --- a/contents/concepts/week1/seungseop.md +++ /dev/null @@ -1,424 +0,0 @@ -# 1주차_서버는 무엇이고 어떻게 동작할까? / 자바 웹 프레임워크는 어떻게 변화해 왔을까? - -생성일: 2024년 3월 29일 오후 3:04 -태그: 서버 스터디 - -### 서버는 무엇이고 어떻게 동작할까요?, 자바 웹 프레임워크는 어떻게 변화해 왔을까요? - -- 서버와 클라이언트는 무엇인가요? -- 자바 웹 프레임워크의 역사 - - J2EE(JavaEE), EJB, Servlet, JSP는 무엇일까요? - - 스프링 프레임워크는 어떻게 탄생하게 되었나요? - -# 서버란? - -> ***ser·ver [**명사]* -> -> 1. *(컴퓨터의) 서버* -> 2. *(테니스 등에서) 서브하는 사람* -> 3. *美 (식당에서) 서빙하는 사람, 웨이터, 웨이터리스* - -서버는 ‘제공하다’의 뜻을 가진 ‘serve’에 사람이라는 뜻을 나타내는 ‘er’을 붙인 단어이다. 즉, 무언가를 제공하는 이를 서버라고 부른다는 것을 알 수 있다. 테니스, 배구 같은 스포츠에서는 처음 공을 던지는(제공하는) 사람을 서버라고 부르고, 식당에서는 손님에게 음식 등을 전달하는(제공하는) 사람을 서버라고 부른다. 그렇다면 컴퓨터에서 서버는 무엇일까? - -![001-1-1](https://github.com/inu-appcenter/server-study-16th/assets/86196038/5fed29be-879a-4c69-a761-0a65cf05f36f) - -> ***서버**(server)는 클라이언트에게 네트워크를 통해 정보나 서비스를 제공하는 컴퓨터 시스템* -> - -서버에는 여러가지가 있다. - -- 웹 서버: 웹 사이트 서비스를 제공하기 위한 서버 -- 도메인 서버 : 도메인을 관리하기 위한 서버 -- 이미지 서버 : 이미지를 관리하기 위한 서버 -- 이메일 서버 : 이메일을 관리하기 위한 서버 -- DB 서버 : 데이터 정보를 관리하기 위한 서버 -- 게임 서버 : 게임을 제공하기 위한 서버 - -또한 서버는 컴퓨터나 장치 같은 ‘하드웨어’만을 의미하지 않는다. 기능을 제공하도록 도와주는 ‘소프트웨어’도 서버라는 개념에 포함된다. - -이해를 돕기 위해 예를 들자면 홈페이지가 인터넷에 구현되기 위해서는 여러 종류의 서버가 필요하다. 그 중 가장 중요한 한 가지가 웹 서버 (web server)라고 할 수 있다. - -![005-1](https://github.com/inu-appcenter/server-study-16th/assets/86196038/950b744a-ffc4-4986-aeb5-03d9b5e8d321) - - -웹 서버 - -홈페이지 제작이 되기 위한 서버를 하드웨어적 측면과 소프트웨어적 측면으로 나눠서 살펴보자면, - -우선, 하드웨어적 측면에서 ‘웹 서버 컴퓨터’가 필요하다. 이는 각각의 목적에 맞춰서 한 대일 수도 여러 대가 될 수도 있다. - -다음으로, 소프트웨어적인 측면에서 웹 서버 컴퓨터 (하드웨어)에 들어있는 홈페이지 재료들을 웹에 뿌려주고 동작하게 하는 ‘웹 서버 프로그램’이 필요하다. 웹 서버 프로그램도 아파치 (Apache), 엔진엑스 (Nginx) 등 여러 가지가 존재한다. - -서버라는 개념은 하드웨어와 소프트웨어를 포함해 굉장히 많은 의미를 내포하고 있다. 따라서 서버는 누군가에게 서비스를 제공하는 ‘역할’이라고 보는 것이 좋다. 즉, 웹 서버는 클라이언트에게 웹 서비스를 제공하는 역할을 하는 것을 의미한다고 볼 수 있다. - -### 클라이언트 서버 모델 - -서버는 단독으로 움직이지 않으며 불특정 다수의 컴퓨터에 일방적으로 서비스를 제공하는 것도 아니다. 서버는 **클라이언트로부터 요청(Request)를 받아야 비로소 처리를 시작하여 서비스를 제공**한다. - -서버가 클라이언트에게 서비스를 제공할 때 다음과 같은 처리가 일어난다. - -1. 클라이언트가 서버에게 어떤 서비스를 요청 -2. 서버는 요청에 응답해 처리를 수행 -3. 서버는 처리 결과를 클라이언트에게 반환 -4. 클라이언트는 처리 결과를 받음 - - ![img1 daumcdn](https://github.com/inu-appcenter/server-study-16th/assets/86196038/2849bf10-e282-423e-8a2c-f86a3df0a43d) - - - -이처럼 서버와 클라이언트로 구성된 시스템을 ‘클라이언트 서버 모델’이라고 한다. - -클라이언트 서버 모델은 서버에서 데이터를 쉽게 관리할 수 있기 때문에 대부분의 컴퓨터 시스템에서 채택하고 있고 웹 시스템은 클라이언트 서버 모델을 사용하는 대표적인 예이다. - -### 웹 시스템에서 클라이언트 서버 모델 - -웹 시스템에서 클라이언트 서버 모델을 알아보기에 앞서 웹에서 클라이언트와 서버는 정확히 무엇을 말하는 것인지 알아보겠다. - -웹 개발에서 **클라이언트 측**은 웹 애플리케이션에서 최종 사용자 장치(클라이언트)에 표시되거나 발생하는 모든 것을 의미한다. 여기에는 텍스트, 이미지, 나머지 UI 등 사용자에게 표시되는 내용과 애플리케이션이 사용자의 브라우저 내에서 수행하는 모든 작업이 포함된다. - -HTML, CSS 등의 마크업 언어는 클라이언트 측의 브라우저에서 해석된다. 최근에는 많은 개발자들이 애플리케이션 아키텍처에 클라이언트 측 프로세스를 포함시키며, 모든 것을 서버 측에서 처리하는 것에서 벗어나고 있다. 예를 들어 최신 웹 애플리케이션에서는 동적 웹 페이지에 대한 비즈니스 로직이 JavaScript로 작성되어 클라이언트 측에서 실행된다. - -클라이언트 측과 마찬가지로 **서버 측**은 클라이언트가 아닌 서버에서 일어나는 모든 일을 의미한다. - -과거에는 거의 모든 비즈니스 로직이 서버 측에서 실행되었으며, 여기에는 동적 웹 페이지 렌더링, 데이터베이스와의 상호 작용, 신원 인증, 푸시 알림 등이 포함되었다. - -![images_juejue_post_9274c6d8-b59a-4fab-a09c-37b985ee3f7a_image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/0b7aea1f-61e0-43c9-b66b-ee78e29976b0) - -위 사진은 웹에서 클라이언트 서버 모델의 기본이 되었던 형태이다. - -웹 브라우저(클라이언트)는 웹 서버에게 페이지를 요청하여 응답받은 페이지를 화면에 띄운다. - -또는 클라이언트에서 DBMS에 정보를 요청을 하며 응답 받은 결과를 사용한다. DBMS는 사용자들이 DB 내의 데이터에 접근할 수 있도록 도와주는 소프트웨어이다. DBMS는 보통 서버 형태로 서비스를 제공하기 때문에 위처럼 클라이언트 측에서 DBMS에 접근하여 동작하는 프로그램이 많이 만들어졌다. - -하지만 이런 형태는 클라이언트 측에서 로직이 많아지고 프로그램의 크기가 커져 클라이언트 측 부담이 많아진다는 문제점이 있다. 게다가 로직이 변경될 때마다 프로그램을 매번 배포해주어야 했고, 로직이 클라이언트에 포함되어 있는 만큼 보안에도 문제가 있었다. - -![images_juejue_post_d214b46d-e7f9-4376-ac66-44ca52dab960_image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/c0022ba4-d5b8-49a5-a3e1-d791cc658873) - -이런 이유로 **미들웨어**가 등장했다. - -클라이언트와 DBMS 사이에 비즈니스 로직을 수행해주는 또 다른 서버, 미들웨어를 두어 클라이언트는 요청을 단순히 미들웨어로 보내면, 미들웨어는 클라이언트가 부담하던 로직을 수행하고, 데이터 조작이 필요하면 DBMS에 부탁한 뒤 결과를 클라이언트에게 전송하도록 하였다. - -미들웨어의 등장으로 클라이언트는 더 이상 복잡한 로직을 담당할 필요가 없어졌고, 프로그램의 크기도 작아졌으며, 로직 수정 시 매번 배포해야 했던 번거로움을 해결했다. - -미들웨어에는 2가지 종류가 있다. - -- **웹 서버(Web Server)** - - ![images_juejue_post_55b55758-25f6-4889-8221-18c8d09ecd9b_image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/9b680e53-ca76-4d35-8257-50b98c234d60) - - - -WS(웹 서버)는 웹 브라우저 클라이언트로부터 HTTP 요청을 받아 정적인 컨텐츠(.html .jpeg .css 등)를 제공한다. 단순히 저장되어 있는 웹 페이지를 클라이언트로 전달하고, 클라이언트로부터 컨텐츠를 전달 받아 저장하거나 처리하는 역할을 담당한다. - -WS의 예로는 Apache Server, Nginx IIS(Windows 전용 Web 서버) 등이 있다. - -- **웹 어플리케이션 서버 (Web Application Server)** - - ![images_juejue_post_c70d1fe7-b139-4fb1-be74-0a0153ef9f5f_image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/848a063b-5b4e-40d2-8d5e-d04cfecc53e8) - - -WAS(웹 어플리케이션 서버)는 DB 조회나 다양한 로직 처리를 요구하는 동적인 컨텐츠를 제공하기 위해 만들어진 Application Server이다. HTTP를 통해 컴퓨터나 장치의 어플리케이션을 수행해주는 미들웨어라고 볼 수 있다. - -웹 서버 + 웹 컨테이너의 형태를 띄고 있고, 웹 서버 기능들을 구조적으로 분리하여 처리하고자 하는 목적으로 제시되었다. - -WAS의 예로는 Tomcat, JBoss, Jeus, Web Sphere 등이 있다. - -![img1 daumcdn](https://github.com/inu-appcenter/server-study-16th/assets/86196038/989d31ad-2169-46da-b543-554e0c6a1654) - - - -# 자바 웹 프레임워크의 역사 - -### 웹 프레임워크(Web Framework)? - -> ***웹 프레임워크**는 웹 개발 프로세스의 일부 측면을 자동화하여 더 쉽고 빠르게 만들 수 있는 소프트웨어 도구* -> - -웹사이트, 웹 어플리케이션, 모바일 앱 또는 소프트웨어의 아키텍처를 구축하는데 도움이 되는 모델을 말한다. - -즉, 자바 웹 프레임워크는 자바 언어로 웹 구축을 쉽게 할 수 있도록 탄생한 도구이다. 대표적으로 Spring 프레임워크를 예로 들 수 있다. - -그렇다면 자바 웹 프레임워크는 어떻게 생겨났고 어떻게 발전해왔을까? 그 과정을 알기 위해 웹의 등장부터 순서대로 알아보겠다. - -### 웹의 시작 - -- **WWW (World-Wide-Web)** - - ![what-is-www](https://github.com/inu-appcenter/server-study-16th/assets/86196038/fdf79441-fbfe-4d27-83a7-be3050b7b088) - - - -웹은 월드 와이드 웹 (WWW)을 짧게 줄여 부르는 말이다. 웹은 1989년, ‘팀 버너스 리’라는 사람이 당시 CERN(유럽 입자 물리 연구소)에서 근무하면서 핵 소립자 실험의 성과를 전 세계 연구자들과 쉽게 공유하고자 하는 니즈에서 시작되었다. - -당대에도 이메일이나 파일 전송과 같은 기술은 존재했으나 그는 수많은 연구자를 상대로 일일이 메일을 보내는 방법이 번거롭다 여겼고 경영진에게 하이퍼텍스트(HyperText) 개념 소개와 함께 ‘정보 관리 네트워크’의 필요성을 주장하며 제안서를 제출한다. 이 제안서가 WWW의 개념적인 시초이다. - -> *하이퍼텍스트(HyperText)란 웹 페이지를 다른 웹 페이지로 연결할 수 있는 문서를 말한다. 이런 하이퍼텍스트의 등장으로 참조하고 있는 다른 페이지에 대한 열람이 쉬워졌고, 정보의 전달 효율은 크게 향상되었다.* -> - -팀 버너스 리는 이후 WWW의 실제 구현에 참여했고 구현 과정에서 웹의 핵심 기술들인 HTML과 HTTP 등이 고안되었다. 그리고 최초의 웹 서버로 불리는 CERN Httpd도 이 시점에 등장하였다. - -- **CGI** - -WWW에 대한 수요가 급속도로 늘어남에 따라 동적 페이지에 대한 요구 또한 증대되었다. - -하지만 초기 웹 서버 모델은 URL에 맞춰 페이지를 반환하기만 할 뿐, 동적인 페이지를 생성할 능력이 없어 동적 페이지 생성을 위해서는 외부 프로그램의 도움이 필요했다. - -따라서 HTTP 요청이 들어오면 그에 걸맞은 적절한 프로그램을 수행하자는 아이디어가 부상하게 되었고, CGI라는 표준 인터페이스가 등장하게 되었다. - -> *CGI란, Common Gateway Interface (공용 게이트웨이 인터페이스)의 약자로 서버와 애플리케이션 간에 데이터를 주고받는 방식을 의미한다.* -> - -![2023-10-25-HISTORY-OF-WEB-APP_002](https://github.com/inu-appcenter/server-study-16th/assets/86196038/a3bc3b7d-79a9-44f5-ae2f-e4b9a0a97dcf) - - -웹 서버는 동적 페이지를 원하는 클라이언트의 요청이 들어오면 CGI 인터페이스를 통해 외부 프로그램을 실행시키면서 적절한 HTTP 응답을 반환할 수 있었다. - -하지만 CGI 방식에는 몇 가지 문제점들이 존재했다. - -1. 요청마다 프로그램을 실행시켜야 해 서버 리소스가 많이 소모됨 -2. HTTP 요청마다 스레드가 아닌 프로세스를 할당하는 구조이기에 서버 부하가 상당함. -3. CGI 프로그램이 C, C++, Perl 등의 언어로 작성되어 어플리케이션 확장이 어려움 - -이에 Java 진영에서 이런 문제점들을 해결할 수 있는 Servlet이라는 모델을 제시했다. - -### 자바 웹 - -- **Servlet** - -Servlet은 Java 코드를 사용해서 웹페이지를 동적으로 생성하는 기술을 의미한다. HTTP 요청이 들어오면 이에 대응하는 클래스의 메서드를 호출하는 방식을 갖고 있다. - -이런 Servlet 방식은 CGI 방식이 요청마다 프로세스를 할당했던 것과는 달리 스레드를 할당하였기 때문에 상당히 경제적이었다. - -구체적으로는 Java Application을 미리 띄워두기 때문에 매번 프로세스를 할당할 필요가 없다. HTTP 요청이 들어오면 Java Application에게 처리를 의뢰하고 Java Application은 스레드를 생성해 요청 처리에 적합한 Servlet을 실행한다. - -또한 Servlet은 Java 진영의 기술이기 때문에 순수 Java로 작성되어 JVM 생태계에 친화적이고, Java의 특징 중 하나인 ‘플랫폼 독립성’을 가장 잘 누릴 수 있게 된다. 즉, Servlet을 한 번만 구현해 두면 어느 플랫폼에서도 쉽게 재사용할 수 있다. - -Servlet의 HTTP 요청 처리 방식은 CGI 방식과 크게 다르진 않다. - -![2023-10-25-HISTORY-OF-WEB-APP_004](https://github.com/inu-appcenter/server-study-16th/assets/86196038/b455fcf8-056c-4447-bbb8-d075be54339c) - - -HTTP 요청이 발생하고 웹 서버에 도달하면 웹 서버는 Servlet Container에게 요청을 전달한다. Servlet Container는 적절한 Servlet(Java 프로그램)을 선택하고 실행시킨다. Servlet은 요청에 걸맞은 동적 페이지를 반환한다. - -> *Servlet Container란 Servlet을 관리해주면서 동적 웹페이지를 제공하기 위한 기타 작업을 수행해주는 역할을 한다. Servlet은 동적 페이지를 만들어내기 위한 프로그램에 불과하므로 이들을 초기화해주고 관리해주는 누군가가 필요하기 때문이다.* -> - -그렇지만 서블릿 방식의 웹 어플리케이션에도 문제점이 있었다. 자바 코드에서 HTML을 다루다보니 비즈니스 로직과 뷰의 영역이 분리되지 않고 모호하게 공존했다. 아래 Servlet 코드에서는 로그인 처리를 위한 코드와 렌더링을 위한 코드가 하나의 메서드에 존재한다. - -```java -public class MyServlet extends HttpServlet { - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) { - String account = request.getHeader("account"); - String password = request.getHeader("password"); - - // 비즈니스 로직 - validateCredential(account, password); - - // 뷰를 위한 로직 - out.write(""); - out.write(" "); - out.write(" Hello world! "); - out.write(""); - } -``` - -뷰와 비즈니스 로직의 수정 지점이 같다보니 유지 보수하는 데 어려움을 겪기 일쑤였다. 프로그래머는 Servlet 코드를 변경하고 싶어도 디자이너가 HTML 작업을 하고 있다면 기다려야 했다. - -따라서 Java 코드와 HTML 코드의 분리를 더 명확히 하자는 요구가 생겨냤고, JSP가 등장하게 된다. - -- **JSP** - -JSP는 Java Server Page의 약자로 (현재는 Jakarta Server Page라고도 불림) HTML 코드에 Java 코드를 넣어 동적 웹 페이지를 생성하는 기술을 의미한다. - -아래 코드는 간단한 JSP 파일의 예시이다. <% %> 블록 안에 Java 코드가 포함되어 있다. <% %>와 같은 식별자들은 JSP 태그라고 하며, JSP 태그를 활용해 Java 코드를 HTML에 삽입할 수 있다. - -```html - -The Welcome User JSP - - <% String user=request.getParameter("user"); %> -

Welcome <%= (user==null) ? "" : user %>!

-

Today is <%= new java.util.Date() %>. Have a nice day! :-)

- Enter name: -
- - -
- - -``` - -JSP를 사용하는 경우 프로그래머는 JSP 태그로 감싸진 부분만 다루면 되고, 디자이너는 JSP 태그 이외의 HTML만 다루면 되므로 순수 Servlet을 사용하는 방법에 비해 유지 보수성이 향상된다. - -사실 위처럼 비즈니스 로직을 직접 JSP 페이지에 작성하기보다는 ‘Java Beans’를 사용해 작성하는 경우가 많았다. Java Beans는 재사용이 가능한 컴포넌트, Java 클래스를 의미한다. - -아래 코드는 Java Beans를 활용해 JSP 프로그래밍을 한 예시이다. userBean, dataBean이라는 Java Bean을 활용해 렌더링에 필요한 정보를 가져온다. - -```html - -The Welcome User JSP - - - - <% String user=request.getParameter("user"); %> -

Welcome <%= userBean.getName() %>!

-

Today is <%= dateBean.getDate() %>. Have a nice day! :-)

- Enter name: -
- - -
- - -``` - -이런 JSP의 경우 어떤 방식으로 사용하느냐에 따라 모델 1 구조와 모델 2 구조로 나뉘어싿. JSP를 통해 뷰의 구성과 제어 로직의 처리까지 모두 수행한다면 모델 1이라고 불렸고, 뷰의 구성만 담당한다면 모델 2라고 불렸다. - -앞서 본 Java Beans를 활용하는 JSP 예시 코드가 모델 1에 해당한다. JSP가 직접 Java Beans를 호출하며 제어 로직을 담당하고 있기 때문이다. - -![2023-10-25-HISTORY-OF-WEB-APP_005](https://github.com/inu-appcenter/server-study-16th/assets/86196038/2bf467fd-320f-49f2-8656-dab44a9c38f1) - -모델 1의 경우 구조가 단순하여 간단한 페이지를 구성할 떄 주로 사용되었지만 규모가 큰 프로그램을 작성할 때에는 상당한 양의 Java 코드가 JSP 파일에 드러나는 점 때문에 JSP의 장점을 살리지 못했다. - -따라서 대안으로 모델 2가 등장하게 된다. 모델 2의 경우 모델 1을 보완하여 제어 로직 처리는 서블릿에게 넘기고 JSP는 렌더링만 담당하는 방식을 갖고 있다. 이를 통해 비즈니스 로직과 뷰의 책임을 명확하게 분리할 수 있었다. - -코드로 나타내면 아래와 같다. 서블릿에서 HTTP 요청을 받고, 적절한 제어 로직을 수행한다. 그리고 request의 Attribute에 렌더링을 원하는 객체를 등록한 뒤, JSP 페이지로 포워딩한다. - -```java -// Servlet 코드 -public class MyServlet extends HttpServlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // 비즈니스 로직 수행 - java.util.Date now = new java.util.Date(); - request.setAttribute("currentDateTime", now); - - // JSP 페이지로 포워딩 - request.getRequestDispatcher("myView.jsp") - .forward(request, response); - } -} -``` - -그리고 JSP 페이지에서는 단순히 currentDateTime 객체를 꺼내 렌더링만 수행한다. - -```html - - -JSP Model 2 example - -

current date and time:

-

<%= request.getAttribute("currentDateTime") %>

-

login form:

-
-
-
- -
- - -``` - -이처럼 모델 2는 Servlet과 JSP의 관심사를 분리하여 유지 보수성을 향상시킨 모델이다. Servlet은 제어 로직을 담당하고, JSP는 뷰 로직을 담당한다. 그리고 이 구조는 현재 우리에게 익숙한 MVC 패턴과 유사하다. - -- **J2EE와 EJB** - - ![2023-10-25-HISTORY-OF-WEB-APP_006](https://github.com/inu-appcenter/server-study-16th/assets/86196038/37ab896c-1dcc-452f-9186-3f1e64704484) - - -앞서 동적 페이지 구현을 위해 살펴본 Servlet과 JSP는 사실 Java EE에 포함되어있다. J2EE라고도 불리며 기업 환경의 어플리케이션을 구성하는 데 필요한 표준의 집합을 의미한다. - - - -J2EE에는 EJB라는 기술이 존재한다. EJB(Enterprise Java Beans)란 분산 애플리케이션을 지원하는 컴포넌트 객체이며, J2EE를 사용해 엔터프라이즈 급 서버를 개발하는 경우 EJB로 비즈니스 로직을 처리하였다. 그리고 이런 EJB 객체들을 관리하는 EJB 컨테이너라는 것도 존재했는데, EJB 컨테이너는 분산 트랜잭션 지원 등의 기술적인 지원을 해주었다. - -하지만 EJB로부터 기술적인 지원을 받기 위해서는 EJB 컨테이너에 종속적인 코드들을 많이 작성해야 했고, 떄문에 순수한 비즈니스 로직을 작성하기 어려웠다. - -다음은 EJB를 사용하는 경우의 예시 코드이다. HelloBean은 단순히 이름이 입력으로 들어왔을 때 “Hello”를 붙여 출력해주는 비즈니스 객체이다. 단순한 비즈니스 로직 수행임에도 불구하고 SessionBean이라는 인터페이스를 구현해야 하고 EJB와 관련된 코드가 상당 부분 차지하고 있는 모습을 확인할 수 있다. - -```java -import javax.ejb.*; - -public class HelloBean implements SessionBean { - - public String sayHello(String myName) throws EJBException { - return ("Hello " + myName); - } - - /* ------------------------------------------------------ - * Begin EJB-required methods. The following methods are called - * by the container, and never called by client code - * ------------------------------------------------------- */ - - public void ejbCreate() throws CreateException { - // when bean is created - } - - public void setSessionContext(SessionContext ctx) { - - } - - // Life Cycle Methods - - public void ejbActivate() { - - } - - public void ejbPassivate() { - - } - - public void ejbCreate() { - - } - - public void ejbRemove() { - - } -} -``` - -이런 형식의 웹 어플리케이션 개발은 유지 보수성에 있어 많은 문제를 불러왔고, 흔히 이 시기를 ‘추운 겨울’이라고 표현하기도 하였다. - -- **Spring 프레임워크의 탄생** - -J2EE 표준을 준수하는 어플리케이션들이 너무나 복잡해지니 로드 존슨이라는 사람이 ‘J2EE Development without EJB’ 라는 책을 출간하게 된다. - -![2023-10-25-HISTORY-OF-WEB-APP_007](https://github.com/inu-appcenter/server-study-16th/assets/86196038/5a77b4d3-c70b-4a0a-a6ca-c471e21977c2) - -로드 존슨은 해당 저서에서 EJB의 문제점을 제시하면서 EJB를 사용하지 않고도 충분히 고품질의 어플리케이션을 개발할 수 있음을 증명했다. 이 저서가 바로 Spring이라는 웹 프레임워크의 시작점이 되었다. - -![image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/4d289e86-3716-4ca9-a2c9-a6f6eaa69313) - -로드 존슨이 주장하는 Spring의 핵심 가치는 ‘POJO를 통해 순수한 비즈니스 로직을 작성하자’이다. Spring은 EJB의 문제점을 해결하기 위한 장치들을 여럿 가지고 있다. 대표적으로는 제어의 역전(IoC), 의존성 주입(DI), 관점 지향 프로그래밍(AOP), 일관된 서비스 추상화(PSA)가 있다. - -이런 Spring을 사용하면 EJB 스펙을 따르지 않아도 EJB와 비슷한 효과를 낼 수 있다. 여기서 주의할 점은 Spring 자체가 J2EE 사양을 대체하기 위한 프레임워크는 아니라 J2EE 사양을 보완하기 위해 등장한 프레임워크라는 것이다. 하지만 현재 Spring은 단순히 J2EE 사양을 보완할 뿐만 아니라 Spring MVC, Spring Batch, Spring Security와 같은 많은 기술이 생겨나며 독자적인 생태계를 구성하고 있다. \ No newline at end of file diff --git a/contents/concepts/week2/seungseop.md b/contents/concepts/week2/seungseop.md deleted file mode 100644 index 287f730..0000000 --- a/contents/concepts/week2/seungseop.md +++ /dev/null @@ -1,874 +0,0 @@ -# 2주차_ORM은 무엇일까요? / 스프링에서 ORM을 어떻게 이용할 수 있을까요? - -생성일: 2024년 4월 7일 오후 5:13 -태그: 서버 스터디 - -# ORM 등장 배경 - -### Persistence Layer - -![image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/9de936ab-d06b-4f61-8ae9-ab615e31f6d4) - -> Persistence (영속성)은 데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성을 의미한다. -> - -우리가 개발을 할 때 객체의 상태를 DB에 저장하게 되는데 이를 객체에 영속성을 부여해주었다고 한다. - -그리고 Mark Richards의 소프트웨어 아키텍처 패턴에서 객체에 영속성을 부여해주는 계층을 Persistence Layer라고 한다. - -이 Persistence Layer를 구현하는 방법은 크게 JDBC만을 이용하거나 Persistence Framework를 이용하는 방법이 있다. - -### JDBC만을 이용한 영속 계층 - -> JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 도움을 주는 자바 API다. -> - -JDBC를 활용하면 DBMS가 제공하는 JDBC 드라이버를 이용해 DBMS의 종류와 상관없이 하나의 JDBC API를 이용하여 DB 작업을 처리할 수 있다. - -![image 1](https://github.com/inu-appcenter/server-study-16th/assets/86196038/0ea9777b-8475-4dc0-9918-eafcdc30d28d) - -- 하지만 JDBC만을 이용하여 개발할 경우에는 불편한 점이 꽤 많다. - - 간단한 SQL을 실행함에도 중복된 코드를 반복적으로 사용 - - DB에 따라 일관성 없는 정보를 가진 채로 Checked Exception(SQLException) 처리 - - 연결과 같은 공유 자원을 제대로 반환하지 않으면 시스템의 자원 부족 현상 발생 - -때문에 복잡하고 번거로운 작업 해결을 위해 데이터베이스와 연동되는 시스템을 빠르게 개발할 수 있는 Persistence Framework를 사용하기 시작했다. - -### SQL Mapper를 이용한 영속 계층 - -> SQL Mapper는 SQL문과 객체를 매핑하여 데이터를 객체화하는 Persistence Framework다. 객체 간의 관계를 매핑하는 것이 아닌 직접 작성한 SQL문의 결과와 객체의 필드를 매핑하는 것이 메인 컨셉이다. -> - -SQL Mapper의 종류로는 JDBC Template와 MyBatis가 있다. - -- SQL Mapper를 이용하면 기존 JDBC만을 이용했을 때보다 간결한 코드와 향상된 유지보수성을 얻을 수 있었지만, 이 또한 몇 가지 문제를 갖고 있었다. - - SQL을 직접 작성하기에 특정 DB에 종속적 - - 비슷한 CRUD SQL 작성 및 DAO를 반복적으로 개발 - - 테이블 필드 변경 시 유지 보수하기 힘듦 - -코드 상에서는 SQL과 JDBC API를 분리했지만 논리적으로는 강한 의존성을 갖고 있어 SQL에 의존적인 개발을 해야 하는 문제가 발생했다. - -또한 RDB에서는 데이터 중심의 구조를 지니고 있기에 객체 중심 구조인 객체 지향과 패러다임의 불일치가 생겼다. - -# ORM을 이용한 영속 계층 - -![image 2](https://github.com/inu-appcenter/server-study-16th/assets/86196038/e826e7a0-85c3-4e30-9661-e13ff2527710) - -> ORM(Object Relational Mapping) 은 객체와 RDB의 테이블을 매핑하는 것을 의미한다. -> - -ORM은 SQL Mapper의 패러다임 불일치를 해소하기 위해 나타났다. - -ORM은 객체 간의 관계들을 바탕으로 SQL문을 자동으로 생성하고 메서드를 통해 직관적으로 데이터를 조작하게 하여 개발자의 불편함을 해소한다. - -### ORM은 왜 필요한가? - -ORM을 사용하면 다음과 같은 장점을 얻을 수 있다. - -1. **추상화:** ORM은 높은 수준의 추상화를 제공하여 데이터베이스와의 상호 작용을 단순화한다. 이를 통해 개발자는 SQL 쿼리 대신 객체로 작업할 수 있다. -2. **보일러 플레이트 코드 감소:** ORM은 대부분의 일반적인 데이터베이스 작업을 ORM 시스템이 처리하기 때문에 반복적인 보일러 플레이트 코드를 줄일 수 있다. - - > **보일러 플레이트 코드**는 최소한의 변경으로 여러 곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드를 의미 - > -3. **이식성:** ORM 시스템은 일반적으로 여러 데이터베이스 시스템을 지원하므로 개발자는 코드 변경을 최소화하면서 서로 다른 데이터베이스 간에 전환을 쉽게 할 수 있다. -4. **생산성:** ORM을 사용하면 개발자는 복잡한 SQL 쿼리를 작성하는 대신 애플리케이션의 비즈니스 논리에 집중할 수 있다. 이는 생산성 향상으로 이어질 수 있다. -5. **유지보수성:** ORM은 객체 지향 설계 패턴을 사용해 구조화되고 유지, 관리하기 쉬운 코드를 만든다. - -### ORM의 단점 - -- query가 복잡해지면 ORM으로 표현하는데 한계가 있다. -- 성능이 raw query에 비해 느리다. - -ORM의 단점을 극복하기 위해 JPQL, QueryDSL 등을 사용하거나 Mybatis를 함께 사용하기도 한다. - -# JPA - -JPA는 ORM의 대표 기술이다. - -> **JPA (Java Persistence API)**는 Java 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스 모음 -> - -image 3 - -JPA는 영속성 컨텍스트인 EntityManager를 통해 Entity를 관리한다. - -Entity는 DB와 매핑 되어 사용자가 Entity에 대한 CRUD를 실행을 했을 때 Entity와 관련된 테이블에 대한 적절한 SQL 쿼리문을 생성하고, 이를 관리하였다가 필요 시 JDBC API를 통해 DB에 날리게 된다. - -### JPA 특징 - -- 1차 캐시와 동일성 보장 - - JPA에서는 같은 트랜잭션 안에서는 같은 엔티티를 반환한다. - - 조회 쿼리를 보내고 결과를 받아올 때, 받아온 결과를 캐시 해두고 사용하여 동일한 조회 코드를 두 번 작성해도 단 하나의 쿼리만 발생한다. - -- 쓰기 지연 기능 - - 쓰기 지연 기능은 트랜잭션을 커밋할 때까지 INSERT 쿼리문을 모아두는 기능을 의미한다. - - 쓰기 지연 기능을 이용하면 쿼리문을 모아두었다가 한 번에 보내기 때문에 네트워크 통신 비용이 절감되는 장점이 있다. - -- 지연 로딩 & 즉시 로딩 - - JPA에서는 지연 로딩과 즉시 로딩 기능을 제공해준다. - - 지연 로딩은 객체가 사용될 때 로딩하는 것을 의미하고, 즉시 로딩은 JOIN SQL로 한번에 연관된 객체까지 조회하는 것을 의미한다. - - -### Spring Data JPA - -> **Spring Data JPA**는 JPA 기반 애플리케이션 개발을 보다 간편하게 만드는 라이브러리/프레임워크이다. -> - -![img1 daumcdn](https://github.com/inu-appcenter/server-study-16th/assets/86196038/498b7710-7ae8-45e3-aec3-c95640619be8) - - - -JPA는 단순한 명세이기 때문에 JPA만 가지고는 어떤 구현 기술을 사용할 수 없다. - -실제로 우리가 사용하는 Repository는 **Spring Data JPA**로부터 제공되는 기술이다. - -JPA의 구현체로는 Hibernate, EclipseLink, DataNucleus 등 다양하게 존재한다. - -Hibernate는 이들 중 가장 범용적으로 다양한 기능을 제공하기 때문에 주로 사용된다. - -### Repository Layer란? - -Repository Layer는 Layered Architecture의 Controller + Service + Repository + Dao 4계층 중 Repository에 해당하는 계층이다. - -> Layered Architecture (계층화 아키텍처)는 각 구성 요소들이 ‘관심사의 분리’를 달성하기 위해 ‘책임’을 가진 계층으로 분리한 아키텍처이다. -> -> -> -> - -계층 구조는 처음에는 Controller + Dao의 2계층으로부터 시작되었다. - -Dao는 DB 관련 책임 (CRUD 수행)을 가지고 있었고 Controller는 DB 관련 이외의 책임을 가지고 있었다. - -하지만 Controller가 너무 많은 책임을 지고 있어 이를 분리하고자 Service 계층이 나타났다. - -Controller + Service + Dao의 3계층은 Controller로부터 비즈니스 로직 수행을 책임지는 Service를 분리시켰다. - -다만 이 경우에도 Service는 비즈니스 로직 수행 책임과 도메인 ↔ DB 전달 객체(DTO, Entity)로 변환 책임 2가지를 지니고 있었다. - -이로써 Controller + Service + Repisitory + Dao의 4계층이 생겨났다. - -Service는 비즈니스 로직을 수행하는 책임만 갖게 되었고 DB에 전달하는 객체의 관리 책임은 Repository가 갖게 되었다. - -> **Controller + Service + Repisitory + Dao의 4계층** -> -> - **Controller** : DB 관련 이외의 책임 -> - HTTP 요청 & 응답 변환 책임 (직렬화/역직렬화 : 데이터 포맷 <-> 자바 객체 변환) -> - **Service** : 비즈니스 로직 수행 책임 -> - **Repository** : 도메인 <-> DB 전달 객체(DTO, Entity)로 변환하여 Service와 상호작용 책임 -> - **Dao** : DB CRUD 수행 책임 - -### JpaRepository 인터페이스 - -Spring Data JPA는 간단한 CRUD 기능을 공통으로 처리하는 인터페이스를 제공한다. - -이를 **JPA 공통 인터페이스**라고 한다. - -```java -public interface UserRepository extends JpaRepository{ -} -``` - -Jpa 공통 인터페이스는 간단하지만 단순 반복으로 작성해야 하는 CRUD 작업들을 Spring Data JPA 구현체인 Hibernate가 애플리케이션 실행 시점에 동적으로 자주 사용되는 쿼리 집합을 만들어 위처럼 UserRepository 인터페이스를 구현해준다. - -이로써 자주 사용하는 CRUD를 굳이 JPQL로 작성하지 않더라도 인터페이스 하나만 상속 받으면 사용할 수 있게 된다. - -JpaRepository 인터페이스는 메서드 이름만으로 쿼리를 생성할 수 있다. - -**Method** - -| method | 기능 | -| --- | --- | -| save() | 레코드 저장 (insert, update) | -| saveAll() | Iterable 가능한 객체를 저장 | -| findOne() | primary key로 레코드 한건 찾기 | -| findAll() | 전체 레코드 불러오기. 정렬(sort), 페이징(pageable) 가능 | -| count() | 레코드 갯수 | -| delete() | 레코드 삭제 | - -**Keyword** - -| 메서드 이름 키워드 | 샘플 | 설명 | -| --- | --- | --- | -| And | findByEmailAndUserId(String email, String userId) | 여러필드를 and 로 검색 | -| Or | findByEmailOrUserId(String email, String userId) | 여러필드를 or 로 검색 | -| Between | findByCreatedAtBetween(Date fromDate, Date toDate) | 필드의 두 값 사이에 있는 항목 검색 | -| LessThan | findByAgeGraterThanEqual(int age) | 작은 항목 검색 | -| GreaterThanEqual | findByAgeGraterThanEqual(int age) | 크거나 같은 항목 검색 | -| Like | findByNameLike(String name) | like 검색 | -| IsNull | findByJobIsNull() | null 인 항목 검색 | -| In | findByJob(String … jobs) | 여러 값중에 하나인 항목 검색 | -| OrderBy | findByEmailOrderByNameAsc(String email) | 검색 결과를 정렬하여 전달 | - -위의 메서드와 키워드를 조합하여 메서드 이름을 생성하면 대부분의 쿼리문을 작성할 수 있다. - -![images_hoyun7443_post_5f456605-e33b-4e04-864d-16465b3156d1_image](https://github.com/inu-appcenter/server-study-16th/assets/86196038/763f0aaa-c318-4487-9248-076fb17adcc5) - -또한 위 사진은 JpaRepository 인터페이스의 계층 구조를 보여주는데 - -- 최상위에 있는 Repository 인터페이스는 특별한 기능을 제공하는 것이 아닌 마크 인터페이스로, 해당 인터페이스가 Repository 용도로 사용될 것임을 알리는 데 쓰인다. -- Repository 인터페이스를 상속받는 CrudRepository는 비로소 CRUD 기능을 사용할 수 있도록 해주고, -- PagingAndSortingRepository 인터페이스는 단순 CRUD 외에 Paging, Sorting과 같은 기능들도 수행할 수 있게 해준다. -- NoRepositoryBean 인터페이스는 @NoRepositoryBean 어노테이션을 붙여 해당 인터페이스가 Repository 용도로서 사용되는 것이 아닌 단순히 Repository의 메서드를 정의하는 인터페이스라는 정보를 부여할 수 있게 한다. - - ```java - @NoRepositoryBean - public interface MyRepository extends Repository { - - E save(E entity); - - List findAll(); - - long count(); - } - - public interface CommentRepository extends MyRepository{ - - Comment save(Comment comment); - - List findAll(); - } - ``` - -- QueryByExampleExecutor 인터페이스는 조회 메서드에 Example 인터페이스를 인자로 받을 수 있게 지원한다. - - Example은 조건을 부여하는 기능을 하는데, 엔티티 자체를 조건으로 한다. - - ```java - public interface QueryByExampleExecutor { - - Optional findOne(Example example); - - Iterable findAll(Example example); - - ... - } - ``` - - ```java - // 검색어를 포함하는 검색 대상 엔티티인 probe 생성 - Team team = new Team(); - team.setName("t"); - - Member member = new Member(); // member가 probe 이다 - member.setName("m"); - member.setTeam(team); - - // 검색 조건을 표현하는 ExampleMatcher - ExampleMatcher matcher = ExampleMatcher.matchingAny() // 모든 matcher를 or 로 연결 - .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()) // name에 대소문자 불문 m 포함 - .withMatcher("team.name", ExampleMatcher.GenericPropertyMatchers.contains()) // team.name에 대소문자 구분 t 포함 - .withIgnorePaths("gender", "team.description") // gender. team.description 검색 조건에서 제외 - .withIgnoreNullValues(); // 값이 null인 필드 검색 조건에서 제외 - - // 검색 조건을 담고 있는 Example - Example example = Example.of(member, matcher); - ``` - - -# 연관관계 매핑이란? - -> 연관관계 매핑이란 객체의 참조와 테이블의 외래 키를 매핑하는 것을 말한다. -> - -### 연관관계 매핑이 필요한 이유 - -연관관계의 매핑이 필요한 이유는 객체 지향적으로 코드를 구현하기 위해서이다. - -DB의 테이블에서는 연관 관계를 구사하기 위해 외래키를 사용한다. - -테이블과 동일하게 객체에 외래키를 넣어준다면 객체와 연관되어있는 객체를 찾기 위하여 그 키 값으로 객체를 또 찾아주어야 하는 번거로움이 있다. - -하지만 객체적인 구현이라면 다른 객체를 참조하는 값을 필드로 갖고 있으면 된다. - -이렇게 구현을 하기 위해 매핑을 해주는 것이다. - -### 연관관계 매핑 시 고려사항 - -1. 방향(Direction) - - 방향에는 단방향과 양방향이 있다. - - 객체는 참조용 필드를 가지고 있는 객체만 연관된 객체를 조회할 수 있으므로 방향이 존재한다. 두 객체가 서로 참조하는 관계를 양방향 관계, 한 객체에서 다른 객체만 참조하는 관계를 단방향 관계라 한다. - - ```java - class A { - B b; - } - - class B { - A a; - } - ``` - - 테이블은 외래 키 하나로 양쪽으로 조인이 가능하다. 따라서 테이블은 방향이 없다고 볼 수도 있고, 항상 양방향이라 할 수 있다. - - ```sql - SELECT *FROM MEMBER M - JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID - - SELECT *FROM TEAM T - JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID - ``` - -2. 다중성(Multiplicity) - - 다대일(N:1, ManyToOne) - - 일대다(1:N, OneToMany) - - 일대일(1:1, OneToMany) - - 다대다(N:M, ManyToMany) -3. 연관관계의 주인(Owner) - - 연관관계를 관리 포인트는 외래 키인데, 양방향 관계를 맺으면 객체 서로가 외래 키를 가질 수 있게 된다. 따라서 **두 객체 중 하나를 외래 키를 관리**해야 한다. 외래 키를 관리하는 객체를 **연관관계의 주인이라 한다.** - - 테이블과 객체를 설계할 때 **외래 키를 가지는 엔티티를 연관관계 주인**으로 정하는데, 그 이유는 외래 키를 가진 테이블과 매핑되는 엔티티가 외래 키를 관리하는 것이 효율적이기 때문이다. - - **연관관계 주인만이 데이터를 등록, 변경할 수 있으며, 주인이 아닌 객체는 읽기만 가능하다.** - - -### 연관관계 매핑을 어떻게 이용할까? - -- **N:1 관계** - - **N:1 단방향 매핑** - - 가장 많이 사용하는 연관관계이다. - - N:1 자체로도 많이 사용하지만, M:N 관계를 매핑할 때 사용하기도 한다. - - ```java - public class Member { - @Id @GeneratedValue - private Long id; - private String name; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") - private Team team; - } - ``` - - - **@ManyToOne**: 말 그대로 **N:1**을 나타내는 어노테이션이다. - - **@JoinColumn**: Team을 참조할 **Foreign Key**의 이름을 정해준다. - - --- - - **N:1 양방향 매핑** - - 아래와 같이 Team에서 Member 리스트를 갖고 있을 수 있다. - - Member에서 Team을 **@ManyToOne**으로 매핑해야 사용할 수 있다. - - 이 경우, Team은 Member 리스트를 읽는 것만 허용되고, 등록이나 수정은 할 수 없다. (cascade 속성을 설정해주면 가능하다.) - - ```java - public class Team { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "team") - private List member; - } - ``` - - - **@OneToMany**: **1:N** 관계를 나타내는 어노테이션 - - **mappedBy**: Member 테이블의 Team 변수명. private Team **team**; 이라고 선언했기 때문에 **"team"**이 된다. - - --- - -- **1:N 관계** - - **1:N 단방향 매핑** - - 한 객체가 반대편 객체를 List 형태로 갖는 구조이다. - - **1:N** 특성 상 외래 키가 **N** 쪽에 있어야 하기 때문에, - - 연관관계의 주인이 반대편 테이블의 **Foreign Key**를 관리하는 특이한 구조가 된다. - - ```java - public class Team { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") - private List member; - } - ``` - - - **@OneToMany**: 1:N 매핑 - - **FetchType의 LAZY와 EAGER** - - LAZY - - 지연로딩 - - 연관관계가 설정된 테이블에 대해 select를 하지 않는다. - - 1:N 과 같이 여러가지 데이터가 로딩이 일어날 경우 사용하는 방식 - - EAGER - - 즉시로딩 - - 연관관계가 설정된 모든 테이블에 대해 조인이 이루어진다. - - 1:1 연관관계와 같이 한 건만 존재할 때 사용하는 방식 - - **@JoinColumn**: Member 테이블에 생성될 **Foreign Key**의 이름을 명시한다. 만약 **@JoinColumn**이 없을 경우 중간에 테이블이 하나 추가되기 때문에 꼭 사용해야 한다. - - 이 관계는 구조도 비정상적이고, 연관관계 관리를 위해 UPDATE 쿼리까지 날려야 해서 비효율적이다. - - 그러니 꼭 사용해야 하는게 아니라면 N:1 양방향 매핑을 사용하는 것이 좋다. - - --- - - **1:N 양방향 매핑** - - 이런 매핑은 없다. - - 읽기 전용 필드를 사용하는 꼼수가 있지만, 그럴바엔 **N:1** 양방향을 사용하자. - - ```java - public class Member { - @Id @GeneratedValue - private Long id; - private String name; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id", insertable = false, updatable = false) - private Team team; - } - ``` - - --- - -- **1:1 관계** - - **1:1 단방향 매핑** - - **1:1**은 뒤집어도 **1:1**이기 때문에 **Foreign Key**를 어디에 두어도 상관없다. 상황에 맞게 선택하자. - - 매핑 방식은 **N:1**과 유사하다. **@ManyToOne / @OneToMany**를 **@OneToOne**으로 바꿔주기만 하면 된다. - - ```java - public class Member { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") - private Team team; - } - ``` - - --- - - **1:1 양방향 매핑** - - ```java - public class Team { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToOne(mappedBy = "team") - private Member member; - } - ``` - - --- - -- **M:N 관계** - - **N:1**과 마찬가지로 많이 사용되는 관계이다. - - 매핑하는 방법이 **@ManyToMany**를 이용하는 방법, **@ManyToOne**을 이용하는 방법 총 2가지가 있다. - - 우선 **@ManyToMany**를 사용하는 방법부터 알아보자. - - ![img1 daumcdn 2](https://github.com/inu-appcenter/server-study-16th/assets/86196038/5274f3f1-776f-41a5-9f81-98c69512597c) - - **@ManyToMany 단방향 매핑** - - DB는 테이블 2개만으로 **M:N** 관계를 만들 수 없다. - - 때문에 **@ManyToMany** 어노테이션을 사용하면 **연결 테이블**을 자동으로 생성해준다. - - ```java - public class Member { - @Id @GeneratedValue - private Long id; - private String name; - - @ManyToMany - @JoinTable(name = "member_team") - private List teamList; - } - ``` - - - **@ManyToMany**: **M:N** 매핑 - - **@JoinTable**: 연결 테이블의 이름 - - --- - - **@ManyToMany 양방향 매핑** - - ```java - public class Team { - @Id @GeneratedValue - private Long id; - private String name; - - @ManyToMany(mappedBy = "teamList") - private List memberList; - } - ``` - - - **@ManyToMany**: **M:N** 매핑 - - **mappedBy**: **N:1** 관계에서 봤듯이 Member 테이블의 Team 리스트 변수를 넣으면 된다. - - --- - - **@ManyToOne을 사용한 M:N 관계 매핑** - - **@ManyToMany**를 사용할 경우 어노테이션만 넣으면 JPA에서 자동으로 **연결 테이블**을 생성해주기에 편리하지만, 다음과 같은 단점들이 존재한다. - - - **추가적인 정보를 넣을 수 없다.** 예를 들어, member_team 테이블에 Member가 Team에 가입한 날짜를 저장하고 싶어도, JPA가 자동으로 생성하는 테이블이기 때문에 넣을 수 없다. - - **예상할 수 없는 쿼리가 실행된다.** JPA가 연결 테이블을 자동 생성함으로써 그 테이블은 JPA에서 자동으로 관리해주기 때문에, CRUD를 할 때 중간 테이블을 거치는 쿼리 또한 자동으로 실행시켜버린다. - - 간단한 프로젝트에선 쓸만 하지만, **Entity**간의 관계가 복잡한 실무에서는 쓰지 않는것이 좋다. - - **@ManyToMany** 대신 연결 테이블을 **Entity**로 승격하여 직접 생성하고, **@ManyToOne** 양방향 관계로 직접 매핑해주자. - - 우선 **연결 테이블**을 선언해준다. - - **Entity**로 승격되었기 때문에 가입 일자 같은 추가적인 데이터가 들어갈 수 있다. - - **(member_id, team_id)**로 **Primary Key**를 선언할 수도 있지만, 제약조건이 많아질 경우 독립적인 ID가 있는 것이 유연하게 대처하기 좋기 때문에 별도의 ID를 만드는 것이 좋다. - - ```java - @Entity - public class MemberTeam { - @Id @GeneratedValue - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") - private Team team; - - private LocalDateTime joinDate; - } - ``` - - 그 다음 Member, Team의 **@ManyToMany**를 **연결 테이블**에 대한 **@OneToMany**로 변경해준다. - - ```java - public class Member { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "member") - private List teamList; - } - ``` - - ```java - public class Team { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "team") - private List memberList; - } - ``` - - --- - -- **연관관계 편의 메소드** - - 연관관계가 매핑 되었더라도 객체 상태일 때를 고려하여 양쪽 모두에 값을 설정해야 한다. - - 예를 들어 Member와 Team을 조회했는데, Team에 Member를 추가하고 Member에 아무런 설정도 해주지 않으면 Team에는 Member가 들어가있지만, Member 입장에서는 Team이 NULL인 상황이 된다. - - 이런 현상을 방지하기 위해 **편의 메소드**를 작성하면 좋다. - - 코드가 복잡하지 않기 때문에 보기만 해도 이해가 될 것이다. - - ```java - public class Member { - @Id @GeneratedValue - private Long id; - private String name; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") - private Team team; - - public void changeTeam(Team team) { - if(team != null) { - team.getMemberList().add(this); - this.team = team; - } - } - } - ``` - - ```java - public class Team { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "team") - private List memberList = new ArrayList<>(); - - public void addMember(Member member) { - memberList.add(member); - member.changeTeam(this); - } - } - ``` - - 코드를 보면 **changeTeam / addMember** 함수를 호출할 때 자신의 값만 설정하는 것이 아니라 상대편의 값도 같이 설정하는 것을 볼 수 있다. - - 이렇게 **연관관계 편의 메소드**를 정의해놓고 사용하면 데이터에 모순이 생기는 것을 방지할 수 있다. - - -# 영속성 전이란? - -### 영속성? - -> 영속성이란 데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성을 말한다. -> - -### 영속성 전이 - -> **영속성 전이(CASCADE)는** 데이터베이스의 관계형 데이터베이스 관리 시스템에서 사용되는 개념으로, **부모 엔티티의 영속성 상태 변화가 자식 엔티티에도 영향을 미치는 것**을 말한다. -> - -JPA에서는 다양한 종류의 Cascade 옵션을 제공하여 영속성 전이 동작을 지원한다. - -- Cascade 옵션 - 1. **CascadeType.ALL** : 모든 상태 변화를 전이한다. 해당 엔티티의 PERSIST, MERGE, REMOVE, REFRESH, DETACH 등의 모든 작업이 연관된 엔티티에도 적용된다. - 2. **CascadeType.PERSIST** : 엔티티가 영속 상태로 전이될 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킨다. - 3. **CascadeType.MERGE :** 엔티티의 변경이 병합될 때(merge) 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킨다. - 4. **CascadeType.REMOVE** : 엔티티가 삭제될 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킨다. - 5. **CascadeType.REFRESH** : 엔티티를 새로고침(refresh)할 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킨다. - 6. **CascadeType.DETACH** : 엔티티를 분리(detach)할 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킨다. - 7. **CascadeType.NONE** : 어떤 상태 변화도 전이하지 않는다. 연관된 엔티티의 상태는 변경되지 않는다. - -CASCADE 옵션을 사용할 때 주의해야 할 점도 있다. - -1. 참조 무결성 제약조건 위반 가능 - - CascadeType.REMOVE 혹은 CascadeType.ALL 옵션을 사용하면 엔티티 삭제 시 연관된 엔티티들이 전부 삭제가 되기 때문에 의도치 않게 참조 무결성 제약조건을 위반할 수도 있다. - - > *참조 무결성 제약조건이란, 관계형 데이터베이스(RDB)에서 릴레이션(relation)은 참조할 수 없는 외래 키(foreign key)를 가져서는 안 된다는 조건을 의미한다.* - > - > - > *이를 위반하는 경우 데이터의 모순이 발생하게 된다.* - > -2. 양방향 연관관계 매핑 시 충돌 가능 - - Comment, Post가 다대일 관계로 구성되어 있고 연관관계의 주인은 Comment라고 가정할 때 아래와 같이 Post의 comments 필드에 CascadeType.PERSIST를 지정하는 경우 문제가 생길 수 있다. - - ```java - // Post.java - @Entity - public class Post { - - @OneToMany(mappedBy = "post", cascade = CascadeType.PERSIST) - private List comments = new ArrayList<>(); - ``` - - ```java - @Test - void bidirectional_bad_case() { - Post post = new Post(); - Comment comment1 = new Comment(); - Comment comment2 = new Comment(); - - post.addComment(comment1); - post.addComment(comment2); - - commentRepository.delete(comment1); - postRepository.save(post); - - assertThat(commentRepository.existsById(comment1.getId())).isTrue(); - } - ``` - - 위 테스트 코드에서 `commentRepository.delete(comment1)`을 호출했음에도 삭제가 되지 않는다. `delete` 를 호출해 comment1이 삭제된 상태에서 post를 `save` 하니 다시 comment1 값이 복원된 것이다. - - 이처럼 영속화에 대한 관리 지점이 두 곳이면 데이터 값을 예측할 수 없는 문제가 생긴다. - - -그러면 영속성 전이는 언제 사용해야 하는가? - -하나의 부모가 자식들을 관리할 때 의미가 있다 (= 소유자가 하나일 때) - -만약, 다른 엔티티와 자식이 관계가 있다면 쓰지 않고 따로 관리해야 한다. - -> 조건 두 가지 모두 만족할 때 사용한다. -> -> -> 1. 부모와 자식의 라이프 사이클 거의 유사할 때 -> -> 2. 단일 소유자 일 때 -> - -### 영속성 전이의 활용 - -실제로 영속성 전이를 사용하는 예제를 확인해보자 - -**영속성 전이 : 저장** - -![image 4](https://github.com/inu-appcenter/server-study-16th/assets/86196038/598a5729-2918-42e8-bc5e-09fd51438ec9) - -```java -@Entity -public class Parent { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "parent") - private List childList = new ArrayList<>(); -} -``` - -```java -@Entity -public class Child { - @Id @GeneratedValue - private Long id; - private String name; - - @ManyToOne - @JoinColumn(name = "parent_id") - private Parent parent; -} -``` - -```java -Parent parent = new Parent(); -em.persist(parent); - -Child child1 = new Child(); -child1.setParent(parent); -parent.getChildList().add(child1); -em.persist(child1); // 자식1 저장 - -Child child2 = new Child(); -child2.setParent(parent); -parent.getChildList().add(child1); -em.persist(child2); // 자식2 저장 -``` - -위의 예제에서는 자식 엔티티도 직접 영속화해줘야 했다. - -하지만 Parent 클래스에서 이렇게 `CascadeType.PERSIST` 로 설정하게 되면, 해당 부모 엔티티와 연관된 자식 엔티티들도 같이 영속성 컨텍스트에 저장된다. - -```java -@Entity -public class Parent { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST) - private List childList = new ArrayList<>(); -} -``` - -```java -Parent parent = new Parent(); - -Child child1 = new Child(); -child1.setParent(parent); -parent.getChildList().add(child1); - -Child child2 = new Child(); -child2.setParent(parent); -parent.getChildList().add(child2); - -em.persist(parent); -``` - -**영속성 전이 : 삭제** - -```java -Parent findParent = em.find(Parent.class, 1L); -Child findChild1 = em.find(Child.class, 1L); -Child findChild2 = em.find(Child.class, 2L); - -em.remove(findParent); -em.remove(findChild1); -em.remove(findChild2); -``` - -영속성 전이 기능 없이 부모 엔티티와 자식 엔티티를 모두 제거하려면 위처럼 각각의 엔티티를 하나씩 제거해야 한다. - -하지만, `CascadeType.REMOVE`를 활용한 영속성 전이를 활용한다면, 부모 엔티티만 삭제함으로써 연관된 자식 엔티티도 함께 삭제할 수 있다. - -```java -Parent findParent = em.find(Parent.class, 1L); - -em.remove(findParent); -``` - -**고아 객체** - -JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공하는데, 이를 **고아 객체(ORPHAN) 제거** 라고 한다. - -이 기능을 사용하면, **부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제되도록 할 수 있다.** - -- `orphanRemoval = true` 옵션을 통해 컬렉션에서 엔티티를 제거하면 데이터베이스의 데이터도 삭제된다. - - ```java - @Entity - public class Parent { - @Id @GeneratedValue - private Long id; - private String name; - - @OneToMany(mappedBy = "parent", orphanRemoval = true) - private List childList = new ArrayList<>(); - } - ``` - - ```java - Parent findParent = em.find(Parent.class, 1L); - findParent.getChildList().remove(0); - ``` - - -고아 객체 제거는 **참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고, 삭제하는 기능**이다. 따라서 이 기능은 참조하는 곳이 하나일 때만 사용해야 한다 -그리고 고아 객체 제거에는 기능이 한 가지 더 있다. 개념적으로 볼 때, **부모를 제거하면 자식은 고아가 된다. 따라서 부모를 제거하면 자식도 같이 제거된다. 따라서, 고아 객체 제거 기능을 사용하면 `CascadeType.REMOVE` 기능도 포함되어 있다** - -**영속성 전이 + 고아 객체 제거, 생명 주기** - -일반적으로 엔티티는 EntityManager.persist()를 통해 영속화되고 EntityManager.remove()를 통해 제거된다. - -이것은 엔티티 스스로 생명주기를 관리한다는 뜻이다. - -그런데 **두 옵션(`CascadeType.ALL` 과 `orphanRemoval = true`)을 모두 활성화하면, 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.** 예를 들면 다음과 같다. - -```java -// 자식을 저장하려면 부모에 등록만 하면 된다 (CASCADE.PERSIST) -Parent parent = em.find(Parent.class, 1L); -parent.addChild(child1); -``` - -```java -// 자식을 삭제하려면, 부모에서 제거하면 된다 (orphanRemoval) -Parent parent = em.find(Parent.class, 1L); -parent.getChildList.remove(child1); -``` \ No newline at end of file diff --git a/contents/concepts/week3/kangwook.md b/contents/concepts/week3/kangwook.md deleted file mode 100644 index 872fafa..0000000 --- a/contents/concepts/week3/kangwook.md +++ /dev/null @@ -1,81 +0,0 @@ -# 📌 API란 무엇인가요? - -Application Programming Interface(애플리케이션 프로그램 인터페이스)의 약자로, - -소프트웨어 응용 프로그램에서 다른 소프트웨어 구성 요소 또는 서비스와 상호 작용하기 위한 인터페이스이다. - -API는 다양한 형태로 존재할 수 있으며 주로 웹 서비스, 운영체제, 라이브러리, 또는 다른 소프트웨어에 대한 접근 방법으로 사용된다. - -API를 활용하면 다음과 같은 효과를 얻을 수 있습니다. - - -  -## 데이터 교환 - -**다른 소프트웨어와 데이터를 교환할 수 있는 방법을 제공한다.** - -**예를 들어, 송금 서비스 앱인 토스는 데이터 교환 API를 이용해서 한 개인의 계좌 및 카드 내역 정보를 앱 내에서 확인할 수 있게 한다.** - -  -## **다른 소프트웨어의 기능 실행** - -**다른 소프트웨어의 기능을 호출하고 실행할 수 있는 방법을 제공한다.** - -**이를 활용하여, 다른 애플리케이션의 기능을 활용하여 복잡한 작업을 간편하게 수행할 수 있다.** - -**예를 들면, 결제가 필요한 애플리케이션에서 카카오페이, 네이버페이같은 결제 서비스의 API를 활용하여 결제 시스템을 구축한 사례를 많이 볼 수 있다.** - -  -## **서비스 접근** - -**웹 서비스나 클라우드 서비스에 접근할 수 있는 방법을 제공한다.** - -**이를 통해 개발자는 다양한 서비스를 사용하여 애플리케이션 기능을 간편하게 확장할 수 있고, 성능을 개선할 수 있다.** - -**클라우드 서비스의 시장 점유율이 가장 높은 AWS는 API로 제공하는 서비스를 접근할 수 있게 제공하고 있다.** - -**개발자는 AWS API를 이용하여 애플리케이션 서버의 성능을 조절하거나, 데이터 분석 솔루션을 적용하는 등의 작업을 간편하게 할 수 있다.** - -  -# 📌 API 명세서란 무엇인가요? - -소프트웨어 개발에서 사용되는 문서로 API의 이름, 파라미터(매개변수), 인터페이스, 인증 및 인가방법(동작방식), 데이터 전달 형식 등 API를 정확하게 호출하고 그 결과를 명확히 해석하는데 필요한 정보들을 일관된 형식으로 기술한 문서이다. - -즉, API의 사용 설명서 같은 것이다. - -  -### API 명세서 구성 - -1. API개요 : API의 목적과 사용 방법을 간략히 설명한다. -2. 엔드 포인트 및 요청 방법 : API에서 제공하는 엔드 포인트(Endpoint)와 각 엔드 포인트에 대한 요청 방법(GET, POST, PUT, DELETE 등)을 설명한다. - - Endpoint는 API가 서버에서 리소스에 접근할 수 있도록 가능하게 하는 URL. - -3. 매개변수와 반환 값 : 각각의 API 요청에 필요한 매개변수와 해당 요청이 반환하는 값의 형식과 구조를 설명하고 예시를 제공한다. -4. 오류처리 : API 요청 중에 발생할 수 있는 오류 상황과 오류처리에 대한 설명을 포함한다. -5. 인증과 보안 : API에 접근하기 위한 인증 방법과 보안 관련 사항을 설명한다. API토큰, OAuth, HTTPS 등의 인증 및 보안 기능에 대한 정보를 제공한다. - -  -# 📌 API를 명세하기 위해 어떤 도구를 사용할 수 있나요? - -API 명세 툴은 대표적으로 Swagger와 Postman이 있다. - -  -## Swagger - -Restful한 웹 서비스를 만들 때 API 문서를 자동으로 만들어주고, API를 직접 테스트할 수 있는 UI를 제공해준다. - -OpenAPI Specification을 기반으로 구축된 오픈 소스이다. - -RESTful API를 정의된 규칙에 맞게 API Spec을 json이나 yaml로 표현하는 방식을 의미한다. - -직접 소스 코드나 문서를 보지 않고 서비스를 이해할 수 있다는 장점이 있다. - -대표적인 라이브러리로는 Springfox Swagger, Springdoc이 존재한다. - -  -## Postman - -Postman는 기본적으로 api 테스트를 위한 툴이지만, api 명세서도 작성할 수 있다. - -postman은 swagger보다 쉽고 더 다양한 기능을 제공하지만 비공개소스이자, 데스크탑 애플리케이션이다. diff --git a/contents/concepts/week3/seungseop.md b/contents/concepts/week3/seungseop.md deleted file mode 100644 index 4989ebb..0000000 --- a/contents/concepts/week3/seungseop.md +++ /dev/null @@ -1,622 +0,0 @@ -# 3주차_객체의 직렬화와 역직렬화는 무엇일까요? / @RequestMapping과 @ModelAttribute의 값 매핑은 어떻게 이뤄지나요? - -생성일: 2024년 4월 15일 오후 2:56 -태그: 서버 스터디 - -# 객체의 직렬화, 역직렬화 - -![img1 daumcdn](https://github.com/inu-appcenter/server-study-16th/assets/86196038/63e6a86c-f838-49fc-8ae3-c692468b3048) - -> ***직렬화** : 객체에 저장된 데이터를 I/O 스트림에 쓰기(출력) 위해 연속적인(serial) 데이터로 변환하는 것* -> -> -> ***역직렬화** : I/O 스트림에서 데이터를 읽어서(입력) 객체를 만드는 것* -> -> - *스트림?* -> -> -> - -### **자바 직렬화,** **역직렬화** - -자바에서 직렬화와 역직렬화는 객체를 파일로 저장하거나 네트워크를 통해 전송하기 위해 제공되는 기능이다. - -객체는 ‘인스턴스 변수의 집합’이므로 객체를 저장/전송하는 것은 객체의 인스턴스 변수의 값을 저장/전송하는 것과 동일하다. -** - -시스템적으로 보면, JVM의 힙(heap) 혹은 스택(Stack) 메모리에 상주하고 있는 객체 데이터를 직렬화를 통해 바이트 형태로 변환하여 데이터베이스나 파일과 같은 외부 저장소에 저장해두고, 다른 컴퓨터에서 이 파일을 가져와 역직렬화를 통해 자바 객체로 변환해서 JVM 메모리에 적재한다고 보면 된다. - -**직렬화가 필요한 이유** - -자바에는 원시타입(Primitive Type)이 byte, short, int, long, float, double, boolean, char 총 8가지가 있다. - -그리고 그 외의 객체들은 주소값을 갖는 참조형 타입이다. - -![image-20230414201817935](https://github.com/inu-appcenter/server-study-16th/assets/86196038/0ed8adbf-0fae-4394-9425-5ca370757c67) - -원시타입은 stack에서 값 그 자체로 갖고 있어 외부로 데이터를 전달할 때, **값을 일정한 형식의 raw byte 형태로 변경하여 전달할 수 있다.** - -하지만, 위 그림과 같이 객체의 경우 실제로는 **Heap 영역에 존재하고 스택에서 Heap 영역에 존재하는 객체의 주소 (메모리 주소)를 갖고 있다.** - -이 주소 값을 그대로 다른 곳에 보낸다고 하자. - -만약 프로그램이 종료되거나 객체가 쓸모없다고 판단되면 Heap 영역에 있던 데이터는 제거된다. 즉, 메모리에서 데이터가 삭제된다. - -외부로 전송했을 때에도, 전송받은 기기의 전달받은 메모리 주소에 전송하려했던 데이터는 존재하지 않는다. - -따라서 이 주소 값의 데이터(실체)를 Primitive한 값 형식의 데이터로 변환하는 작업을 거친 후 전달해야 하며 직렬화를 통해 이를 해결할 수 있다. - -### **자바 직렬화, 역직렬화 방법** - -자바에서는 객체의 직렬화, 역직렬화를 위해 ObjectInputStream과 ObjectOutputStream을 제공한다. - -이는 객체를 스트림에 쓰거나(출력) 읽는 기능(입력)을 제공하는 보조 스트림으로 - -ObjectOutputStream은 직렬화, 스트림에 객체를 출력하기 위해 사용하고 - -ObjectInputStream은 역직렬화, 스트림으로부터 객체를 입력 받기 위해 사용한다. - -간단한 예제를 보면 - -```java -public class Member implements Serializable { - - String name; - transient String password; // 직렬화 대상에서 제외되어 직렬화 시 null 처리 -} -``` - -먼저 직렬화 하고자 하는 객체는 java.io.Serializable 인터페이스를 구현한 클래스여야 한다. Serializable 인터페이스는 기능이 없고 단순히 객체 직렬화를 명시하는 용도의 마크 인터페이스이다. - -또한 직렬화에서 제외하고 싶은 대상은 transient를 붙여 제외할 수 있다. transient 필드는 null(참조형) 또는 타입의 기본값으로 반환된다. - -```java -// 객체를 직렬화하여 파일에 저장 -ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objectfile.ser")); -oos.writeObject(new Member()); - -// 파일로부터 객체를 읽어 객체 생성 -ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objectfile.ser")); -Member member = (Member) ois.readObject(); // Object로 리턴되므로 명시적 형변환 필요 -``` - -Serializable로 마크된 객체는 writeObject()를 통해 직렬화를 하고 readObject()를 통해 역직렬화를 수행할 수 있다. - -### **JSON 직렬화, 역직렬화** - -직전에 설명한 자바 직렬화/역직렬화는 JVM과 ObjectOutputStream/ObjectIntputStream에 위임하여 바이트 형태와 전환하는 방식이었지만 XML, JSON과 같은 포맷으로의 직렬화도 가능하다. - -이를 가능하게 하는 JSON 라이브러리는 여러가지가 있다. - -- Jackson -- Google-gson -- JSON-lib -- Flexjson -- Json-io -- Genson -- JSONij - -이 중 가장 잘 알려져 있으며 대표적인 라이브러리는 Jackson이다. - -Jackson 라이브러리에서는 ObjectMapper를 사용해 Object - JSON의 직렬화, 역직렬화를 수행한다. - -ObjectMapper에 대해서는 뒤에서 설명하겠다. - -### **자바 직렬화 vs JSON** - -JSON은 웹(Web) 뿐만 게임 쪽에서도 설정 파일로 쓰이거나 데이터를 교환 할 때 범용적으로 사용된다. - -실제로 바이트로 직렬화가 오로지 자바 프로그램에서만 사용이 가능한 것과 달리, JSON 형태로 객체 데이터를 저장해두면 파이썬, 자바스크립트에서도 범용적으로 사용이 가능하다. - -때문에 JSON으로의 직렬화가 가능하다면 굳이 바이트로 변환하는 자바 직렬화가 필요한지 의문이 들 수 있다. - -하지만 자바 직렬화도 장점이 있다. - -**자바 직렬화의 장점** - -1. 직렬화는 자바의 고유 기술인 만큼 자바 시스템에서 개발에 최적화 되어있다. -2. 자바의 광활한 레퍼런스 타입에 대해 제약 없이 외부에 내보낼 수 있다. - -기본형(int, double, string) 타입이나 배열(array)와 같은 타입들은 왠만한 프로그래밍 언어가 공통적으로 사용하는 타입이기 때문에, 이러한 값들은 JSON만으로도 충분히 상호 이용이 가능하다. - -하지만 자바의 온갖 컬렉션이나 클래스, 인터페이스 타입 혹은 사용자가 생성한 커스텀 자료형 타입은 외부에 내보내기 위해선 각 데이터를 매칭시키는 별도의 파싱이 필요하다. - -그에 반해 직렬화를 이용하면 비록 파이썬이나 자바스크립트와 같은 다른 시스템에서는 사용하지 못할지라도, 직렬화 기본 조건만 지킨다면 하드한 작업 없이 바로 외부에 보낼 수가 있다. - -그리고 역직렬화를 통해 읽어 들이면 데이터 타입이 자동으로 맞춰지기 때문에 별도의 파싱 없이 자바 클래스의 기능들을 곧바로 다시 이용할 수 있다. 그래서 직렬화된 문자열을 데이터베이스에 저장해두고 꺼내쓰기도 한다. - -**자바 직렬화의 문제점** - -위에서는 장점을 이야기 했지만 사실 직렬화는 장점보다는 단점이 극명하게 많다. 때문에 자바 직렬화의 문제점을 간단하게 살펴보겠다. - -- 직렬화는 용량이 크다 - - 직렬화는 객체의 데이터 뿐 아니라 타입 정보, 클래스 메타 정보도 갖고 있으므로 용량을 많이 차지한다. - JSON과 비교하자면 파일 용량 크기가 거의 2배 이상 차이가 난다. -- 역직렬화는 위험하다 - - 직렬화 설정 자체는 문제 없지만, 남이 만든 것을 역직렬화 하는 과정에서 나도 모르게 공격 당할 위험성이 있다. - 바이트 스트림을 역직렬화 하는 ObjectInputStream의 readObject() 메서드를 호출하게 되면 객체 그래프가 역직렬화 되어 classpath 안의 모든 타입의 객체를 만들어 내게 되는데, 해당 타입 객체 안의 모든 코드를 수행할 수 있게 되므로 나의 프로그램 코드 전체가 공격 범위에 들어가게 된다. - - 또는 객체를 직렬화 하여 외부로 전송하는 과정에서 중간에 누가 가로채 파일 바이트 내용을 조작하면, 송신자가 역직렬화 하는 과정에서 인스턴스에 위험한 값을 대입시켜 불변을 깨는 식으로의 공격이 가능해진다. - 이는 역직렬화는 생성자 없이 인스턴스화가 가능하기 때문이다. -- 릴리즈 후에 수정이 어렵다 - - 클래스가 Serializable을 구현하게 되면 직렬화 된 바이트 스트림 인코딩도 하나의 공개 API가 되는 것이다. - 직렬화를 구현한 클래스가 널리 퍼지면 직렬화 형태도 영원히 지원해야하기 때문에 객체의 유지보수가 직렬화에 묶이게 된다. -- 클래스 캡슐화가 깨진다 - - 만약 직렬화할 클래스에 private 멤버가 있어도 직렬화를 하게 되면 그대로 외부로 노출되게 된다. - 직렬화를 제외하려면 별도로 transient 설정을 해야한다. - 따라서 Serializable을 구현하면 직렬화 형태가 하나의 공개 API가 되어 캡슐화가 깨진다. -- 버그와 보안에 취약하다 - - 자바에서는 객체를 생성자를 이용해 만드는 것이 기본이다. - 하지만 역직렬화는 언어의 기본 매커니즘을 우회하여 객체를 바로 생성하도록 한다. - 만약 어느 객체가 생성자를 통해 인스턴스화 할 때 불변식이나 허가되지 않는 접근을 설정하였을 경우, 이를 무시하고 생성된다는 문제가 있다. - 다만 이 부분은 역직렬화 방어 기법 중 하나인 직렬화 프록시 패턴으로 극복할 수 있다. -- 새로운 버전을 릴리즈할 때 테스트 요소가 많아진다 - - 만일 직렬화 가능한 클래스가 업데이트 되면 구버전의 직렬화 형태가 신버전에서 역직렬화가 가능한지 테스트 해야 한다. - 즉, 테스트의 양이 직렬화 가능 클래스의 수와 릴리즈 횟수에 비례하게 된다. -- 상속용 클래스와 인터페이스에 직렬화 구현을 주의해야 한다. - - 상속 목적으로 설계된 클래스와 인터페이스를 Serializable로 구현한다는 것은, 위에서 언급한 자바 직렬화의 위험성을 고스란히 하위 클래스에 전이하게 되는 것과 다름이 없다. -- 내부 클래스는 직렬화를 구현하면 안된다 - - 내부 클래스 (inner class)의 직렬화 형태는 불분명하여 Serializable을 구현하면 안된다. - 단, 정적 내부 클래스 (static inner class)는 Serializable을 구현해도 상관 없다. - -이처럼 자바 직렬화에는 많은 단점과 위험 요소가 존재한다. - -때문에 가급적 JSON 등의 데이터 표현을 사용하는 방식을 채택하는 것이 좋을 것이다. - -하지만 직렬화는 1997년에 탄생하여 여전히 자바 생태계 곳곳에 쓰이고 있다. 만약 어쩔 수 없이 Serializable을 구현해야 한다면 위의 문제점을 잘 고려하여 설계해야 할 것이다. - -# 스프링에서 직렬화, 역직렬화 - -스프링에서 객체 데이터를 JSON으로 주고 받을 때 많이 사용하는 방법에는 ObjectMapper와 @RequestBody, @ResponseBody가 있고 @RequestBody, @ResponseBody는 내부적으로 ObjectMapper를 사용한다. - -스프링 부트에서는 기본적으로 Jackson이 내장되어 있고, 위에서 말했 듯 Jackson 내부에 ObjectMapper 클래스가 있다. - -즉, 스프링에서 직렬화, 역직렬화를 알려면 ObjectMapper에 대해서 알아야 한다. - -### **ObjectMapper** - -![img1 daumcdn 1](https://github.com/inu-appcenter/server-study-16th/assets/86196038/ba9c156c-0556-4d70-a7bf-de183a3eee85) - -> ***ObjectMapper**란 Java Object와 JSON 데이터 간 형태를 자유롭게 변경하기 위해 사용하는 기술이다.* -> - -ObjectMapper는 POJO, Plain Old Java Object를 기준으로 동작한다. POJO는 기본 생성자, getter, setter를 가진 자바 클래스를 의미한다. - -그래서 XXX라는 필드가 있다면 직렬화 시 `getXXX` 메서드로 필드 값을 읽어서 JSON으로 구축하고, -역직렬화 시 기본 생성자로 객체를 생성한 뒤 `setXXX` 메서드로 필드에 값을 주입하게 된다. - -더 자세히 보자면 ObjectMapper는 기본적으로 public 필드를 대상으로 삼는다. -public으로 선언한 필드는 자동으로 매핑이 되지만 통상 클래스 선언 시에는 필드를 private으로 선언하기 때문에 해당 필드들을 매핑하기 위해 getter 혹은 setter를 사용한다. -이 때, ObjectMapper는 getter와 setter의 메서드명 중 get, set을 제거한 이름의 첫 문자를 소문자로 치환하여 필드명을 유추한다. -getter와 setter는 private 필드를 인식하게 해주지만 직렬화의 경우 setter만으로는 private 필드를 인식할 수가 없다. 이는 getter를 가진 private 필드는 property로 간주되지만 setter는 그렇지 않기 때문이다. - -반대로 역직렬화의 경우에는 setter만 있어도 private 필드를 인식할 수 있고 값을 주입할 수도 있다. - -그러나 객체의 불변성 보장을 위해 setter를 사용하지 않는 경우도 많다. - -이 경우 private 필드를 인식하여 필드명을 알아내는 데에는 getter를 사용하고, 데이터를 객체에 바인딩할 때에는 리플렉션의 필드 접근 방식을 사용하게 된다. - - -💡 ***리플렉션 (Reflection)** 은 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API이다.* - -여기서 중요한 것은 역직렬화의 경우 객체를 생성해야 하기 때문에 생성자가 필요한데, ObjectMapper는 기본 생성자를 사용해 객체를 생성하고 이후 값을 바인딩 할 때 setter 혹은 리플렉션을 사용한다는 점이다. - -때문에 기본적으로는 다른 생성자가 있어도 @NoArgsContructor를 사용하거나 직접 기본 생성자를 만들어줘야 한다. - -> ObjectMapper에서 인자를 가진 생성자가 아니라 기본 생성자를 통해 객체를 생성하는 이유가 리플렉션이 생성자의 파라미터 정보를 가져올 수 없기 때문이라는 이야기가 많은데, 이는 Java8 이전까지의 이야기이고 Java8 이후부터는 파라미터 정보도 가져올 수 있게 되었다. -다만 기본 설정으로는 여전히 기본 생성자 없이 역직렬화는 불가능하고, 만약 기본 생성자를 생성하지 않고 역직렬화를 하고 싶다면 @jsonProperty를 사용하여 필드 정보를 명시해주면 가능하다. -> - -# 스프링의 요청 매핑 - -요청 매핑을 보기에 앞서 Controller 클래스에서 사용하는 몇 가지 어노테이션을 먼저 살펴보겠다. - -- @ResponseBody - - 반환 값이 String 이면 뷰 이름으로 인식해서 뷰를 찾고 뷰를 렌더링 하던 것과는 달리 @ResponseBody를 메서드 위에 붙이면 반환 값으로 뷰를 찾는 게 아니라, String을 HTTP 바디에 바로 입력한다. -- @RestController - - @ResponseBody를 메서드 위에 각각 붙여 사용하는 대신 @RestController를 클래스 위에 붙여 사용한다. -- @RequestMapping("/xxx") - - /xxx URL이 호출되면 해당 메서드를 호출한다. - - 대부분의 속성을 배열[]로 제공하기 때문에 다중 설정도 가능하다. - - 클래스 위에 붙여 공통으로 들어갈 경로를 설정 가능하다. - - 메서드에서 사용될 때에는 축약 어노테이션을 사용해서 지정할 수 있다. - - > **@GetMapping**: GET 요청일 경우만 호출  (= @RequestMapping(value="", method = RequestMethod.GET) - **@PostMapping**: Post 요청일 경우만 호출 - **@DeleteMapping**: Delete 요청일 경우만 호출 - **@PatchMapping**: Patch 요청일 경우만 호출 - **@PutMapping**: Put 요청일 경우만 호출 - > - -### 요청 매핑 - -- **@PathVariable 경로 변수** - -```java -@GetMapping("/mapping/{userId}/{orderId}") -public String mappingPath(@PathVariable("userId") String userId, @PathVariable("orderId") String orderId) { - log.info("mappingPath userId ={}, orderId={}", userId, orderId); - - return "Ok"; -} -``` - -메소드 내부에 @PathVariable를 사용해 경로변수를 설정할 수 있다. - -만약 @PathVariable 변수 이름과 매핑된 URL 변수 이름이 같다면 ****@PathVariable을 생략할 수 있다. - -**@RequestMapping - 특정 파라미터 조건 매핑 (params)** - -```java -/** - * 파라미터로 추가 매핑 - * params="mode", - * params="!mode" - * params="mode=debug" - * params="mode!=debug" (! = ) - * params = {"mode=debug","data=good"} - */ -@GetMapping(value = "/mapping-param", params = "mode=debug") -public String mappingParam() { - log.info("mappingParam"); - return "ok"; -} -``` - -특정 파리미터가 있거나 없는 조건을 추가할 수 있으나 잘 사용하진 않는다. - -위 코드는 다음 요청 URL로 호출한다. - -> localhost:8080/mapping-param?mode=debug -> - -**@RequestMapping - 특정 헤더 조건 매핑 (header)** - -```java -/** - *특정 헤더로 추가 매핑 - * headers="mode", - * headers="!mode" - * headers="mode=debug" - * headers="mode!=debug" (! = ) - */ -@GetMapping(value = "/mapping-header", headers = "mode=debug") -public String mappingHeader() { - log.info("mappingHeader"); - return "ok"; -} -``` - -파라미터와 유사하지만 HTTP 헤더를 사용한다. - -**@RequestMapping - 헤더 기반 추가 매핑 Media Type (consumes)** - -```java -/** - * Content-Type 헤더 기반 추가 매핑 Media Type - * consumes="application/json" - * consumes="!application/json" - * consumes="application/*" - * consumes="*\/*" - * MediaType.APPLICATION_JSON_VALUE - */ -@PostMapping(value = "/mapping-consume", consumes = "application/json") -public String mappingConsumes() { - log.info("mappingConsumes"); - return "ok"; -} -``` - -HTTP 요청의 Content-Type 헤더를 기반으로 미디어 타입으로 매핑한다. - -만약 맞지 않으면 HTTP 415 상태코드(Unsupported Media Type)를 리턴한다. - -**@RequestMapping - Accept 헤더 기반 Media Type 콘텐츠 네고시에이션 ( produces )** - -```java -/** - * Accept 헤더 기반 Media Type ( 콘텐츠 네고시에이션 ) - * produces = "text/html" - * produces = "!text/html" - * produces = "text/*" - * produces = "* \/*" -*/ -@PostMapping(value = "/mapping-produce", produces = "text/html") -public String mappingProduces() { - log.info("mappingProduces"); - return "ok"; -} -``` - -HTTP 요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑한다. - -만약 맞지 않으면 HTTP 406 상태코드(Not Acceptable)를 반환한다. - -여기까지는 HttpServletRequest가 제공하는 방식으로 요청 파라미터를 조회하는 방식을 살펴보았고 이제부터 스프링으로 요청 파라미터를 조회하는 방법을 알아보겠다. - -**@RequestParam** - -```java -// @RequestParam 사용 - String, int, Integer 같은 단순 타입 -@ResponseBody -@RequestMapping("/request-param") -public String requestParamV2(@RequestParam("username") String username, - @RequestParam("age") int age) throws IOException -{ - log.info("username = {}, age={}", username, age); - return "OK"; -} -``` - -@RequestParam 에 파라미터를 바인딩해서 요청 파라미터를 조회할 수 있다. - -@RequestParam의 name(value) 속성이 파라미터 이름으로 사용된다. - -> @RequestParam("username") String memberName  -→ request.getParameter("username") -> - -@PathVariable과 마찬가지로 @RequestParam에서도 변수이름과 value가 같으면 value를 생략할 수 있다. - -또한 String, int, Integer와 같은 단순 타입일 경우에는 @RequestParam도 생략할 수 있다. 다만 명시적이지 않아 읽는 사람이 읽기 어려울 수 있어 권장하진 않는다. - -@RequestParam은 속성을 통해 필수 파라미터와 기본값을 지정할 수 있다. - -```java -@ResponseBody -@RequestMapping("/request-param-default") -public String requestParamDefault( - @RequestParam(required = true, defaultValue = "guest") String username, - @RequestParam(required = false, defaultValue = "1") Integer age) { - log.info("username={}, age={}", username, age); - return "OK"; -} -``` - -required 옵션을 true로 설정한 파라미터는 요청 시 필수적으로 있어야 한다. - -> 주의 : 빈 문자("")도 통과한다. → (?username=""&age=20) -> - -defaultValue 옵션을 설정한 파라미터는 요청 시 입력하지 않으면 defaultValue로 설정된다. - -defaultValue를 true로 설정한 경우 required 옵션은 의미가 사라진다. ( 디폴트로 값이 설정되므로 ) - -> defaultValue는 빈 문자의 경우에도 설정한 기본 값이 적용된다. -> - -또한 @RequestParam은 Map, MultiMap을 통한 파라미터 조회가 가능하다. - -```java -@ResponseBody -@RequestMapping("/request-param-map") -public String requestParamMap(@RequestParam Map paramMap) -{ - log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age")); - return "OK"; -} - -@ResponseBody -@RequestMapping("/request-param-Multimap") -public String requestParamMap(@RequestParam MultiValueMap paramMultiMap) -{ - log.info("username={}, age={}", paramMultiMap.get("username"), paramMultiMap.get("age")); - return "OK"; -} -``` - -요청 파라미터의 값이 1개가 확실하다면 Map 을 사용해도 되지만, 그렇지 않다면 MultiValueMap을 사용해야 한다. - -**@ModelAttribute** - -```java -@Data // @Setter, @Getter, @Tostring, @EqualsAndHashCode, @RequiredArgsConstructor -public class HelloData { - private String username; - private int age; -} -``` - -요청 파라미터를 바인딩한 객체가 위와 같을 때 다음 코드와 같이 @ModelAttribute를 통해 요청 파라미터를 받는다. - -```java -@ResponseBody -@RequestMapping("/model-attribute-v1") -public String modelAttributeV1(@ModelAttribute HelloData helloData) -{ - log.info("username = {} , age = {} ", helloData.getUsername(), helloData.getAge()); - log.info("data = {}",helloData); - - return "ok"; -} -``` - -> 스프링 MVC에서는 @ModelAttribute가 있으면 다음과 같이 실행한다. -> -> 1. HelloData 객체를 생성한다. -> 2. 요청 파라미터의 이름으로 HelloData 객체의 property (username, age)를 찾는다. -> 3. 해당 프로퍼티의 setter를 호출해 파라미터의 값을 입력(바인딩)하여 객체에 값을 주입한다. -> -> ex) username -> setUsername() 메소드를 찾아 값 주입 -> -> ❗️바인딩 오류 : age=abc 와 같이 숫자가 들어가야 할 곳에 문자가 들어가면 BindException 예외가 발생 -> - -@ModelAttribute 또한 생략 가능하다. -하지만 @RequestParam 도 생략 가능하기 때문에 혼란이 발생할 수 있어 권장하지는 않는다. - -**단순 텍스트** - -요청 파라미터와 다르게 HTTP 메시지 바디를 통해 데이터가 직접 넘어오는 경우에는 HTML Form 형식으로 전달되는 경우가 아니라면 @RequestParam과 @ModelAttribute를 사용할 수 없다. - -HTTP 메시지 바디의 데이터는 InputStream을 사용해 직접 읽을 수 있다. - -```java -/** - * @param inputStream : HTTP 요청 메시지 바디의 내용을 직접 조회 - * @param responseWriter : HTTP 응답 메시지의 바디에 직접 결과 출력 - * @return - * @throws IOException - */ -@PostMapping("/request-body-string-v2") -public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException { - String messagebody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); - log.info("messageBody = {}", messagebody); - responseWriter.write("ok"); -} -``` - -스프링 MVC는 다음 파라미터를 지원한다. - -- InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회 -- OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력 - -HttpEntity를 통해서도 메시지 바디 조회가 가능하다 - -```java - /** - * HttpEntity 패키지 사용 - * @param httpEntity - * @return - * @throws IOException - */ - @PostMapping("/request-body-string-v3") - public HttpEntity requestBodyStringV3(HttpEntity httpEntity) throws IOException { - - String messagebody = httpEntity.getBody(); - log.info("messageBody = {}", messagebody); - - return new HttpEntity("ok"); - -// return new ResponseEntity<>("ok", HttpStatus.CREATED); -// RequestEntity, ResponseEntity는 HttpEntity를 상속받은 객체로 -// RequestEntity는 HttpMethod, url 정보가 추가되어 , request에서 사용 -// ResponseEntity는 HTTP 상태코드를 설정할 수 있고, response에서 사용 - } -``` - -HttpEntity 는 HTTP 헤더, body 정보를 편리하게 조회할 수 있도록 도와주는 객체이다. - -요청 뿐만 아니라 응답에서도 HttpEntity를 사용할 수 있다. - -스프링 MVC는 다음 파라미터를 지원한다. - -- HttpEntity: HTTP header, body 정보를 편리하게 조회 - - 메시지 바디 정보를 직접 조회 - - 요청 파라미터를 조회하는 기능과 관계 없음 @RequestParam X, @ModelAttribute X -- HttpEntity는 응답에도 사용 가능 - - 메시지 바디 정보 직접 반환 - - 헤더 정보 포함 가능 - - view 조회 X - - -또한 @RequestBody를 사용한 메시지 바디 조회도 가능하다. - -```java -/** - * @RequestBody 사용 - 실무에서 가장 많이 사용하는 방식 - * @param messageBody - * @return - */ -@ResponseBody -@PostMapping("/request-body-string-v4") -public String requestBodyStringV4(@RequestBody String messageBody) -{ - log.info("message body = {}",messageBody); - return "OK"; -} -``` - -만약 헤더 정보가 필요하다면 HttpEntity를 사용하거나 @RequestHeader를 사용하면 된다. - -💡 이렇게 메시지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam, @ModelAttribute와는 전혀 관계가 없다. - -요청 파라미터 조회 : @RequestParam, @ModelAttribute - -메시지 바디 조회 : @RequestBody - -**JSON** - -단순 텍스트형식의 메시지바디와 Json형식의 메시지 바디 조회는 크게 다르지 않다. - -```java -@ResponseBody -@PostMapping("/request-body-json-v2") -public String requestBodyJsonV2(@RequestBody String messagebody) throws IOException -{ - HelloData data = objectMapper.readValue(messagebody, HelloData.class); - log.info("username = {} , age = {}", data.getUsername(), data.getAge()); - return "Ok"; -} -``` - -단순 텍스트처럼 @RequestBody를 사용해 HTTP 메시지에서 데이터를 꺼내고 messagebody에 저장한다. - -문자로 된 JSON 데이터인 messagebody를 objectMapper를 통해 자바 객체로 변환한다. - -💡 ❗️@RequestBody는 생략이 불가능하다. - -스프링은 @ModelAttribute, @RequestParam과 같은 어노테이션을 생략할 때 아래 규칙을 적용한다. - -- String , Integer, int 와 같은 단순 타입 = @RequestParam -- 그 외의 타입 = @ModelAttribute ( argument resolver로 지정해둔 타입을 제외한 모든 타입) - -따라서 이 경우 HelloData에 @RequestBody를 생략하면 @ModelAttribute가 적용되어 버리기 때문에 메시지 바디가 아닌 요청 파라미터를 처리하게 된다. - - -@RequestBody에 String이 아닌 객체 파라미터를 사용할 수도 있다. - -```java -// @RequestBody에 객체를 파라미터로 지정할 수 있다. -@ResponseBody -@PostMapping("/request-body-json-v3") -public String requestBodyJsonV3(@RequestBody HelloData data) -{ - log.info("username = {}, age = {}",data.getUsername(),data.getAge()); - return "OK"; -} -``` - -@RequestBody나 HttpEntity를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해 준다. - - -💡 HTTP 메시지 컨버터는 내부에서 ObjectMapper를 호출한다. - - -아래는 HttpEntity를 사용한 코드이다. - -```java -@ResponseBody -@PostMapping("/request-body-json-v4") -public String requestBodyJsonV4(HttpEntity dataHttpEntity) -{ - HelloData data = dataHttpEntity.getBody(); - log.info("username = {}, age = {}",data.getUsername(),data.getAge()); - return "OK"; -} -``` - -요청 매핑은 아니지만 @ResponseBody에 String이 아닌 객체를 리턴할 경우도 추가로 살펴보자면 - -```java -@ResponseBody -@PostMapping("/request-body-json-v5") -public HelloData requestBodyJsonV5(@RequestBody HelloData data) -{ - log.info("username = {}, age = {}", data.getUsername(),data.getAge()); - return data; -} -``` - -위에서 살펴보았 듯 스프링에 내장된 Jackson의 ObjectMapper 클래스가 객체 정보를 JSON 형태로 변환 시켜 메시지 바디에 리턴한다. - -이것 또한 마찬가지로 HttpEntity를 사용해도 된다. - -> @RequestBody 요청 : JSON 요청 -> HTTP 메시지 컨버터 -> 객체 -> -> -> @ResponseBody 응답 : 객체 -> HTTP 메시지 컨버터 -> JSON 응답 -> \ No newline at end of file diff --git a/contents/concepts/week4/hyeonseung.md b/contents/concepts/week4/hyeonseung.md deleted file mode 100644 index 71a1658..0000000 --- a/contents/concepts/week4/hyeonseung.md +++ /dev/null @@ -1,187 +0,0 @@ -## 예외처리의 개념 - -### 오류(Error)와 예외(Exception) 의 차이는? - ---- - -오류 : 시스템 레벨에서 발생하는 프로그램 코드로 해결될 수 없는 심각한 문제를 의미한다. - -대부분의 에러는 자바의 경우, JVM에서 발생하며 메모리부족(OutMemoryError)이나 스택 오버플로(StackOverFlowError)와 같은 비정상적인 상황에서 발생한다. - -**이러한 에러는 시스템에 심각한 문제가 있다는 신호로 알 수 있으며, 코드로 대응을 하기 보다는 문제의 원인을 찾아서 해결하는 것이 중요하다.** - -예외 : 프로그램 실행 중 발생할 수 있는 예외적인 조건을 의미하며, 개발자가 코드 내에서 적절히 처리할 수 있다. - -예외는 또한 체크된 예외(checked exceptions) 와 체크되지 않은 예외(unchecked exceptions)으로 나뉘고, 각각 다른 방식으로 처리된다. - -**예외는 개발자가 구현한 로직에서 발생한 실수나 사용자의 영향에 의해 발생하므로 이를 미리 예측하여 방지할 수 있도록 상황에 맞는 예외 처리를 하는 것이 중요하다.** - -오류와 예외의 차이는 **개발자가 코드로 해결할 수 있는지 없는지의 문제**이다. -오류는 대부분 시스템에 의해 발생하는 비가역적인 심각한 문제로, 개발자가 코드로 해결할 수 없는 문제들인 반면, 예외는 코드 실행 중에 발생하는 예측가능하고, 대응이 가능한 문제이다. 따라서, 개발자가 예상하고 적절히 예외를 처리할 수 있는 문제들이다. - -### 이들을 구분하는 이유는? - -프로그램을 개발하고 유지보수하는 과정에서 예상치 못한 상황에 대처하고, 시스템의 안정성을 확보하기 위함이다. - -에러는 심각한 문제로 인식하여 시스템적인 차원에서 개입이 필요한 반면, 예외는 처리 가능한 문제이기 때문에 코드를 통한 예외처리로 프로그램의 견고함을 증진시킬 수 있다. - -예외 처리(Exception Handling)는 효율적인 방법으로 프로그램의 안정성을 높이고 사용자에게 명확한 피드백을 제공하는 메커니즘을 마련하는 것을 목표로 한다. - -![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/4275b07c-5390-489c-8bbf-82e4caa3dbbc/214e04ce-af62-4174-a6ab-ecf4540ad407/Untitled.png) - -예외와 오류 모두 Java에서의 최상위 객체인 Object클래스를 상속받고, 그 사이 Throwable 클래스와도 상속관계를 가진다. 이 클래스는 **오류나 예외에 대한 메시지를 담는다.** - -이 Throwable 객체가 가진 정보와 할 수 있는 행위는 getMessage()와 printStackTrace()라는 메서드로 구현되어 있다. 이는 예외가 연결될 때 연결된 예외의 정보들을 기록하는 기능도 있다. - -![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/4275b07c-5390-489c-8bbf-82e4caa3dbbc/9d088c0e-6770-48e5-b8b2-cb59dd7d19f6/Untitled.png) - -[Error] - -✔️ OutOfMemoryError - - : JVM이 할당된 메모리의 부족으로 더이상 객체를 할당할 수 없을 때 던져지는오류이다. - -- heap 사이즈 부족 -- 너무 많은 클래스 로드 -- 가용가능한 swap이 없을시 -- GC에 의해 추가적인 메모리가 확보되지 못하는 상황일 때 - -✔️ StackOverFlowError - -: 응용프로그램이 너무 많이 반복되어 stackoverflow가 발생할 때 던져지는 오류 - -다만, 간접적인 예방은 가능 - -stackoverflow : 재귀조심, 가시적인 loop사용… - -outofmemory : 메모리 차단, heap크기 늘려줌… - -와 같이 전체적인 코드와 시스템적으로 봐야함. - -[Exception] 예외 - -체크되지 않은 예외의 대표적인 예로는 NullPointException, ArrayIndexOutBoundsException와 같은 오류를 가리킨다. 체크된 예외의 경우에는 IOException와 같은 오류로, 반드시 예외 처리를 해야하는 경우이다. - -✏️ Checked Exception VS Unchecked Exception - -- Checked Exception - - 예외처리가 필수적이며, 처리하지 않으면 컴파일 되지 않는다. - - `try-catch`로 감싸거나, `throw`로 던져서 예외처리를 해야한다. - - 컴파일 단계에서 명확하게 exception체크가 가능하다. - -- Unchecked Exception - - RuntimeException 하위의 모든 예외 - - NullPointerException , ArrayIndexOutofBoundsException 등등 - - 실행과정중 어떤 특정한 논리에 의해 발견되는 Exception - - 명시적인 예외처리를 하지 않아도 된다. - -## 예외 처리의 방법 - 예외 복구/예외 처리 회피/예외 전환 - ---- - -- 예외 복구 - - 예외 상황을 파악하고 문제를 해결하여 정상상태로 돌려놓는 방법이다. - - try~catch문 - - ```java - final int MAX_RETRY = 100; - public Object someMethod() { - int maxRetry = MAX_RETRY; - while(maxRetry > 0) { - try { - ... - } catch(SomeException e) { - // 로그 출력. 정해진 시간만큼 대기한다. - } finally { - // 리소스 반납 및 정리 작업 - } - } - // 최대 재시도 횟수를 넘기면 직접 예외를 발생시킨다. - throw new RetryFailedException(); - } - - // while 문에서 예외를 잡아서 대기하거나, 재시도를 통하여 문제를 해결한다. - // 정해놓은 횟수나 시간을 넘기면 예외를 발생시킨다. - ``` - -- 예외 처리 회피 - - 예외 처리를 직접 담당하지 않고 호출한 메서드로 위임해 회피하는 방법이다. - - throws문 - - ```java - // Example 1 - public void add() throws SQLException { - // ...생략 - } - - // Example 2 - public void add() throws SQLException { - try { - // ... 생략 - } catch(SQLException e) { - // 로그를 출력하고 다시 날린다! - throw e; - } - } - - // 예시 1처럼 바로 위임해서 던질 수 있지만, - // 긴밀한 관계를 가진 것이 아니라면, 예시 2처럼 어느정도 처리하고 던지는 것이 좋다. - ``` - -- 예외 전환 - - 예외 회피와 비슷하게 메서드 밖으로 예외를 위임하지만, 그냥 위임하지 않고 적절한 예외로 전환해서 넘기는 방법이다. - - ```java - // 조금 더 명확한 예외로 던진다. - public void add(User user) throws DuplicateUserIdException, SQLException { - try { - // ...생략 - } catch(SQLException e) { - if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) { - throw DuplicateUserIdException(); - } - else throw e; - } - } - - // 예외를 단순하게 포장한다. - public void someMethod() { - try { - // ...생략 - } - catch(NamingException ne) { - throw new EJBException(ne); - } - catch(SQLException se) { - throw new EJBException(se); - } - catch(RemoteException re) { - throw new EJBException(re); - } - } - - // 조금 더 명확한 의미로 전달되기 위해 적합한 의미를 가진 예외로 변경하여 던진다. (사용자 정의 가능) - // 예시 2처럼 단순하게 만들어서 각 예외별로 포장(wrap)하여 예외를 처리할 수 있다. - ``` - - -## 자바의 예외 클래스는? - Checked Exception / Unchecked Exception - ---- - -앞서 설명했지만, 클래스별로 자세하게 알아보자. - -![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/4275b07c-5390-489c-8bbf-82e4caa3dbbc/6b45dc95-7fcc-4651-aff5-251a2b3f83ee/Untitled.png) - -| | Checked Exception | Unchecked Exception | -| --- | --- | --- | -| 처리 여부 | 반드시 예외를 처리해야 함 | 명시적인 처리를 안해도 됨 | -| 확인 시점 | 컴파일 단계 | 런타임 단계 | -| 예외 종류 | RuntimeException을 제외한, Exception 클래스와 그를 상속받는 하위 예외 IOException FileNotFoundException SQLException - | RuntimeException 과 그 하위 예외NullPointerException- IllegalArgumentException- IndexOutOfBoundException- SystemException | - diff --git a/contents/concepts/week4/jiyun.md b/contents/concepts/week4/jiyun.md index ef2b527..6356024 100644 --- a/contents/concepts/week4/jiyun.md +++ b/contents/concepts/week4/jiyun.md @@ -28,7 +28,53 @@ Client와 Server 모두 유효성 검사 가능하다.
- 안정적 유효성 검사 및 DB를 통한 유효성 검사 가능 - Client의 몫까지 다 할 수 있음 but, 검사할 일이 늘어나는 것이니 속도 처리 속도 느려짐 -결과적으로 Client와 Server에 유효성 검사를 적절히 분배해야 한다.

+결과적으로 Client와 Server에 유효성 검사를 적절히 분배해야 한다. + +--- + +
+ +그렇다면 Server인 `Spring` 에서 유효성 검사를 어디에서 해야 할까? + +![validationSpring](../Img/week4/validationPosition.png) + +사용자가 입력한 데이터는 각 계층을 지난다. 계층 간 전송되는 데이터로 DTO 객체를 주로 활용하기 때문에 DTO 객체에 대한 유효성 검사를 수행하는 것이 일반적이다.
+_(유효성 검사는 모든 계층에서 가능하다.)_
+ +- **Controller** + + - 사용자의 입력을 처음 받는 곳 + + - 사용자의 요청 데이터에 대한 초기 유효성 검사 수행 가능 + - 주로 입력 형식이 올바른지 확인하는 데에 중점 (ex. 아이디, 비밀번호, 이메일 형식 확인) + +- **Service** + + - 비즈니스 로직 (중복 체크, 인증 처리, 재고 확인..) 을 처리하는 계층 + + - 데이터의 유효성뿐만 아니라 비즈니스 규칙에 대한 검증도 수행 가능 + - 주로 비즈니스 규칙을 반영하는 데에 중점 (유효성 검사를 하고 싶으면 @Validated 이용하기) + +- **Repository** + + - DB와의 상호작용을 하는 계층 + + - DB 스키마의 제약 조건에 대한 검증 일어남 + - 유효성 검사 수행은 드묾 (유효성 검사를 하고 싶으면 @Validated 이용하기) + +
+ +유효성 검사는 보통 Controller에서 진행한다. 사용자의 입력을 제일 처음 받는 곳이며, 잘못된 데이터가 시스템 깊숙이 들어가는 것을 바로 걸러낼 수 있다. +
+
+Controller 이외의 계층에서도 검사를 진행할 수 있지만, 각 계층의 주요 책임들이 존재한다. 책임에 집중할 수 있도록 이 전 층에서는 전송 데이터 검사를 적절하게 진행하는 것이 좋다. +
+
+그렇다고 모든 검사를 Controller에 의존하는 것 또한 바람직하지 않다. (한 계층이 다른 계층을 의존하는 것은 좋지 않음)
+Controller에서 Service로 정상값이 항상 전달된다는 보장이 없다. 상황에 맞는 검사를 진행하자. +
+
+추가로 계층 간 데이터 전달을 위해 사용되는 `DTO`와 DB와 연결돼 사용하는 `Entity` 또한 마찬가지이다. 계층-계층으로 DTO가 전달돼 Entity에 데이터가 들어갈 텐데, 이때 DTO에 정상 데이터가 담겨있다고 확신할 수 있나? 때문에 DTO와 Entity에도 유효성 검사를 해주는 것이 좋다. ## :evergreen_tree: @Valid vs @Validated From cb0cef0e6e19c02038d3ca883c2f6b9e9e0908ce Mon Sep 17 00:00:00 2001 From: jiyun Date: Tue, 14 May 2024 01:07:12 +0900 Subject: [PATCH 05/13] =?UTF-8?q?[Refactor]=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20&=20Swagger=20API=20=EB=AA=85=EC=84=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20-34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/jiyunio/todolist/ResponseDTO.java | 8 ++- .../jiyunio/todolist/category/Category.java | 2 - .../todolist/category/CategoryController.java | 16 ++++-- .../todolist/category/GetCategoryDTO.java | 3 +- .../todolist/customError/CustomException.java | 4 +- .../customError/CustomExceptionHandler.java | 24 ++++++++- .../todolist/customError/ErrorCode.java | 17 +++--- .../todolist/customError/ErrorDTO.java | 1 + .../todolist/member/MemberController.java | 52 +++++-------------- .../todolist/member/MemberService.java | 8 +-- .../todolist/member/dto/ChangeUserPwDTO.java | 7 +++ .../todolist/member/dto/SignInDTO.java | 3 ++ .../todolist/member/dto/SignUpDTO.java | 7 ++- .../java/com/jiyunio/todolist/todo/Todo.java | 2 +- .../jiyunio/todolist/todo/TodoController.java | 40 +++++--------- .../todolist/todo/dto/CreateTodoDTO.java | 2 + .../jiyunio/todolist/todo/dto/GetTodoDTO.java | 2 + .../todolist/todo/dto/UpdateTodoDTO.java | 2 + 18 files changed, 105 insertions(+), 95 deletions(-) diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/ResponseDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/ResponseDTO.java index 67b9c90..e22e5f9 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/ResponseDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/ResponseDTO.java @@ -7,14 +7,12 @@ @Getter @Setter public class ResponseDTO { - Long id; - String userId; + String result; String msg; @Builder - ResponseDTO(Long id, String userId, String msg) { - this.id = id; - this.userId = userId; + ResponseDTO(String result, String msg) { + this.result = result; this.msg = msg; } } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java index 684d2a0..a2ae2ed 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/Category.java @@ -32,5 +32,3 @@ protected void updateCategory(String category) { this.category = category; } } - - diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/CategoryController.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/CategoryController.java index 4e7fc67..ad7cdb6 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/CategoryController.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/CategoryController.java @@ -1,6 +1,9 @@ package com.jiyunio.todolist.category; import com.jiyunio.todolist.ResponseDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -13,11 +16,13 @@ @RestController @RequiredArgsConstructor @Validated +@Tag(name = "Category", description = "카테고리 API") public class CategoryController { private final CategoryService categoryService; @PostMapping("/category{memberId}") - public ResponseEntity createCategory(@PathVariable Long memberId, @RequestParam @NotBlank String categoryName) { + @Operation(summary = "카테고리 생성") + public ResponseEntity createCategory(@Parameter(description = "member의 id") @PathVariable Long memberId, @RequestParam @NotBlank String categoryName) { categoryService.createCategory(memberId, categoryName); ResponseDTO responseDTO = ResponseDTO.builder() .msg("카테고리 생성 성공") @@ -26,12 +31,14 @@ public ResponseEntity createCategory(@PathVariable Long memberId, @ } @GetMapping("/category/{memberId}") - public List getCategory(@PathVariable Long memberId) { + @Operation(summary = "카테고리 조회") + public List getCategory(@Parameter(description = "member의 id") @PathVariable Long memberId) { return categoryService.getCategory(memberId); } @PutMapping("/category/{categoryId}") - public ResponseEntity updateCategory(@PathVariable Long categoryId, @RequestParam @NotBlank String categoryName) { + @Operation(summary = "카테고리 수정") + public ResponseEntity updateCategory(@Parameter(description = "카테고리의 id") @PathVariable Long categoryId, @RequestParam @NotBlank String categoryName) { categoryService.updateCategory(categoryId, categoryName); ResponseDTO responseDTO = ResponseDTO.builder() .msg("카테고리 수정 성공") @@ -40,7 +47,8 @@ public ResponseEntity updateCategory(@PathVariable Long categoryId, } @DeleteMapping("/category/{categoryId}") - public ResponseEntity deleteCategory(@PathVariable Long categoryId) { + @Operation(summary = "카테고리 삭제") + public ResponseEntity deleteCategory(@Parameter(description = "카테고리의 id") @PathVariable Long categoryId) { categoryService.deleteCategory(categoryId); ResponseDTO responseDTO = ResponseDTO.builder() .msg("카테고리 삭제 성공") diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/GetCategoryDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/GetCategoryDTO.java index dcc3f89..3f54434 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/GetCategoryDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/category/GetCategoryDTO.java @@ -1,12 +1,13 @@ package com.jiyunio.todolist.category; -import com.jiyunio.todolist.member.Member; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; import lombok.Setter; @Getter @Setter +@Schema(description = "카테고리 조회") public class GetCategoryDTO { private String category; diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomException.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomException.java index 3fca9a7..b3a8fe0 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomException.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomException.java @@ -1,6 +1,6 @@ package com.jiyunio.todolist.customError; -import lombok.*; +import lombok.Getter; import org.springframework.http.HttpStatus; @Getter @@ -8,7 +8,7 @@ public class CustomException extends RuntimeException { private final HttpStatus httpStatus; private final ErrorCode errorCode; - public CustomException(HttpStatus httpStatus, ErrorCode errorCode){ + public CustomException(HttpStatus httpStatus, ErrorCode errorCode) { this.httpStatus = httpStatus; this.errorCode = errorCode; } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomExceptionHandler.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomExceptionHandler.java index 3d91aa3..027b6b0 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomExceptionHandler.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/CustomExceptionHandler.java @@ -1,13 +1,35 @@ package com.jiyunio.todolist.customError; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import java.util.ArrayList; +import java.util.List; + @ControllerAdvice public class CustomExceptionHandler { @ExceptionHandler(CustomException.class) - protected ResponseEntity handleCustomException(CustomException e){ + protected ResponseEntity handleCustomException(CustomException e) { return ErrorDTO.toResponseEntity(e); } + + @ExceptionHandler(MethodArgumentNotValidException.class) + protected ResponseEntity> beanValidationException(MethodArgumentNotValidException e) { + List list = e.getBindingResult().getFieldErrors(); + List responseDTOList = new ArrayList<>(); + + for (FieldError error : list) { + ErrorDTO errorDTO = ErrorDTO.builder() + .code("400_Bad_Request") + .msg(error.getDefaultMessage()) + .build(); + + responseDTOList.add(errorDTO); + } + return new ResponseEntity<>(responseDTOList, HttpStatus.BAD_REQUEST); + } } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorCode.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorCode.java index b513908..b9c86ce 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorCode.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorCode.java @@ -5,15 +5,16 @@ @Getter public enum ErrorCode { // 400 Bad Request - EXIST_USERID("001_EXIST_USERID", "이미 존재하는 아이디입니다."), - EXIST_EMAIL("002_EXIST_EMAIL", "이미 존재하는 이메일입니다."), - NOT_SAME_CONFIRM_PASSWORD("003_NOT_SAME_CONFIRM_PASSWORD", "비밀번호 확인이 맞지 않습니다."), + NOT_SAME_CONFIRM_PASSWORD("400_Bad_Request", "비밀번호 확인이 맞지 않습니다."), + WRONG_USERID_PASSWORD("400_Bad_Request", "아이디 및 비밀번호가 맞지 않습니다."), - //404 Not Found - NOT_EXIST_MEMBER("401_NOT_EXIST_MEMBER", "회원이 존재하지 않습니다."), - NOT_EXIST_TODO("402_NOT_EXIST_MEMBER", "TODO가 존재하지 않습니다."), - NOT_EXIST_USERID("403_NOT_EXIST_USERID", "아이디가 존재하지 않습니다."), - WRONG_PASSWORD("404_WRONG_PASSWORD", "비밀번호가 다릅니다."); + // 404 Not Found + NOT_EXIST_MEMBER("404_Not_Found", "회원이 존재하지 않습니다."), + NOT_EXIST_TODO("404_Not_Found", "TODO가 존재하지 않습니다."), + + // 409 Conflict 중복된 값 + EXIST_USERID("409_Conflict", "이미 존재하는 아이디입니다."), + EXIST_EMAIL("409_Conflict", "이미 존재하는 이메일입니다."); private final String code; private final String message; diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorDTO.java index b10365d..8b9c580 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/customError/ErrorDTO.java @@ -1,4 +1,5 @@ package com.jiyunio.todolist.customError; + import lombok.Builder; import lombok.Getter; import lombok.Setter; diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberController.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberController.java index 09a48b8..156a82d 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberController.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberController.java @@ -4,57 +4,44 @@ import com.jiyunio.todolist.member.dto.ChangeUserPwDTO; import com.jiyunio.todolist.member.dto.SignInDTO; import com.jiyunio.todolist.member.dto.SignUpDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; -import java.util.List; - @RestController @RequiredArgsConstructor +@Tag(name = "Member", description = "회원 API") public class MemberController { private final MemberService memberService; @PostMapping("/signUp") - public ResponseEntity signUp(@Valid @RequestBody SignUpDTO signUpDto, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - List responseDTOList = returnBindingResult(bindingResult); - return new ResponseEntity<>(responseDTOList, HttpStatus.BAD_REQUEST); - } - + @Operation(summary = "회원가입", description = "아이디, 비밀번호, 이메일 이용\n\n 아이디 : 5 ~ 10자 \n\n 비밀번호: 8~16자의 영문 대/소문자, 숫자, 특수문자") + public ResponseEntity signUp(@Valid @RequestBody SignUpDTO signUpDto) { ResponseDTO responseDTO = ResponseDTO.builder() - .userId(memberService.signUp(signUpDto)) // 화면에 "ㅇㅇ님 환영합니다" 글씨 원함 + .result(memberService.signUp(signUpDto)) // 화면에 "ㅇㅇ님 환영합니다" 글씨 원함 .msg("회원가입 성공") .build(); return new ResponseEntity<>(responseDTO, HttpStatus.CREATED); } @PostMapping("/signIn") - public ResponseEntity signIn(@Valid @RequestBody SignInDTO signInDto, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - List responseDTOList = returnBindingResult(bindingResult); - return new ResponseEntity<>(responseDTOList, HttpStatus.BAD_REQUEST); - } - + @Operation(summary = "로그인", description = "아이디와 비밀번호 이용") + public ResponseEntity signIn(@Valid @RequestBody SignInDTO signInDto) { ResponseDTO responseDTO = ResponseDTO.builder() - .userId(memberService.signIn(signInDto)) // 로그인하면 회원 페이지에 ㅇㅇ님 원함 + .result(memberService.signIn(signInDto)) // 로그인하면 회원 페이지에 ㅇㅇ님 원함 .msg("로그인 성공") .build(); return ResponseEntity.ok(responseDTO); } @PutMapping("/{id}/update") - public ResponseEntity updateUserPw(@PathVariable Long id, @Valid @RequestBody ChangeUserPwDTO changeUserPwDto, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - List responseDTOList = returnBindingResult(bindingResult); - return new ResponseEntity<>(responseDTOList, HttpStatus.BAD_REQUEST); - } - + @Operation(summary = "회원 비밀번호 수정", description = "비밀번호, 수정 비밀번호 이용") + public ResponseEntity updateUserPw(@Parameter(description = "member의 id") @PathVariable Long id, @Valid @RequestBody ChangeUserPwDTO changeUserPwDto) { memberService.updateUserPw(id, changeUserPwDto); ResponseDTO responseDTO = ResponseDTO.builder() .msg("비밀번호 변경 성공") @@ -63,23 +50,12 @@ public ResponseEntity updateUserPw(@PathVariable Long id, @Valid @RequestBody } @DeleteMapping("/{id}/delete") - public ResponseEntity deleteMember(@PathVariable Long id, @RequestParam String userPw) { + @Operation(summary = "회원 탈퇴", description = "비밀번호 이용") + public ResponseEntity deleteMember(@Parameter(description = "member의 id") @PathVariable Long id, @RequestParam String userPw) { memberService.deleteMember(id, userPw); ResponseDTO responseDTO = ResponseDTO.builder() .msg("회원 탈퇴 성공") .build(); return new ResponseEntity<>(responseDTO, HttpStatus.NO_CONTENT); } - - public List returnBindingResult(BindingResult bindingResult) { - List list = bindingResult.getFieldErrors(); - List responseDTOList = new ArrayList<>(); - for (FieldError error : list) { - ResponseDTO responseDTO = ResponseDTO.builder() - .msg(error.getDefaultMessage()) - .build(); - responseDTOList.add(responseDTO); - } - return responseDTOList; - } } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java index d4ced74..c1f9822 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/MemberService.java @@ -48,10 +48,10 @@ public String signIn(@Valid SignInDTO signInDto) { return member.getUserId(); } // 회원의 비밀번호와 불일치 - throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_PASSWORD); + throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_USERID_PASSWORD); } // 아이디 없음 - throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.NOT_EXIST_USERID); + throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_USERID_PASSWORD); } public void updateUserPw(Long id, @Valid ChangeUserPwDTO changeUserPwDto) { @@ -66,7 +66,7 @@ public void updateUserPw(Long id, @Valid ChangeUserPwDTO changeUserPwDto) { throw new CustomException(HttpStatus.BAD_REQUEST, ErrorCode.NOT_SAME_CONFIRM_PASSWORD); } // 회원의 비밀번호와 불일치 - throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_PASSWORD); + throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_USERID_PASSWORD); } public void deleteMember(Long id, String userPw) { @@ -76,6 +76,6 @@ public void deleteMember(Long id, String userPw) { memberRepository.deleteById(id); } // 비밀번호 불일치 - throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_PASSWORD); + throw new CustomException(HttpStatus.NOT_FOUND, ErrorCode.WRONG_USERID_PASSWORD); } } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDTO.java index 5e9f53b..5d62e69 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/ChangeUserPwDTO.java @@ -1,18 +1,25 @@ package com.jiyunio.todolist.member.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import lombok.Getter; import lombok.Setter; @Getter @Setter +@Schema(description = "회원 비밀번호 수정") public class ChangeUserPwDTO { @NotBlank(message = "비밀번호를 입력하세요.") + @Schema(description = "회원 비밀번호") private String userPw; @NotBlank(message = "변경 비밀번호를 입력하세요.") + @Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,16}") + @Schema(description = "회원 수정 비밀번호", example = "qwer1234!") private String changePw; @NotBlank(message = "확인 비밀번호를 입력하세요.") + @Schema(description = "회원 수정 확인 비밀번호") private String confirmChangePw; } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDTO.java index 8830ebd..7e75d3d 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignInDTO.java @@ -1,5 +1,6 @@ package com.jiyunio.todolist.member.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; @@ -8,8 +9,10 @@ @Setter public class SignInDTO { @NotBlank(message = "아이디를 입력하세요.") + @Schema(example = "qwe123") private String userId; @NotBlank(message = "비밀번호를 입력하세요.") + @Schema(example = "qwer1234!") private String userPw; } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDTO.java index 280b1e1..79c46af 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/member/dto/SignUpDTO.java @@ -1,5 +1,6 @@ package com.jiyunio.todolist.member.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; @@ -8,17 +9,21 @@ @Getter @Setter +@Schema(description = "회원가입") public class SignUpDTO { + @NotBlank(message = "아이디를 입력하세요.") @Pattern(regexp = "(?=.*[a-zA-Z])(?=\\S+$).{5,10}", message = "아이디 : 5~10자") + @Schema(description = "회원의 userId : 영문 대/소문자 5~10자", example = "qwe123") private String userId; - @NotBlank(message = "비밀번호를 입력하세요.") @Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,16}", message = "비밀번호: 8~16자의 영문 대/소문자, 숫자, 특수문자를 사용하십쇼.") + @Schema(description = "회원의 비밀번호 : 8~16자의 영문 대/소문자, 숫자, 특수문자", example = "qwer123!") private String userPw; @NotBlank(message = "이메일를 입력하세요.") @Email(message = "이메일 형식이 맞지 않습니다.") + @Schema(description = "회원의 이메일", example = "qwer@google.com") private String userEmail; @NotBlank(message = "확인 비밀번호를 입력하세요.") diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/Todo.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/Todo.java index 8adc6dc..4021981 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/Todo.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/Todo.java @@ -20,7 +20,7 @@ public class Todo { private Long id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "memberId") + @JoinColumn(name = "member Id") private Member member; @Lob // 길이 제한 X diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/TodoController.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/TodoController.java index bb468db..5d9a2df 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/TodoController.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/TodoController.java @@ -4,29 +4,27 @@ import com.jiyunio.todolist.todo.dto.CreateTodoDTO; import com.jiyunio.todolist.todo.dto.GetTodoDTO; import com.jiyunio.todolist.todo.dto.UpdateTodoDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/todo") @RequiredArgsConstructor +@Tag(name = "Todo", description = "todo API") public class TodoController { private final TodoService todoService; @PostMapping("/{memberId}") - public ResponseEntity createTodo(@PathVariable Long memberId, @Valid @RequestBody CreateTodoDTO createTodo, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - List responseDTOList = returnBindingResult(bindingResult); - return new ResponseEntity<>(responseDTOList, HttpStatus.BAD_REQUEST); - } + @Operation(summary = "todo 생성", description = "todo checked 기본 값 = False") + public ResponseEntity createTodo(@Parameter(description = "member의 id") @PathVariable Long memberId, @Valid @RequestBody CreateTodoDTO createTodo) { todoService.createTodo(memberId, createTodo); ResponseDTO responseDTO = ResponseDTO.builder() .msg("Todo 생성 완료") @@ -35,17 +33,14 @@ public ResponseEntity createTodo(@PathVariable Long memberId, @Valid @Request } @GetMapping("/{memberId}") - public List getTodo(@PathVariable Long memberId) { + @Operation(summary = "todo 조회") + public List getTodo(@Parameter(description = "member의 id") @PathVariable Long memberId) { return todoService.getTodo(memberId); } @PutMapping("/{todoId}") - public ResponseEntity updateTodo(@PathVariable Long todoId, @Valid @RequestBody UpdateTodoDTO updateTodo, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - List responseDTOList = returnBindingResult(bindingResult); - return new ResponseEntity<>(responseDTOList, HttpStatus.BAD_REQUEST); - } - + @Operation(summary = "todo 수정") + public ResponseEntity updateTodo(@Parameter(description = "todo의 id") @PathVariable Long todoId, @Valid @RequestBody UpdateTodoDTO updateTodo) { todoService.updateTodo(todoId, updateTodo); ResponseDTO responseDTO = ResponseDTO.builder() .msg("Todo 수정 완료") @@ -54,23 +49,12 @@ public ResponseEntity updateTodo(@PathVariable Long todoId, @Valid @RequestBo } @DeleteMapping("/{todoId}") - public ResponseEntity deleteTodo(@PathVariable Long todoId) { + @Operation(summary = "todo 삭제") + public ResponseEntity deleteTodo(@Parameter(description = "todo의 id") @PathVariable Long todoId) { todoService.deleteTodo(todoId); ResponseDTO responseDTO = ResponseDTO.builder() .msg("Todo 삭제 완료") .build(); return new ResponseEntity<>(responseDTO, HttpStatus.NO_CONTENT); } - - public List returnBindingResult(BindingResult bindingResult) { - List list = bindingResult.getFieldErrors(); - List responseDTOList = new ArrayList<>(); - for (FieldError error : list) { - ResponseDTO responseDTO = ResponseDTO.builder() - .msg(error.getDefaultMessage()) - .build(); - responseDTOList.add(responseDTO); - } - return responseDTOList; - } } diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDTO.java index 310cd50..90182c3 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/CreateTodoDTO.java @@ -1,5 +1,6 @@ package com.jiyunio.todolist.todo.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Getter; @@ -9,6 +10,7 @@ @Getter @Setter +@Schema(description = "todo 생성 : todo checked 기본 값 False") public class CreateTodoDTO { @NotBlank(message = "todo를 작성해주세요.") private String content; diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/GetTodoDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/GetTodoDTO.java index 04e9197..75fc145 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/GetTodoDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/GetTodoDTO.java @@ -1,5 +1,6 @@ package com.jiyunio.todolist.todo.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -8,6 +9,7 @@ @Getter @Setter +@Schema(description = "todo 조회") public class GetTodoDTO { private String content; diff --git a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDTO.java b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDTO.java index 66e54ac..a4d0dcd 100644 --- a/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDTO.java +++ b/contents/todoListAPI/jiyun/todolist/src/main/java/com/jiyunio/todolist/todo/dto/UpdateTodoDTO.java @@ -1,5 +1,6 @@ package com.jiyunio.todolist.todo.dto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Getter; @@ -9,6 +10,7 @@ @Getter @Setter +@Schema(description = "todo 수정") public class UpdateTodoDTO { @NotBlank(message = "todo를 작성해주세요.") private String content; From 877d8d564bd90c9db9ed7459f72855af1b3da08f Mon Sep 17 00:00:00 2001 From: 82everywin <82everywin@gmail.com> Date: Mon, 20 May 2024 17:58:33 +0900 Subject: [PATCH 06/13] =?UTF-8?q?[Feat]=20week5=20=EB=B0=9C=ED=91=9C?= =?UTF-8?q?=EC=9E=90=EB=A3=8C=20=EC=97=85=EB=A1=9C=EB=93=9C=20&=20UserServ?= =?UTF-8?q?ice=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1-=20#47?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contents/concepts/wee6/hyeonseung.md | 206 ++++++++++++++++++ .../hyeonseung/todolist/build.gradle | 4 + .../todolist/todolist/domain/BaseEntity.java | 3 +- .../com/todolist/todolist/domain/Member.java | 4 +- .../dto/member/MemberLoginResponseDto.java | 2 +- .../todolist/dto/member/MemberRequestDto.java | 6 +- .../todolist/dto/todo/TodoResponseDto.java | 2 + .../todolist/service/MemberService.java | 2 +- .../controller/MemberControllerTest.java | 15 ++ .../todolist/service/MemberServiceTest.java | 140 ++++++++++++ 10 files changed, 375 insertions(+), 9 deletions(-) create mode 100644 contents/concepts/wee6/hyeonseung.md create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/service/MemberServiceTest.java diff --git a/contents/concepts/wee6/hyeonseung.md b/contents/concepts/wee6/hyeonseung.md new file mode 100644 index 0000000..39d5e0f --- /dev/null +++ b/contents/concepts/wee6/hyeonseung.md @@ -0,0 +1,206 @@ +# 자바에서의 테스트 코드 작성 + +## 자바에서 테스트를 위해 사용되는 메소드 + +JUnit 프레임워크 : 테스트 프레임 워크로 주로, 단위 테스트를 작성하고 실행할 수 있는 기능이 있음 + +- JUnit 특징 + - @Test 메서드가 호출할 때마다 새로운 인스턴스를 생성하여 독립적인 테스트가 이루어짐. + - 단정(assert) 메서드로 테스트 케이스의 수행결과를 판별 가능 + +📌 기본 어노테이션 + +- @Test : 테스트를 진행할 메소드를 표시 +- @BeforeEach : 각 테스트 메소드가 실행되기 전에, 실행되는 메소드 +- @AfterEach : 각 테스트 메소드가 실행된 후, 실행되는 메소드 +- @BeforeAll : 모든 테스트 메소드가 실행되기 전에, 한 번 실행되는 메소드 +- @AfterAll : 모든 테스트 메소드가 실행된 뒤에, 한번 실행되는 메소드 +- @Disabled : 특정 테스트 메소드를 비활성화함 + +| assertArrayEquals(expected, actual) | 예상값 expected와 실제값 actual이 일치함을 확인 | +| --- | --- | +| assertEquals(expected, actual) | 예상 값과 실제값이 같은 값을 가지는 지 확인 | +| assertEquals( a, b, c) | c의 오차범위 내에서 객체 a 와 b가 같이 일치하는 지 확인. | +| assertSame(a, b) | 객체 a 와 b가 같은 객체임을 확인 | +| assertTrue(condition) | 조건이 참인지 확인 | +| assertNotNull(actual) | 값이 null이 아님을 확인 | +| assertThrows(expectedType, executable) | 특정 예외가 발생하는지 확인 | +| assertTimeout(duration, executable) | 특정 시간 안에 실행이 완료되는지 확 | + +AssertJ 라이브러리 + +기본 JUnit이 제공하는 메소드보다 더 다양한 Assertion 기능과 가독성 높은 문법을 제공. + +⇒ 컬렉션이나 문제열 같은 복잡한 객체의 상태를 검증하는데 유용 + +기본 어셜션 + +| isEqualTo() , isNotEqualTo() | 값이 같은지 , 같지 않은지 확인 | +| --- | --- | +| isNull(), isNotNull() | 값이 Null인지 , 아닌지 확인 | +| isTrue() , isFalse() | 값이 true() 인지, 아닌지 확인 | + +문자열 어셜션 + +| startsWith(), endsWith | 특정 문자열로 시작하는지, 끝나는지 확 | +| --- | --- | +| contains(), doesNotContain() | 특정 문자열을 포함하는지, 포함하지 않는지 확인 | +| isEmpty(), isNotEmpty() | 문자열이 비어있는지 비어있지 않은지 확인 | + +컬렉션 어셜선 + +| hasSize() | 컬렉션의 크기를 확인 | +| --- | --- | +| contains() | 컬렉션이 특정 요소를 포함하는지 확인 | +| containExactly() | 컬렉션이 정확히 특정 요소들만 포함하는지 확인 | +| containsAnyOf() | 컬렉션이 특정 요소들 중 하나라도 포함하는지 확인 | +| doesNotContain() | 컬렉션이 특정 요소를 포함하지 않은지 확인 | +| isEmpty(), isNotEmpty(( | 컬렉션이 비어있는지 , 비어 있지 않은지 확인 | + +예외 어셜션 + +| assertThatThrownBy() | 특정 코드 블록이 예외를 던지는지 확인 | +| --- | --- | +| isInstanceOf() | 예외가 특정 클래스의 인스턴스인지 확인 | +| hasMessage() | 예외의 메시지가 특정 문자열인지 확인 | +| hasMessageContaining() | 예외의 메시지가 특정 문자열을 포함하는지 확인 | +- Mockito + +실제 객체를 모방한 가짜 객체, 즉 Mock 객체 생성 + +`@Mock` 이나 `@MockBean` 애노테이션 사용하여 주입하면 됨 + +## 실제 자바에서의 테스트 코드 예시 + + + +### Service 계층에서의 테스트 코드 예시 + +```java + +@ExtendWith(MockitoExtension.class) +public class MemberServiceTest { + + private Member member; + + private MemberRequestDto requestDto; + + @Mock + private MemberRepository memberRepository; + + @InjectMocks + private MemberService memberService; + + @BeforeEach + void setUp() { + member = Member.builder() + .name("test") + .loginId("test123") + .password("test123!@") + .build(); + + memberService = new MemberService(memberRepository); + requestDto = new MemberRequestDto("test", "test123", "test123!@"); + + } + + @Test + @DisplayName("멤버 생성") + void createMemberSuccess(){ + + member = MemberMapper.INSTANCE.toEntity(requestDto); + + when(memberRepository.existsByLoginId(requestDto.getLoginId())).thenReturn(false); + when(memberRepository.save(any(Member.class))).thenReturn(member); + + MemberResponseDto responseDto = memberService.create(requestDto); + + assertThat(responseDto.getLoginId()).isEqualTo(requestDto.getLoginId()); + assertThat(responseDto.getName()).isEqualTo(requestDto.getName()); + verify(memberRepository, times(1)).save(any(Member.class)); + } + + @Test + @DisplayName("로그인") + void LoginMember() { + when(memberRepository.findByLoginId(requestDto.getLoginId())).thenReturn(Optional.of(member)); + + MemberRequestDto.LoginRequestDto loginRequestDto = new MemberRequestDto.LoginRequestDto("test123" ,"test123!@"); + MemberLoginResponseDto responseDto = memberService.login(loginRequestDto); + + assertThat(responseDto.getLoginId()).isEqualTo(requestDto.getLoginId()); + } + + @Test + @DisplayName("단일 회원 검색") + void SearchMemberById(){ + setMemberId(member, 1L); + when(memberRepository.findById(any(Long.class))).thenReturn(Optional.of(member)); + + MemberResponseDto responseDto = memberService.searchId(1L); + + assertThat(responseDto.getId()).isEqualTo(member.getId()); + assertThat(responseDto.getLoginId()).isEqualTo(requestDto.getLoginId()); + assertThat(responseDto.getName()).isEqualTo(requestDto.getName()); + } + + @Test + @DisplayName("전체 회원 검색") + void SearchAll(){ + when(memberRepository.findAll()).thenReturn(Arrays.asList(member)); + + List responseDtos = memberService.searchAll(); + + assertThat(responseDtos).hasSize(1); + assertThat(responseDtos.get(0).getLoginId()).isEqualTo(requestDto.getLoginId()); + } + + @Test + @DisplayName("회원정보 수정") + void updateMember() { + setMemberId(member,1L); + when(memberRepository.findById(any(Long.class))).thenReturn(Optional.of(member)); + when(memberRepository.existsByLoginId(requestDto.getLoginId())).thenReturn(false); + + MemberRequestDto newRequestDto = new MemberRequestDto("newTest", "newTest123", "test456!@#"); + + MemberResponseDto responseDto = memberService.update(1L, newRequestDto); + + assertThat(responseDto.getId()).isEqualTo(member.getId()); + assertThat(responseDto.getLoginId()).isEqualTo(newRequestDto.getLoginId()); + assertThat(responseDto.getName()).isEqualTo(newRequestDto.getName()); + verify(memberRepository, times(1)).save(any(Member.class)); + } + + @Test + @DisplayName("회원삭제") + void deleteMember(){ + setMemberId(member, 1L); + when(memberRepository.findById(any(Long.class))).thenReturn(Optional.of(member)); + + memberService.delete(1L); + + verify(memberRepository, times(1)).deleteById(1L); + + } + + private void setMemberId(Member member, Long id) { + try { + Field idField = Member.class.getDeclaredField("id"); + idField.setAccessible(true); + idField.set(member, id); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + +} + +``` diff --git a/contents/todoListAPI/hyeonseung/todolist/build.gradle b/contents/todoListAPI/hyeonseung/todolist/build.gradle index 61f3969..001cf59 100644 --- a/contents/todoListAPI/hyeonseung/todolist/build.gradle +++ b/contents/todoListAPI/hyeonseung/todolist/build.gradle @@ -34,6 +34,10 @@ dependencies { annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final' // Dto Mapper implementation 'org.springframework.boot:spring-boot-starter-validation' //유효성검사 implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.11' + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + + implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.8.0' } tasks.named('test') { diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java index e370c0e..d2d389c 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/BaseEntity.java @@ -6,6 +6,7 @@ import lombok.Getter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.time.LocalDateTime; @@ -23,7 +24,7 @@ public abstract class BaseEntity { @Column(updatable = false) private LocalDateTime createdAt; - @LastModifiedBy + @LastModifiedDate @Column(insertable = false) private LocalDateTime modifiedAt; diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java index 2354fb4..ec5cb22 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Member.java @@ -36,13 +36,11 @@ private Member(String name, String loginId, String password, List todoList this.todoList = todoList; } - - public void updateLoginId(String loginId){ this.loginId = loginId; } - public void updatePassword(String Password){ + public void updatePassword(String password){ this.password = password; } diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberLoginResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberLoginResponseDto.java index 40b6925..6e3cdb0 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberLoginResponseDto.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberLoginResponseDto.java @@ -6,5 +6,5 @@ @Getter @AllArgsConstructor public class MemberLoginResponseDto { - private Long id; + private String loginId; } diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java index 4fe85b8..f68a575 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberRequestDto.java @@ -4,9 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; @Getter @AllArgsConstructor @@ -33,6 +31,8 @@ public class MemberRequestDto { @Getter + @RequiredArgsConstructor + @AllArgsConstructor public static class LoginRequestDto{ @NotBlank(message = "아이디를 입력해주세요.") private String loginId; diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java index c60ffc5..e62727f 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java @@ -19,4 +19,6 @@ public class TodoResponseDto { private boolean isCompleted; private LocalDateTime dueAt; private Long memberId; + + } diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java index ca89f32..ca6f716 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/MemberService.java @@ -47,7 +47,7 @@ public MemberLoginResponseDto login(MemberRequestDto.LoginRequestDto request){ Member member = throwFindbyLoginId(request.getLoginId()); if (!member.getPassword().equals(request.getPassword())) throw new BaseException(ErrorCode.UNAUTHORIZED_LOGIN); - return new MemberLoginResponseDto(member.getId()); + return new MemberLoginResponseDto(member.getLoginId()); } // 3. 회원 검색 diff --git a/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java new file mode 100644 index 0000000..9659eb9 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java @@ -0,0 +1,15 @@ +package com.todolist.todolist.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; + +@SpringBootTest +@AutoConfigureMockMvc +public class MemberControllerTest { + + @Autowired + private MockMvc mockMvc; + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/service/MemberServiceTest.java b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/service/MemberServiceTest.java new file mode 100644 index 0000000..3f0883a --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/service/MemberServiceTest.java @@ -0,0 +1,140 @@ +package com.todolist.todolist.service; + +import com.todolist.todolist.domain.Member; +import com.todolist.todolist.dto.member.MemberLoginResponseDto; +import com.todolist.todolist.dto.member.MemberMapper; +import com.todolist.todolist.dto.member.MemberRequestDto; +import com.todolist.todolist.dto.member.MemberResponseDto; +import com.todolist.todolist.repository.MemberRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class MemberServiceTest { + private Member member; + private MemberRequestDto requestDto; + @Mock + private MemberRepository memberRepository; + @InjectMocks + private MemberService memberService; + + + @BeforeEach + void setUp() { + member = Member.builder() + .name("test") + .loginId("test123") + .password("test123!@") + .build(); + + memberService = new MemberService(memberRepository); + requestDto = new MemberRequestDto("test", "test123", "test123!@"); + + } + + @Test + @DisplayName("멤버 생성") + void createMemberSuccess(){ + + member = MemberMapper.INSTANCE.toEntity(requestDto); + + when(memberRepository.existsByLoginId(requestDto.getLoginId())).thenReturn(false); + when(memberRepository.save(any(Member.class))).thenReturn(member); + + MemberResponseDto responseDto = memberService.create(requestDto); + + assertThat(responseDto.getLoginId()).isEqualTo(requestDto.getLoginId()); + assertThat(responseDto.getName()).isEqualTo(requestDto.getName()); + verify(memberRepository, times(1)).save(any(Member.class)); + } + + @Test + @DisplayName("로그인") + void LoginMember() { + when(memberRepository.findByLoginId(requestDto.getLoginId())).thenReturn(Optional.of(member)); + + MemberRequestDto.LoginRequestDto loginRequestDto = new MemberRequestDto.LoginRequestDto("test123" ,"test123!@"); + MemberLoginResponseDto responseDto = memberService.login(loginRequestDto); + + assertThat(responseDto.getLoginId()).isEqualTo(requestDto.getLoginId()); + } + + + @Test + @DisplayName("단일 회원 검색") + void SearchMemberById(){ + setMemberId(member, 1L); + when(memberRepository.findById(any(Long.class))).thenReturn(Optional.of(member)); + + MemberResponseDto responseDto = memberService.searchId(1L); + + assertThat(responseDto.getId()).isEqualTo(member.getId()); + assertThat(responseDto.getLoginId()).isEqualTo(requestDto.getLoginId()); + assertThat(responseDto.getName()).isEqualTo(requestDto.getName()); + } + + @Test + @DisplayName("전체 회원 검색") + void SearchAll(){ + when(memberRepository.findAll()).thenReturn(Arrays.asList(member)); + + List responseDtos = memberService.searchAll(); + + assertThat(responseDtos).hasSize(1); + assertThat(responseDtos.get(0).getLoginId()).isEqualTo(requestDto.getLoginId()); + } + + @Test + @DisplayName("회원정보 수정") + void updateMember() { + setMemberId(member,1L); + when(memberRepository.findById(any(Long.class))).thenReturn(Optional.of(member)); + when(memberRepository.existsByLoginId(any(String.class))).thenReturn(false); + + MemberRequestDto newRequestDto = new MemberRequestDto("newTest", "newTest123", "test456!@#"); + + MemberResponseDto responseDto = memberService.update(1L, newRequestDto); + + //assertThat(responseDto.getId()).isEqualTo(member.getId()); + assertThat(responseDto.getLoginId()).isEqualTo(newRequestDto.getLoginId()); + assertThat(responseDto.getName()).isEqualTo(newRequestDto.getName()); + verify(memberRepository, times(1)).save(any(Member.class)); + } + + @Test + @DisplayName("회원삭제") + void deleteMember(){ + setMemberId(member, 1L); + when(memberRepository.findById(any(Long.class))).thenReturn(Optional.of(member)); + + memberService.delete(1L); + + verify(memberRepository, times(1)).deleteById(1L); + + } + + private void setMemberId(Member member, Long id) { + try { + Field idField = Member.class.getDeclaredField("id"); + idField.setAccessible(true); + idField.set(member, id); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + +} From 4baff4eaee0d58ef1bdada17b3a778cce25fe6f3 Mon Sep 17 00:00:00 2001 From: 82everywin <82everywin@gmail.com> Date: Mon, 20 May 2024 18:45:21 +0900 Subject: [PATCH 07/13] =?UTF-8?q?[Feat]=20week5=20=EB=B0=9C=ED=91=9C?= =?UTF-8?q?=EC=9E=90=EB=A3=8C=20=EC=97=85=EB=A1=9C=EB=93=9C=20&=20UserServ?= =?UTF-8?q?ice=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1-=20#47?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hyeonseung/todolist/build.gradle | 4 +- .../dto/member/MemberResponseDto.java | 4 +- .../controller/MemberControllerTest.java | 50 +++++++++++++++++-- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/contents/todoListAPI/hyeonseung/todolist/build.gradle b/contents/todoListAPI/hyeonseung/todolist/build.gradle index 001cf59..255fa17 100644 --- a/contents/todoListAPI/hyeonseung/todolist/build.gradle +++ b/contents/todoListAPI/hyeonseung/todolist/build.gradle @@ -36,8 +36,8 @@ dependencies { implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.11' testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' - - implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.8.0' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' + // implementation 'com.google.code.gson:gson:2.8.8' } tasks.named('test') { diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java index 2d43e44..657404a 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberResponseDto.java @@ -17,6 +17,4 @@ public class MemberResponseDto { private String loginId; private LocalDateTime createdAt; private LocalDateTime modifiedAt; - - -} +} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java index 9659eb9..c1d2de5 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/test/java/com/todolist/todolist/controller/MemberControllerTest.java @@ -1,15 +1,57 @@ package com.todolist.todolist.controller; +import com.todolist.todolist.domain.Member; +import com.todolist.todolist.dto.member.MemberRequestDto; +import com.todolist.todolist.dto.member.MemberResponseDto; +import com.todolist.todolist.service.MemberService; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -@SpringBootTest -@AutoConfigureMockMvc +import java.lang.reflect.Field; +import java.time.LocalDateTime; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(MemberController.class) +@ExtendWith(MockitoExtension.class) public class MemberControllerTest { @Autowired private MockMvc mockMvc; + @MockBean + private MemberService memberService; + + @Autowired + // private Gson gson; + + void createMember() throws Exception { + MemberRequestDto requestDto = new MemberRequestDto("test","test123", "test123!@"); + MemberResponseDto responseDto = new MemberResponseDto(1L, "test","test123", LocalDateTime.now(), LocalDateTime.now()); + + when(memberService.create(any(MemberRequestDto.class))).thenReturn(responseDto); + +// mockMvc.perform(post("/api/member") +// .contentType(MediaType.APPLICATION_JSON) +// .content(String.valueOf(requestDto)) +// .andExpect(status().isCreated()) +// .andExpect() + } + private void setMemberId(Member member, Long id) { + try { + Field idField = Member.class.getDeclaredField("id"); + idField.setAccessible(true); + idField.set(member, id); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } } From 7f49806af66dddb52151479d223dd87900920d04 Mon Sep 17 00:00:00 2001 From: 82everywin <82everywin@gmail.com> Date: Mon, 20 May 2024 19:05:30 +0900 Subject: [PATCH 08/13] =?UTF-8?q?[Refactor]=20week6=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contents/concepts/{wee6 => week6}/hyeonseung.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contents/concepts/{wee6 => week6}/hyeonseung.md (100%) diff --git a/contents/concepts/wee6/hyeonseung.md b/contents/concepts/week6/hyeonseung.md similarity index 100% rename from contents/concepts/wee6/hyeonseung.md rename to contents/concepts/week6/hyeonseung.md From 7decaefaabef30c04e1bbfcffc1cc6bb4c642437 Mon Sep 17 00:00:00 2001 From: 82everywin <82everywin@gmail.com> Date: Mon, 20 May 2024 19:13:18 +0900 Subject: [PATCH 09/13] =?UTF-8?q?[Refactor]=20=EB=B3=91=ED=95=A9=20?= =?UTF-8?q?=EC=B6=A9=EB=8F=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../todolist/TodolistApplication.java | 16 +++ .../todolist/config/SwaggerConfig.java | 25 ++++ .../todolist/controller/MemberController.java | 69 +++++++++++ .../todolist/controller/TodoController.java | 65 +++++++++++ .../com/todolist/todolist/domain/Todo.java | 65 +++++++++++ .../todolist/todolist/dto/EntityMapper.java | 6 + .../todolist/dto/member/MemberMapper.java | 25 ++++ .../todolist/dto/todo/TodoMapper.java | 28 +++++ .../todolist/dto/todo/TodoRequestDto.java | 34 ++++++ .../todolist/dto/todo/TodoResponseDto.java | 2 - .../todolist/repository/MemberRepository.java | 17 +++ .../todolist/repository/TodoRepository.java | 17 +++ .../todolist/service/TodoService.java | 110 ++++++++++++++++++ .../todolist/validators/BaseException.java | 11 ++ .../todolist/validators/ErrorCode.java | 29 +++++ .../todolist/validators/ErrorResponseDto.java | 27 +++++ .../validators/GlobalExceptionHandler.java | 40 +++++++ 17 files changed, 584 insertions(+), 2 deletions(-) create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/BaseException.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorCode.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorResponseDto.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/GlobalExceptionHandler.java diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java new file mode 100644 index 0000000..9793ac7 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/TodolistApplication.java @@ -0,0 +1,16 @@ +package com.todolist.todolist; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + + +@SpringBootApplication +@EnableJpaAuditing +public class TodolistApplication { + + public static void main(String[] args) { + SpringApplication.run(TodolistApplication.class, args); + } + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java new file mode 100644 index 0000000..5027e64 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SwaggerConfig.java @@ -0,0 +1,25 @@ +package com.todolist.todolist.config; + + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + @Bean + public OpenAPI openAPI() { + return new OpenAPI() + .components(new Components()) + .info(apiInfo()); + } + + private Info apiInfo() { + return new Info() + .title("Swagger API Test") + .description("Springdoc을 사용한 Swagger Api test") + .version("1.0.0"); + } +} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java new file mode 100644 index 0000000..252faea --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/MemberController.java @@ -0,0 +1,69 @@ +package com.todolist.todolist.controller; + + +import com.todolist.todolist.dto.member.MemberLoginResponseDto; +import com.todolist.todolist.dto.member.MemberResponseDto; +import com.todolist.todolist.dto.member.MemberRequestDto; +import com.todolist.todolist.service.MemberService; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RequestMapping("api/members") +@RestController +@RequiredArgsConstructor +public class MemberController { + private final MemberService memberService; + + @Operation(summary = "회원가입") + @PostMapping + public ResponseEntity createMember(@Valid @RequestBody MemberRequestDto request) { + + MemberResponseDto responseDto = memberService.create(request); + return ResponseEntity.status(HttpStatus.CREATED).body(responseDto); + } + + @Operation(summary = "로그인") + @PostMapping("/login") + public ResponseEntity loginMember(@RequestBody @Valid MemberRequestDto.LoginRequestDto request){ + MemberLoginResponseDto responseDto = memberService.login(request); + return ResponseEntity.status(HttpStatus.CREATED).body(responseDto); + } + @Operation(summary = "회원정보 수정") + @PutMapping("/{memberId}") + public ResponseEntity updateMember(@RequestBody @Valid MemberRequestDto request, @PathVariable Long memberId){ + + MemberResponseDto responseDto = memberService.update(memberId, request); + return ResponseEntity.status(HttpStatus.OK).body(responseDto); + } + + @Operation(summary = "Id별 회원 조회") + @GetMapping("/{memberId}") + public ResponseEntity readOneMember(@PathVariable Long memberId){ + MemberResponseDto responseDto = memberService.searchId(memberId); + + return ResponseEntity.status(HttpStatus.OK).body(responseDto); + } + + @Operation(summary = "일괄 회원 조회") + @GetMapping + public ResponseEntity> readAllMember(){ + List responseDto = memberService.searchAll(); + + return ResponseEntity.status(HttpStatus.OK).body(responseDto); + } + + @Operation(summary = "회원 삭제") + @DeleteMapping("/{memberId}") + public ResponseEntity delete(@PathVariable Long memberId){ + memberService.delete(memberId); + return ResponseEntity.noContent().build(); + } + + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java new file mode 100644 index 0000000..1646ba3 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/controller/TodoController.java @@ -0,0 +1,65 @@ +package com.todolist.todolist.controller; + +import com.todolist.todolist.dto.todo.TodoRequestDto; +import com.todolist.todolist.dto.todo.TodoResponseDto; +import com.todolist.todolist.service.TodoService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RequestMapping("api/todo") +@RestController +@RequiredArgsConstructor +public class TodoController { + private final TodoService todoService; + // private final ErrorMessageHandler messageHandler; + + + @Operation(summary = "Todo 추가") + @PostMapping("/{memberId}") + public ResponseEntity addTodo(@PathVariable Long memberId, @RequestBody @Valid TodoRequestDto request){ + + TodoResponseDto responseDto = todoService.add(memberId, request); + return ResponseEntity.status(HttpStatus.CREATED).body(responseDto); + } + + @Operation(summary = "Todo 전체 목록 조회") + @GetMapping + public ResponseEntity> readAll(){ + List responseDto = todoService.searchAll(); + return ResponseEntity.status(HttpStatus.OK).body(responseDto); + } + + @Operation(summary = "회원별 Todo 목록 조회 ") + @GetMapping("/{memberId}") + public ResponseEntity> readMemberTodo (@PathVariable Long memberId){ + List responseDto = todoService.searchById(memberId); + return ResponseEntity.status(HttpStatus.OK).body(responseDto); + } + + @Operation(summary = "Todo 수정") + @PutMapping("/{memberId}/{todoId}") + public ResponseEntity update(@PathVariable Long memberId, @PathVariable Long todoId, @RequestBody @Valid TodoRequestDto request){ + + TodoResponseDto responseDto = todoService.update(memberId,todoId,request); + return ResponseEntity.status(HttpStatus.OK).body(responseDto); + } + + @Operation(summary = "Todo 삭제") + @DeleteMapping("/{todoId}") + public ResponseEntity deleteOne(@PathVariable Long todoId){ + + todoService.delete(todoId); + return ResponseEntity.noContent().build(); + } + +} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java new file mode 100644 index 0000000..ae45cd2 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Todo.java @@ -0,0 +1,65 @@ +package com.todolist.todolist.domain; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +import java.time.LocalDateTime; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class Todo extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String title; + + private String contents; + + @ColumnDefault("false") + private Boolean isCompleted = false; + + private LocalDateTime dueAt; + + // 할일을 작성한 멤버 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @Builder + protected Todo(String title, String contents, Boolean isCompleted, LocalDateTime dueAt, Member member) { + this.title = title; + this.contents = contents; + this.isCompleted = isCompleted; + this.dueAt = dueAt; + this.member = member; + } + + public void matchMember(Member member){ + this.member = member; + } + + public void updateTitle(String title) { + if(title != null) this.title = title; + } + + public void updateContents(String contents) { + if(contents != null) this.contents = contents; + } + + public void updateIsCompleted(Boolean isCompleted) { + if(isCompleted != null) this.isCompleted = isCompleted; + } + + public void updateDueAt(LocalDateTime dueAt) { + if(dueAt != null) this.dueAt = dueAt; + } + +} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java new file mode 100644 index 0000000..e7e192b --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/EntityMapper.java @@ -0,0 +1,6 @@ +package com.todolist.todolist.dto; + +public interface EntityMapper { + ENTITY toEntity(final REQUEST request); + RESPONSE toDto(final ENTITY entity); +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java new file mode 100644 index 0000000..22084eb --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/member/MemberMapper.java @@ -0,0 +1,25 @@ +package com.todolist.todolist.dto.member; + +import com.todolist.todolist.domain.Member; +import com.todolist.todolist.dto.EntityMapper; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + + +/* Mapper 사용 +Service와 Controller 의 목적을 정확히 구분하고, +이들 사이에서 Entity <-> DTO 간의 객체 mapping을 편하게 도와주기 위해 + */ +@Mapper +public interface MemberMapper extends EntityMapper { + // 해당하는 INSTANCE가 MemberMapper을 상속받아, MemberMapperImpl로 구현하게 될것. + MemberMapper INSTANCE = Mappers.getMapper(MemberMapper.class); + + @Override + @Mapping(target = "todoList",ignore = true) // Member 엔티티가 @Builder 이다 보니. 제거 대상 + Member toEntity(final MemberRequestDto requestDto); + @Override + MemberResponseDto toDto(final Member member); + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java new file mode 100644 index 0000000..e56588c --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoMapper.java @@ -0,0 +1,28 @@ +package com.todolist.todolist.dto.todo; + +import com.todolist.todolist.domain.Member; +import com.todolist.todolist.domain.Todo; +import com.todolist.todolist.dto.EntityMapper; +import jakarta.persistence.Column; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDateTime; + +@Mapper +public interface TodoMapper extends EntityMapper { + + TodoMapper INSTANCE = Mappers.getMapper(TodoMapper.class); + + @Override + @Mapping(target = "member", ignore = true) + Todo toEntity(final TodoRequestDto todoRequestDto); + + @Override + @Mapping(target = "memberId", source = "member.id") + TodoResponseDto toDto(final Todo todo); +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java new file mode 100644 index 0000000..427ed00 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoRequestDto.java @@ -0,0 +1,34 @@ +package com.todolist.todolist.dto.todo; + +import com.todolist.todolist.domain.Member; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class TodoRequestDto { + + @Schema(example= "할일 추가") + @Size(min=1, max=30) + @NotBlank(message = "제목을 입력해주세요.") + private String title; + + @Schema(example = "add Todolist") + private String contents; + + @Schema(example = "false") + private Boolean isCompleted; + + private LocalDateTime dueAt; + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java index e62727f..c60ffc5 100644 --- a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/dto/todo/TodoResponseDto.java @@ -19,6 +19,4 @@ public class TodoResponseDto { private boolean isCompleted; private LocalDateTime dueAt; private Long memberId; - - } diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java new file mode 100644 index 0000000..bd174ce --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/MemberRepository.java @@ -0,0 +1,17 @@ +package com.todolist.todolist.repository; + +import com.todolist.todolist.domain.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface MemberRepository extends JpaRepository { + + Optional findByLoginId(String loginId); + Optional findById(Long id); + + boolean existsByLoginId(String LoginId); + + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java new file mode 100644 index 0000000..dd2761d --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/repository/TodoRepository.java @@ -0,0 +1,17 @@ +package com.todolist.todolist.repository; + +import com.todolist.todolist.domain.Member; +import com.todolist.todolist.domain.Todo; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface TodoRepository extends JpaRepository { + + List findAll (); + Optional findById(Long id); + List findAllByMember(Member member); + + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java new file mode 100644 index 0000000..f64a61a --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/service/TodoService.java @@ -0,0 +1,110 @@ +package com.todolist.todolist.service; + +import com.todolist.todolist.domain.Member; +import com.todolist.todolist.domain.Todo; +import com.todolist.todolist.dto.todo.TodoMapper; +import com.todolist.todolist.dto.todo.TodoRequestDto; +import com.todolist.todolist.dto.todo.TodoResponseDto; +import com.todolist.todolist.repository.MemberRepository; +import com.todolist.todolist.repository.TodoRepository; +import com.todolist.todolist.validators.BaseException; +import com.todolist.todolist.validators.ErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class TodoService { + + private final TodoRepository todoRepository; + private final MemberRepository memberRepository; + + /* + 1. Todo 추가 + 2. Todo 수정 + 3. Todo 전체 조회 + 4. Todo 리스트 조회 (memberId로 조회) + 5. Todo 삭제 + 6. Todo 전체 삭제 + */ + + // 1. Todo 추가 + public TodoResponseDto add(Long id, TodoRequestDto requestDto) { + + Member member = memberRepository.findById(id) + .orElseThrow(() -> new BaseException(ErrorCode.NOT_EXIST_ID)); + + Todo todo = TodoMapper.INSTANCE.toEntity(requestDto); + todo.matchMember(member); + todoRepository.save(todo); + + return TodoMapper.INSTANCE.toDto(todo); + } + + // 2. Todo 수정 + public TodoResponseDto update(Long memberId, Long todoId, TodoRequestDto requestDto) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new BaseException(ErrorCode.NOT_EXIST_ID)); + // 회원과 할일 간에 -> 관계가 매핑되어 있지 않음 + List todos = todoRepository.findAllByMember(member); + if (todos.isEmpty()) { + throw new BaseException(ErrorCode.NOT_MATCH_TODO_ID); + } + + + Todo targetTodo = todos.stream() + .filter(todo -> todo.getId().equals(todoId)) + .findFirst() + .orElseThrow(() -> new BaseException(ErrorCode.NOT_MATCH_TODO_ID)); + + targetTodo.updateTitle(requestDto.getTitle()); + targetTodo.updateContents(requestDto.getContents()); + targetTodo.updateIsCompleted(requestDto.getIsCompleted()); + targetTodo.updateDueAt(requestDto.getDueAt()); + todoRepository.save(targetTodo); + + return TodoMapper.INSTANCE.toDto(targetTodo); + } + + // 3. Todo 전체 조회 + public List searchAll() { + List todos = todoRepository.findAll(); + + return todos.stream() + .map(TodoMapper.INSTANCE::toDto) + .collect(Collectors.toList()); + + } + + // 4. Todo 리스트 조회 (memberId로 조회) + public List searchById(Long id) { + // 회원찾기 + Member member = memberRepository.findById(id) + .orElseThrow(() -> new BaseException(ErrorCode.NOT_EXIST_ID)); + // 회원으로 + List todos = todoRepository.findAllByMember(member); + if (todos.isEmpty()) { + throw new BaseException(ErrorCode.NOT_MATCH_TODO_ID); + } + + return todos.stream() + .map(TodoMapper.INSTANCE::toDto) + .collect(Collectors.toList()); + + } + + // 5. Todo 삭제 + public void delete(Long id) { + Todo todo = todoRepository.findById(id) + .orElseThrow(()-> new BaseException(ErrorCode.NOT_EXIST_TODO)); + todoRepository.deleteById(todo.getId()); + } + +} \ No newline at end of file diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/BaseException.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/BaseException.java new file mode 100644 index 0000000..c4d8903 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/BaseException.java @@ -0,0 +1,11 @@ +package com.todolist.todolist.validators; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class BaseException extends RuntimeException{ + private final ErrorCode errorCode; + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorCode.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorCode.java new file mode 100644 index 0000000..86d4ee5 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorCode.java @@ -0,0 +1,29 @@ +package com.todolist.todolist.validators; + + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.*; + +@Getter +@RequiredArgsConstructor +public enum ErrorCode { + + + // 401 + UNAUTHORIZED_LOGIN(UNAUTHORIZED,"아이디 혹은 비밀번호를 잘못입력했습니다."), + + // 404 NOT_FOUND ERROR + NOT_EXIST_ID(NOT_FOUND,"존재하지 않는 회원입니다."), + NOT_EXIST_TODO(NOT_FOUND, "존재하지 않는 Todo입니다."), + NOT_MATCH_TODO_ID(NOT_FOUND,"회원과 일치하는 TODOLIST가 존재하지 않습니다."), + + // 409 CONFLICT ERROR + DUPLICATE_LOGINID(CONFLICT,"이미 존재하는 아이디입니다."); + + + private final HttpStatus status; + private final String message; + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorResponseDto.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorResponseDto.java new file mode 100644 index 0000000..d49eef2 --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/ErrorResponseDto.java @@ -0,0 +1,27 @@ +package com.todolist.todolist.validators; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; + +@Getter +@Builder +@RequiredArgsConstructor +public class ErrorResponseDto { + + private final String code; + private final String message; + + + public static ResponseEntity fromErrorCode(final ErrorCode errorCode) { + return ResponseEntity.status(errorCode.getStatus()) + .body(ErrorResponseDto.builder() + .code(errorCode.name()) + .message(errorCode.getMessage()) + .build() + ); + } + +} diff --git a/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/GlobalExceptionHandler.java b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/GlobalExceptionHandler.java new file mode 100644 index 0000000..9e1e3ac --- /dev/null +++ b/contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/validators/GlobalExceptionHandler.java @@ -0,0 +1,40 @@ +package com.todolist.todolist.validators; + +import org.springframework.http.*; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.util.ArrayList; +import java.util.List; + +@RestControllerAdvice +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler(BaseException.class) + private ResponseEntity ErrorResponse(BaseException e){ + ErrorCode errorCode = e.getErrorCode(); + return ErrorResponseDto.fromErrorCode(errorCode); + } + + // Bean Validation 예외 + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { + List fieldErrors = ex.getBindingResult().getFieldErrors(); + List errors = new ArrayList<>(); + + for(FieldError fieldError: fieldErrors){ + ErrorResponseDto errorResponseDto = ErrorResponseDto.builder() + .code(fieldError.getField()) + .message(fieldError.getDefaultMessage()) + .build(); + errors.add(errorResponseDto); + } + return ResponseEntity.status(status).body(errors); + + + } +} From d2f68b199a88effb2178d00d803d5ded18a3eaab Mon Sep 17 00:00:00 2001 From: 82everywin <82everywin@gmail.com> Date: Mon, 27 May 2024 17:59:47 +0900 Subject: [PATCH 10/13] =?UTF-8?q?[Docs]=207=EC=A3=BC=EC=B0=A8=20=EB=B0=9C?= =?UTF-8?q?=ED=91=9C=EC=9E=90=EB=A3=8C=20=EC=97=86=EB=A1=9C=EB=93=9C=20&?= =?UTF-8?q?=20[Feat]=20=EC=8A=A4=ED=94=84=EB=A7=81=20=EC=8B=9C=ED=81=90?= =?UTF-8?q?=EB=A6=AC=ED=8B=B0=20-=20#62,=20#63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.gradle/8.4/checksums/checksums.lock | Bin 17 -> 17 bytes .../.gradle/8.4/checksums/md5-checksums.bin | Bin 0 -> 19197 bytes .../.gradle/8.4/checksums/sha1-checksums.bin | Bin 0 -> 19739 bytes .../8.4/executionHistory/executionHistory.bin | Bin 19877 -> 102885 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .../.gradle/8.4/fileHashes/fileHashes.bin | Bin 18697 -> 22247 bytes .../.gradle/8.4/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.4/fileHashes/resourceHashesCache.bin | Bin 0 -> 19959 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 +- .../buildOutputCleanup/outputFiles.bin | Bin 18785 -> 18983 bytes .../todolist/.gradle/file-system.probe | Bin 8 -> 8 bytes .../hyeonseung/todolist/.idea/gradle.xml | 1 + .../hyeonseung/todolist/build.gradle | 11 +- .../todolist/config/JwtTokenFilter.class | Bin 0 -> 3825 bytes .../todolist/config/SecurityConfig.class | Bin 0 -> 5281 bytes .../controller/MemberController.class | Bin 5516 -> 5869 bytes .../domain/Member$MemberBuilder.class | Bin 2190 -> 2514 bytes .../com/todolist/todolist/domain/Member.class | Bin 2619 -> 3069 bytes .../com/todolist/todolist/domain/Role.class | Bin 0 -> 1142 bytes .../security/CustomUserDetailService.class | Bin 0 -> 2844 bytes .../todolist/security/JwtTokenProvider.class | Bin 0 -> 6009 bytes .../todolist/security/PasswordConfig.class | Bin 0 -> 710 bytes .../todolist/service/MemberService.class | Bin 5800 -> 5800 bytes .../todolist/dto/member/MemberMapperImpl.java | 4 +- .../todolist/dto/todo/TodoMapperImpl.java | 4 +- .../resources/main/application 2.properties | 20 --- .../resources/main/application.properties | 15 +-- .../stash-dir/JwtTokenFilter.class.uniqueId3 | Bin 0 -> 3825 bytes .../JwtTokenProvider.class.uniqueId1 | Bin 0 -> 5584 bytes .../Member$MemberBuilder.class.uniqueId6 | Bin 2190 -> 0 bytes .../stash-dir/Member.class.uniqueId4 | Bin 2619 -> 0 bytes .../MemberController.class.uniqueId0 | Bin 0 -> 5870 bytes .../MemberController.class.uniqueId2 | Bin 5516 -> 0 bytes .../stash-dir/MemberMapper.class.uniqueId11 | Bin 1472 -> 0 bytes .../MemberMapperImpl.class.uniqueId7 | Bin 2868 -> 0 bytes .../stash-dir/MemberMapperImpl.java.uniqueId5 | 44 ------- .../MemberRepository.class.uniqueId1 | Bin 1048 -> 0 bytes .../stash-dir/MemberService.class.uniqueId12 | Bin 5800 -> 0 bytes .../stash-dir/SecurityConfig.class.uniqueId2 | Bin 0 -> 5281 bytes .../Todo$TodoBuilder.class.uniqueId10 | Bin 2393 -> 0 bytes .../stash-dir/Todo.class.uniqueId15 | Bin 3090 -> 0 bytes .../stash-dir/TodoController.class.uniqueId3 | Bin 4690 -> 0 bytes .../stash-dir/TodoMapper.class.uniqueId14 | Bin 1510 -> 0 bytes .../stash-dir/TodoMapperImpl.class.uniqueId0 | Bin 3577 -> 0 bytes .../stash-dir/TodoMapperImpl.java.uniqueId9 | 64 ---------- .../stash-dir/TodoRepository.class.uniqueId8 | Bin 1199 -> 0 bytes .../stash-dir/TodoService.class.uniqueId13 | Bin 6477 -> 0 bytes .../compileJava/previous-compilation-data.bin | Bin 50021 -> 69099 bytes .../todolist/config/JwtTokenFilter.java | 70 +++++++++++ .../todolist/config/SecurityConfig.java | 42 +++++++ .../todolist/controller/MemberController.java | 21 +++- .../com/todolist/todolist/domain/Member.java | 6 +- .../com/todolist/todolist/domain/Role.java | 6 + .../security/CustomUserDetailService.java | 39 ++++++ .../todolist/security/JwtTokenProvider.java | 114 ++++++++++++++++++ .../todolist/security/PasswordConfig.java | 14 +++ .../todolist/service/MemberService.java | 4 +- .../src/main/resources/application.properties | 29 +++++ 59 files changed, 362 insertions(+), 148 deletions(-) create mode 100644 contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/checksums/md5-checksums.bin create mode 100644 contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/checksums/sha1-checksums.bin create mode 100644 contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/fileHashes/resourceHashesCache.bin create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/classes/java/main/com/todolist/todolist/config/JwtTokenFilter.class create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/classes/java/main/com/todolist/todolist/config/SecurityConfig.class create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/classes/java/main/com/todolist/todolist/domain/Role.class create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/classes/java/main/com/todolist/todolist/security/CustomUserDetailService.class create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/classes/java/main/com/todolist/todolist/security/JwtTokenProvider.class create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/classes/java/main/com/todolist/todolist/security/PasswordConfig.class delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/resources/main/application 2.properties create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/JwtTokenFilter.class.uniqueId3 create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/JwtTokenProvider.class.uniqueId1 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/Member$MemberBuilder.class.uniqueId6 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/Member.class.uniqueId4 create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberController.class.uniqueId0 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberController.class.uniqueId2 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberMapper.class.uniqueId11 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberMapperImpl.class.uniqueId7 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberMapperImpl.java.uniqueId5 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberRepository.class.uniqueId1 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/MemberService.class.uniqueId12 create mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/SecurityConfig.class.uniqueId2 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/Todo$TodoBuilder.class.uniqueId10 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/Todo.class.uniqueId15 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/TodoController.class.uniqueId3 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/TodoMapper.class.uniqueId14 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/TodoMapperImpl.class.uniqueId0 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/TodoMapperImpl.java.uniqueId9 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/TodoRepository.class.uniqueId8 delete mode 100644 contents/todoListAPI/hyeonseung/todolist/build/tmp/compileJava/compileTransaction/stash-dir/TodoService.class.uniqueId13 create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/JwtTokenFilter.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/config/SecurityConfig.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/domain/Role.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/security/CustomUserDetailService.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/security/JwtTokenProvider.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/java/com/todolist/todolist/security/PasswordConfig.java create mode 100644 contents/todoListAPI/hyeonseung/todolist/src/main/resources/application.properties diff --git a/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/checksums/checksums.lock b/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/checksums/checksums.lock index 797f52f69dc4a00c96c2f696d0b2901ce02170b5..2893066ff783716e2bfc4da9f9a12f8ba7177064 100644 GIT binary patch literal 17 UcmZP${cpD}Zj1VS1_;mv05mNGNdN!< literal 17 TcmZP${cpD}Zj1VS1}FdkGynt~ diff --git a/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/checksums/md5-checksums.bin b/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..8f25b06ad9d7cb8f3e077ef468d1c2e0ba3cfa7f GIT binary patch literal 19197 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 delta 43 ycmaF5m~H87#tG6Jjh~56bdZ=VDIv|sI5|~9nNf42;S2GN4mW|q>YE)sQdj|5a}MGF diff --git a/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/executionHistory/executionHistory.lock b/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/executionHistory/executionHistory.lock index a07e081cd866b22136ba179ca5696b1560c2d024..d9542fc1cbe5a623728be889698ef07d73d1c624 100644 GIT binary patch literal 17 UcmZQJ4LAM%_+;~a1_;mw062vN^#A|> literal 17 UcmZQJ4LAM%_+;~a1_)pV061L)%>V!Z diff --git a/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/fileHashes/fileHashes.bin b/contents/todoListAPI/hyeonseung/todolist/.gradle/8.4/fileHashes/fileHashes.bin index 8615f2db25d8785ef9ccf41d502717e488ef0853..aca9eae68059f73e7ea1247983b22a8e3eed7631 100644 GIT binary patch literal 22247 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 O`2SmDkz4J*8h-=$@J~4a delta 52 zcmaF9ma%gZ;|3E6MwZF75)zX`B_$^Bm6Dj8D?Z3PnC;$bZ02F`%Pyh-*0Vn_kpa2wr0#E=7KmjNK1^zDu%x6zTh&UNZ zRqnaP(vuX*`o*&gs{ajxr)PM_G>P4Ym(cGA{wXG{mOMe_B+o`XAVN(=e`j(Q$=4ws zJj18{i9Xa$a7H5HAcLKR=1J<^gJIhe3U$Vf$T$XMZ6$;;7g z;}I`bYH?mNB}#I`X2dH7i%KUvZR82xP#E#bbgQeKnZt1;H%7cVKBRu_&GSbH&ag+k zA(|Sx?oNv(!Rf~lZ)1zA8M`HM2yT#scsE^G>uGLd>LK2zS@_#e4_CMo+=zC;$bZ02F`%Pyh-*0Vwca zE}$`caC3kD6`OmA8jbEO8ggfUbdu3zrCRGt&O(`g8s$o!%m30AUvfA>>tGeP<0ahi zDWWJ%%L+G`)^V%RqAp*?4O5@^+Izz1$1ZSQ?|S#VaRDP-=i*+=iZgY_{?lb+_pXoQ zGfD@WW;!zDV>2e6_;Lz&nu01@{c}_WtSWu*(5a={EOqziFvClRV`@ImdGqn5$Msxjq<)oSEm=$ zvy=DvYp%KRF7V0eca`^U8kY>yD50Cbto|+-pJB%@Qfk&^kuGCXz{_5&p@guR7v?=Nh>k-_zcttjIG(5*7I4Gx6F8FE! zZj6Z7zdk`5(>E1*lU^buXn-45oU;P0*-K0EDRQ6e&g|4*z$oW(Eqa#Q>iyU}TE*o0 zUEC;Nvb8P6u+}Et+?yF7y*LmzhO+ukUXin1vYCC-OHEE;3O7#qzN$K~(#9oU;Ly)i zZ@m`yM(vxt8+z1txbUz`O1p^Jj08R->_kxMyCmlEJF0N@~C?29Q8lSi&apy2`!>y)$$j2&PeymPl)A!vnF1YdD>dvvwQ&&>6 zvkE_y?JaD^jYMmWCZDq=eEG6JMDKs6y%9Ik(mm}OZ+ESa6U(-5i)k{(4aaSq`)|4j z)wS(2Jk4@ltQ~dJ*n^9iL%#YgGHA zf1Kq9%?z=ARo*Pz;A^8xJH1tRqS-akhM%XI;s%>{gH{V;>z01it_P literal 17 VcmZRUHT?MCbmUAX1~6c$0{}5<1Y`gJ diff --git a/contents/todoListAPI/hyeonseung/todolist/.gradle/buildOutputCleanup/cache.properties b/contents/todoListAPI/hyeonseung/todolist/.gradle/buildOutputCleanup/cache.properties index 1bef4dd..a90361e 100644 --- a/contents/todoListAPI/hyeonseung/todolist/.gradle/buildOutputCleanup/cache.properties +++ b/contents/todoListAPI/hyeonseung/todolist/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Mon May 20 18:55:02 KST 2024 +#Mon May 27 04:36:59 KST 2024 gradle.version=8.4 diff --git a/contents/todoListAPI/hyeonseung/todolist/.gradle/buildOutputCleanup/outputFiles.bin b/contents/todoListAPI/hyeonseung/todolist/.gradle/buildOutputCleanup/outputFiles.bin index 64826c2938d06fe3f33596ff6cff4a4c68d0ac93..c3b70c66ac0480d21efe77ba7cf4fb1393c1aa5b 100644 GIT binary patch literal 18983 zcmeI%Ur3Wt7{~FG8cp}2`7b9iR0Jm)qKJdSF0_A}7m5r8FT4m9&7mSHL&6Bn{?N!U zB{G!gDhp9B26Mv_L?}{Zk$551g*ng=ouWt#?H%WN5-+-uywTr*_ub)po(<0Dc2|Ya zo!z4)_E+rw7CQ()00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##j*CEvdXX@B8Qq1T zz$U^bM5dx{&fgW=Z6YC6Bacm0{Qp7w@cNP`&d^HT!rk8T%X{4r@>O>8P43SeZ+33@ zn$0x-fqPG6<;S_+>F+fEgZpT!w$E>Hv{0Yn?nqLexZXui%U%%6-E}P{^-5-bJI%ZQ z_Fiw8=63y`A6J87p>KNsnK>(w{f3eDXyqr z4_~03$NigSHd@Ke4H&A++{t~_8n<&NPa7qBK`{4-i?-d2araxvu_2A-7rB>jWOU^8_ixgC z5%sW}#SIf469vI|s=Hcb4I_0f=^>@O#w;{Gske#`QIdV6=T zg4(qoCN7e)+$(9-mvpFl$;oRa#SP10vQmv7?UL_!$w6gpVdBPyvGP1wJsnWfE>5&1zEv0i2Y&)7 literal 8 PcmZQzVC +