├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── appspec.yml ├── build.gradle ├── docs └── Project Branch, Commit Convetion.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── scripts └── deploy.sh ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── yapp │ │ └── ios1 │ │ ├── Ios1Application.java │ │ ├── annotation │ │ ├── Auth.java │ │ └── ReAuth.java │ │ ├── aop │ │ ├── AuthAspect.java │ │ └── UserContext.java │ │ ├── config │ │ ├── AsyncConfig.java │ │ ├── CacheKey.java │ │ ├── RedisCacheConfig.java │ │ ├── RestTemplateConfig.java │ │ ├── SecurityConfig.java │ │ ├── SwaggerConfig.java │ │ ├── filter │ │ │ └── CustomServletWrappingFilter.java │ │ └── interceptor │ │ │ ├── InterceptorConfig.java │ │ │ └── LoggingInterceptor.java │ │ ├── controller │ │ ├── AlarmController.java │ │ ├── BucketController.java │ │ ├── EmailController.java │ │ ├── FriendController.java │ │ ├── HealthController.java │ │ ├── OauthController.java │ │ ├── ProfileController.java │ │ ├── S3Controller.java │ │ ├── SearchController.java │ │ ├── TokenController.java │ │ ├── UserController.java │ │ ├── UserInfoController.java │ │ └── dto │ │ │ ├── bucket │ │ │ └── BucketRequestDto.java │ │ │ ├── email │ │ │ ├── EmailCodeDto.java │ │ │ └── EmailDto.java │ │ │ └── user │ │ │ ├── ProfileUpdateDto.java │ │ │ ├── login │ │ │ ├── PasswordDto.java │ │ │ ├── SignInDto.java │ │ │ └── SignUpDto.java │ │ │ └── social │ │ │ ├── SocialLoginDto.java │ │ │ └── SocialType.java │ │ ├── dto │ │ ├── ResponseDto.java │ │ ├── bookmark │ │ │ └── BookmarkListDto.java │ │ ├── bucket │ │ │ ├── BucketDetailDto.java │ │ │ └── BucketHomeDto.java │ │ ├── jwt │ │ │ ├── JwtPayload.java │ │ │ ├── RefreshTokenDto.java │ │ │ └── TokenResponseDto.java │ │ ├── notification │ │ │ ├── FcmMessage.java │ │ │ ├── NotificationDto.java │ │ │ ├── NotificationForOneDto.java │ │ │ ├── NotificationLogDto.java │ │ │ └── NotificationTestDto.java │ │ └── user │ │ │ ├── UserInfoDto.java │ │ │ └── UserStatusDto.java │ │ ├── enums │ │ ├── AlarmStatus.java │ │ ├── BucketLogStatus.java │ │ ├── BucketStatus.java │ │ └── FriendStatus.java │ │ ├── error │ │ ├── ErrorResponse.java │ │ ├── GlobalExceptionHandler.java │ │ └── exception │ │ │ ├── BusinessException.java │ │ │ ├── EntityNotFoundException.java │ │ │ ├── ErrorCode.java │ │ │ ├── InvalidValueException.java │ │ │ ├── alarm │ │ │ └── AlarmNotFoundException.java │ │ │ ├── aws │ │ │ └── S3Exception.java │ │ │ ├── bucket │ │ │ ├── BucketNotFoundException.java │ │ │ └── bucketStateIdInvalidException.java │ │ │ ├── common │ │ │ └── JsonWriteException.java │ │ │ ├── email │ │ │ ├── EmailCodeException.java │ │ │ └── EmailSendException.java │ │ │ ├── jwt │ │ │ ├── JwtException.java │ │ │ ├── JwtExpiredException.java │ │ │ └── JwtParseException.java │ │ │ └── user │ │ │ ├── DeviceTokenNotFoundException.java │ │ │ ├── EmailDuplicatedException.java │ │ │ ├── EmailNotExistException.java │ │ │ ├── NickNameDuplicatedException.java │ │ │ ├── PasswordNotMatchException.java │ │ │ ├── UserAuthenticationException.java │ │ │ └── UserNotFoundException.java │ │ ├── mapper │ │ ├── AlarmMapper.java │ │ ├── BucketMapper.java │ │ ├── FriendMapper.java │ │ ├── ProfileMapper.java │ │ ├── SearchMapper.java │ │ ├── TokenMapper.java │ │ └── UserMapper.java │ │ ├── message │ │ ├── AlarmMessage.java │ │ ├── ResponseMessage.java │ │ └── ValidMessage.java │ │ ├── model │ │ ├── bookmark │ │ │ └── Bookmark.java │ │ ├── bucket │ │ │ ├── Bucket.java │ │ │ └── BucketTimeline.java │ │ ├── image │ │ │ └── Image.java │ │ ├── notification │ │ │ └── Notification.java │ │ ├── tag │ │ │ └── Tag.java │ │ └── user │ │ │ ├── Friend.java │ │ │ ├── Profile.java │ │ │ └── User.java │ │ ├── properties │ │ ├── EmailProperties.java │ │ ├── FirebaseProperties.java │ │ ├── JwtProperties.java │ │ ├── S3Properties.java │ │ └── SocialLoginProperties.java │ │ ├── service │ │ ├── EmailService.java │ │ ├── FriendService.java │ │ ├── OauthService.java │ │ ├── S3Service.java │ │ ├── SearchService.java │ │ ├── alarm │ │ │ ├── AlarmService.java │ │ │ └── FirebaseService.java │ │ ├── bucket │ │ │ ├── BucketFindService.java │ │ │ └── BucketService.java │ │ ├── jwt │ │ │ ├── JwtIssueService.java │ │ │ └── JwtService.java │ │ └── user │ │ │ ├── ProfileService.java │ │ │ ├── UserFindService.java │ │ │ ├── UserInfoService.java │ │ │ └── UserService.java │ │ ├── utils │ │ ├── AlarmMessageUtil.java │ │ └── RedisUtil.java │ │ └── validator │ │ ├── AlarmValidator.java │ │ ├── BucketValidator.java │ │ └── UserValidator.java └── resources │ ├── logback-spring.xml │ ├── logback.xml │ ├── mapper │ ├── alarmMapper.xml │ ├── bucketMapper.xml │ ├── friendMapper.xml │ ├── profileMapper.xml │ ├── searchMapper.xml │ ├── tokenMapper.xml │ └── userMapper.xml │ └── templates │ └── email.html └── test └── java └── com └── yapp └── ios1 ├── DBConnectionTest.java ├── Ios1ApplicationTests.java ├── dto └── ResponseDtoTest.java └── service ├── EmailServiceTest.java ├── JwtServiceTest.java └── UserServiceTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | application.yml 30 | application-local.yml 31 | application-dev.yml 32 | application-prod.yml 33 | firebase.json -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11-jre-slim 2 | 3 | WORKDIR /root 4 | 5 | COPY ./build/libs/*.jar . 6 | 7 | CMD java -jar -Dspring.profiles.active=${active} *.jar -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bucket buok 2 | 3 |
4 | 5 | ![buok](https://user-images.githubusercontent.com/45676906/122062627-8af21000-ce2a-11eb-86cf-bc67d2e97ebb.png) 6 | 7 | 버킷리스트를 작성하며 나를 기록해 보세요! 8 | 9 | 미래를 ‘완성된 집’ 현재를 ‘설계도’라고 생각해 봅시다. 10 | 11 | buok은 당신이 멋진 집을 완성할 수 있도록 도와드릴 거예요. 12 | 13 | 어떤 집을 짓고 싶은지 찾아보고, 구체적인 설계 계획을 할 수 있도록요! 14 | 15 | 생각날 때마다 미래 계획을 담을 버킷북을 만들어 보세요. 16 | 17 | 완성된 버킷북 중 나를 잘 나타내는 것을 골라 나만의 히스토리로 만들어보세요. 18 | 19 | 저희와 함께하다 보면 당신의 꿈이 이뤄져 있을 거예요. 20 | 21 |
22 | 23 | --- 24 | 25 |
26 | 27 | ## 📚 API Docs 28 | 29 | - [API Description Link](https://github.com/YAPP-18th/iOS1_Backend/wiki) 30 | 31 |
32 | 33 | ## 📐프로젝트 전체 구성도 34 | 35 | ![스크린샷 2021-06-16 오후 2 35 32](https://user-images.githubusercontent.com/45676906/122163400-1bbeff00-ceb0-11eb-8ecc-180cf128aef8.png) 36 | 37 |
38 | 39 | ## 🛠 사용한 기술 스택 40 | 41 | ![TechStack](https://user-images.githubusercontent.com/45676906/122160183-6dfd2180-ceaa-11eb-8865-df08ec11d13f.png) 42 | 43 |
44 | 45 | ## 📂 Database Modeling 46 | 47 | | ER Diagram | 48 | |:---:| 49 | || 50 | 51 |
52 | 53 | ## 프로젝트 주요 관심사 54 | 55 | ### 공통사항 56 | 57 | - 지속적인 성능 개선 58 | - 나쁜 냄새가 나는 코드에 대한 리팩토링 59 | 60 | ### 코드 컨벤션 61 | 62 | - 프로젝트 전반적으로 `일관되게` 코드를 작성하려고 노력 63 | 64 | ### 성능 최적화 65 | - DB 서버와의 통신을 최소화(당연한 이야기지만 N+1 쿼리를 지양하려고 노력) 66 | 67 |
68 | 69 | ## 프로젝트 하면서 겪은 과정들 70 | 71 | **AccessToken, RefreshToken 과정 정리** 72 | > Spring Security 없이 JWT 연동

73 | > [스프링부트 환경에서 JWT 연동하기](https://velog.io/@ayoung0073/springboot-jwt-without-springsecurity) - [아영](https://github.com/ayoung0073)
74 | > Redis Cache 적용하기 - [아영](https://github.com/ayoung0073) 75 | 76 |
77 | 78 | **Session을 사용하지 않고 JWT를 사용한 이유는 무엇일까?** 79 | 80 | > 정균(작성) 81 | 82 |
83 | 84 | **JPA가 아니라 MyBatis를 사용한 이유** 85 | 86 | > [프로젝트에서 JPA가 아닌 MyBatis를 선택한 이유는?](https://devlog-wjdrbs96.tistory.com/350) - [정균](https://github.com/wjdrbs96) 87 | 88 |
89 | 90 | **FireBase Alarm Async 보내기** 91 | 92 | > 정균(작성) 93 | 94 |
95 | 96 | **Spring Logback으로 Slack, CloudWatch로 에러 로그 전송하기** 97 | 98 | > [Spring Error log CloudWatch로 전송하기](https://devlog-wjdrbs96.tistory.com/329) - [정균](https://github.com/wjdrbs96)
99 | > [Spring Error log Slack으로 전송하는 법](https://devlog-wjdrbs96.tistory.com/327) - [정균](https://github.com/wjdrbs96)
100 | > [Spring Filter, Interceptor로 Request logging 하기]() - [정균](https://github.com/wjdrbs96) 101 | 102 |
103 | 104 | **수 많은 에러들을 어떻게 관리하고 있을까?** 105 | 106 | > [Error 클래스 상속 관계를 통한 ControllerAdvice, ExceptionHandler 처리하기](https://devlog-wjdrbs96.tistory.com/348) - [정균](https://github.com/wjdrbs96) 107 | 108 |
109 | 110 | **이메일 인증까지의 과정** 111 | 112 | > 비밀번호 재설정을 위한 이메일 전송부터 인증까지의 과정

113 | > [Thymeleaf을 이용한 이메일 전송하기](https://velog.io/@ayoung0073/SpringBoot-%ED%83%80%EC%9E%84%EB%A6%AC%ED%94%84%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%A0%84%EC%86%A1) - [아영](https://github.com/ayoung0073)
114 | > [Redis 이용한 이메일 인증하기](https://velog.io/@ayoung0073/SpringBoot-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%9D%B8%EC%A6%9D-%EA%B3%BC%EC%A0%95-Redis) - [아영](https://github.com/ayoung0073) 115 | 116 |
117 | 118 | **비밀번호 암호화** 119 | 120 | > [단방향 해시 함수와 BCrypt로 비밀번호 암호화하기](https://velog.io/@ayoung0073/Security-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EC%95%94%ED%98%B8%ED%99%94) - [아영](https://github.com/ayoung0073)
121 | 122 |
123 | 124 | **AOP로 중복로직 제거하기** 125 | 126 | > 프로젝트에서 대부분 API에서 인가 체크가 필요했는데, AOP를 적용하여 중복 로직을 제거

127 | > [AOP를 사용하여 중복 로직 제거하기](https://devlog-wjdrbs96.tistory.com/344) - [정균](https://github.com/wjdrbs96)
128 | > [ThreadLocal로 사용자 정보 저장하기](https://velog.io/@ayoung0073/Java-ThreadLocal) - [아영](https://github.com/ayoung0073) 129 |
130 | 131 | **yml 파일 prod, dev, local 환경 분리하기** 132 | 133 | > [application.yml을 prod, dev, local로 분리시키기](https://devlog-wjdrbs96.tistory.com/343) - [정균](https://github.com/wjdrbs96)
134 | 135 |
136 | 137 | **이미지 리사이징** 138 | 139 | > 버킷리스트 앱의 특성상 이미지 업로드 양이 많기 때문에 AWS Lambda를 이용하여 이미지 리사이징 기능을 추가
140 | > [Lambda로 Image Resize 하기](https://devlog-wjdrbs96.tistory.com/330?category=885022) - [정균](https://github.com/wjdrbs96) 141 | 142 |
143 | 144 | **Jenkins와 CodeDeploy, Docker를 이용하여 CI/CD 구현하기** 145 | 146 | > 무중단 자동화 배포 기능을 추가

147 | > [Jenkins CI 설정](https://velog.io/@ayoung0073/jenkins-ci) - [아영](https://github.com/ayoung0073)
148 | > [CodeDeploy, Load-Balancer 설정](https://devlog-wjdrbs96.tistory.com/345) - [정균](https://github.com/wjdrbs96) 149 | 150 |
151 | 152 | ## 브랜치 관리 전략 & 커밋 컨벤션 153 | 154 | - [iOS 1팀 BackEnd Branch && Commit Convention](https://github.com/YAPP-18th/iOS1_Backend/blob/develop/docs/Project%20Branch%2C%20Commit%20Convetion.md) 155 | 156 |
157 | 158 | ## Contributors ✨ 159 | 160 | 161 | 162 | 163 | 164 | 165 |

Gyunny

💻

Ayoung

💻
166 | 167 | [기여자 목록](https://github.com/YAPP-18th/iOS1_Backend/graphs/contributors) 을 확인하여 이 프로젝트에 대해 자세히 확인할 수 있습니다. 168 | 169 |
170 | 171 | ## 🔗 Repository Link 172 | 173 | - [iOS](https://github.com/YAPP-18th/iOS1_Client) 174 | -------------------------------------------------------------------------------- /appspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.0 2 | os: linux 3 | files: 4 | - source: / 5 | destination: /home/ec2-user/yapp 6 | overwrite: yes 7 | 8 | permissions: 9 | - object: / 10 | pattern: "**" 11 | owner: root 12 | group: root 13 | 14 | hooks: 15 | ApplicationStart: 16 | - location: scripts/deploy.sh 17 | timeout: 60 18 | runas: root -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.4.3' 3 | id 'io.spring.dependency-management' version '1.0.11.RELEASE' 4 | id 'java' 5 | } 6 | 7 | group = 'com.yapp' 8 | version = '0.0.1-SNAPSHOT' 9 | sourceCompatibility = '11' 10 | 11 | configurations { 12 | compileOnly { 13 | extendsFrom annotationProcessor 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | } 20 | 21 | dependencies { 22 | implementation 'org.springframework.boot:spring-boot-starter-web' 23 | compileOnly 'org.projectlombok:lombok' 24 | annotationProcessor 'org.projectlombok:lombok' 25 | 26 | // DataBase 27 | runtimeOnly 'mysql:mysql-connector-java' 28 | implementation 'org.springframework.boot:spring-boot-starter-data-redis' 29 | implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4' 30 | 31 | // JWT 32 | implementation 'javax.xml.bind:jaxb-api' 33 | implementation 'io.jsonwebtoken:jjwt-api:0.11.2' 34 | implementation 'com.nimbusds:nimbus-jose-jwt:3.10' 35 | runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.2") 36 | runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.2") 37 | 38 | implementation 'com.google.firebase:firebase-admin:6.8.1' 39 | 40 | implementation 'org.springframework.boot:spring-boot-starter-aop' 41 | 42 | implementation 'com.googlecode.json-simple:json-simple:1.1' 43 | implementation 'com.google.code.gson:gson:2.8.6' 44 | 45 | // AWS 46 | compile 'org.springframework.cloud:spring-cloud-starter-aws:2.0.1.RELEASE' 47 | 48 | // logback 49 | compile group: 'ca.pjer', name: 'logback-awslogs-appender', version: '1.4.0' 50 | implementation 'com.github.maricn:logback-slack-appender:1.4.0' 51 | 52 | implementation group: 'org.codehaus.janino', name: 'janino', version: '3.0.7' 53 | 54 | compile "javax.xml.bind:jaxb-api" 55 | 56 | implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security' 57 | 58 | // Swagger 59 | implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2' 60 | implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2' 61 | 62 | // validation 63 | implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.4.5' 64 | 65 | // Test 66 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 67 | 68 | // Email 69 | implementation group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2' 70 | implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' 71 | 72 | 73 | // ConfigurationProperties 74 | annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" 75 | } 76 | 77 | test { 78 | useJUnitPlatform() 79 | } 80 | -------------------------------------------------------------------------------- /docs/Project Branch, Commit Convetion.md: -------------------------------------------------------------------------------- 1 | # `우리팀의 Branch, Commit Convention을 어떻게 진행하고 있을까?` 2 | 3 | YAPP 18기에서 진행하는 `백엔드 iOS 1팀`은 협업 툴로 `JIRA`를 사용하고 있습니다. JIRA는 처음 사용해봤는데 되게 편리했습니다. 4 | 저희팀은 어떻게 사용을 했는가 하면, 현재 각자 수행하고 있는 이슈들을 등록해서 그 이슈를 기반으로 브랜치를 만들고, 커밋 컨벤션을 정의해서 작업을 진행하였습니다. 5 | 6 | ![스크린샷 2021-06-29 오전 10 18 50](https://user-images.githubusercontent.com/45676906/123722610-a4cc3200-d8c3-11eb-8328-c7600edb0bcc.png) 7 | 8 | 위에서 보이시는 것처럼 백엔드 파트 뿐만 아니라 iOS 파트와 같이 사용하고 있기 때문에 다른 파트들도 어떻게 진행되고 있는지를 쉽게 파악할 수 있었습니다. 9 | 또한 누가 어떤 이슈를 남겼는지도 쉽게 알 수 있기 때문에 편리하고 생상성 높게 협업을 진행할 수 있었습니다. 10 | 11 | 그리고 위에 이슈를 만들 때마다 `YITEAM-이슈번호`로 생성이 되는데요. 저희 iOS 1팀 백엔드는 `JIRA 이슈` 번호를 기반으로 branch를 작성하였습니다. 기존에 프로젝트를 했을 때는 `feature/~~`, `bug/~~` 등등 다양하게 브랜치 역할에 맡게 브랜치를 만들었지만 이번에는 JIRA 이슈 기반으로 브챈치 컨벤션을 정해서 해보았습니다. 12 | 13 |
14 | 15 | ![스크린샷 2021-06-29 오전 10 27 08](https://user-images.githubusercontent.com/45676906/123723063-929ec380-d8c4-11eb-837d-02fc7dad4961.png) 16 | 17 | 실제로도 커밋을 할 때 위와 같이 `커밋 컨벤션`을 유지하면서 프로젝트를 진행하였기에, 커밋과 JIRA 이슈를 보면서 현재 어떤 이슈를 진행 중인지 좀 더 명확하게 알 수 있었습니다. 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YAPP-18th/iOS1_Backend/30c3be758e76f43eb86e4ad19a1c2aacfe2ae784/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CONTAINER_ID=$(docker container ls -f "name=yapp" -q) 4 | 5 | echo "> 컨테이너 ID는 무엇?? ${CONTAINER_ID}" 6 | 7 | if [ -z ${CONTAINER_ID} ] 8 | then 9 | echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ec2-user/yapp/deploy.log 10 | else 11 | echo "> docker stop ${CONTAINER_ID}" 12 | sudo docker stop ${CONTAINER_ID} 13 | echo "> docker rm ${CONTAINER_ID}" 14 | sudo docker rm ${CONTAINER_ID} 15 | #sudo docker rmi yapp 16 | sleep 5 17 | fi 18 | # && docker build -t yapp . 19 | cd /home/ec2-user/yapp 20 | docker run --name yapp -d -e active=prod -p 8080:8080 -v $(pwd)/build/libs:/root yapp -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ios1' 2 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/Ios1Application.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | import org.springframework.scheduling.annotation.EnableAsync; 7 | import org.springframework.scheduling.annotation.EnableScheduling; 8 | 9 | @EnableScheduling 10 | @EnableAsync 11 | @EnableCaching 12 | @SpringBootApplication 13 | public class Ios1Application { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(Ios1Application.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/annotation/Auth.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * created by jg 2021/04/11 10 | */ 11 | @Target({ElementType.METHOD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface Auth { 14 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/annotation/ReAuth.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * created by jg 2021/06/04 10 | */ 11 | @Target({ElementType.METHOD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface ReAuth { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/aop/AuthAspect.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.aop; 2 | 3 | import com.yapp.ios1.dto.jwt.JwtPayload; 4 | import com.yapp.ios1.model.user.User; 5 | import com.yapp.ios1.error.exception.jwt.JwtException; 6 | import com.yapp.ios1.error.exception.jwt.JwtExpiredException; 7 | import com.yapp.ios1.service.jwt.JwtIssueService; 8 | import com.yapp.ios1.service.jwt.JwtService; 9 | import com.yapp.ios1.service.user.UserFindService; 10 | import io.jsonwebtoken.ExpiredJwtException; 11 | import io.jsonwebtoken.MalformedJwtException; 12 | import io.jsonwebtoken.UnsupportedJwtException; 13 | import io.jsonwebtoken.security.SignatureException; 14 | import lombok.RequiredArgsConstructor; 15 | import org.aspectj.lang.ProceedingJoinPoint; 16 | import org.aspectj.lang.annotation.Around; 17 | import org.aspectj.lang.annotation.Aspect; 18 | import org.springframework.stereotype.Component; 19 | 20 | import javax.servlet.http.HttpServletRequest; 21 | 22 | /** 23 | * created by jg 2021/04/11 24 | */ 25 | @RequiredArgsConstructor 26 | @Aspect 27 | @Component 28 | public class AuthAspect { 29 | 30 | private static final String AUTHORIZATION = "accessToken"; 31 | private static final String REAUTHORIZATION = "refreshToken"; 32 | 33 | private final JwtService jwtService; 34 | private final JwtIssueService jwtIssueService; 35 | private final UserFindService userFindService; 36 | private final HttpServletRequest httpServletRequest; 37 | 38 | @Around("@annotation(com.yapp.ios1.annotation.Auth)") 39 | public Object accessToken(final ProceedingJoinPoint pjp) throws Throwable { 40 | try { 41 | String accessToken = httpServletRequest.getHeader(AUTHORIZATION); 42 | JwtPayload payload = jwtService.getPayload(accessToken); 43 | User user = userFindService.getUser(payload.getId()); 44 | UserContext.USER_CONTEXT.set(new JwtPayload(user.getId())); 45 | return pjp.proceed(); 46 | } catch (SignatureException | ExpiredJwtException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e) { 47 | throw new JwtException(); 48 | } 49 | } 50 | 51 | @Around("@annotation(com.yapp.ios1.annotation.ReAuth)") 52 | public Object refreshToken(final ProceedingJoinPoint pjp) throws Throwable { 53 | try { 54 | String refreshToken = httpServletRequest.getHeader(REAUTHORIZATION); 55 | JwtPayload payload = jwtService.getPayload(refreshToken); 56 | User user = userFindService.getUser(payload.getId()); 57 | 58 | String dbRefreshToken = jwtIssueService.getRefreshTokenByUserId(user.getId()); 59 | checkRefreshTokenExpired(dbRefreshToken, refreshToken); 60 | UserContext.USER_CONTEXT.set(new JwtPayload(user.getId())); 61 | return pjp.proceed(); 62 | } catch (SignatureException | ExpiredJwtException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e) { 63 | throw new JwtException(); 64 | } 65 | } 66 | 67 | private void checkRefreshTokenExpired(String dbRefreshToken, String refreshToken) { 68 | if (!dbRefreshToken.equals(refreshToken)) { 69 | throw new JwtExpiredException(); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/aop/UserContext.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.aop; 2 | 3 | import com.yapp.ios1.dto.jwt.JwtPayload; 4 | import com.yapp.ios1.error.exception.jwt.JwtException; 5 | 6 | /** 7 | * created by ayoung 2021/05/01 8 | */ 9 | public class UserContext { 10 | 11 | public static final ThreadLocal USER_CONTEXT = new ThreadLocal<>(); 12 | 13 | public static Long getCurrentUserId() { 14 | if (UserContext.USER_CONTEXT.get() != null) { 15 | return UserContext.USER_CONTEXT.get().getId(); 16 | } 17 | 18 | throw new JwtException(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/AsyncConfig.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 6 | 7 | import java.util.concurrent.Executor; 8 | import java.util.concurrent.ThreadPoolExecutor; 9 | 10 | /** 11 | * created by jg 2021/05/21 12 | */ 13 | @Configuration 14 | public class AsyncConfig { 15 | 16 | @Bean("asyncTask") 17 | public Executor threadPoolExecutor() { 18 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 19 | executor.setThreadNamePrefix("asyncTask-"); // thread 이름 설정 20 | executor.setCorePoolSize(5); // 동시에 실행시킬 쓰래드의 개수를 의미 21 | executor.setMaxPoolSize(100); // 쓰레드 풀의 최대 사이즈 22 | executor.setQueueCapacity(0); // 쓰레드 풀 큐의 사이즈. corePoolSize 개수를 넘어서는 task가 들어왔을 때 23 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); 24 | return executor; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/CacheKey.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config; 2 | 3 | /** 4 | * created by ayoung 2021/06/03 5 | */ 6 | public class CacheKey { 7 | 8 | public static final String TOKEN = "token"; 9 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/RedisCacheConfig.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.cache.CacheKeyPrefix; 7 | import org.springframework.data.redis.cache.RedisCacheConfiguration; 8 | import org.springframework.data.redis.cache.RedisCacheManager; 9 | import org.springframework.data.redis.connection.RedisConnectionFactory; 10 | import org.springframework.data.redis.serializer.RedisSerializationContext; 11 | import org.springframework.data.redis.serializer.StringRedisSerializer; 12 | 13 | import java.time.Duration; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * created by ayoung 2021/06/03 19 | */ 20 | @Configuration 21 | public class RedisCacheConfig { 22 | 23 | @Value("${jwt.refreshToken.validTime}") 24 | private Long REFRESH_VALID_TIME; 25 | 26 | @Bean(name = "cacheManager") 27 | public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { 28 | 29 | RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig() 30 | .disableCachingNullValues() 31 | .computePrefixWith(CacheKeyPrefix.simple()) 32 | .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); 33 | 34 | Map cacheConfigurations = new HashMap<>(); 35 | cacheConfigurations.put(CacheKey.TOKEN, RedisCacheConfiguration.defaultCacheConfig() 36 | .entryTtl(Duration.ofMillis(REFRESH_VALID_TIME))); 37 | 38 | return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory).cacheDefaults(configuration) 39 | .withInitialCacheConfigurations(cacheConfigurations).build(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/RestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config; 2 | 3 | import org.springframework.boot.web.client.RestTemplateBuilder; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.http.client.BufferingClientHttpRequestFactory; 7 | import org.springframework.http.client.SimpleClientHttpRequestFactory; 8 | import org.springframework.http.converter.StringHttpMessageConverter; 9 | import org.springframework.web.client.RestTemplate; 10 | 11 | import java.nio.charset.Charset; 12 | import java.nio.charset.StandardCharsets; 13 | import java.time.Duration; 14 | 15 | /** 16 | * created by ayoung 2021/05/06 17 | */ 18 | @Configuration 19 | public class RestTemplateConfig { 20 | 21 | @Bean 22 | public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { 23 | return restTemplateBuilder 24 | .requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory())) 25 | .setConnectTimeout(Duration.ofMillis(5000)) // connection-timeout 26 | .setReadTimeout(Duration.ofMillis(5000)) // read-timeout 27 | .additionalMessageConverters(new StringHttpMessageConverter(StandardCharsets.UTF_8)) 28 | .build(); 29 | } 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | 11 | /** 12 | * created by ayoung 2021/04/15 13 | */ 14 | @EnableWebSecurity 15 | @Configuration 16 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 17 | 18 | @Bean 19 | public PasswordEncoder getPasswordEncoder() { 20 | return new BCryptPasswordEncoder(); 21 | } 22 | 23 | @Override 24 | protected void configure(HttpSecurity http) throws Exception { 25 | http.authorizeRequests() 26 | .antMatchers("/api/v2/**", "/health", "/swagger-ui.html", "/swagger/**", 27 | "/swagger-resources/**", "/webjars/**", "/v2/api-docs").permitAll() 28 | .anyRequest().authenticated() 29 | .and() 30 | .csrf().disable() 31 | .formLogin(); 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config; 2 | 3 | import com.google.common.collect.Lists; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.service.ApiKey; 11 | import springfox.documentation.service.AuthorizationScope; 12 | import springfox.documentation.service.SecurityReference; 13 | import springfox.documentation.spi.DocumentationType; 14 | import springfox.documentation.spi.service.contexts.SecurityContext; 15 | import springfox.documentation.spring.web.plugins.Docket; 16 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * created by ayoung 2021/05/03 22 | */ 23 | @Configuration 24 | @EnableSwagger2 25 | public class SwaggerConfig { 26 | 27 | @Bean 28 | public Docket api() { 29 | return new Docket(DocumentationType.SWAGGER_2) 30 | .apiInfo(apiInfo()) 31 | .select() 32 | .apis(RequestHandlerSelectors.any()) 33 | .paths(PathSelectors.ant("/api/v2/**")) 34 | .build() 35 | .securityContexts(Lists.newArrayList(securityContext())) // JWT 인증 기능 추가 36 | .securitySchemes(Lists.newArrayList(apiKey())); 37 | } 38 | 39 | private ApiInfo apiInfo() { 40 | String applicationName = "Buok API Documents"; 41 | return new ApiInfoBuilder() 42 | .title(applicationName) 43 | .build(); 44 | } 45 | 46 | private ApiKey apiKey() { 47 | return new ApiKey("JWT", "accessToken", "header"); 48 | } 49 | 50 | private SecurityContext securityContext() { 51 | return SecurityContext.builder().securityReferences(defaultAuth()).build(); 52 | } 53 | 54 | List defaultAuth() { 55 | AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); 56 | AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; 57 | authorizationScopes[0] = authorizationScope; 58 | return Lists.newArrayList(new SecurityReference("JWT", authorizationScopes)); 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/filter/CustomServletWrappingFilter.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config.filter; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.web.filter.OncePerRequestFilter; 5 | import org.springframework.web.util.ContentCachingRequestWrapper; 6 | import org.springframework.web.util.ContentCachingResponseWrapper; 7 | 8 | import javax.servlet.FilterChain; 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | /** 15 | * created by jg 2021/06/27 16 | */ 17 | @Component 18 | public class CustomServletWrappingFilter extends OncePerRequestFilter { 19 | 20 | @Override 21 | protected void doFilterInternal(HttpServletRequest request, 22 | HttpServletResponse response, 23 | FilterChain chain) throws ServletException, IOException { 24 | ContentCachingRequestWrapper wrappingRequest = new ContentCachingRequestWrapper(request); 25 | ContentCachingResponseWrapper wrappingResponse = new ContentCachingResponseWrapper(response); 26 | 27 | chain.doFilter(wrappingRequest, wrappingResponse); 28 | 29 | wrappingResponse.copyBodyToResponse(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/interceptor/InterceptorConfig.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config.interceptor; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | /** 9 | * created by jg 2021/06/27 10 | */ 11 | @RequiredArgsConstructor 12 | @Configuration 13 | public class InterceptorConfig implements WebMvcConfigurer { 14 | 15 | private final LoggingInterceptor loggingInterceptor; 16 | 17 | @Override 18 | public void addInterceptors(InterceptorRegistry registry) { 19 | registry.addInterceptor(loggingInterceptor); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/config/interceptor/LoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.config.interceptor; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.servlet.HandlerInterceptor; 8 | import org.springframework.web.util.ContentCachingRequestWrapper; 9 | import org.springframework.web.util.ContentCachingResponseWrapper; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | /** 15 | * created by jg 2021/06/27 16 | */ 17 | @RequiredArgsConstructor 18 | @Slf4j 19 | @Component 20 | public class LoggingInterceptor implements HandlerInterceptor { 21 | 22 | private final ObjectMapper objectMapper; 23 | 24 | @Override 25 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 26 | String[] requestURI = request.getRequestURI().split("/"); 27 | if (requestURI[1].equals("api") && requestURI[2].equals("v2")) { 28 | final String requestMethod = request.getMethod(); 29 | 30 | log.error("=============="); 31 | log.error("Request URL : " + request.getRequestURL() + "\n" + 32 | "Query String : " + request.getQueryString() + " || Request Method : " + requestMethod); 33 | 34 | if (requestMethod.equals("POST")) { 35 | final ContentCachingRequestWrapper cachingRequest = (ContentCachingRequestWrapper) request; 36 | final ContentCachingResponseWrapper cachingResponse = (ContentCachingResponseWrapper) response; 37 | 38 | log.error(String.format("Request Body : %s", objectMapper.readTree(cachingRequest.getContentAsByteArray()))); 39 | log.error(String.format("Response Body : %s", objectMapper.readTree(cachingResponse.getContentAsByteArray()))); 40 | } 41 | log.error("=============="); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/AlarmController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.dto.notification.NotificationForOneDto; 5 | import com.yapp.ios1.dto.notification.NotificationTestDto; 6 | import com.yapp.ios1.service.alarm.AlarmService; 7 | import com.yapp.ios1.annotation.Auth; 8 | import com.yapp.ios1.aop.UserContext; 9 | import com.yapp.ios1.service.alarm.FirebaseService; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import lombok.RequiredArgsConstructor; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import static com.yapp.ios1.message.ResponseMessage.DELETE_ALARM_LOG; 18 | import static com.yapp.ios1.message.ResponseMessage.GET_ALARM_LOG; 19 | 20 | /** 21 | * created by jg 2021/05/24 22 | */ 23 | @Api(tags = "Alarm") 24 | @RequiredArgsConstructor 25 | @RestController 26 | @RequestMapping("/api/v2/alarm") 27 | public class AlarmController { 28 | 29 | private final AlarmService alarmService; 30 | private final FirebaseService firebaseService; 31 | 32 | @ApiOperation("알람 로그 조회") 33 | @Auth 34 | @GetMapping("") 35 | public ResponseEntity alarmLog() { 36 | Long userId = UserContext.getCurrentUserId(); 37 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_ALARM_LOG, alarmService.getAlarmLog(userId))); 38 | } 39 | 40 | @ApiOperation("알람 로그 삭제 (alarmStatus: 1(전체 알람), 2(친구 알람))") 41 | @Auth 42 | @DeleteMapping("/{alarmId}") 43 | public ResponseEntity deleteAlarm(@PathVariable Long alarmId, @RequestParam("alarm_status") int alarmStatus) { 44 | Long userId = UserContext.getCurrentUserId(); 45 | alarmService.deleteAlarm(alarmId, userId, alarmStatus); 46 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, DELETE_ALARM_LOG)); 47 | } 48 | 49 | // @ApiOperation("푸시 알림 테스트") 50 | // @PostMapping("/test") 51 | // public ResponseEntity alarmTest(@RequestBody NotificationTestDto requestDto) { 52 | // NotificationForOneDto notificationForOne = NotificationForOneDto.builder() 53 | // .title(requestDto.getTitle()) 54 | // .message(requestDto.getMessage()) 55 | // .deviceToken(requestDto.getDeviceToken()) 56 | // .build(); 57 | // firebaseService.sendByTokenForOne(notificationForOne); 58 | // return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, "푸시 알림 보냄")); 59 | // } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/BucketController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.controller.dto.bucket.BucketRequestDto; 5 | import com.yapp.ios1.service.bucket.BucketFindService; 6 | import com.yapp.ios1.service.bucket.BucketService; 7 | import com.yapp.ios1.annotation.Auth; 8 | import com.yapp.ios1.aop.UserContext; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import lombok.RequiredArgsConstructor; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | import javax.validation.Valid; 17 | 18 | import static com.yapp.ios1.message.ResponseMessage.*; 19 | 20 | /** 21 | * created by jg 2021/05/05 22 | */ 23 | @Api(tags = "Bucket") 24 | @RequiredArgsConstructor 25 | @RestController 26 | @RequestMapping("/api/v2/buckets") 27 | public class BucketController { 28 | 29 | private final BucketService bucketService; 30 | private final BucketFindService bucketFindService; 31 | 32 | /** 33 | * @INFO state 1(전체), 2(예정), 3(진행 중), 4(완료), 5(실패) 34 | * @INFO category 1(전체), 2(여행), 3(취미), 4(소유), 5(재정), 6(건강) 35 | 7(목표), 8(조직), 9(봉사), 10(기타) 36 | * @INFO sortI= 1(작성 순), sortId = 2(가나다 순) 37 | */ 38 | @ApiOperation("홈 화면 버킷 조회") 39 | @Auth 40 | @GetMapping("") 41 | public ResponseEntity homeBucket(@RequestParam("state") int bucketState, 42 | @RequestParam("category") int category, 43 | @RequestParam("sort") int sort) { 44 | Long userId = UserContext.getCurrentUserId(); 45 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_BUCKET_LIST, 46 | bucketFindService.getHomeBucketList(bucketState, category, userId, sort))); 47 | } 48 | 49 | @ApiOperation("버킷 상세 조회") 50 | @GetMapping("/{bucketId}") 51 | public ResponseEntity myBucket(@PathVariable Long bucketId) { 52 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_BUCKET_DETAIL, bucketFindService.getBucketDetail(bucketId))); 53 | } 54 | 55 | // bucketStateId 2(예정), 3(진행 중), 4(완료), 5(실패) 56 | @ApiOperation("버킷 상태 변경") 57 | @Auth 58 | @PutMapping("/{bucketId}/state/{bucketStateId}") 59 | public ResponseEntity updateBucketState(@PathVariable Long bucketId, 60 | @PathVariable int bucketStateId) { 61 | Long userId = UserContext.getCurrentUserId(); 62 | bucketService.updateBucketState(userId, bucketId, bucketStateId); 63 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, UPDATE_BUCKET_STATE)); 64 | } 65 | 66 | @ApiOperation("버킷 핀 설정 or 해제") 67 | @Auth 68 | @PutMapping("/{bucketId}/fin") 69 | public ResponseEntity registerBucketFin(@PathVariable Long bucketId, @RequestParam("state") boolean isFin) { 70 | Long userId = UserContext.getCurrentUserId(); 71 | bucketService.setBucketFin(bucketId, userId, isFin); 72 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, REGISTER_BUCKET_FIN_SUCCESS)); 73 | } 74 | 75 | @ApiOperation("버킷 등록") 76 | @Auth 77 | @PostMapping("") 78 | public ResponseEntity registerBucket(@RequestBody @Valid BucketRequestDto bucket) { 79 | bucket.setUserId(UserContext.getCurrentUserId()); 80 | bucketService.saveBucket(bucket); 81 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.CREATED, REGISTER_BUCKET_SUCCESS)); 82 | } 83 | 84 | @ApiOperation("버킷 수정") 85 | @Auth 86 | @PutMapping("/{bucketId}") 87 | public ResponseEntity updateBucket(@PathVariable Long bucketId, @RequestBody @Valid BucketRequestDto requestDto) { 88 | bucketService.updateBucket(bucketId, requestDto, UserContext.getCurrentUserId()); 89 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, UPDATE_BUCKET_SUCCESS)); 90 | } 91 | 92 | @ApiOperation("북마크 설정 or 해제") 93 | @Auth 94 | @PutMapping("/{bucketId}/bookmark") 95 | public ResponseEntity setBookmark(@PathVariable("bucketId") Long bucketId, @RequestParam("state") boolean isBookmark) { 96 | Long userId = UserContext.getCurrentUserId(); 97 | bucketService.saveBookmark(bucketId, userId, isBookmark); 98 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, UPDATE_BUCKET_SUCCESS)); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/EmailController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.controller.dto.email.EmailCodeDto; 4 | import com.yapp.ios1.controller.dto.email.EmailDto; 5 | import com.yapp.ios1.dto.ResponseDto; 6 | import com.yapp.ios1.dto.jwt.JwtPayload; 7 | import com.yapp.ios1.service.EmailService; 8 | import com.yapp.ios1.service.jwt.JwtIssueService; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import lombok.RequiredArgsConstructor; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.RequestBody; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | import javax.validation.Valid; 20 | 21 | import static com.yapp.ios1.message.ResponseMessage.EMAIL_AUTH_SUCCESS; 22 | import static com.yapp.ios1.message.ResponseMessage.EMAIL_SEND_SUCCESS; 23 | 24 | /** 25 | * created by ayoung 2021/05/30 26 | */ 27 | @Api(tags = "Email") 28 | @RequiredArgsConstructor 29 | @RestController 30 | @RequestMapping("/api/v2/email") 31 | public class EmailController { 32 | 33 | private final EmailService emailService; 34 | private final JwtIssueService jwtIssueService; 35 | 36 | @ApiOperation("이메일 인증 코드 전송") 37 | @PostMapping("/send") 38 | public ResponseEntity sendEmail(@RequestBody @Valid EmailDto email) { 39 | emailService.sendEmailMessage(email.getEmail()); 40 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, EMAIL_SEND_SUCCESS)); 41 | } 42 | 43 | @ApiOperation("인증 코드 검증") 44 | @PostMapping("/verify") 45 | public ResponseEntity verifyCode(@RequestBody @Valid EmailCodeDto code) { 46 | Long userId = emailService.getUserIdByCode(code.getCode()); 47 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, EMAIL_AUTH_SUCCESS, jwtIssueService.createAccessToken(new JwtPayload(userId)))); 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/FriendController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.annotation.Auth; 4 | import com.yapp.ios1.aop.UserContext; 5 | import com.yapp.ios1.dto.ResponseDto; 6 | import com.yapp.ios1.model.user.Friend; 7 | import com.yapp.ios1.service.FriendService; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.*; 14 | import springfox.documentation.annotations.ApiIgnore; 15 | 16 | import java.util.List; 17 | 18 | import static com.yapp.ios1.message.ResponseMessage.*; 19 | 20 | /** 21 | * created by jg 2021/05/21 22 | */ 23 | @Api(tags = "Friend") 24 | @RequiredArgsConstructor 25 | @RestController 26 | @RequestMapping("/api/v2") 27 | public class FriendController { 28 | 29 | private final FriendService friendService; 30 | 31 | @ApiOperation("친구 요청") 32 | @Auth 33 | @PostMapping("/friend/{friendId}/request") 34 | public ResponseEntity followRequest(@PathVariable Long friendId) { 35 | Long myUserId = UserContext.getCurrentUserId(); 36 | friendService.requestFollow(myUserId, friendId); 37 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.CREATED, FRIEND_REQUEST)); 38 | } 39 | 40 | @ApiOperation("친구 요청 수락, 거절") 41 | @Auth 42 | @PostMapping("/friend/{friendId}/{alarmId}") 43 | public ResponseEntity followAccept(@PathVariable Long friendId, 44 | @PathVariable Long alarmId, 45 | @RequestParam("accept") boolean isAccept) { 46 | Long myUserId = UserContext.getCurrentUserId(); 47 | friendService.checkFollowAccept(isAccept, myUserId, friendId, alarmId); 48 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.CREATED, FRIEND_MESSAGE, isAccept)); 49 | } 50 | 51 | @ApiOperation("친구 리스트") 52 | @GetMapping("/users/{userId}/friends") 53 | public ResponseEntity getFriendList(@PathVariable Long userId) { 54 | List friendList = friendService.getFriendList(userId); 55 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_FRIEND_LIST, friendList)); 56 | } 57 | 58 | @Auth 59 | @ApiOperation("친구 끊기") 60 | @DeleteMapping("/friend/{friendId}") 61 | public ResponseEntity deleteFriend(@PathVariable Long friendId) { 62 | Long myUserId = UserContext.getCurrentUserId(); 63 | friendService.deleteFriend(myUserId, friendId); 64 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, FRIEND_DELETE)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/HealthController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import springfox.documentation.annotations.ApiIgnore; 6 | 7 | /** 8 | * created by jg 2021/06/02 9 | */ 10 | @RestController 11 | public class HealthController { 12 | 13 | // 로드 밸런서 용 14 | @ApiIgnore 15 | @GetMapping("/health") 16 | public String loadBalancer() { 17 | return "health"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/OauthController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.dto.user.UserStatusDto; 5 | import com.yapp.ios1.controller.dto.user.social.SocialLoginDto; 6 | import com.yapp.ios1.controller.dto.user.social.SocialType; 7 | import com.yapp.ios1.service.OauthService; 8 | import io.swagger.annotations.Api; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.validation.Valid; 15 | 16 | import static com.yapp.ios1.message.ResponseMessage.LOGIN_SUCCESS; 17 | 18 | /** 19 | * created by ayoung 2021/05/04 20 | */ 21 | @RequiredArgsConstructor 22 | @Slf4j 23 | @RestController 24 | @RequestMapping("/api/v2/social") 25 | @Api(tags = "Social Login") 26 | public class OauthController { 27 | 28 | private final OauthService oauthService; 29 | 30 | @PostMapping("/{social_type}") 31 | public ResponseEntity socialLogin(@PathVariable("social_type") SocialType socialType, 32 | @RequestBody @Valid SocialLoginDto socialDto) { 33 | UserStatusDto statusDto = oauthService.getSocialUser(socialType.name(), socialDto); 34 | return ResponseEntity.ok(ResponseDto.of(statusDto.getStatus(), LOGIN_SUCCESS, statusDto.getTokenDto())); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/ProfileController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.annotation.Auth; 4 | import com.yapp.ios1.aop.UserContext; 5 | import com.yapp.ios1.controller.dto.user.ProfileUpdateDto; 6 | import com.yapp.ios1.dto.ResponseDto; 7 | import com.yapp.ios1.service.user.ProfileService; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import static com.yapp.ios1.message.ResponseMessage.GET_PROFILE_SUCCESS; 16 | import static com.yapp.ios1.message.ResponseMessage.UPDATE_PROFILE_SUCCESS; 17 | 18 | /** 19 | * created by jg 2021/06/11 20 | */ 21 | @Api(tags = "Profile") 22 | @RequiredArgsConstructor 23 | @RestController 24 | @RequestMapping("/api/v2/profile") // TODO 뭐가 좋을지 생각 25 | public class ProfileController { 26 | 27 | private final ProfileService profileService; 28 | 29 | @ApiOperation("프로필 가져오기") 30 | @Auth 31 | @GetMapping("") 32 | public ResponseEntity getProfile() { 33 | Long userId = UserContext.getCurrentUserId(); 34 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_PROFILE_SUCCESS, profileService.getProfile(userId))); 35 | } 36 | 37 | @ApiOperation("프로필 수정") 38 | @Auth 39 | @PutMapping("") 40 | public ResponseEntity updateProfile(@RequestBody ProfileUpdateDto profile) { 41 | Long userId = UserContext.getCurrentUserId(); 42 | profileService.updateProfile(profile, userId); 43 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, UPDATE_PROFILE_SUCCESS)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/S3Controller.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.service.S3Service; 5 | import com.yapp.ios1.annotation.Auth; 6 | import com.yapp.ios1.aop.UserContext; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import lombok.RequiredArgsConstructor; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.multipart.MultipartFile; 14 | 15 | import static com.yapp.ios1.message.ResponseMessage.NOT_EXIST_IMAGE; 16 | import static com.yapp.ios1.message.ResponseMessage.UPLOAD_IMAGE_SUCCESS; 17 | 18 | /** 19 | * created by ayoung 2021/03/29 20 | */ 21 | @Api(tags = "Image Upload") 22 | @RequiredArgsConstructor 23 | @RestController 24 | @RequestMapping("/api/v2") 25 | public class S3Controller { 26 | 27 | private final S3Service s3Service; 28 | 29 | @ApiOperation("이미지 url 배열 리턴") 30 | @Auth 31 | @PostMapping("/images") 32 | public ResponseEntity registerBucketImageList(@RequestParam(value = "image") MultipartFile[] imageList) { 33 | if (imageList == null) { 34 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.BAD_REQUEST, NOT_EXIST_IMAGE)); 35 | } 36 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, UPLOAD_IMAGE_SUCCESS, s3Service.upload(imageList, UserContext.getCurrentUserId()))); 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.service.SearchService; 5 | import com.yapp.ios1.annotation.Auth; 6 | import com.yapp.ios1.aop.UserContext; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import lombok.RequiredArgsConstructor; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import static com.yapp.ios1.message.ResponseMessage.NOT_FOUND_SEARCH_TYPE; 18 | import static com.yapp.ios1.message.ResponseMessage.SUCCESS_SEARCH; 19 | 20 | /** 21 | * created by jg 2021/05/17 22 | */ 23 | @Api(tags = "Search") 24 | @RequiredArgsConstructor 25 | @RestController 26 | @RequestMapping("/api/v2") 27 | public class SearchController { 28 | 29 | private final SearchService searchService; 30 | 31 | @ApiOperation("검색, type = my(마이북), user(유저), mark(북마크) 검색, keyword = 검색키워드") 32 | @Auth 33 | @GetMapping("/search") 34 | public ResponseEntity search(@RequestParam("type") String type, 35 | @RequestParam("keyword") String keyword) { 36 | ResponseDto responseDto = ResponseDto.of(HttpStatus.OK, SUCCESS_SEARCH); 37 | Long userId = UserContext.getCurrentUserId(); 38 | 39 | switch (type) { 40 | case "my": 41 | responseDto.setData(searchService.searchMyBook(keyword, userId)); 42 | break; 43 | case "user": 44 | responseDto.setData(searchService.searchUser(keyword, userId)); 45 | break; 46 | case "mark": 47 | responseDto.setData(searchService.searchBookMark(keyword, userId)); 48 | break; 49 | default: 50 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.BAD_REQUEST, NOT_FOUND_SEARCH_TYPE)); 51 | } 52 | 53 | return ResponseEntity.ok(responseDto); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/TokenController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.dto.jwt.JwtPayload; 5 | import com.yapp.ios1.service.jwt.JwtService; 6 | import com.yapp.ios1.service.jwt.JwtIssueService; 7 | import com.yapp.ios1.annotation.ReAuth; 8 | import com.yapp.ios1.aop.UserContext; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import lombok.RequiredArgsConstructor; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | import static com.yapp.ios1.message.ResponseMessage.REISSUE_TOKEN_SUCCESS; 17 | 18 | /** 19 | * created by jg 2021/05/05 20 | */ 21 | @Api(tags = "Token") 22 | @RequiredArgsConstructor 23 | @RestController 24 | @RequestMapping("/api/v2") 25 | public class TokenController { 26 | 27 | private final JwtService jwtService; 28 | private final JwtIssueService jwtIssueService; 29 | 30 | @ApiOperation("서버 토큰 발급 용") 31 | @GetMapping("/token") 32 | public String getToken() { 33 | return jwtIssueService.createAccessToken(new JwtPayload(157L)); 34 | } 35 | 36 | @ApiOperation("토큰 재발급") 37 | @ReAuth 38 | @PostMapping("/token/refresh") 39 | public ResponseEntity reissueToken() { 40 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, REISSUE_TOKEN_SUCCESS, jwtService.createTokenResponse(UserContext.getCurrentUserId()))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.dto.ResponseDto; 4 | import com.yapp.ios1.model.user.User; 5 | import com.yapp.ios1.controller.dto.user.login.PasswordDto; 6 | import com.yapp.ios1.controller.dto.user.login.SignInDto; 7 | import com.yapp.ios1.controller.dto.user.login.SignUpDto; 8 | import com.yapp.ios1.service.jwt.JwtService; 9 | import com.yapp.ios1.service.user.UserService; 10 | import com.yapp.ios1.annotation.Auth; 11 | import com.yapp.ios1.aop.UserContext; 12 | import com.yapp.ios1.validator.UserValidator; 13 | import io.swagger.annotations.Api; 14 | import io.swagger.annotations.ApiOperation; 15 | import lombok.RequiredArgsConstructor; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.web.bind.annotation.*; 20 | 21 | import javax.validation.Valid; 22 | 23 | import static com.yapp.ios1.message.ResponseMessage.*; 24 | 25 | /** 26 | * created by jg 2021/03/28 27 | */ 28 | @Api(tags = "User") 29 | @RequiredArgsConstructor 30 | @Slf4j 31 | @RestController 32 | @RequestMapping("/api/v2/users") 33 | public class UserController { 34 | 35 | private final UserService userService; 36 | private final UserValidator userValidator; 37 | private final JwtService jwtService; 38 | 39 | @ApiOperation("이메일 존재 여부") 40 | @GetMapping("/email-check") 41 | public ResponseEntity emailCheck(@RequestParam String email) { 42 | userValidator.checkEmailDuplicate(email); 43 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, POSSIBLE_EMAIL)); 44 | } 45 | 46 | @ApiOperation("닉네임 존재 여부") 47 | @GetMapping("/nickname-check") 48 | public ResponseEntity nicknameCheck(@RequestParam String nickname) { 49 | userValidator.checkNickName(nickname); 50 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, POSSIBLE_NICKNAME)); 51 | } 52 | 53 | @ApiOperation("회원가입") 54 | @PostMapping("/signup") 55 | public ResponseEntity signUp(@RequestBody @Valid SignUpDto signUpDto) { 56 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.CREATED, SIGN_UP_SUCCESS, userService.signUp(User.of(signUpDto)))); 57 | } 58 | 59 | @ApiOperation("로그인") 60 | @PostMapping("/signin") 61 | public ResponseEntity signIn(@RequestBody @Valid SignInDto signInDto) { 62 | User user = userValidator.checkPassword(signInDto); 63 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, LOGIN_SUCCESS, jwtService.createTokenResponse(user.getId()))); 64 | } 65 | 66 | @ApiOperation("비밀번호 재설정") 67 | @Auth 68 | @PutMapping("/password") 69 | public ResponseEntity changePassword(@RequestBody @Valid PasswordDto passwordDto) { 70 | Long userId = UserContext.getCurrentUserId(); 71 | userService.changePassword(userId, passwordDto.getPassword()); 72 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, CHANGE_PASSWORD_SUCCESS)); 73 | } 74 | 75 | @ApiOperation("회원 탈퇴") 76 | @Auth 77 | @DeleteMapping("") 78 | public ResponseEntity deleteUser() { 79 | userService.deleteUser(UserContext.getCurrentUserId()); 80 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, DELETE_USER_SUCCESS)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/UserInfoController.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller; 2 | 3 | import com.yapp.ios1.annotation.Auth; 4 | import com.yapp.ios1.aop.UserContext; 5 | import com.yapp.ios1.dto.ResponseDto; 6 | import com.yapp.ios1.service.user.UserInfoService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import lombok.RequiredArgsConstructor; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import static com.yapp.ios1.message.ResponseMessage.GET_MY_INFO; 18 | import static com.yapp.ios1.message.ResponseMessage.GET_USER_INFO; 19 | 20 | /** 21 | * created by ayoung 2021/06/12 22 | */ 23 | @Api(tags = "User Info") 24 | @RequiredArgsConstructor 25 | @RestController 26 | @RequestMapping("/api/v2/users") 27 | public class UserInfoController { 28 | 29 | private final UserInfoService userInfoService; 30 | 31 | @ApiOperation("마이 페이지") 32 | @Auth 33 | @GetMapping("/me") 34 | public ResponseEntity getMyInfo() { 35 | Long userId = UserContext.getCurrentUserId(); 36 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_MY_INFO, userInfoService.getUserInfo(userId))); 37 | } 38 | 39 | @ApiOperation("사용자 페이지") 40 | @Auth 41 | @GetMapping("/{userId}") 42 | public ResponseEntity getUserInfo(@PathVariable Long userId) { 43 | Long currentUserId = UserContext.getCurrentUserId(); 44 | return ResponseEntity.ok(ResponseDto.of(HttpStatus.OK, GET_USER_INFO, userInfoService.getOtherUserInfo(currentUserId, userId))); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/bucket/BucketRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.bucket; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | 7 | import javax.validation.constraints.Max; 8 | import javax.validation.constraints.Min; 9 | import javax.validation.constraints.NotBlank; 10 | import javax.validation.constraints.NotNull; 11 | import java.time.LocalDate; 12 | import java.util.List; 13 | 14 | import static com.yapp.ios1.message.ValidMessage.*; 15 | 16 | /** 17 | * created by ayoung 2021/05/08 18 | */ 19 | @Getter 20 | @Builder 21 | public class BucketRequestDto { 22 | 23 | @JsonIgnore 24 | private Long id; 25 | @JsonIgnore 26 | private Long userId; 27 | @NotBlank(message = NOT_VALID_BUCKET_NAME) 28 | private String bucketName; 29 | @Min(value = 2, message = NOT_VALID_STATE) 30 | @Max(value = 5, message = NOT_VALID_STATE) 31 | private int bucketState; 32 | @Min(value = 2, message = NOT_VALID_CATEGORY_ID) 33 | @Max(value = 10, message = NOT_VALID_CATEGORY_ID) 34 | private int categoryId; 35 | @NotNull 36 | private LocalDate endDate; 37 | @NotNull 38 | private String content; 39 | @NotNull 40 | private List imageList; 41 | @NotNull 42 | private List tagList; 43 | 44 | public void setUserId(Long userId) { 45 | this.userId = userId; 46 | } 47 | 48 | public void setId(Long id) { this.id = id; } 49 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/email/EmailCodeDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.email; 2 | 3 | import lombok.Getter; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | 7 | /** 8 | * created by ayoung 2021/05/30 9 | */ 10 | @Getter 11 | public class EmailCodeDto { 12 | @NotBlank 13 | private String code; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/email/EmailDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.email; 2 | 3 | import lombok.Getter; 4 | 5 | import javax.validation.constraints.Email; 6 | import javax.validation.constraints.NotBlank; 7 | 8 | import static com.yapp.ios1.message.ValidMessage.NOT_VALID_EMAIL; 9 | 10 | /** 11 | * created by ayoung 2021/04/20 12 | */ 13 | @Getter 14 | public class EmailDto { 15 | @NotBlank 16 | @Email(message = NOT_VALID_EMAIL) 17 | private String email; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/user/ProfileUpdateDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.user; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | import javax.validation.constraints.NotBlank; 8 | import javax.validation.constraints.NotNull; 9 | 10 | /** 11 | * created by ayoung 2021/05/18 12 | */ 13 | @AllArgsConstructor 14 | @Getter 15 | public class ProfileUpdateDto { 16 | @JsonIgnore 17 | private Long userId; 18 | @NotBlank 19 | private String nickname; 20 | @NotNull 21 | private String intro; 22 | @NotNull 23 | private String profileUrl; 24 | 25 | public void setUserId(Long userId) { 26 | this.userId = userId; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/user/login/PasswordDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.user.login; 2 | 3 | import lombok.Getter; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | 7 | /** 8 | * created by ayoung 2021/05/30 9 | */ 10 | @Getter 11 | public class PasswordDto { 12 | @NotBlank 13 | private String password; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/user/login/SignInDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.user.login; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import javax.validation.constraints.Email; 7 | import javax.validation.constraints.NotBlank; 8 | 9 | import static com.yapp.ios1.message.ValidMessage.NOT_VALID_EMAIL; 10 | 11 | /** 12 | * created by ayoung 2021/04/15 13 | */ 14 | @AllArgsConstructor 15 | @Getter 16 | public class SignInDto { 17 | @NotBlank 18 | @Email(message = NOT_VALID_EMAIL) 19 | private String email; 20 | @NotBlank 21 | private String password; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/user/login/SignUpDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.user.login; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | 8 | import javax.validation.constraints.Email; 9 | import javax.validation.constraints.NotBlank; 10 | import javax.validation.constraints.NotNull; 11 | 12 | import static com.yapp.ios1.message.ValidMessage.NOT_VALID_EMAIL; 13 | 14 | /** 15 | * created by ayoung 2021/04/14 16 | */ 17 | @AllArgsConstructor 18 | @Builder 19 | @Getter 20 | public class SignUpDto { 21 | @NotBlank 22 | @Email(message = NOT_VALID_EMAIL) 23 | private String email; 24 | @JsonIgnore 25 | private String socialType; 26 | @NotBlank 27 | private String password; 28 | @NotBlank 29 | private String nickname; 30 | @NotNull 31 | private String intro; 32 | @JsonIgnore 33 | private String socialId; 34 | @NotBlank 35 | private String deviceToken; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/user/social/SocialLoginDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.user.social; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import javax.validation.constraints.Email; 7 | import javax.validation.constraints.NotBlank; 8 | import javax.validation.constraints.NotNull; 9 | 10 | /** 11 | * created by ayoung 2021/05/25 12 | */ 13 | @Getter 14 | public class SocialLoginDto { 15 | @NotNull 16 | @Email 17 | private String email; 18 | @NotBlank 19 | private String socialId; 20 | @NotBlank 21 | private String deviceToken; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/controller/dto/user/social/SocialType.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.controller.dto.user.social; 2 | 3 | /** 4 | * created by ayoung 2021/05/06 5 | */ 6 | public enum SocialType { 7 | apple, google, kakao 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/ResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.springframework.http.HttpStatus; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * created by ayoung 2021/04/10 12 | */ 13 | @Getter 14 | @Setter 15 | @AllArgsConstructor 16 | public class ResponseDto { 17 | 18 | private int status; 19 | private String message; 20 | private Object data; 21 | 22 | public ResponseDto(int status, String message) { 23 | this.status = status; 24 | this.message = message; 25 | } 26 | 27 | public static ResponseDto of(HttpStatus httpStatus, String message) { 28 | int status = Optional.ofNullable(httpStatus) 29 | .orElse(HttpStatus.OK) 30 | .value(); 31 | return new ResponseDto(status, message); 32 | } 33 | 34 | public static ResponseDto of(HttpStatus httpStatus, String message, Object data) { 35 | int status = Optional.ofNullable(httpStatus) 36 | .orElse(HttpStatus.OK) 37 | .value(); 38 | return new ResponseDto(status, message, data); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/bookmark/BookmarkListDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.bookmark; 2 | 3 | import com.yapp.ios1.model.bookmark.Bookmark; 4 | import lombok.Getter; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * created by ayoung 2021/05/11 10 | * 북마크 Dto 11 | */ 12 | @Getter 13 | public class BookmarkListDto { 14 | private List bookmarkList; 15 | private int bookMarkCount; 16 | 17 | public BookmarkListDto(List bookmarkList, int bookMarkCount) { 18 | this.bookmarkList = bookmarkList; 19 | this.bookMarkCount = bookMarkCount; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/bucket/BucketDetailDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.bucket; 2 | 3 | import com.yapp.ios1.model.bucket.Bucket; 4 | import com.yapp.ios1.model.bucket.BucketTimeline; 5 | import com.yapp.ios1.model.image.Image; 6 | import com.yapp.ios1.model.tag.Tag; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Getter; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * created by jg 2021/06/06 14 | * 버킷 하나 조회 Dto 15 | */ 16 | @AllArgsConstructor 17 | @Getter 18 | public class BucketDetailDto { 19 | private Bucket bucket; 20 | private List images; 21 | private List tags; 22 | private List bucketTimelines; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/bucket/BucketHomeDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.bucket; 2 | 3 | import com.yapp.ios1.model.bucket.Bucket; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * created by jg 2021/05/09 11 | * 홈 화면 Dto 12 | */ 13 | @Builder 14 | @Getter 15 | public class BucketHomeDto { 16 | private List buckets; 17 | private int bucketCount; 18 | private boolean isAlarmCheck; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/jwt/JwtPayload.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.jwt; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | 6 | /** 7 | * created by jg 2021/04/11 8 | */ 9 | @Getter 10 | @NoArgsConstructor 11 | public class JwtPayload { 12 | private long id; 13 | 14 | public JwtPayload(long id) { 15 | this.id = id; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/jwt/RefreshTokenDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.jwt; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by ayoung 2021/06/03 7 | */ 8 | @Getter 9 | public class RefreshTokenDto { 10 | private Long userId; 11 | private String refreshToken; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/jwt/TokenResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.jwt; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | 8 | import java.util.Date; 9 | 10 | /** 11 | * created by ayoung 2021/05/23 12 | */ 13 | @AllArgsConstructor 14 | @Getter 15 | @Builder 16 | public class TokenResponseDto { 17 | private String accessToken; 18 | private String refreshToken; 19 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul") 20 | private Date accessExpiredAt; 21 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul") 22 | private Date refreshExpiredAt; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/notification/FcmMessage.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.notification; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | 7 | @Builder 8 | @AllArgsConstructor 9 | @Getter 10 | public class FcmMessage { 11 | private Message message; 12 | 13 | @Builder 14 | @AllArgsConstructor 15 | @Getter 16 | public static class Message { 17 | private Notification notification; 18 | private String token; 19 | } 20 | 21 | @Builder 22 | @AllArgsConstructor 23 | @Getter 24 | public static class Notification { 25 | private String title; 26 | private String body; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/notification/NotificationDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.notification; 2 | 3 | import lombok.Getter; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | /** 8 | * created by jg 2021/05/17 9 | */ 10 | @Getter 11 | public class NotificationDto { 12 | private String title; 13 | private String message; 14 | private LocalDateTime localDateTime; 15 | 16 | public NotificationDto(String title, String message, LocalDateTime localDateTime) { 17 | this.title = title; 18 | this.message = message; 19 | this.localDateTime = localDateTime; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/notification/NotificationForOneDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.notification; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * created by jg 2021/05/21 10 | */ 11 | @Getter 12 | public class NotificationForOneDto extends NotificationDto { 13 | private Long alarmId; 14 | private String deviceToken; 15 | 16 | @Builder 17 | public NotificationForOneDto(String title, String message, LocalDateTime localDateTime, String deviceToken) { 18 | super(title, message, localDateTime); 19 | this.deviceToken = deviceToken; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/notification/NotificationLogDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.notification; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by jg 2021/05/26 7 | */ 8 | @Getter 9 | public class NotificationLogDto { 10 | private Long alarmId; 11 | private String title; 12 | private String message; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/notification/NotificationTestDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.notification; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by ayoung 2021/07/02 7 | */ 8 | @Getter 9 | public class NotificationTestDto { 10 | private String title; 11 | private String message; 12 | private String deviceToken; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/user/UserInfoDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.user; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.yapp.ios1.dto.bookmark.BookmarkListDto; 5 | import com.yapp.ios1.model.bucket.Bucket; 6 | import com.yapp.ios1.model.user.Profile; 7 | import lombok.Builder; 8 | import lombok.Getter; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * created by ayoung 2021/05/11 14 | * 마이페이지 Dto 15 | */ 16 | @Getter 17 | @Builder 18 | public class UserInfoDto { 19 | private Profile user; 20 | private int friendCount; 21 | private int bucketCount; 22 | private BookmarkListDto bookmark; 23 | @JsonInclude(JsonInclude.Include.NON_NULL) 24 | private int isFriend; 25 | @JsonInclude(JsonInclude.Include.NON_NULL) 26 | private List bucket; 27 | 28 | public void setBucket(List bucket) { 29 | this.bucket = bucket; 30 | } 31 | 32 | public void setFriend(int friend) { 33 | this.isFriend = friend; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/dto/user/UserStatusDto.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto.user; 2 | 3 | import com.yapp.ios1.dto.jwt.TokenResponseDto; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import org.springframework.http.HttpStatus; 7 | 8 | /** 9 | * created by ayoung 2021/05/05 10 | * 소셜 로그인 로그인, 회원가입 구분하는 Dto 11 | */ 12 | @AllArgsConstructor 13 | @Getter 14 | public class UserStatusDto { 15 | private HttpStatus status; 16 | private TokenResponseDto tokenDto; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/enums/AlarmStatus.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.enums; 2 | 3 | /** 4 | * created by jg 2021/06/07 5 | */ 6 | public enum AlarmStatus { 7 | WHOLE_ALARM(1), // 전체 알람 8 | FOLLOW_ALARM(2) // 친구 알람 9 | ; 10 | private final int alarmStatus; 11 | 12 | AlarmStatus(int alarmStatus) { 13 | this.alarmStatus = alarmStatus; 14 | } 15 | 16 | public int get() { 17 | return alarmStatus; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/enums/BucketLogStatus.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.enums; 2 | 3 | /** 4 | * created by ayoung 2021/06/28 5 | */ 6 | public enum BucketLogStatus { 7 | BUCKET_NAME_LOG(1), // 버킷 이름 로그 8 | BUCKET_END_DATE_LOG(2) // 버킷 완료 날짜 로그 9 | ; 10 | private final int bucketLogStatus; 11 | 12 | BucketLogStatus(int bucketLogStatus) { 13 | this.bucketLogStatus = bucketLogStatus; 14 | } 15 | 16 | public int get() { 17 | return bucketLogStatus; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/enums/BucketStatus.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.enums; 2 | 3 | /** 4 | * created by jg 2021/06/10 5 | */ 6 | public enum BucketStatus { 7 | BUCKET_WHOLE(1), // 전체 버킷 8 | BUCKET_EXPECTED(2), // 예정 버킷 9 | BUCKET_ONGOING(3), // 진행 중 버킷 10 | BUCKET_COMPLETE(4), // 완료 버킷 11 | BUCKET_FAIL(5) // 실패 버킷 12 | ; 13 | private final int bucketStatus; 14 | 15 | BucketStatus(int bucketStatus) { 16 | this.bucketStatus = bucketStatus; 17 | } 18 | 19 | public int get() { 20 | return bucketStatus; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/enums/FriendStatus.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.enums; 2 | 3 | /** 4 | * created by jg 2021/05/21 5 | */ 6 | public enum FriendStatus { 7 | FRIEND(1), // 친구 8 | REQUEST(2) // 요청 중 9 | ; 10 | private final int friendStatus; 11 | 12 | FriendStatus(int friendStatus) { 13 | this.friendStatus = friendStatus; 14 | } 15 | 16 | public int get() { 17 | return friendStatus; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import org.springframework.validation.BindingResult; 8 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * created by jg 2021/06/03 16 | */ 17 | 18 | @Getter 19 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 20 | public class ErrorResponse { 21 | 22 | private String message; 23 | private int status; 24 | private List errors; 25 | private String code; 26 | 27 | private ErrorResponse(final ErrorCode code, final List errors) { 28 | this.message = code.getMessage(); 29 | this.status = code.getStatus(); 30 | this.errors = errors; 31 | this.code = code.getCode(); 32 | } 33 | 34 | private ErrorResponse(final ErrorCode code) { 35 | this.message = code.getMessage(); 36 | this.status = code.getStatus(); 37 | this.code = code.getCode(); 38 | this.errors = new ArrayList<>(); 39 | } 40 | 41 | public static ErrorResponse of(final ErrorCode code, final BindingResult bindingResult) { 42 | return new ErrorResponse(code, FieldError.of(bindingResult)); 43 | } 44 | 45 | public static ErrorResponse of(final ErrorCode code) { 46 | return new ErrorResponse(code); 47 | } 48 | 49 | public static ErrorResponse of(final ErrorCode code, final List errors) { 50 | return new ErrorResponse(code, errors); 51 | } 52 | 53 | public static ErrorResponse of(MethodArgumentTypeMismatchException e) { 54 | final String value = e.getValue() == null ? "" : e.getValue().toString(); 55 | final List errors = ErrorResponse.FieldError.of(e.getName(), value, e.getErrorCode()); 56 | return new ErrorResponse(ErrorCode.INVALID_TYPE_VALUE, errors); 57 | } 58 | 59 | @Getter 60 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 61 | public static class FieldError { 62 | private String field; 63 | private String value; 64 | private String reason; 65 | 66 | private FieldError(final String field, final String value, final String reason) { 67 | this.field = field; 68 | this.value = value; 69 | this.reason = reason; 70 | } 71 | 72 | public static List of(final String field, final String value, final String reason) { 73 | List fieldErrors = new ArrayList<>(); 74 | fieldErrors.add(new FieldError(field, value, reason)); 75 | return fieldErrors; 76 | } 77 | 78 | private static List of(final BindingResult bindingResult) { 79 | final List fieldErrors = bindingResult.getFieldErrors(); 80 | return fieldErrors.stream() 81 | .map(error -> new FieldError( 82 | error.getField(), 83 | error.getRejectedValue() == null ? "" : error.getRejectedValue().toString(), 84 | error.getDefaultMessage())) 85 | .collect(Collectors.toList()); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error; 2 | 3 | import com.yapp.ios1.error.exception.BusinessException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.http.converter.HttpMessageNotReadableException; 9 | import org.springframework.web.HttpRequestMethodNotSupportedException; 10 | import org.springframework.web.bind.MethodArgumentNotValidException; 11 | import org.springframework.web.bind.annotation.ControllerAdvice; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.client.HttpClientErrorException; 14 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; 15 | 16 | /** 17 | * created by jg 2021/06/03 18 | */ 19 | @ControllerAdvice 20 | @Slf4j 21 | public class GlobalExceptionHandler { 22 | 23 | /** 24 | * Bucket 등록할 때 LocalDate 형식 오류 25 | */ 26 | @ExceptionHandler(HttpMessageNotReadableException.class) 27 | protected ResponseEntity httpMessageNotReadableException() { 28 | log.error("HttpMessageNotReadableException"); 29 | final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_TYPE_VALUE); 30 | return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); 31 | } 32 | 33 | /** 34 | * javax.validation.Valid or @Validated 으로 binding error 발생시 발생한다. 35 | * HttpMessageConverter 에서 등록한 HttpMessageConverter binding 못할경우 발생 36 | * 주로 @RequestBody, @RequestPart 어노테이션에서 발생 37 | */ 38 | @ExceptionHandler(MethodArgumentNotValidException.class) 39 | protected ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { 40 | log.error("MethodArgumentNotValidException : " + e.getMessage()); 41 | final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getBindingResult()); 42 | return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); 43 | } 44 | 45 | /** 46 | * enum type 일치하지 않아 binding 못할 경우 발생 47 | * 주로 @RequestParam enum으로 binding 못했을 경우 발생 48 | */ 49 | @ExceptionHandler(MethodArgumentTypeMismatchException.class) 50 | protected ResponseEntity handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) { 51 | log.error("MethodArgumentTypeMismatchException : " + e.getMessage()); 52 | final ErrorResponse response = ErrorResponse.of(e); 53 | return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); 54 | } 55 | 56 | /** 57 | * 지원하지 않은 HTTP method 호출 할 경우 발생 58 | */ 59 | @ExceptionHandler(HttpRequestMethodNotSupportedException.class) 60 | protected ResponseEntity handleHttpRequestMethodNotSupportedException() { 61 | log.error("HttpRequestMethodNotSupportedException"); 62 | final ErrorResponse response = ErrorResponse.of(ErrorCode.METHOD_NOT_ALLOWED); 63 | return new ResponseEntity<>(response, HttpStatus.METHOD_NOT_ALLOWED); 64 | } 65 | 66 | /** 67 | * RuntimeException 하위 클래스 68 | */ 69 | @ExceptionHandler(BusinessException.class) 70 | protected ResponseEntity handleBusinessException(final BusinessException e) { 71 | log.error("BusinessException : " + e.getMessage()); 72 | final ErrorCode errorCode = e.getErrorCode(); 73 | final ErrorResponse response = ErrorResponse.of(errorCode); 74 | return new ResponseEntity<>(response, HttpStatus.valueOf(errorCode.getStatus())); 75 | } 76 | 77 | /** 78 | * 예상치 못한 에러 처리 79 | */ 80 | @ExceptionHandler(Exception.class) 81 | protected ResponseEntity handleException(final Exception e) { 82 | log.error("Exception : " + e.getMessage()); 83 | final ErrorResponse response = ErrorResponse.of(ErrorCode.INTERNAL_SERVER_ERROR); 84 | return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception; 2 | 3 | /** 4 | * created by jg 2021/06/03 5 | */ 6 | public class BusinessException extends RuntimeException { 7 | 8 | private ErrorCode errorCode; 9 | 10 | public BusinessException(String message) { 11 | super(message); 12 | } 13 | 14 | public BusinessException(ErrorCode errorCode) { 15 | super(errorCode.getMessage()); 16 | this.errorCode = errorCode; 17 | } 18 | 19 | public ErrorCode getErrorCode() { 20 | return errorCode; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/EntityNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception; 2 | 3 | /** 4 | * created by jg 2021/06/03 5 | */ 6 | public class EntityNotFoundException extends BusinessException { 7 | 8 | public EntityNotFoundException(ErrorCode errorCode) { 9 | super(errorCode); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | 5 | /** 6 | * created by jg 2021/06/03 7 | */ 8 | @JsonFormat(shape = JsonFormat.Shape.OBJECT) 9 | public enum ErrorCode { 10 | 11 | // Common 12 | INVALID_INPUT_VALUE(400, "C001", " Invalid Input Value"), 13 | METHOD_NOT_ALLOWED(405, "C002", " Invalid Input Value"), 14 | ENTITY_NOT_FOUND(400, "C003", " Entity Not Found"), 15 | INTERNAL_SERVER_ERROR(500, "C004", "Server Error"), 16 | INVALID_TYPE_VALUE(400, "C005", " Invalid Type Value"), 17 | HANDLE_ACCESS_DENIED(403, "C006", "Access is Denied"), 18 | JSON_WRITE_ERROR(401, "C007", "JSON content that are not pure I/O problems"), 19 | 20 | // JWT 21 | JWT_ERROR(401, "J001", "JWT가 없거나 잘못된 값 입니다"), 22 | JWT_PARSE_ERROR(401, "J002", "JWT Parse Error"), 23 | JWT_EXPIRED_ERROR(401, "J003", "JWT Expired Error"), 24 | 25 | // User 26 | EMAIL_NOT_FOUND(400, "M000", "Email is not Exist"), 27 | EMAIL_DUPLICATION(400, "M001", "Email is Duplication"), 28 | USER_NOT_FOUND(400, "M003", "User is not Exist"), 29 | NICKNAME_EMAIL_DUPLICATION(400, "M004", "NickName is Duplication"), 30 | USER_NOT_AUTHENTICATION(401, "M005", "User is not Authentication"), 31 | PASSWORD_MISMATCH_ERROR(400, "M008", "Password MisMatch Error"), 32 | DEVICE_TOKEN_NOT_FOUND_ERROR(400, "M008", "DeviceToken is not Exist"), 33 | 34 | // Alarm 35 | ALARM_NOT_FOUND_ERROR(400, "N001", "Alarm is not Exist"), 36 | 37 | // Email 38 | EMAIL_SEND_ERROR(500, "P001", "Email Send Error"), 39 | 40 | // AWS 41 | AWS_S3_ERROR(500, "A001", "AWS S3 Error"); 42 | 43 | 44 | private final String code; 45 | private final String message; 46 | private int status; 47 | 48 | ErrorCode(final int status, final String code, final String message) { 49 | this.status = status; 50 | this.message = message; 51 | this.code = code; 52 | } 53 | 54 | public String getMessage() { 55 | return this.message; 56 | } 57 | 58 | public String getCode() { 59 | return code; 60 | } 61 | 62 | public int getStatus() { 63 | return status; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/InvalidValueException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception; 2 | 3 | /** 4 | * created by jg 2021/06/03 5 | */ 6 | public class InvalidValueException extends BusinessException { 7 | 8 | public InvalidValueException(ErrorCode errorCode) { 9 | super(errorCode); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/alarm/AlarmNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.alarm; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by jg 2021/06/07 8 | */ 9 | public class AlarmNotFoundException extends InvalidValueException { 10 | public AlarmNotFoundException() { 11 | super(ErrorCode.ALARM_NOT_FOUND_ERROR); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/aws/S3Exception.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.aws; 2 | 3 | import com.yapp.ios1.error.exception.BusinessException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | 6 | /** 7 | * created by jg 2021/06/04 8 | */ 9 | public class S3Exception extends BusinessException { 10 | public S3Exception() { 11 | super(ErrorCode.AWS_S3_ERROR); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/bucket/BucketNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.bucket; 2 | 3 | import com.yapp.ios1.error.exception.EntityNotFoundException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | 6 | /** 7 | * created by ayoung 2021/05/21 8 | */ 9 | public class BucketNotFoundException extends EntityNotFoundException { 10 | public BucketNotFoundException() { 11 | super(ErrorCode.ENTITY_NOT_FOUND); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/bucket/bucketStateIdInvalidException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.bucket; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by jg 2021/06/07 8 | */ 9 | public class bucketStateIdInvalidException extends InvalidValueException { 10 | public bucketStateIdInvalidException() { 11 | super(ErrorCode.INVALID_INPUT_VALUE); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/common/JsonWriteException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.common; 2 | 3 | import com.yapp.ios1.error.exception.BusinessException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | 6 | /** 7 | * created by jg 2021/06/03 8 | */ 9 | public class JsonWriteException extends BusinessException { 10 | public JsonWriteException() { 11 | super(ErrorCode.JSON_WRITE_ERROR); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/email/EmailCodeException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.email; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by ayoung 2021/06/15 8 | */ 9 | public class EmailCodeException extends InvalidValueException { 10 | public EmailCodeException() { 11 | super(ErrorCode.INVALID_INPUT_VALUE); 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/email/EmailSendException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.email; 2 | 3 | import com.yapp.ios1.error.exception.BusinessException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | 6 | /** 7 | * created by jg 2021/06/03 8 | */ 9 | public class EmailSendException extends BusinessException { 10 | public EmailSendException() { 11 | super(ErrorCode.EMAIL_SEND_ERROR); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/jwt/JwtException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.jwt; 2 | 3 | import com.yapp.ios1.error.exception.BusinessException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | 6 | /** 7 | * created by jg 2021/06/03 8 | */ 9 | public class JwtException extends BusinessException { 10 | public JwtException() { 11 | super(ErrorCode.JWT_ERROR); 12 | } 13 | 14 | public JwtException(ErrorCode errorCode) { 15 | super(errorCode); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/jwt/JwtExpiredException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.jwt; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | 5 | /** 6 | * created by ayoung 2021/06/04 7 | */ 8 | public class JwtExpiredException extends JwtException { 9 | public JwtExpiredException() { 10 | super(ErrorCode.JWT_EXPIRED_ERROR); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/jwt/JwtParseException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.jwt; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | 5 | /** 6 | * created by jg 2021/06/03 7 | */ 8 | public class JwtParseException extends JwtException { 9 | public JwtParseException() { 10 | super(ErrorCode.JWT_PARSE_ERROR); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/DeviceTokenNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by jg 2021/06/06 8 | */ 9 | public class DeviceTokenNotFoundException extends InvalidValueException { 10 | public DeviceTokenNotFoundException() { 11 | super(ErrorCode.DEVICE_TOKEN_NOT_FOUND_ERROR); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/EmailDuplicatedException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | import lombok.Getter; 6 | 7 | /** 8 | * created by ayoung 2021/04/14 9 | */ 10 | @Getter 11 | public class EmailDuplicatedException extends InvalidValueException { 12 | 13 | public EmailDuplicatedException() { 14 | super(ErrorCode.EMAIL_DUPLICATION); 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/EmailNotExistException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | import lombok.Getter; 6 | 7 | /** 8 | * created by ayoung 2021/05/25 9 | */ 10 | @Getter 11 | public class EmailNotExistException extends InvalidValueException { 12 | 13 | public EmailNotExistException() { 14 | super(ErrorCode.EMAIL_NOT_FOUND); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/NickNameDuplicatedException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by jg 2021/06/03 8 | */ 9 | public class NickNameDuplicatedException extends InvalidValueException { 10 | 11 | public NickNameDuplicatedException() { 12 | super(ErrorCode.NICKNAME_EMAIL_DUPLICATION); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/PasswordNotMatchException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by ayoung 2021/04/15 8 | */ 9 | public class PasswordNotMatchException extends InvalidValueException { 10 | 11 | public PasswordNotMatchException() { 12 | super(ErrorCode.PASSWORD_MISMATCH_ERROR); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/UserAuthenticationException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.ErrorCode; 4 | import com.yapp.ios1.error.exception.InvalidValueException; 5 | 6 | /** 7 | * created by jg 2021/06/03 8 | */ 9 | public class UserAuthenticationException extends InvalidValueException { 10 | 11 | public UserAuthenticationException() { 12 | super(ErrorCode.USER_NOT_AUTHENTICATION); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/error/exception/user/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.error.exception.user; 2 | 3 | import com.yapp.ios1.error.exception.EntityNotFoundException; 4 | import com.yapp.ios1.error.exception.ErrorCode; 5 | 6 | /** 7 | * created by jg 2021/04/11 8 | */ 9 | public class UserNotFoundException extends EntityNotFoundException { 10 | public UserNotFoundException() { 11 | super(ErrorCode.USER_NOT_FOUND); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/AlarmMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import com.yapp.ios1.dto.notification.NotificationDto; 4 | import com.yapp.ios1.dto.notification.NotificationForOneDto; 5 | import com.yapp.ios1.model.notification.Notification; 6 | import org.apache.ibatis.annotations.Mapper; 7 | import org.apache.ibatis.annotations.Param; 8 | 9 | import java.time.LocalDateTime; 10 | import java.util.List; 11 | import java.util.Optional; 12 | 13 | /** 14 | * created by jg 2021/05/21 15 | */ 16 | @Mapper 17 | public interface AlarmMapper { 18 | 19 | void insertFollowAlarmLog(@Param("notification") NotificationForOneDto notification, 20 | @Param("fromUserId") Long fromUserId, 21 | @Param("alarmStatus") int alarmStatus, 22 | @Param("time") LocalDateTime localDateTime, 23 | @Param("friendId") Long friendId); 24 | 25 | void updateFollowAlarmLog(@Param("notification") NotificationForOneDto notification, 26 | @Param("alarmId") Long alarmId); 27 | 28 | void insertWholeAlarmLog(@Param("alarm") NotificationDto notificationDto, 29 | @Param("alarmStatus") int alarmStatus); 30 | 31 | List getCommonAlarmLog(Long userId); 32 | List getFollowAlarmLog(Long userId); 33 | 34 | void deleteFollowAlarmLog(Long alarmId); 35 | void deleteWholeAlarmLog(Long alarmId, Long userId); 36 | 37 | Optional findWholeAlarmByAlarmId(Long alarmId); 38 | Optional findFollowAlarmByAlarmId(Long alarmId); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/BucketMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import com.yapp.ios1.controller.dto.bucket.BucketRequestDto; 4 | import com.yapp.ios1.model.bookmark.Bookmark; 5 | import com.yapp.ios1.model.bucket.Bucket; 6 | import com.yapp.ios1.model.bucket.BucketTimeline; 7 | import com.yapp.ios1.model.image.Image; 8 | import com.yapp.ios1.model.tag.Tag; 9 | import org.apache.ibatis.annotations.Mapper; 10 | import org.apache.ibatis.annotations.Param; 11 | 12 | import java.util.List; 13 | import java.util.Optional; 14 | 15 | /** 16 | * created by jg 2021/05/05 17 | */ 18 | @Mapper 19 | public interface BucketMapper { 20 | 21 | Optional findByBucketIdAndUserId(Long bucketId, Long userId); 22 | 23 | Optional findByBucketId(Long bucketId); 24 | 25 | void registerBucket(BucketRequestDto registerDto); 26 | 27 | void updateBucket(BucketRequestDto updateDto); 28 | 29 | void saveBucketImageUrlList(@Param("bucketId") Long bucketId, List imageUrlList); 30 | 31 | void saveBucketIdAndTagId(@Param("bucketId") Long bucketId, List tagList); 32 | 33 | void saveTagList(List tagList); 34 | 35 | List findByBucketStateAndCategory(@Param("bucketState") int bucketState, 36 | @Param("category") int category, 37 | @Param("userId") Long userId, 38 | @Param("sort") int sort); 39 | 40 | List findByUserId(Long userId); 41 | 42 | List findBookmarkListByUserId(@Param("userId") Long userId); 43 | 44 | int getBucketCountByUserId(@Param("userId") Long userId); 45 | 46 | void deleteTagListByBucketId(Long bucketId); 47 | 48 | void deleteImageListByBucketId(Long bucketId); 49 | 50 | void saveBucketLog(Long bucketId, String content, int updateType); 51 | 52 | void setBookmark(Long bucketId, boolean isBookmark); 53 | 54 | List findByBucketTagByBucketId(Long bucketId); 55 | 56 | List findByBucketImageByBucketId(Long bucketId); 57 | 58 | List findByBucketTimelineByBucketId(Long bucketId); 59 | 60 | void setBucketFin(Long bucketId, boolean isFin); 61 | 62 | void updateBucketState(Long bucketId, Long userId, int bucketStateId); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/FriendMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import com.yapp.ios1.model.user.Friend; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * created by ayoung 2021/05/11 11 | */ 12 | @Mapper 13 | public interface FriendMapper { 14 | 15 | int getFollowCountByUserId(Long userId); 16 | 17 | List getFollowListByUserId(Long userId); 18 | 19 | int checkFriendStatus(Long myUserId, Long otherUserId); 20 | 21 | void insertFollow(@Param("myUserId") Long myUserId, 22 | @Param("friendId") Long friendId, 23 | @Param("followRequest") int followRequest, 24 | @Param("alarmId") Long alarmId); 25 | 26 | void deleteFriend(Long myUserId, Long friendId); 27 | 28 | Long findByFollowAlarmId(Long myUserId, Long friendId); 29 | 30 | void updateFriendStatus(@Param("myUserId") Long myUserId, 31 | @Param("friendId") Long friendId, 32 | @Param("friendStatus") int friendStatus); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/ProfileMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import com.yapp.ios1.controller.dto.user.ProfileUpdateDto; 4 | import com.yapp.ios1.model.user.Profile; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * created by jg 2021/06/11 12 | */ 13 | @Mapper 14 | public interface ProfileMapper { 15 | 16 | Optional findProfileByUserId(@Param("userId") Long userId); 17 | int updateProfile(ProfileUpdateDto profile, Long userId); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/SearchMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import com.yapp.ios1.model.bucket.Bucket; 4 | import com.yapp.ios1.model.user.Friend; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * created by jg 2021/05/17 12 | */ 13 | @Mapper 14 | public interface SearchMapper { 15 | 16 | List searchUser(@Param("keyword") String keyword, @Param("userId") Long userId); 17 | List searchMyBook(@Param("keyword") String keyword, @Param("userId") Long userId); 18 | List searchBookMark(@Param("keyword") String keyword, @Param("userId") Long userId); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/TokenMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | 5 | /** 6 | * created by ayoung 2021/06/03 7 | */ 8 | @Mapper 9 | public interface TokenMapper { 10 | void updateToken(String refreshToken, Long userId); 11 | 12 | String getTokenByUserId(Long userId); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.mapper; 2 | 3 | import com.yapp.ios1.model.user.User; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | import java.util.Optional; 9 | 10 | /** 11 | * created by jg 2021/03/28 12 | */ 13 | @Mapper 14 | public interface UserMapper { 15 | 16 | Optional findByUserId(@Param("userId") Long userId); 17 | 18 | // TODO id 없으면 왜 에러인지 알아보기 19 | Optional findByEmail(@Param("email") String email); 20 | 21 | Optional findByNickname(@Param("nickname") String nickname); 22 | 23 | Optional findBySocialIdAndSocialType(String socialId, String socialType); 24 | 25 | void changePassword(Long userId, String password); 26 | 27 | void signUp(User user); 28 | 29 | Optional findDeviceTokenByUserId(Long userId); 30 | 31 | List findAllUserDeviceToken(); 32 | 33 | void deleteUser(Long userId); 34 | 35 | void updateAlarmStatus(Long userId, boolean alarmReadStatus); 36 | 37 | boolean alarmCheckStatus(Long userId); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/message/AlarmMessage.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.message; 2 | 3 | /** 4 | * created by jg 2021/06/06 5 | */ 6 | public class AlarmMessage { 7 | private AlarmMessage() {} 8 | 9 | public static final String FOLLOW_REQUEST_TITLE = "친구 요청이 왔어요"; 10 | public static final String FOLLOW_REQUEST_MESSAGE = "님이 회원님과 친구가 되고 싶어 합니다."; 11 | public static final String FOLLOW_ACCEPT_TITLE = "친구 요청을 수락했습니다."; 12 | public static final String FOLLOW_ACCEPT_MESSAGE = "님이 회원님과 친구가 되었습니다"; 13 | 14 | public static final String WHOLE_ALARM_TITLE = "전체 알람 메시지 제목"; 15 | public static final String WHOLE_ALARM_MESSAGE = "전체 알람 메세지 내용"; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/message/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.message; 2 | 3 | /** 4 | * created by jg 2021/05/05 5 | */ 6 | public class ResponseMessage { 7 | private ResponseMessage() {} 8 | 9 | // Bucket 10 | public static final String GET_BUCKET_LIST = "버킷 리스트 조회 성공입니다."; 11 | public static final String UPLOAD_IMAGE_SUCCESS = "이미지 업로드 성공입니다."; 12 | public static final String NOT_EXIST_IMAGE = "업로드할 이미지 존재하지 않습니다."; 13 | public static final String REGISTER_BUCKET_SUCCESS = "버킷 등록 성공입니다."; 14 | public static final String UPDATE_BUCKET_SUCCESS = "버킷 수정 성공입니다."; 15 | public static final String GET_BUCKET_DETAIL = "버킷 상세 조회 성공입니다"; 16 | public static final String REGISTER_BUCKET_FIN_SUCCESS = "버킷 핀 등록 성공입니다"; 17 | public static final String UPDATE_BUCKET_STATE = "버킷 상태 변경 성공입니다"; 18 | 19 | // Login 20 | public static final String LOGIN_SUCCESS = "로그인 성공입니다."; 21 | public static final String SIGN_UP_SUCCESS = "회원가입 성공입니다."; 22 | public static final String CHANGE_PASSWORD_SUCCESS = "비밀번호 재설정 성공입니다."; 23 | public static final String POSSIBLE_NICKNAME = "사용가능한 닉네임입니다."; 24 | public static final String POSSIBLE_EMAIL = "사용가능한 이메일입니다."; 25 | public static final String REISSUE_TOKEN_SUCCESS = "토큰 재발급 성공입니다."; 26 | 27 | // User 28 | public static final String GET_PROFILE_SUCCESS = "프로필 가져오기 성공입니다."; 29 | public static final String UPDATE_PROFILE_SUCCESS = "프로필 수정 성공입니다."; 30 | public static final String GET_MY_INFO = "마이페이지 정보입니다."; 31 | public static final String GET_USER_INFO = "사용자페이지 정보입니다."; 32 | public static final String GET_FRIEND_LIST = "친구 목록입니다."; 33 | public static final String DELETE_USER_SUCCESS = "탈퇴 성공입니다."; 34 | 35 | // Notification 36 | public static final String GET_ALARM_LOG = "알람 로그 조회 성공입니다"; 37 | public static final String DELETE_ALARM_LOG = "알람 로그 삭제되었습니다"; 38 | 39 | // Search 40 | public static final String NOT_FOUND_SEARCH_TYPE = "존재하지 않는 검색 조건입니다."; 41 | public static final String SUCCESS_SEARCH = "검색 성공입니다."; 42 | 43 | // Follow 44 | public static final String FRIEND_REQUEST = "팔로우 요청 성공입니다."; 45 | public static final String FRIEND_MESSAGE = "팔로우 응답 성공입니다."; 46 | public static final String FRIEND_DELETE = "친구 끊기 성공입니다"; 47 | 48 | // Email 49 | public static final String EMAIL_SEND_SUCCESS = "이메일 전송 성공입니다."; 50 | public static final String EMAIL_AUTH_SUCCESS = "이메일 인증 성공입니다."; 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/message/ValidMessage.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.message; 2 | 3 | /** 4 | * created by jg 2021/06/07 5 | */ 6 | public class ValidMessage { 7 | private ValidMessage() {} 8 | 9 | // Valid 10 | public static final String NOT_VALID_BUCKET_NAME = "버킷 제목 작성 필수입니다."; 11 | public static final String NOT_VALID_CATEGORY_ID = "유효한 카테고리 ID가 아닙니다."; 12 | public static final String NOT_VALID_STATE = "유효한 버킷 state가 아닙니다."; 13 | public static final String NOT_VALID_EMAIL = "이메일 형식 제대로 입력해주세요."; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/bookmark/Bookmark.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.bookmark; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by ayoung 2021/05/11 7 | */ 8 | @Getter 9 | public class Bookmark { 10 | private Long id; 11 | private String bucketName; 12 | private String endDate; 13 | private int categoryId; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/bucket/Bucket.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.bucket; 2 | 3 | import lombok.Getter; 4 | 5 | import java.time.LocalDate; 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * created by jg 2021/05/05 10 | * 버킷 홈, 나의버킷-북마크 검색 모델 11 | */ 12 | @Getter 13 | public class Bucket { 14 | private Long id; 15 | private Long userId; 16 | private String bucketName; 17 | private String content; 18 | private String createdDate; 19 | private String endDate; 20 | private int bucketState; 21 | private Integer categoryId; 22 | private boolean isBookmark; 23 | private boolean isFin; 24 | private String userProfileUrl; 25 | private boolean isAlarmCheck; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/bucket/BucketTimeline.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.bucket; 2 | 3 | import lombok.Getter; 4 | 5 | import java.time.LocalDate; 6 | 7 | /** 8 | * created by jg 2021/06/07 9 | */ 10 | @Getter 11 | public class BucketTimeline { 12 | private String content; 13 | private LocalDate modifiedDate; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/image/Image.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.image; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by jg 2021/06/06 7 | */ 8 | @Getter 9 | public class Image { 10 | private String imageUrl; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/notification/Notification.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.notification; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by jg 2021/05/26 7 | * 알림 로그 모델 8 | */ 9 | @Getter 10 | public class Notification { 11 | private Long alarmId; 12 | private Long friendId; 13 | private String title; 14 | private String message; 15 | private String nickName; 16 | private String profileUrl; 17 | private int friendStatus; 18 | private int alarmStatus; 19 | private String createdAt; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/tag/Tag.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.tag; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * created by ayoung 2021/05/08 9 | */ 10 | @JsonInclude(JsonInclude.Include.NON_NULL) 11 | @NoArgsConstructor 12 | @Getter 13 | public class Tag { 14 | private Long id; 15 | private String tagName; 16 | 17 | public void setId(Long id) { 18 | this.id = id; 19 | } 20 | 21 | public Tag(String tagName) { 22 | this.tagName = tagName; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/user/Friend.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.user; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by ayoung 2021/05/12 7 | * 친구 목록 조회, 유저 검색 모델 8 | */ 9 | @Getter 10 | public class Friend { 11 | private Long userId; 12 | private String email; 13 | private String nickname; 14 | private String intro; 15 | private String profileUrl; 16 | private int friendStatus; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/user/Profile.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.user; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * created by ayoung 2021/05/18 7 | * 디바이스 토큰, 패스워드 제외한 프로필 모델 8 | */ 9 | @Getter 10 | public class Profile { 11 | private Long id; 12 | private String email; 13 | private String nickname; 14 | private String createdDate; 15 | private String intro; 16 | private String profileUrl; 17 | private String socialType; 18 | private String socialId; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/model/user/User.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.model.user; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.yapp.ios1.controller.dto.user.login.SignUpDto; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | /** 11 | * created by jg 2021/03/28 12 | */ 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Getter 16 | @Builder 17 | public class User { 18 | private Long id; 19 | private String email; 20 | @JsonIgnore 21 | private String socialType; 22 | private String nickname; 23 | @JsonIgnore 24 | private String password; 25 | private String intro; 26 | private String createdDate; 27 | @JsonIgnore 28 | private String socialId; 29 | @JsonIgnore 30 | private String deviceToken; 31 | private String profileUrl; 32 | private boolean isAlarmCheck; 33 | 34 | public static User of(SignUpDto signUpDto) { 35 | return User.builder() 36 | .email(signUpDto.getEmail()) 37 | .nickname(signUpDto.getNickname()) 38 | .password(signUpDto.getPassword()) 39 | .intro(signUpDto.getIntro()) 40 | .socialType(signUpDto.getSocialType()) 41 | .socialId(signUpDto.getSocialId()) 42 | .deviceToken(signUpDto.getDeviceToken()) 43 | .build(); 44 | } 45 | 46 | public void encodePassword(String password) { 47 | this.password = password; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/properties/EmailProperties.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * created by ayoung 2021/05/30 10 | */ 11 | @Getter 12 | @Setter 13 | @ConfigurationProperties(prefix = "buok.email") 14 | @Configuration 15 | public class EmailProperties { 16 | private String name; 17 | private String link; 18 | private Long validTime; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/properties/FirebaseProperties.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * created by jg 2021/06/07 10 | */ 11 | @Getter 12 | @Setter 13 | @ConfigurationProperties(prefix = "fcm.account") 14 | @Configuration 15 | public class FirebaseProperties { 16 | private String path; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/properties/JwtProperties.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * created by jg 2021/06/04 10 | */ 11 | @Getter 12 | @Setter 13 | @ConfigurationProperties(prefix = "jwt") 14 | @Configuration 15 | public class JwtProperties { 16 | // TODO AccessToken, RefreshToken SecretKey 분리하기 17 | private String secretKey; 18 | private AccessToken accessToken; 19 | private RefreshToken refreshToken; 20 | 21 | @Getter @Setter 22 | public static class AccessToken { 23 | private Long validTime; 24 | } 25 | 26 | @Getter @Setter 27 | public static class RefreshToken { 28 | private Long validTime; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/properties/S3Properties.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * created by jg 2021/06/04 10 | */ 11 | @Getter 12 | @Setter 13 | @ConfigurationProperties(prefix = "cloud.aws.s3") 14 | @Configuration 15 | public class S3Properties { 16 | private String bucket; 17 | private String dir; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/properties/SocialLoginProperties.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * created by jg 2021/06/04 10 | */ 11 | @Getter 12 | @Setter 13 | @ConfigurationProperties(prefix = "social") 14 | @Configuration 15 | public class SocialLoginProperties { 16 | private String key; 17 | private Host host; 18 | 19 | @Getter @Setter 20 | public static class Host { 21 | private String google; 22 | private String kakao; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/EmailService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.yapp.ios1.error.exception.email.EmailCodeException; 4 | import com.yapp.ios1.model.user.User; 5 | import com.yapp.ios1.error.exception.email.EmailSendException; 6 | import com.yapp.ios1.properties.EmailProperties; 7 | import com.yapp.ios1.utils.RedisUtil; 8 | import com.yapp.ios1.validator.UserValidator; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.mail.javamail.JavaMailSender; 12 | import org.springframework.stereotype.Service; 13 | import org.thymeleaf.context.Context; 14 | import org.thymeleaf.spring5.SpringTemplateEngine; 15 | 16 | import javax.mail.internet.InternetAddress; 17 | import javax.mail.internet.MimeMessage; 18 | import java.util.Random; 19 | 20 | /** 21 | * created by ayoung 2021/05/30 22 | */ 23 | @Slf4j 24 | @RequiredArgsConstructor 25 | @Service 26 | public class EmailService { 27 | 28 | private final JavaMailSender emailSender; 29 | private final RedisUtil redisUtil; 30 | private final EmailProperties emailProperties; 31 | private final UserValidator userValidator; 32 | private final SpringTemplateEngine templateEngine; 33 | 34 | public void sendEmailMessage(String email) { 35 | userValidator.checkEmailPresent(email); 36 | try { 37 | String code = createCode(); 38 | redisUtil.setDataExpire(code, email, emailProperties.getValidTime()); 39 | MimeMessage message = createMessage(email, code); 40 | emailSender.send(message); 41 | } catch (Exception e) { 42 | throw new EmailSendException(); 43 | } 44 | } 45 | 46 | private MimeMessage createMessage(String email, String code) throws Exception { 47 | MimeMessage message = emailSender.createMimeMessage(); 48 | message.addRecipients(MimeMessage.RecipientType.TO, email); 49 | message.setSubject("[buok] 비밀번호를 잊으셨나요? " + code); 50 | message.setText(setContext(code), "utf-8", "html"); 51 | message.setFrom(new InternetAddress(emailProperties.getLink(), emailProperties.getName())); 52 | return message; 53 | } 54 | 55 | private String setContext(String code) { 56 | Context context = new Context(); 57 | context.setVariable("code", code); 58 | return templateEngine.process("email", context); 59 | } 60 | 61 | private String createCode() { 62 | StringBuilder code = new StringBuilder(); 63 | Random rnd = new Random(); 64 | for (int i = 0; i < 7; i++) { 65 | int rIndex = rnd.nextInt(3); 66 | switch (rIndex) { 67 | case 0: 68 | code.append((char) (rnd.nextInt(26) + 97)); 69 | break; 70 | case 1: 71 | code.append((char) (rnd.nextInt(26) + 65)); 72 | break; 73 | case 2: 74 | code.append((rnd.nextInt(10))); 75 | break; 76 | } 77 | } 78 | return code.toString(); 79 | } 80 | 81 | public Long getUserIdByCode(String code) { 82 | String email = redisUtil.getData(code); 83 | if (email == null) { 84 | throw new EmailCodeException(); 85 | } 86 | 87 | User user = userValidator.checkEmailPresent(email); 88 | return user.getId(); 89 | } 90 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/FriendService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.yapp.ios1.dto.notification.NotificationForOneDto; 4 | import com.yapp.ios1.mapper.AlarmMapper; 5 | import com.yapp.ios1.mapper.FriendMapper; 6 | import com.yapp.ios1.model.user.Friend; 7 | import com.yapp.ios1.service.alarm.FirebaseService; 8 | import com.yapp.ios1.service.user.UserService; 9 | import com.yapp.ios1.utils.AlarmMessageUtil; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.transaction.annotation.Transactional; 14 | 15 | import java.time.LocalDateTime; 16 | import java.util.List; 17 | 18 | import static com.yapp.ios1.enums.AlarmStatus.FOLLOW_ALARM; 19 | import static com.yapp.ios1.enums.FriendStatus.FRIEND; 20 | import static com.yapp.ios1.enums.FriendStatus.REQUEST; 21 | import static com.yapp.ios1.message.AlarmMessage.*; 22 | 23 | /** 24 | * created by jg 2021/05/21 25 | */ 26 | @Slf4j 27 | @RequiredArgsConstructor 28 | @Service 29 | public class FriendService { // TODO 친구 관련 API 들이 N+1 쿼리가 너무 많음 => 리팩터링 필수 30 | 31 | private final FirebaseService firebaseService; 32 | private final FriendMapper followMapper; 33 | private final AlarmMapper alarmMapper; 34 | private final UserService userService; 35 | private final AlarmMessageUtil alarmMessage; 36 | 37 | // TODO 어떻게 리팩터링 할까 38 | @Transactional 39 | public void requestFollow(Long myUserId, Long friendId) { 40 | NotificationForOneDto notificationForOne = alarmMessage.createFollowAlarmMessage(FOLLOW_REQUEST_TITLE, FOLLOW_REQUEST_MESSAGE, friendId); 41 | // alarm_status = 1(전체알람), 2 (친구 알람) 42 | alarmMapper.insertFollowAlarmLog(notificationForOne, myUserId, FOLLOW_ALARM.get(), LocalDateTime.now(), friendId); 43 | followMapper.insertFollow(myUserId, friendId, REQUEST.get(), notificationForOne.getAlarmId()); 44 | userService.updateUserAlarmReadStatus(friendId, false); 45 | firebaseService.sendByTokenForOne(notificationForOne, myUserId); 46 | } 47 | 48 | public List getFriendList(Long userId) { 49 | return followMapper.getFollowListByUserId(userId); 50 | } 51 | 52 | // friendStatus = 1(친구), 2(요청 중) 53 | @Transactional 54 | public void checkFollowAccept(boolean isAccept, Long myUserId, Long friendId, Long alarmId) { 55 | if (isAccept) { 56 | acceptFollow(myUserId, friendId, alarmId); 57 | return; 58 | } 59 | noAcceptFollow(alarmId, myUserId, friendId); 60 | } 61 | 62 | // TODO 어떻게 리팩터링 할까 63 | private void acceptFollow(Long myUserId, Long friendId, Long alarmId) { 64 | NotificationForOneDto notificationForOne = alarmMessage.createFollowAlarmMessage(FOLLOW_ACCEPT_TITLE, FOLLOW_ACCEPT_MESSAGE, friendId); 65 | alarmMapper.updateFollowAlarmLog(notificationForOne, alarmId); 66 | alarmMapper.insertFollowAlarmLog(notificationForOne, myUserId, FOLLOW_ALARM.get(), LocalDateTime.now(), friendId); 67 | followMapper.insertFollow(myUserId, friendId, FRIEND.get(), notificationForOne.getAlarmId()); 68 | followMapper.updateFriendStatus(myUserId, friendId, FRIEND.get()); 69 | userService.updateUserAlarmReadStatus(friendId, false); 70 | firebaseService.sendByTokenForOne(notificationForOne, myUserId); 71 | } 72 | 73 | // TODO 리팩터링 74 | private void noAcceptFollow(Long alarmId, Long myUserId, Long friendId) { 75 | followMapper.deleteFriend(myUserId, friendId); 76 | followMapper.deleteFriend(friendId, myUserId); 77 | alarmMapper.deleteFollowAlarmLog(alarmId); 78 | } 79 | 80 | // TODO: 망가진 API (어떻게 리팩터링 할까) => Mybatis에서 Multi Query 지원 하는 듯 81 | @Transactional 82 | public void deleteFriend(Long myUserId, Long friendId) { 83 | Long followRequestAlarmId = getFollowAlarmId(myUserId, friendId); 84 | Long followAcceptAlarmId = getFollowAlarmId(friendId, myUserId); 85 | alarmMapper.deleteFollowAlarmLog(followRequestAlarmId); 86 | alarmMapper.deleteFollowAlarmLog(followAcceptAlarmId); 87 | followMapper.deleteFriend(myUserId, friendId); 88 | followMapper.deleteFriend(friendId, myUserId); 89 | } 90 | 91 | private Long getFollowAlarmId(Long myUserId, Long friendId) { 92 | return followMapper.findByFollowAlarmId(myUserId, friendId); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/OauthService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.yapp.ios1.model.user.User; 4 | import com.yapp.ios1.dto.user.UserStatusDto; 5 | import com.yapp.ios1.controller.dto.user.login.SignUpDto; 6 | import com.yapp.ios1.controller.dto.user.social.SocialLoginDto; 7 | import com.yapp.ios1.properties.SocialLoginProperties; 8 | import com.yapp.ios1.service.jwt.JwtService; 9 | import com.yapp.ios1.service.user.UserFindService; 10 | import com.yapp.ios1.service.user.UserService; 11 | import com.yapp.ios1.validator.UserValidator; 12 | import lombok.RequiredArgsConstructor; 13 | import org.springframework.http.*; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.Optional; 18 | 19 | /** 20 | * created by ayoung 2021/05/04 21 | */ 22 | @RequiredArgsConstructor 23 | @Service 24 | public class OauthService { 25 | 26 | private final UserService userService; 27 | private final UserFindService userFindService; 28 | private final UserValidator userValidator; 29 | private final JwtService jwtService; 30 | private final SocialLoginProperties socialLoginProperties; 31 | 32 | @Transactional 33 | public UserStatusDto getSocialUser(String socialType, SocialLoginDto socialDto) { 34 | String socialId = socialDto.getSocialId(); 35 | String email = socialDto.getEmail(); 36 | 37 | Optional optionalUser = userFindService.findBySocialIdAndSocialType(socialId, socialType); 38 | 39 | if (optionalUser.isEmpty()) { 40 | if (!email.equals("")) { 41 | userValidator.checkEmailDuplicate(email); 42 | } 43 | return socialSignUp(socialType, socialDto); 44 | } 45 | return new UserStatusDto(HttpStatus.OK, jwtService.createTokenResponse(optionalUser.get().getId())); 46 | } 47 | 48 | private UserStatusDto socialSignUp(String socialType, SocialLoginDto socialDto) { 49 | SignUpDto signUpDto = SignUpDto.builder() 50 | .socialType(socialType) 51 | .email(socialDto.getEmail()) 52 | .password(socialLoginProperties.getKey()) 53 | .socialId(socialDto.getSocialId()) 54 | .deviceToken(socialDto.getDeviceToken()) 55 | .build(); 56 | return new UserStatusDto(HttpStatus.CREATED, userService.signUp(User.of(signUpDto))); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/S3Service.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.amazonaws.services.s3.AmazonS3Client; 4 | import com.amazonaws.services.s3.model.CannedAccessControlList; 5 | import com.amazonaws.services.s3.model.ObjectMetadata; 6 | import com.amazonaws.services.s3.model.PutObjectRequest; 7 | import com.amazonaws.util.IOUtils; 8 | import com.yapp.ios1.error.exception.aws.S3Exception; 9 | import com.yapp.ios1.properties.S3Properties; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.multipart.MultipartFile; 14 | 15 | import java.io.ByteArrayInputStream; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.UUID; 19 | 20 | /** 21 | * created by ayoung 2021/03/29 22 | */ 23 | @Slf4j 24 | @RequiredArgsConstructor 25 | @Service 26 | public class S3Service { 27 | 28 | private final AmazonS3Client s3Client; 29 | private final S3Properties s3Properties; 30 | 31 | public List upload(MultipartFile[] multipartFileList, Long userId) { 32 | List imageUrlList = new ArrayList<>(); 33 | for (MultipartFile multipartFile : multipartFileList) { 34 | imageUrlList.add(upload(multipartFile, userId)); 35 | } 36 | return imageUrlList; 37 | } 38 | 39 | public String upload(MultipartFile file, Long userId) { 40 | try { 41 | String fileName = userId + "-" + UUID.randomUUID() + "-" + file.getOriginalFilename(); 42 | ObjectMetadata objMeta = new ObjectMetadata(); 43 | 44 | byte[] bytes = IOUtils.toByteArray(file.getInputStream()); 45 | objMeta.setContentLength(bytes.length); 46 | 47 | ByteArrayInputStream byteArrayIs = new ByteArrayInputStream(bytes); 48 | 49 | s3Client.putObject(new PutObjectRequest(s3Properties.getBucket(), s3Properties.getDir() + fileName, byteArrayIs, objMeta) 50 | .withCannedAcl(CannedAccessControlList.PublicRead)); 51 | 52 | return s3Client.getUrl(s3Properties.getBucket(), s3Properties.getDir() + fileName).toString(); 53 | } catch (Exception e) { 54 | throw new S3Exception(); 55 | } 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/SearchService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.yapp.ios1.mapper.SearchMapper; 4 | import com.yapp.ios1.model.bucket.Bucket; 5 | import com.yapp.ios1.model.user.Friend; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * created by jg 2021/05/17 13 | */ 14 | @RequiredArgsConstructor 15 | @Service 16 | public class SearchService { 17 | 18 | private final SearchMapper searchMapper; 19 | 20 | public List searchMyBook(String keyword, Long userId) { 21 | return searchMapper.searchMyBook(keyword, userId); 22 | } 23 | 24 | public List searchUser(String keyword, Long userId) { 25 | return searchMapper.searchUser(keyword, userId); 26 | } 27 | 28 | public List searchBookMark(String keyword, Long userId) { 29 | return searchMapper.searchBookMark(keyword, userId); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/alarm/AlarmService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.alarm; 2 | 3 | import com.yapp.ios1.mapper.AlarmMapper; 4 | import com.yapp.ios1.mapper.UserMapper; 5 | import com.yapp.ios1.model.notification.Notification; 6 | import com.yapp.ios1.validator.AlarmValidator; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.scheduling.annotation.Scheduled; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.Comparator; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | import java.util.stream.Stream; 15 | 16 | import static com.yapp.ios1.enums.AlarmStatus.WHOLE_ALARM; 17 | 18 | /** 19 | * created by jg 2021/06/10 20 | */ 21 | @RequiredArgsConstructor 22 | @Service 23 | public class AlarmService { 24 | 25 | private final FirebaseService firebaseService; 26 | private final AlarmValidator alarmValidator; 27 | private final AlarmMapper alarmMapper; 28 | private final UserMapper userMapper; 29 | 30 | public List getAlarmLog(Long userId) { 31 | List followAlarmLog = alarmMapper.getFollowAlarmLog(userId); 32 | List commonAlarmLog = alarmMapper.getCommonAlarmLog(userId); 33 | // 알림 로그 읽었다는 뜻 34 | userMapper.updateAlarmStatus(userId, true); 35 | 36 | return Stream.concat(followAlarmLog.stream(), commonAlarmLog.stream()) 37 | .sorted(Comparator.comparing(Notification::getCreatedAt)) 38 | .collect(Collectors.toList()); 39 | } 40 | 41 | public void deleteAlarm(Long alarmId, Long userId, int alarmStatus) { 42 | if (alarmStatus == WHOLE_ALARM.get()) { 43 | alarmValidator.checkValidWholeAlarm(alarmId); 44 | alarmMapper.deleteWholeAlarmLog(alarmId, userId); 45 | return; 46 | } 47 | 48 | alarmValidator.checkValidFollowAlarm(alarmId); 49 | alarmMapper.deleteFollowAlarmLog(alarmId); 50 | } 51 | 52 | // // 초, 분, 시간, 일, 월, 요일 (매월, 1일, 20시 53분 30초에 알림을 보내도록 임시로 설정) 53 | // @Scheduled(cron = "10 12 14 * * ?", zone = "Asia/Seoul") 54 | // public void notificationSchedule() { 55 | // alarmMapper.insertWholeAlarmLog(firebaseService.getWholeAlarmMessage(), WHOLE_ALARM.get()); // alarm_status = 1 (전체 알람) 56 | // firebaseService.sendByTokenForMulti(); 57 | // } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/alarm/FirebaseService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.alarm; 2 | 3 | import com.google.auth.oauth2.GoogleCredentials; 4 | import com.google.firebase.messaging.*; 5 | import com.yapp.ios1.dto.notification.FcmMessage; 6 | import com.yapp.ios1.dto.notification.NotificationDto; 7 | import com.yapp.ios1.dto.notification.NotificationForOneDto; 8 | import com.yapp.ios1.model.user.User; 9 | import com.yapp.ios1.properties.FirebaseProperties; 10 | import com.yapp.ios1.service.user.UserFindService; 11 | import lombok.RequiredArgsConstructor; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.core.io.ClassPathResource; 14 | import org.springframework.http.*; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | import javax.annotation.PostConstruct; 19 | import java.io.IOException; 20 | import java.time.LocalDateTime; 21 | import java.util.List; 22 | import java.util.stream.Collectors; 23 | 24 | import static com.yapp.ios1.message.AlarmMessage.WHOLE_ALARM_MESSAGE; 25 | import static com.yapp.ios1.message.AlarmMessage.WHOLE_ALARM_TITLE; 26 | 27 | /** 28 | * created by jg 2021/05/02 29 | */ 30 | @RequiredArgsConstructor 31 | @Slf4j 32 | @Service 33 | public class FirebaseService { 34 | 35 | private final UserFindService userFindService; 36 | private final FirebaseProperties firebaseProperties; 37 | private final RestTemplate restTemplate; 38 | private String fcmAccessToken; 39 | 40 | @PostConstruct 41 | public void init() { 42 | try { 43 | GoogleCredentials googleCredentials = 44 | GoogleCredentials.fromStream(new ClassPathResource(firebaseProperties.getPath()).getInputStream()) 45 | .createScoped(List.of("https://www.googleapis.com/auth/cloud-platform")); 46 | googleCredentials.refreshIfExpired(); 47 | fcmAccessToken = googleCredentials.getAccessToken().getTokenValue(); 48 | } catch (IOException e) { 49 | log.error("cannot initial firebase " + e.getMessage()); 50 | } 51 | } 52 | 53 | public void sendByTokenForMulti() { 54 | List deviceTokens = userFindService.getAllDeviceToken(); 55 | NotificationDto pushNotificationRequest = getWholeAlarmMessage(); 56 | 57 | List messages = deviceTokens.stream().map(token -> Message.builder() 58 | .putData("title", pushNotificationRequest.getTitle()) 59 | .putData("message", pushNotificationRequest.getMessage()) 60 | .setToken(token) 61 | .build()).collect(Collectors.toList()); 62 | 63 | BatchResponse response; 64 | try { 65 | response = FirebaseMessaging.getInstance().sendAll(messages); 66 | log.info("send message: " + response); 67 | } catch (FirebaseMessagingException e) { 68 | log.error("cannot send to member push message. error info : {}", e.getMessage()); 69 | } 70 | } 71 | 72 | public void sendByTokenForOne(NotificationForOneDto messageInfo, Long userId) { 73 | HttpHeaders headers = new HttpHeaders(); 74 | headers.setBearerAuth(fcmAccessToken); 75 | headers.setContentType(MediaType.APPLICATION_JSON); 76 | 77 | FcmMessage message = makeMessage(messageInfo, userId); 78 | 79 | HttpEntity request = new HttpEntity<>(message, headers); 80 | try { 81 | ResponseEntity response = restTemplate.exchange( 82 | "https://fcm.googleapis.com/v1/projects/buok-ios/messages:send", 83 | HttpMethod.POST, 84 | request, 85 | String.class 86 | ); 87 | log.info("send message: " + response); 88 | } catch (Exception e) { 89 | log.error("cannot send message by token. error info : {}", e.getMessage()); 90 | } 91 | } 92 | 93 | private FcmMessage makeMessage(NotificationForOneDto messageInfo, Long userId) { 94 | User user = userFindService.getUser(userId); 95 | return FcmMessage.builder() 96 | .message(FcmMessage.Message.builder() 97 | .token(messageInfo.getDeviceToken()) 98 | .notification(FcmMessage.Notification.builder() 99 | .title(messageInfo.getTitle()) 100 | .body(user.getNickname() + messageInfo.getMessage()) 101 | .build()) 102 | .build() 103 | ) 104 | .build(); 105 | } 106 | 107 | public NotificationDto getWholeAlarmMessage() { 108 | return new NotificationDto(WHOLE_ALARM_TITLE, WHOLE_ALARM_MESSAGE, LocalDateTime.now()); 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/bucket/BucketFindService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.bucket; 2 | 3 | import com.yapp.ios1.dto.bucket.BucketDetailDto; 4 | import com.yapp.ios1.dto.bucket.BucketHomeDto; 5 | import com.yapp.ios1.error.exception.bucket.BucketNotFoundException; 6 | import com.yapp.ios1.mapper.BucketMapper; 7 | import com.yapp.ios1.mapper.UserMapper; 8 | import com.yapp.ios1.model.bookmark.Bookmark; 9 | import com.yapp.ios1.model.bucket.Bucket; 10 | import com.yapp.ios1.model.bucket.BucketTimeline; 11 | import com.yapp.ios1.model.image.Image; 12 | import com.yapp.ios1.model.tag.Tag; 13 | import lombok.RequiredArgsConstructor; 14 | import org.springframework.stereotype.Service; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * created by jg 2021/06/15 20 | */ 21 | @RequiredArgsConstructor 22 | @Service 23 | public class BucketFindService { 24 | 25 | private final BucketMapper bucketMapper; 26 | private final UserMapper userMapper; 27 | 28 | public BucketHomeDto getHomeBucketList(int bucketState, int category, Long userId, int sort) { 29 | List buckets = bucketMapper.findByBucketStateAndCategory(bucketState, category, userId, sort); 30 | return BucketHomeDto.builder() 31 | .buckets(buckets) 32 | .bucketCount(buckets.size()) 33 | .isAlarmCheck(userMapper.alarmCheckStatus(userId)) 34 | .build(); 35 | } 36 | 37 | public BucketDetailDto getBucketDetail(Long bucketId) { 38 | return new BucketDetailDto( 39 | getBucket(bucketId), 40 | getBucketImage(bucketId), 41 | getBucketTag(bucketId), 42 | getBucketTimeline(bucketId) 43 | ); 44 | } 45 | 46 | public Bucket getBucket(Long bucketId) { 47 | return bucketMapper.findByBucketId(bucketId) 48 | .orElseThrow(BucketNotFoundException::new); 49 | } 50 | 51 | public Bucket getBucket(Long bucketId, Long userId) { 52 | return bucketMapper.findByBucketIdAndUserId(bucketId, userId) 53 | .orElseThrow(BucketNotFoundException::new); 54 | } 55 | 56 | private List getBucketTag(Long bucketId) { 57 | return bucketMapper.findByBucketTagByBucketId(bucketId); 58 | } 59 | 60 | private List getBucketImage(Long bucketId) { 61 | return bucketMapper.findByBucketImageByBucketId(bucketId); 62 | } 63 | 64 | private List getBucketTimeline(Long bucketId) { 65 | return bucketMapper.findByBucketTimelineByBucketId(bucketId); 66 | } 67 | 68 | public List getUserBucketList(Long userId) { 69 | return bucketMapper.findByUserId(userId); 70 | } 71 | 72 | public List getBookmarkList(Long userId) { 73 | return bucketMapper.findBookmarkListByUserId(userId); 74 | } 75 | 76 | public int getBucketCountByUserId(Long userId) { 77 | return bucketMapper.getBucketCountByUserId(userId); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/bucket/BucketService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.bucket; 2 | 3 | import com.yapp.ios1.controller.dto.bucket.BucketRequestDto; 4 | import com.yapp.ios1.mapper.BucketMapper; 5 | import com.yapp.ios1.model.bucket.Bucket; 6 | import com.yapp.ios1.validator.BucketValidator; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import java.util.List; 13 | 14 | import static com.yapp.ios1.enums.BucketLogStatus.*; 15 | 16 | /** 17 | * created by jg 2021/05/05 18 | */ 19 | @Slf4j 20 | @RequiredArgsConstructor 21 | @Service 22 | public class BucketService { 23 | 24 | private final BucketFindService bucketFindService; 25 | private final BucketValidator bucketValidator; 26 | private final BucketMapper bucketMapper; 27 | 28 | @Transactional 29 | public void saveBucket(BucketRequestDto registerDto) { 30 | bucketMapper.registerBucket(registerDto); 31 | 32 | Long bucketId = registerDto.getId(); 33 | saveTagList(bucketId, registerDto.getTagList()); 34 | saveImageUrlList(bucketId, registerDto.getImageList()); 35 | } 36 | 37 | @Transactional 38 | public void updateBucket(Long bucketId, BucketRequestDto updateDto, Long userId) { 39 | Bucket bucketDto = bucketFindService.getBucket(bucketId, userId); 40 | 41 | String updateBucketName = updateDto.getBucketName(); 42 | String updateEndDate = updateDto.getEndDate().toString(); 43 | 44 | updateDto.setId(bucketId); 45 | bucketMapper.updateBucket(updateDto); 46 | 47 | updateTag(bucketId, updateDto.getTagList()); 48 | updateImageUrlList(bucketId, updateDto.getImageList()); 49 | 50 | if (!updateBucketName.equals(bucketDto.getBucketName())) { 51 | bucketMapper.saveBucketLog(bucketId, updateBucketName, BUCKET_NAME_LOG.get()); 52 | } 53 | 54 | if (!updateEndDate.equals(bucketDto.getEndDate())) { 55 | bucketMapper.saveBucketLog(bucketId, updateEndDate.replaceAll("-", ". "), BUCKET_END_DATE_LOG.get()); 56 | } 57 | } 58 | 59 | private void saveTagList(Long bucketId, List tagList) { 60 | if (!tagList.isEmpty()) { 61 | bucketMapper.saveTagList(tagList); 62 | bucketMapper.saveBucketIdAndTagId(bucketId, tagList); 63 | } 64 | } 65 | 66 | private void updateTag(Long bucketId, List tagList) { 67 | bucketMapper.deleteTagListByBucketId(bucketId); 68 | saveTagList(bucketId, tagList); 69 | } 70 | 71 | private void saveImageUrlList(Long bucketId, List imageUrlList) { 72 | if (!imageUrlList.isEmpty()) { 73 | bucketMapper.saveBucketImageUrlList(bucketId, imageUrlList); 74 | } 75 | } 76 | 77 | private void updateImageUrlList(Long bucketId, List imageUrlList) { 78 | bucketMapper.deleteImageListByBucketId(bucketId); 79 | saveImageUrlList(bucketId, imageUrlList); 80 | } 81 | 82 | // TODO 모든 버킷마다 검증하는 메소드가 들어가는데 이거를 AOP 로 빼던가 해보아도 좋을 거 같음 (얘기 해보기) 83 | public void saveBookmark(Long bucketId, Long userId, boolean isBookmark) { 84 | bucketValidator.checkValidBucket(bucketId, userId); 85 | bucketMapper.setBookmark(bucketId, isBookmark); 86 | } 87 | 88 | public void setBucketFin(Long bucketId, Long userId, boolean isFin) { 89 | bucketValidator.checkValidBucket(bucketId, userId); 90 | bucketMapper.setBucketFin(bucketId, isFin); 91 | } 92 | 93 | @Transactional 94 | public void updateBucketState(Long userId, Long bucketId, int bucketStateId) { 95 | bucketValidator.checkValidBucketStateId(bucketStateId); 96 | bucketValidator.checkValidBucket(bucketId, userId); 97 | bucketMapper.updateBucketState(bucketId, userId, bucketStateId); 98 | } 99 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/jwt/JwtIssueService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.jwt; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.yapp.ios1.config.CacheKey; 6 | import com.yapp.ios1.dto.jwt.JwtPayload; 7 | import com.yapp.ios1.error.exception.common.JsonWriteException; 8 | import com.yapp.ios1.mapper.TokenMapper; 9 | import com.yapp.ios1.properties.JwtProperties; 10 | import io.jsonwebtoken.Jwts; 11 | import io.jsonwebtoken.SignatureAlgorithm; 12 | import lombok.RequiredArgsConstructor; 13 | import org.springframework.cache.annotation.CachePut; 14 | import org.springframework.cache.annotation.Cacheable; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.transaction.annotation.Transactional; 17 | 18 | import javax.crypto.spec.SecretKeySpec; 19 | import javax.xml.bind.DatatypeConverter; 20 | import java.security.Key; 21 | import java.util.Date; 22 | 23 | /** 24 | * created by ayoung 2021/06/03 25 | */ 26 | @RequiredArgsConstructor 27 | @Service 28 | public class JwtIssueService { 29 | 30 | private final JwtProperties jwtProperties; 31 | private final ObjectMapper objectMapper; 32 | private final TokenMapper tokenMapper; 33 | 34 | private String createToken(JwtPayload payload, Long expireTime) { 35 | SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; 36 | byte[] secretKeyBytes = DatatypeConverter.parseBase64Binary(jwtProperties.getSecretKey()); 37 | Key signingKey = new SecretKeySpec(secretKeyBytes, signatureAlgorithm.getJcaName()); 38 | return Jwts.builder() 39 | .setSubject(writeJsonAsString(payload)) 40 | .signWith(signingKey, signatureAlgorithm) 41 | .setExpiration(new Date(System.currentTimeMillis() + expireTime)) 42 | .compact(); 43 | } 44 | 45 | private String writeJsonAsString(JwtPayload payload) { 46 | try { 47 | return objectMapper.writeValueAsString(payload.getId()); 48 | } catch (JsonProcessingException e) { 49 | throw new JsonWriteException(); 50 | } 51 | } 52 | 53 | public String createAccessToken(JwtPayload payload) { 54 | return createToken(payload, jwtProperties.getAccessToken().getValidTime()); 55 | } 56 | 57 | @Transactional 58 | @CachePut(value = CacheKey.TOKEN, key = "#payload.id") 59 | public String createRefreshToken(JwtPayload payload) { 60 | String refreshToken = createToken(payload, jwtProperties.getRefreshToken().getValidTime()); 61 | tokenMapper.updateToken(refreshToken, payload.getId()); 62 | return refreshToken; 63 | } 64 | 65 | @Cacheable(value = CacheKey.TOKEN, key = "#userId") 66 | public String getRefreshTokenByUserId(Long userId) { 67 | return tokenMapper.getTokenByUserId(userId); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/jwt/JwtService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.jwt; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.yapp.ios1.dto.jwt.JwtPayload; 6 | import com.yapp.ios1.dto.jwt.TokenResponseDto; 7 | import com.yapp.ios1.properties.JwtProperties; 8 | import io.jsonwebtoken.Claims; 9 | import io.jsonwebtoken.Jwts; 10 | import lombok.RequiredArgsConstructor; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.xml.bind.DatatypeConverter; 15 | import java.util.Date; 16 | import java.util.function.Function; 17 | 18 | /** 19 | * created by jg 2021/04/11 20 | */ 21 | @Slf4j 22 | @RequiredArgsConstructor 23 | @Service 24 | public class JwtService { 25 | 26 | private final JwtIssueService jwtIssueService; 27 | private final JwtProperties jwtProperties; 28 | private final ObjectMapper objectMapper; 29 | 30 | public JwtPayload getPayload(String token) throws JsonProcessingException { 31 | Claims claims = getAllClaimsFromToken(token); 32 | return objectMapper.readValue(claims.getSubject(), JwtPayload.class); 33 | } 34 | 35 | public Date getExpirationDateFromToken(String token) { 36 | return getClaimFromToken(token, Claims::getExpiration); 37 | } 38 | 39 | public T getClaimFromToken(String token, Function claimsResolver) { 40 | final Claims claims = getAllClaimsFromToken(token); 41 | return claimsResolver.apply(claims); 42 | } 43 | 44 | private Claims getAllClaimsFromToken(String token) { 45 | return Jwts.parserBuilder() 46 | .setSigningKey(DatatypeConverter.parseBase64Binary(jwtProperties.getSecretKey())) 47 | .build() 48 | .parseClaimsJws(token) 49 | .getBody(); 50 | } 51 | 52 | public TokenResponseDto createTokenResponse(Long userId) { 53 | JwtPayload jwtPayload = new JwtPayload(userId); 54 | String accessToken = jwtIssueService.createAccessToken(jwtPayload); 55 | String refreshToken = jwtIssueService.createRefreshToken(jwtPayload); 56 | 57 | return TokenResponseDto.builder() 58 | .accessToken(accessToken) 59 | .refreshToken(refreshToken) 60 | .accessExpiredAt(getExpirationDateFromToken(accessToken)) 61 | .refreshExpiredAt(getExpirationDateFromToken(refreshToken)) 62 | .build(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/user/ProfileService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.user; 2 | 3 | import com.yapp.ios1.controller.dto.user.ProfileUpdateDto; 4 | import com.yapp.ios1.error.exception.user.NickNameDuplicatedException; 5 | import com.yapp.ios1.error.exception.user.UserNotFoundException; 6 | import com.yapp.ios1.mapper.ProfileMapper; 7 | import com.yapp.ios1.model.user.Profile; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | /** 13 | * created by jg 2021/06/11 14 | */ 15 | @RequiredArgsConstructor 16 | @Service 17 | public class ProfileService { 18 | 19 | private final ProfileMapper profileMapper; 20 | 21 | public Profile getProfile(Long userId) { 22 | return profileMapper.findProfileByUserId(userId) 23 | .orElseThrow(UserNotFoundException::new); 24 | } 25 | 26 | @Transactional 27 | public void updateProfile(ProfileUpdateDto profileUpdateDto, Long userId) { 28 | int change = profileMapper.updateProfile(profileUpdateDto, userId); 29 | if (change == 0) { 30 | throw new NickNameDuplicatedException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/user/UserFindService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.user; 2 | 3 | import com.yapp.ios1.error.exception.user.DeviceTokenNotFoundException; 4 | import com.yapp.ios1.error.exception.user.UserNotFoundException; 5 | import com.yapp.ios1.mapper.UserMapper; 6 | import com.yapp.ios1.model.user.User; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | import java.util.Optional; 12 | 13 | /** 14 | * created by jg 2021/06/15 15 | */ 16 | @RequiredArgsConstructor 17 | @Service 18 | public class UserFindService { 19 | 20 | private final UserMapper userMapper; 21 | 22 | public String getDeviceToken(Long userId) { 23 | return userMapper.findDeviceTokenByUserId(userId) 24 | .orElseThrow(DeviceTokenNotFoundException::new); 25 | } 26 | 27 | public List getAllDeviceToken() { 28 | return userMapper.findAllUserDeviceToken(); 29 | } 30 | 31 | public User getUser(Long userId) { 32 | return userMapper.findByUserId(userId) 33 | .orElseThrow(UserNotFoundException::new); 34 | } 35 | 36 | public Optional findBySocialIdAndSocialType(String socialId, String socialType) { 37 | return userMapper.findBySocialIdAndSocialType(socialId, socialType); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/user/UserInfoService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.user; 2 | 3 | import com.yapp.ios1.dto.bookmark.BookmarkListDto; 4 | import com.yapp.ios1.dto.user.UserInfoDto; 5 | import com.yapp.ios1.mapper.FriendMapper; 6 | import com.yapp.ios1.model.bookmark.Bookmark; 7 | import com.yapp.ios1.model.user.Profile; 8 | import com.yapp.ios1.service.bucket.BucketFindService; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * created by ayoung 2021/06/12 18 | */ 19 | @RequiredArgsConstructor 20 | @Service 21 | public class UserInfoService { 22 | 23 | private final ProfileService profileService; 24 | private final BucketFindService bucketFindService; 25 | private final FriendMapper friendMapper; 26 | 27 | @Transactional(readOnly = true) 28 | public UserInfoDto getOtherUserInfo(Long myUserId, Long otherUserId) { 29 | UserInfoDto userInfo = getUserInfo(otherUserId); 30 | 31 | int friendStatus = friendMapper.checkFriendStatus(myUserId, otherUserId); 32 | userInfo.setFriend(friendStatus); 33 | // 친구 일 때 34 | if (friendStatus == 1) { 35 | userInfo.setBucket(bucketFindService.getUserBucketList(otherUserId)); 36 | } 37 | 38 | return userInfo; 39 | } 40 | 41 | @Transactional(readOnly = true) 42 | public UserInfoDto getUserInfo(Long userId) { 43 | Profile profile = profileService.getProfile(userId); 44 | 45 | int friendCount = friendMapper.getFollowCountByUserId(userId); 46 | int bucketCount = bucketFindService.getBucketCountByUserId(userId); 47 | 48 | List bookmarkList = bucketFindService.getBookmarkList(userId); 49 | 50 | return UserInfoDto.builder() 51 | .user(profile) 52 | .friendCount(friendCount) 53 | .bucketCount(bucketCount) 54 | .bookmark(new BookmarkListDto(bookmarkList, bookmarkList.size())) 55 | .build(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/service/user/UserService.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service.user; 2 | 3 | import com.yapp.ios1.dto.jwt.TokenResponseDto; 4 | import com.yapp.ios1.mapper.UserMapper; 5 | import com.yapp.ios1.model.user.User; 6 | import com.yapp.ios1.service.jwt.JwtService; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.stereotype.Service; 11 | 12 | /** 13 | * created by jg 2021/03/28 14 | */ 15 | @Slf4j 16 | @RequiredArgsConstructor 17 | @Service 18 | public class UserService { 19 | 20 | private final PasswordEncoder passwordEncoder; 21 | private final JwtService jwtService; 22 | private final UserMapper userMapper; 23 | 24 | // 최신 알림 로그 확인한 상태(true), 확인하지 않은 알림 로그가 존재하는 상태(false) 25 | public void updateUserAlarmReadStatus(Long userId, boolean alarmReadStatus) { 26 | userMapper.updateAlarmStatus(userId, alarmReadStatus); 27 | } 28 | 29 | public TokenResponseDto signUp(User user) { 30 | user.encodePassword(passwordEncoder.encode(user.getPassword())); 31 | userMapper.signUp(user); 32 | return jwtService.createTokenResponse(user.getId()); 33 | } 34 | 35 | public void changePassword(Long userId, String password) { 36 | String encodePassword = passwordEncoder.encode(password); 37 | userMapper.changePassword(userId, encodePassword); 38 | } 39 | 40 | public void deleteUser(Long userId) { 41 | userMapper.deleteUser(userId); 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/utils/AlarmMessageUtil.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.utils; 2 | 3 | import com.yapp.ios1.dto.notification.NotificationForOneDto; 4 | import com.yapp.ios1.service.user.UserFindService; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * created by jg 2021/06/12 10 | */ 11 | @RequiredArgsConstructor 12 | @Component 13 | public class AlarmMessageUtil { 14 | 15 | private final UserFindService userFindService; 16 | 17 | public NotificationForOneDto createFollowAlarmMessage(String title, String message, Long sendUserId) { 18 | String deviceToken = userFindService.getDeviceToken(sendUserId); 19 | return NotificationForOneDto.builder() 20 | .title(title) 21 | .message(message) 22 | .deviceToken(deviceToken) 23 | .build(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/utils/RedisUtil.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.utils; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.data.redis.core.StringRedisTemplate; 5 | import org.springframework.data.redis.core.ValueOperations; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.time.Duration; 10 | 11 | /** 12 | * created by ayoung 2021/05/23 13 | */ 14 | @RequiredArgsConstructor 15 | @Component 16 | public class RedisUtil { 17 | 18 | private final StringRedisTemplate redisTemplate; 19 | 20 | public String getData(String key) { 21 | ValueOperations valueOperations = redisTemplate.opsForValue(); 22 | return valueOperations.get(key); 23 | } 24 | 25 | public void setDataExpire(String key, String value, long duration) { 26 | ValueOperations valueOperations = redisTemplate.opsForValue(); 27 | Duration expireDuration = Duration.ofMillis(duration); 28 | valueOperations.set(key, value, expireDuration); 29 | } 30 | 31 | public void deleteData(String key) { 32 | redisTemplate.delete(key); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/validator/AlarmValidator.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.validator; 2 | 3 | import com.yapp.ios1.error.exception.alarm.AlarmNotFoundException; 4 | import com.yapp.ios1.mapper.AlarmMapper; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * created by jg 2021/06/10 10 | */ 11 | @RequiredArgsConstructor 12 | @Component 13 | public class AlarmValidator { 14 | 15 | private final AlarmMapper alarmMapper; 16 | 17 | public void checkValidWholeAlarm(Long alarmId) { 18 | alarmMapper.findWholeAlarmByAlarmId(alarmId) 19 | .orElseThrow(AlarmNotFoundException::new); 20 | } 21 | 22 | public void checkValidFollowAlarm(Long alarmId) { 23 | alarmMapper.findFollowAlarmByAlarmId(alarmId) 24 | .orElseThrow(AlarmNotFoundException::new); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/validator/BucketValidator.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.validator; 2 | 3 | import com.yapp.ios1.error.exception.bucket.BucketNotFoundException; 4 | import com.yapp.ios1.error.exception.bucket.bucketStateIdInvalidException; 5 | import com.yapp.ios1.mapper.BucketMapper; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.stereotype.Component; 8 | 9 | import static com.yapp.ios1.enums.BucketStatus.BUCKET_FAIL; 10 | import static com.yapp.ios1.enums.BucketStatus.BUCKET_WHOLE; 11 | 12 | /** 13 | * created by jg 2021/06/10 14 | */ 15 | @RequiredArgsConstructor 16 | @Component 17 | public class BucketValidator { 18 | 19 | private final BucketMapper bucketMapper; 20 | 21 | // TODO findByBucketIdAndUserId 과 checkValidBucket 이름의 관계를 다시 생각해보기.. 22 | public void checkValidBucket(Long bucketId, Long userId) { 23 | bucketMapper.findByBucketIdAndUserId(bucketId, userId) 24 | .orElseThrow(BucketNotFoundException::new); 25 | } 26 | 27 | // TODO Validate 책임 28 | public void checkValidBucketStateId(int bucketStateId) { 29 | if (bucketStateId <= BUCKET_WHOLE.get() || bucketStateId > BUCKET_FAIL.get()) { 30 | throw new bucketStateIdInvalidException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/yapp/ios1/validator/UserValidator.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.validator; 2 | 3 | import com.yapp.ios1.controller.dto.user.login.SignInDto; 4 | import com.yapp.ios1.error.exception.user.*; 5 | import com.yapp.ios1.mapper.UserMapper; 6 | import com.yapp.ios1.model.user.User; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.Optional; 12 | 13 | /** 14 | * created by jg 2021/06/10 15 | */ 16 | @RequiredArgsConstructor 17 | @Component 18 | public class UserValidator { 19 | 20 | private final UserMapper userMapper; 21 | private final PasswordEncoder passwordEncoder; 22 | 23 | public void checkEmailDuplicate(String email) { 24 | Optional user = userMapper.findByEmail(email); 25 | if (user.isPresent()) { 26 | throw new EmailDuplicatedException(); 27 | } 28 | } 29 | 30 | public User checkEmailPresent(String email) { 31 | return userMapper.findByEmail(email) 32 | .orElseThrow(EmailNotExistException::new); 33 | } 34 | 35 | public void checkNickName(String nickname) { 36 | Optional user = userMapper.findByNickname(nickname); 37 | if (user.isPresent()) { 38 | throw new NickNameDuplicatedException(); 39 | } 40 | } 41 | 42 | public User checkPassword(SignInDto signInDto) { 43 | User user = userMapper.findByEmail(signInDto.getEmail()) 44 | .orElseThrow(UserNotFoundException::new); 45 | 46 | if (!passwordEncoder.matches(signInDto.getPassword(), user.getPassword())) { 47 | throw new PasswordNotMatchException(); 48 | } 49 | 50 | return user; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ${SLACK_WEBHOOK_URI} 6 | 7 | %d{yyyy-MM-dd HH:mm:ss.SSS} %msg %n 8 | 9 | Buok-Server-log 10 | :stuck_out_tongue_winking_eye: 11 | true 12 | 13 | 14 | 15 | 16 | 17 | %d %-5level %logger{35} - %msg%n 18 | 19 | 20 | 21 | 22 | 23 | 24 | ERROR 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ERROR 12 | 13 | 14 | 15 | 16 | [%date] %highlight([%level]) [%logger{10} %file:%line] %msg%n 17 | 18 | 19 | 20 | YAPP-log 21 | 22 | 23 | YAPP/ 24 | 25 | 26 | ap-northeast-2 27 | 28 | 29 | 30 | 50 31 | 32 | 33 | 34 | 30000 35 | 36 | 37 | 38 | 39 | 5000 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 47 | 48 | 49 | 50 | 51 | [%date] %highlight([%level]) [%logger{10} %file:%line] %msg%n 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/main/resources/mapper/alarmMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | INSERT INTO follow_alarm_log (title, message, from_user_id, alarm_status, created_at, user_id) 9 | VALUES (#{notification.title}, #{notification.message}, #{fromUserId}, #{alarmStatus}, #{time}, #{friendId}) 10 | 11 | 12 | 13 | UPDATE follow_alarm_log 14 | SET title = #{notification.title}, 15 | message = #{notification.message} 16 | WHERE id = #{alarmId} 17 | 18 | 19 | 20 | INSERT INTO whole_alarm_log (title, message, alarm_status, created_at) 21 | VALUES (#{alarm.title}, #{alarm.message}, #{alarmStatus}, #{alarm.localDateTime}) 22 | 23 | 24 | 34 | 35 | 52 | 53 | 58 | 59 | 64 | 65 | 66 | DELETE FROM follow_alarm_log 67 | WHERE id = #{alarmId} 68 | 69 | 70 | 71 | INSERT INTO whole_alarm_delete (alarm_id, user_id) 72 | VALUES (#{alarmId}, #{userId}) 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/mapper/bucketMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 20 | 21 | 34 | 35 | 65 | 66 | 77 | 78 | 81 | 82 | 83 | INSERT INTO bucket (bucket_name, bucket_content, end_date, bucket_state, user_id, category_id) 84 | VALUES(#{bucketName}, #{content}, #{endDate}, #{bucketState}, #{userId}, #{categoryId}); 85 | 86 | 87 | 88 | UPDATE bucket 89 | SET bucket_name = #{bucketName}, 90 | bucket_content = #{content}, 91 | end_date = #{endDate}, 92 | bucket_state = #{bucketState}, 93 | category_id = #{categoryId} 94 | WHERE id = #{id}; 95 | 96 | 97 | 98 | UPDATE bucket 99 | SET bucket_state = #{bucketStateId} 100 | WHERE id = #{bucketId} AND user_id = #{userId} 101 | 102 | 103 | 104 | 105 | INSERT INTO image (bucket_id, image_url) 106 | VALUES 107 | 108 | (#{bucketId}, #{item}) 109 | 110 | 111 | 112 | 113 | 119 | 120 | 121 | INSERT INTO bucket_tag (bucket_id, tag_id) 122 | 123 | SELECT #{bucketId}, (SELECT id tag_id 124 | FROM tag 125 | WHERE tag_name = #{item}) 126 | 127 | 128 | 129 | 130 | INSERT INTO tag (tag_name) 131 | VALUES 132 | 133 | (#{item}) 134 | 135 | ON DUPLICATE KEY 136 | UPDATE 137 | tag_name = VALUES (tag_name) 138 | 139 | 140 | 149 | 150 | 155 | 156 | 157 | DELETE FROM bucket_tag WHERE bucket_id = #{bucketId}; 158 | 159 | 160 | 161 | DELETE FROM image WHERE bucket_id = #{bucketId}; 162 | 163 | 164 | 165 | INSERT INTO bucket_log (bucket_id, update_type, content) 166 | VALUES 167 | 168 | (#{item.bucketId}, #{item.updateType}, #{item.content}) 169 | 170 | 171 | 172 | 173 | INSERT INTO bucket_log (bucket_id, content) 174 | VALUES 175 | 176 | 177 | (#{bucketId}, CONCAT('제목이 ', #{content}, '로 변경되었습니다.')) 178 | 179 | 180 | (#{bucketId}, CONCAT('완료일이 ', #{content}, '로 변경되었습니다.')) 181 | 182 | 183 | 184 | 185 | 186 | INSERT INTO bucket_log (bucket_id, update_type, content) 187 | SELECT id, 1, bucket_name 188 | FROM bucket WHERE id = #{bucketId}; 189 | 190 | 191 | 192 | INSERT INTO bucket_log (bucket_id, update_type, content) 193 | SELECT id, 0, end_date 194 | FROM bucket WHERE id = #{bucketId}; 195 | 196 | 197 | 198 | UPDATE bucket 199 | SET 200 | bookmark = #{isBookmark} 201 | WHERE id = #{bucketId}; 202 | 203 | 204 | 205 | UPDATE bucket 206 | SET 207 | fin = #{isFin} 208 | WHERE id = #{bucketId}; 209 | 210 | 211 | 218 | 219 | 226 | 227 | 236 | -------------------------------------------------------------------------------- /src/main/resources/mapper/friendMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 12 | 24 | 25 | 32 | 33 | 34 | INSERT INTO follow (following_id, follower_id, friend_status, alarm_id) 35 | VALUES (#{friendId}, #{myUserId}, #{followRequest}, #{alarmId}) 36 | 37 | 38 | 39 | UPDATE follow 40 | SET friend_status = #{friendStatus} 41 | WHERE following_id = #{myUserId} AND follower_id = #{friendId} 42 | 43 | 44 | 45 | DELETE FROM follow 46 | WHERE (following_id = #{myUserId} AND follower_id = #{friendId}) 47 | 48 | 49 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/main/resources/mapper/profileMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 17 | 18 | 19 | UPDATE 20 | user as a 21 | SET a.nickname = #{profile.nickname}, 22 | a.intro = #{profile.intro}, 23 | a.profile_url = #{profile.profileUrl} 24 | WHERE ( 25 | SELECT c.nickname as nickname 26 | FROM ( 27 | SELECT b.nickname as nickname 28 | FROM user as b 29 | WHERE b.id NOT IN (#{userId}) 30 | ) as c 31 | WHERE c.nickname IN (#{profile.nickname}) 32 | ) IS NULL 33 | AND a.id = #{userId}; 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/mapper/searchMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 21 | 22 | 36 | 37 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/main/resources/mapper/tokenMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | INSERT INTO token (user_id, token) 9 | VALUES (#{userId}, #{refreshToken}) ON DUPLICATE KEY 10 | UPDATE 11 | token = #{refreshToken}; 12 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /src/main/resources/mapper/userMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | INSERT INTO user (social_type, password, nickname, intro, social_id, device_token) 10 | VALUES (#{socialType}, #{password}, #{nickname}, #{intro}, #{socialId}, #{deviceToken}) 11 | 12 | 13 | INSERT INTO user (email, social_type, password, nickname, intro, social_id, device_token) 14 | VALUES (#{email}, #{socialType}, #{password}, #{nickname}, #{intro}, #{socialId}, #{deviceToken}) 15 | 16 | 17 | 18 | 19 | 24 | 25 | 30 | 31 | 36 | 37 | 43 | 44 | 45 | UPDATE user 46 | SET password = #{password} 47 | WHERE id = #{userId}; 48 | 49 | 50 | 55 | 56 | 60 | 61 | 66 | 67 | 68 | UPDATE user 69 | SET alarm_check = #{alarmReadStatus} 70 | WHERE id = #{userId} 71 | 72 | 73 | 74 | DELETE 75 | FROM user 76 | WHERE id = #{userId}; 77 | 78 | -------------------------------------------------------------------------------- /src/main/resources/templates/email.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |

비밀번호를 잊으셨나요?
너무 걱정 마세요. 저희도 가끔 잊어버린답니다.

7 |
32322323
8 |

buok으로 돌아가 위 인증번호를 입력해 주세요.

9 |

10 | 혹시 비밀번호 재설정을 요청하지 않으셨거나,
11 | 비밀번호를 찾으셨다면 이 이메일을 무시해 주세요. 12 |

13 | 그럼, 계속 저희와 함께 미래 계획을 세워나가 볼까요? 14 |
15 | 16 | -------------------------------------------------------------------------------- /src/test/java/com/yapp/ios1/DBConnectionTest.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | 5 | //@SpringBootTest(properties = "spring.config.location=classpath:application.yml") 6 | public class DBConnectionTest { 7 | 8 | // private final Logger logger = LoggerFactory.getLogger(this.getClass()); 9 | // 10 | // @Value("${spring.datasource.driver-class-name}") 11 | // private String DRIVER; 12 | // 13 | // @Value("${spring.datasource.url}") 14 | // private String URL; 15 | // 16 | // @Value("${spring.datasource.username}") 17 | // private String USER; 18 | // 19 | // @Value("${spring.datasource.password}") 20 | // private String PASSWORD; 21 | // 22 | // @Test 23 | // public void testConnection() throws ClassNotFoundException { 24 | // Class.forName(DRIVER); 25 | // try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) { 26 | // logger.info("Connection : " + connection); 27 | // } catch (Exception e) { 28 | // logger.info("Exception : " + e.getMessage()); 29 | // } 30 | // } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/yapp/ios1/Ios1ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Ios1ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/com/yapp/ios1/dto/ResponseDtoTest.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.dto; 2 | 3 | import org.junit.jupiter.api.DisplayName; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | /** 9 | * created by ayoung 2021/04/10 10 | */ 11 | public class ResponseDtoTest { 12 | 13 | @DisplayName("응답 테스트") 14 | @Test 15 | public void responseTest() { 16 | 17 | // //given 18 | // User userDto = new User("ayong703@gmail.com", SocialType.GOOGLE, "문아영","test", "test"); 19 | // 20 | // //when 21 | // ResponseDto res1 = ResponseDto.of(HttpStatus.OK, "응답 테스트 메세지1", userDto); 22 | // ResponseDto res2 = ResponseDto.of(HttpStatus.BAD_REQUEST, "응답 테스트 메세지2"); 23 | // 24 | // //then 25 | // assertThat(res1.getStatus()).isEqualTo(200); 26 | // assertThat(res1.getMessage()).isEqualTo("응답 테스트 메세지1"); 27 | // assertThat(res1.getData()).isEqualTo(userDto); 28 | // 29 | // assertThat(res2.getStatus()).isEqualTo(400); 30 | // assertThat(res2.getMessage()).isEqualTo("응답 테스트 메세지2"); 31 | // assertThat(res2.getData()).isEqualTo(null); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/yapp/ios1/service/EmailServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.yapp.ios1.error.exception.user.EmailNotExistException; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertThrows; 9 | 10 | /** 11 | * created by ayoung 2021/06/15 12 | */ 13 | //@SpringBootTest 14 | class EmailServiceTest { 15 | 16 | // @Autowired 17 | // private EmailService emailService; 18 | // 19 | // @Test 20 | // void 이메일_전송_성공_테스트() { 21 | // emailService.sendEmailMessage("ayong0310@naver.com"); 22 | // } 23 | // 24 | // @Test 25 | // void 이메일_존재X_실패_테스트() { 26 | // assertThrows(EmailNotExistException.class, 27 | // () -> emailService.sendEmailMessage("ang0310@naver.com")); 28 | // } 29 | } -------------------------------------------------------------------------------- /src/test/java/com/yapp/ios1/service/JwtServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.nimbusds.jwt.ReadOnlyJWTClaimsSet; 4 | import com.nimbusds.jwt.SignedJWT; 5 | import org.junit.jupiter.api.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.text.ParseException; 10 | import java.util.Date; 11 | 12 | /** 13 | * 임시 토큰 테스트 14 | * 15 | * created by ayoung 2021/05/15 16 | */ 17 | public class JwtServiceTest { 18 | 19 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 20 | 21 | @Test 22 | public void decode_테스트() throws ParseException { 23 | SignedJWT signedJWT = SignedJWT.parse("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNjIyODU5ODk0fQ.nLl9b-mGhDdL7p3jnJzVE6Se07nzFkPnHvKF8mhA_6Q"); 24 | ReadOnlyJWTClaimsSet payload = signedJWT.getJWTClaimsSet(); 25 | 26 | Date currentTime = new Date(System.currentTimeMillis()); 27 | if (!currentTime.before(payload.getExpirationTime())) { 28 | logger.info("유효기간 지남"); 29 | } 30 | 31 | logger.info("" + payload.getSubject()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/yapp/ios1/service/UserServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.yapp.ios1.service; 2 | 3 | import com.yapp.ios1.mapper.UserMapper; 4 | import com.yapp.ios1.service.user.UserService; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.mockito.InjectMocks; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @ExtendWith(MockitoExtension.class) 13 | public class UserServiceTest { 14 | 15 | @Mock 16 | private UserMapper userMapper; 17 | 18 | @InjectMocks 19 | private UserService userService; 20 | // 21 | // @Test 22 | // @DisplayName("해당 이메일 존재하지 않을 때 리턴값 테스트") 23 | // public void 이메일_존재X_테스트() throws SQLException { 24 | // Optional optional = Optional.ofNullable(null); 25 | // given(userMapper.findByEmail("없는계정@naver.com")).willReturn(optional); 26 | // 27 | // assertThat(userService.emailCheck("없는계정@naver.com")).isEqualTo(Optional.empty()); 28 | // } 29 | // 30 | // @Test 31 | // @DisplayName("해당 이메일 존재할 때 리턴값 테스트") 32 | // public void 이메일_존재O_테스트() throws SQLException { 33 | // User user = new User("ayong0310@naver.com", null, "문아영", "test", "test"); 34 | // Optional optional = Optional.of(user); 35 | // given(userMapper.findByEmail("ayong0310@naver.com")).willReturn(optional); 36 | // 37 | // Optional retUser = userService.emailCheck("ayong0310@naver.com"); 38 | // assertThat(retUser).isEqualTo(Optional.of(user)); 39 | // } 40 | } 41 | --------------------------------------------------------------------------------