├── .github ├── ISSUE_TEMPLATE │ └── issue-template.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── seung_ci.yml ├── .gitignore ├── Dockerfile ├── Dockerfile-seung ├── HELP.md ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── hermes │ │ └── ithermes │ │ ├── AppConfig.java │ │ ├── ItHermesApplication.java │ │ ├── RedisConfig.java │ │ ├── application │ │ ├── AlarmService.java │ │ ├── ContentsService.java │ │ ├── CrawlingContentsLastUrlService.java │ │ ├── ExternalAlarmClient.java │ │ ├── JobService.java │ │ ├── SubscribeService.java │ │ ├── TelegramAlarm.java │ │ ├── UpdateUserChatId.java │ │ ├── UrlRecordService.java │ │ ├── UserService.java │ │ └── YoutubeAndNewsService.java │ │ ├── domain │ │ ├── entity │ │ │ ├── AlarmSearch.java │ │ │ ├── BaseEntity.java │ │ │ ├── ContentsViewMapping.java │ │ │ ├── CrawlingContents.java │ │ │ ├── CrawlingContentsLastUrl.java │ │ │ ├── Job.java │ │ │ ├── JobSearch.java │ │ │ ├── Keyword.java │ │ │ ├── Subscribe.java │ │ │ ├── UrlRecord.java │ │ │ ├── User.java │ │ │ ├── UserKeywordRegistry.java │ │ │ ├── YoutubeAndNews.java │ │ │ └── YoutubeAndNewsSearch.java │ │ ├── exception │ │ │ ├── EnumTypeFormatException.java │ │ │ ├── ExpireTokenException.java │ │ │ ├── JsonParseException.java │ │ │ ├── NoAlarmDataException.java │ │ │ ├── NoCrawlingDataException.java │ │ │ ├── NotExistsRequestParamException.java │ │ │ ├── SameIdException.java │ │ │ ├── SameNicknameException.java │ │ │ ├── SameUserException.java │ │ │ ├── UnMatchedPasswordException.java │ │ │ └── WrongIdOrPasswordException.java │ │ ├── factory │ │ │ ├── CrawlingContentsLastUrlFactory.java │ │ │ ├── JobFactory.java │ │ │ ├── KeywordFactory.java │ │ │ ├── RedisFactory.java │ │ │ ├── SubscribeFactory.java │ │ │ ├── UrlRecordFactory.java │ │ │ ├── UserFactory.java │ │ │ ├── UserKeywordRegistryFactory.java │ │ │ └── YoutubeAndNewsFactory.java │ │ └── util │ │ │ ├── ActiveType.java │ │ │ ├── CategoryType.java │ │ │ ├── ContentsProviderType.java │ │ │ ├── ElasticSearchType.java │ │ │ ├── GradeType.java │ │ │ ├── JobType.java │ │ │ ├── OrderType.java │ │ │ └── RecommendKeywordType.java │ │ ├── infrastructure │ │ ├── CrawlingContentsLastUrlRepository.java │ │ ├── JobRepository.java │ │ ├── KeywordRepository.java │ │ ├── SubscribeRepository.java │ │ ├── UrlRecordRepository.java │ │ ├── UserKeywordRegistryRepository.java │ │ ├── UserRepository.java │ │ ├── YoutubeAndNewsRepository.java │ │ └── elastic │ │ │ ├── AlarmSearchRepository.java │ │ │ ├── JobSearchRepository.java │ │ │ └── YoutubeAndNewsSearchRepository.java │ │ └── presentation │ │ ├── GlobalExceptionHandler.java │ │ ├── aop │ │ ├── ControllerLogAop.java │ │ └── ServiceLogAop.java │ │ ├── config │ │ ├── AbstractElasticsearchConfiguration.java │ │ └── ElasticSearchConfig.java │ │ ├── controller │ │ ├── AlarmController.java │ │ ├── ContentsController.java │ │ ├── CrawlingContentsLastUrlController.java │ │ ├── JobController.java │ │ ├── SubscribeController.java │ │ ├── UrlRecordController.java │ │ ├── UserController.java │ │ └── YoutubeAndNewsController.java │ │ ├── dto │ │ ├── CommonResponseDto.java │ │ ├── alarm │ │ │ ├── AlarmDtoInterface.java │ │ │ ├── JobAlarmDto.java │ │ │ └── YoutubeAndNewsAlarmDto.java │ │ ├── contents │ │ │ ├── CategoryCountDto.java │ │ │ ├── ContentsDto.java │ │ │ ├── ContentsDtoInterface.java │ │ │ ├── MainPageContentsDto.java │ │ │ └── SearchContentsDto.java │ │ ├── crawlingcontentslasttitle │ │ │ └── CrawlingContentsLastUrlFindAllResponseDto.java │ │ ├── error │ │ │ ├── EntryPointErrorResponse.java │ │ │ └── UserErrorDto.java │ │ ├── job │ │ │ ├── JobCrawlingDto.java │ │ │ └── JobInsertRequestDto.java │ │ ├── subscribe │ │ │ ├── SubscribeContentsDto.java │ │ │ ├── SubscribeFindSubscribeRequestDto.java │ │ │ ├── SubscribeFindSubscribeResponseDto.java │ │ │ └── SubscribePutSubscribeRequestDto.java │ │ ├── urlrecord │ │ │ └── UrlRecordPutViewCountRequestDto.java │ │ ├── user │ │ │ ├── UserCheckRefreshTokenResponseDto.java │ │ │ ├── UserCreateUserRequestDto.java │ │ │ ├── UserDeleteUserRequestDto.java │ │ │ ├── UserDuplicateIdRequestDto.java │ │ │ ├── UserDuplicateNicknameRequestDto.java │ │ │ ├── UserFindMyDataRequestDto.java │ │ │ ├── UserFindMyDataResponseDto.java │ │ │ ├── UserFindUserListResponseDto.java │ │ │ ├── UserLoginRequestDto.java │ │ │ ├── UserLoginResponseDto.java │ │ │ └── UserUpdateNicknameRequestDto.java │ │ └── youtubeandnews │ │ │ ├── YoutubeAndNewsCrawlingDto.java │ │ │ └── YoutubeAndNewsInsertDto.java │ │ └── security │ │ ├── CustomAccessDeniedHandler.java │ │ ├── CustomAuthenticationEntryPoint.java │ │ ├── JwtFilter.java │ │ ├── JwtUtil.java │ │ ├── SecurityConfiguration.java │ │ └── SecurityErrorCode.java └── resources │ ├── application-eun.yml │ ├── application-local.yml │ ├── application-seung.yml │ ├── application.yml │ └── ehcache.xml └── test ├── java └── com │ └── hermes │ └── ithermes │ ├── application │ ├── ContentsServiceTest.java │ ├── SubscribeServiceTest.java │ └── UserServiceTest.java │ └── presentation │ └── controller │ ├── SubscribeControllerTest.java │ └── UserControllerTest.java └── resources └── application.yml /.github/ISSUE_TEMPLATE/issue-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue Template 3 | about: "\U0001F4D6 이슈 템플릿입니다." 4 | title: 'Prefix: 이슈 타이틀' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## ❗About 11 | 12 | * 13 | 14 | 15 | ## 📝 To do 16 | 17 | - [ ] 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 📌 관련 이슈 2 | - Resolved # 3 | 4 | ## ✔️ 작업 내용 5 | - 6 | -------------------------------------------------------------------------------- /.github/workflows/seung_ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time 6 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle 7 | 8 | name: Java CI with Gradle 9 | 10 | on: 11 | push: 12 | branches: "**" 13 | pull_request: 14 | branches: [ "main" ] 15 | 16 | jobs: 17 | build: 18 | 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: Set up JDK 17 24 | uses: actions/setup-java@v3 25 | with: 26 | java-version: '17' 27 | distribution: 'temurin' 28 | - name: Validate Gradle wrapper 29 | uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b 30 | - name: Build with Gradle 31 | uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 32 | with: 33 | arguments: build 34 | 35 | - name: Gradlew에 권한 부여 36 | run: chmod +x gradlew 37 | 38 | - name: 스프링 부트 애플리케이션 코드, 테스트코드 확인 39 | run: ./gradlew clean build 40 | 41 | - name: 테스트 코드 실행 42 | run: ./gradlew --info test 43 | 44 | - name: 테스트 결과 시각화 45 | uses: EnricoMi/publish-unit-test-result-action@v1 46 | if: ${{ always() }} 47 | with: 48 | files: build/test-results/**/*.xml -------------------------------------------------------------------------------- /.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 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | src/main/resources/application.properties 39 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:17-jdk-alpine 2 | ARG JAR_FILE_PATH=./build/libs/it-hermes-0.0.1-SNAPSHOT.jar 3 | COPY ${JAR_FILE_PATH} app.jar 4 | ENTRYPOINT ["java","-Dspring.profiles.active=eun","-jar","/app.jar","-Dspring-boot.run.arguments=--datasource.password=${PASSWORD}, --jwt.secret=${JWT_KEY}, --telegram-key=${TELEGRAM_KEY}"] 5 | -------------------------------------------------------------------------------- /Dockerfile-seung: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:17-jdk-alpine 2 | ARG JAR_FILE_PATH=./build/libs/it-hermes-0.0.1-SNAPSHOT.jar 3 | COPY ${JAR_FILE_PATH} app.jar 4 | ENTRYPOINT ["java","-Dspring.profiles.active=seung","-jar","/app.jar","-Dspring-boot.run.arguments=--datasource.username=${DATASOURCE_USERNAME}, --datasource.password=${DATASOURCE_PASSWORD}, --jwt.secret=${JWT_KEY}, --telegram-key=${TELEGRAM_KEY}"] 5 | -------------------------------------------------------------------------------- /HELP.md: -------------------------------------------------------------------------------- 1 | # Read Me First 2 | The following was discovered as part of building this project: 3 | 4 | * The original package name 'com.hermes.it-hermes' is invalid and this project uses 'com.hermes.ithermes' instead. 5 | 6 | # Getting Started 7 | 8 | ### Reference Documentation 9 | For further reference, please consider the following sections: 10 | 11 | * [Official Gradle documentation](https://docs.gradle.org) 12 | * [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.0.0/gradle-plugin/reference/html/) 13 | * [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.0.0/gradle-plugin/reference/html/#build-image) 14 | * [Spring Web](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#web) 15 | * [Spring Data JDBC](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#data.sql.jdbc) 16 | * [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#using.devtools) 17 | 18 | ### Guides 19 | The following guides illustrate how to use some features concretely: 20 | 21 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 22 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 23 | * [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) 24 | * [Using Spring Data JDBC](https://github.com/spring-projects/spring-data-examples/tree/master/jdbc/basics) 25 | 26 | ### Additional Links 27 | These additional references should also help you: 28 | 29 | * [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle) 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PROJECT IT-Hermes 2 | 3 | :paperclip: [서비스 링크](https://it-hermes.site) 4 | 5 | :paperclip: [IT-Hermes 크롤링서버 레포](https://github.com/f-lab-edu/IT-Hermes-Crawling) 6 | :paperclip: [IT-Hermes 배치서버 레포](https://github.com/f-lab-edu/IT-Hermes-Batch) 7 | :paperclip: [IT-Hermes 프론트 레포](https://github.com/f-lab-edu/IT-Hermes-Front) 8 |
9 | 10 | ## :thought_balloon: IT 관련 컨텐츠 알림 서비스 11 | 12 | ```프로젝트 기간: 2023.01.04 ~``` 13 | 14 | > IT에 관심이 많은 유저에게 채용, 유투브, 뉴스 정보 등의 각종 IT 관련 컨텐츠를 15 | > 유저 맞춤형으로 자동 알림해주는 서비스 16 | 17 | - 20분 간격으로 배치서버를 통해 크롤링 서버를 호출해서 최신 IT 관련 컨텐츠를 수집 18 | - 30분 간격으로 배치서버를 통해 애플리케이션 서버를 호출해서 유저 구독 정보 알림 제공 19 | - 객체지향 원리와 디자인 패턴을 적용하여 코드 작성 20 | - 깃허브 액션으로 CI, 젠킨스로 CD 구축 21 | - 성능 부하 테스트를 통해 트랜잭션 처리 시간을 측정해서 처리 속도 개선 22 | - 스프링 시큐리티를 적용해서 인증 관련 로직을 반복을 최소화하면서 기능 구현 23 | - RabbitMQ를 이용해서 Batch 서버와 Crawling 서버 장애 대응 24 | - ElasticSearch를 이용해서 검색 트랜잭션 처리속도 개선 경험 25 | 26 |
27 | 28 | ## :page_facing_up: 기술 스택 29 | 30 | 31 | `spring boot 3.0`, `Java 17` 32 | `spring security` 33 | `Mysql 8.0`,`h2`,`Spring Data JPA` 34 | `Jenkins`, `Github action` 35 | `Docker`, `Docker hub` 36 | `Nodejs, NCP` 37 | `Feign Client` 38 | `Html`,`CSS`,`Javascript` 39 | `RabbitMQ`,`ElasticSearch` 40 | `Redis`,`EH Cache` 41 | 42 | ## :thought_balloon: 전체 구조 43 | ![68A30EE6-7C85-4FD7-B51C-AFB90683363D_1_105_c](https://user-images.githubusercontent.com/70764912/230696042-70781f1d-6f8f-46d4-9e45-86ad4fa57cb5.jpeg) 44 | 45 |
46 | 47 |
48 | 49 | ## :page_facing_up: 트러블슈팅 개선 50 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.0.0' 4 | id 'io.spring.dependency-management' version '1.1.0' 5 | } 6 | 7 | group = 'com.hermes' 8 | version = '0.0.1-SNAPSHOT' 9 | sourceCompatibility = '17' 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-data-jpa' 23 | implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' 24 | implementation 'org.springframework.data:spring-data-elasticsearch:4.2.2' 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | compileOnly 'org.projectlombok:lombok' 27 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 28 | annotationProcessor 'org.projectlombok:lombok' 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | runtimeOnly 'mysql:mysql-connector-java' 31 | implementation 'com.github.kshashov:spring-boot-starter-telegram:0.27' 32 | implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6' 33 | implementation 'org.springframework.boot:spring-boot-starter-validation' 34 | implementation 'org.springframework.boot:spring-boot-starter-security' 35 | // https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt 36 | implementation 'io.jsonwebtoken:jjwt:0.9.1' 37 | // https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api 38 | implementation 'javax.xml.bind:jaxb-api:2.3.1' 39 | // https://mvnrepository.com/artifact/org.springframework.security/spring-security-test 40 | testImplementation 'org.springframework.security:spring-security-test' 41 | testImplementation 'com.h2database:h2' 42 | implementation 'org.springframework.boot:spring-boot-starter-cache' 43 | implementation 'net.sf.ehcache:ehcache:2.10.3' 44 | implementation 'org.springframework.boot:spring-boot-starter-data-redis' 45 | // https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 46 | implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3' 47 | implementation 'com.fasterxml.jackson.core:jackson-databind' 48 | 49 | 50 | } 51 | 52 | tasks.named('test') { 53 | useJUnitPlatform() 54 | } 55 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f-lab-edu/IT-Hermes-Server/49321940d116d1f838b22829e14edadeaea014d7/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-7.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /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% equ 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% equ 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 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'it-hermes' 2 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/AppConfig.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.hermes.ithermes.application.UpdateUserChatId; 5 | import com.hermes.ithermes.infrastructure.UserRepository; 6 | import com.pengrad.telegrambot.TelegramBot; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | 14 | @EnableWebSecurity 15 | @Configuration 16 | @RequiredArgsConstructor 17 | public class AppConfig { 18 | @Value("${telegram-key}") 19 | private String telegramKey; 20 | private final UserRepository userRepository; 21 | 22 | @Bean 23 | public UpdateUserChatId updateUserChatId() { 24 | UpdateUserChatId updateUserChatId = new UpdateUserChatId(telegramBot()); 25 | updateUserChatId.updateUserChatId(userRepository); 26 | return updateUserChatId; 27 | } 28 | 29 | @Bean 30 | public BCryptPasswordEncoder passwordEncoder() { 31 | return new BCryptPasswordEncoder(); 32 | } 33 | 34 | @Bean 35 | public TelegramBot telegramBot() { 36 | return new TelegramBot(telegramKey); 37 | } 38 | 39 | @Bean 40 | public ObjectMapper objectMapper() { 41 | return new ObjectMapper(); 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/ItHermesApplication.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes; 2 | 3 | import com.hermes.ithermes.infrastructure.elastic.AlarmSearchRepository; 4 | import com.hermes.ithermes.infrastructure.elastic.JobSearchRepository; 5 | import com.hermes.ithermes.infrastructure.elastic.YoutubeAndNewsSearchRepository; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.cache.annotation.EnableCaching; 9 | import org.springframework.context.annotation.ComponentScan; 10 | import org.springframework.context.annotation.FilterType; 11 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 12 | 13 | @EnableCaching 14 | @SpringBootApplication 15 | @EnableJpaRepositories(excludeFilters = @ComponentScan.Filter( 16 | type = FilterType.ASSIGNABLE_TYPE, 17 | classes = {JobSearchRepository.class, YoutubeAndNewsSearchRepository.class, AlarmSearchRepository.class})) 18 | public class ItHermesApplication { 19 | public static void main(String[] args) { 20 | SpringApplication.run(ItHermesApplication.class, args); 21 | } 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes; 2 | 3 | import com.hermes.ithermes.presentation.dto.contents.ContentsDtoInterface; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.Primary; 9 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | @Configuration 16 | @Slf4j 17 | @EnableRedisRepositories 18 | public class RedisConfig { 19 | @Value("${spring.redis.ipAddress}") 20 | private String ipAddress; 21 | 22 | @Bean 23 | @Primary 24 | LettuceConnectionFactory lettuceConnectionFactory() { 25 | LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(ipAddress,6379); 26 | return lettuceConnectionFactory; 27 | } 28 | 29 | @Bean 30 | LettuceConnectionFactory cacheConnectionFactory() { 31 | LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(ipAddress,6380); 32 | return lettuceConnectionFactory; 33 | } 34 | 35 | @Bean 36 | public RedisTemplate redisTemplate() { 37 | RedisTemplate template = new RedisTemplate<>(); 38 | template.setConnectionFactory(lettuceConnectionFactory()); 39 | template.setKeySerializer(new StringRedisSerializer()); 40 | template.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class)); 41 | return template; 42 | } 43 | 44 | @Bean 45 | public RedisTemplate cacheRedisTemplate() { 46 | RedisTemplate template = new RedisTemplate<>(); 47 | template.setConnectionFactory(cacheConnectionFactory()); 48 | template.setKeySerializer(new StringRedisSerializer()); 49 | template.setHashKeySerializer(new StringRedisSerializer()); 50 | template.setHashValueSerializer(new StringRedisSerializer()); 51 | template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); 52 | return template; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/AlarmService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.*; 4 | import com.hermes.ithermes.domain.exception.NoAlarmDataException; 5 | import com.hermes.ithermes.domain.util.*; 6 | import com.hermes.ithermes.infrastructure.*; 7 | import com.hermes.ithermes.infrastructure.elastic.AlarmSearchRepository; 8 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 9 | import com.hermes.ithermes.presentation.dto.alarm.AlarmDtoInterface; 10 | import com.hermes.ithermes.presentation.dto.alarm.JobAlarmDto; 11 | import com.hermes.ithermes.presentation.dto.alarm.YoutubeAndNewsAlarmDto; 12 | import com.hermes.ithermes.presentation.dto.crawlingcontentslasttitle.CrawlingContentsLastUrlFindAllResponseDto; 13 | import lombok.RequiredArgsConstructor; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | import java.util.stream.Stream; 21 | 22 | @Service 23 | @RequiredArgsConstructor 24 | @Transactional 25 | public class AlarmService { 26 | 27 | private final ExternalAlarmClient externalAlarmClient; 28 | private final UserRepository userRepository; 29 | private final SubscribeRepository subscribeRepository; 30 | private final YoutubeAndNewsRepository youtubeAndNewsRepository; 31 | private final JobRepository jobRepository; 32 | private final CrawlingContentsLastUrlRepository crawlingContentsLastUrlRepository; 33 | private final AlarmSearchRepository alarmSearchRepository; 34 | 35 | public CommonResponseDto sendSubscribeAlarm() { 36 | List youtubeAlarm = alarmSearchRepository.findByCategory(CategoryType.YOUTUBE) 37 | .orElseThrow(()-> new NoAlarmDataException()); 38 | /*List newsAlarm = alarmSearchRepository.findByCategory(CategoryType.NEWS) 39 | .orElseThrow(()-> new NoAlarmDataException());*/ 40 | /*List jobAlarm = alarmSearchRepository.findByCategory(CategoryType.JOB) 41 | .orElseThrow(()-> new NoAlarmDataException());*/ 42 | 43 | for(int i = 0; i< youtubeAlarm.size(); i++){ 44 | AlarmSearch alarmSearch = youtubeAlarm.get(i); 45 | externalAlarmClient.sendContentsMessage(getUserYoutubeAndNewsAlarmContents(alarmSearch),alarmSearch.getTelegramId()); 46 | } 47 | 48 | /* 49 | for(int i = 0; i < newsAlarm.size(); i++){ 50 | AlarmSearch alarmSearch = newsAlarm.get(i); 51 | externalAlarmClient.sendContentsMessage(getUserYoutubeAndNewsAlarmContents(alarmSearch),alarmSearch.getTelegramId()); 52 | }*/ 53 | 54 | return new CommonResponseDto(); 55 | } 56 | 57 | public CommonResponseDto sendRecommendAlarm(){ 58 | List userIdArr = userRepository.findUserId(); 59 | 60 | /* 61 | for(int i = 0; i < userIdArr.size(); i++){ 62 | externalAlarmClient.sendContentsMessage(getUserRecommendAlarmContents(userIdArr.get(i),CategoryType.YOUTUBE), userIdArr.get(i)); 63 | externalAlarmClient.sendContentsMessage(getUserRecommendAlarmContents(userIdArr.get(i),CategoryType.NEWS), userIdArr.get(i)); 64 | externalAlarmClient.sendJobMessage(getUserRecommendAlarmJobContents(userIdArr.get(i)),userIdArr.get(i)); 65 | }*/ 66 | 67 | return new CommonResponseDto(); 68 | } 69 | 70 | public List getUserYoutubeAndNewsAlarmContents(AlarmSearch alarmSearch){ 71 | List youtubeAndNewsAlarmList = new ArrayList<>(); 72 | 73 | youtubeAndNewsAlarmList = youtubeAndNewsRepository.findYoutubeAndNewsByUrlGreater(crawlingContentsLastUrlRepository.findByContentsProvider(alarmSearch.getContentsProvider()).get().getLastUrl(),alarmSearch.getContentsProvider()); 74 | 75 | return youtubeAndNewsAlarmList.stream() 76 | .map(m -> YoutubeAndNewsAlarmDto.convertEntityToDto(m)) 77 | .collect(Collectors.toList()); 78 | } 79 | 80 | public List getUserJobAlarmContents(long userIdx){ 81 | List subscribe = subscribeRepository.findByUserIdAndCategoryAndIsActive(userIdx,CategoryType.JOB,ActiveType.ACTIVE); 82 | int userExperienceYear = userRepository.findUsersById(userIdx).getYearOfExperience(); 83 | JobType jobType = userRepository.findUsersById(userIdx).getJob(); 84 | List jobAlarmList = new ArrayList<>(); 85 | 86 | for(int i = 0; i < subscribe.size(); i++){ 87 | jobAlarmList = jobRepository.findJobByUrlGreater(crawlingContentsLastUrlRepository.findByContentsProvider(subscribe.get(i).getContentsProvider()).get().getLastUrl(),subscribe.get(i).getContentsProvider(),GradeType.checkGradleType(userExperienceYear),jobType); 88 | } 89 | 90 | return jobAlarmList.stream() 91 | .map(m -> JobAlarmDto.convertEntityToDto(m)) 92 | .collect(Collectors.toList()); 93 | } 94 | 95 | public List getUserRecommendAlarmContents(long userIdx, CategoryType type){ 96 | List userRecommendKeywords = getRecommendKeywords(userIdx); 97 | List userContentsProviderList = subscribeRepository.findContentsProvider(ActiveType.ACTIVE, userIdx, type); 98 | 99 | List youtubeAndNewsSubscribeContents = userContentsProviderList.stream() 100 | .map(m -> youtubeAndNewsRepository.findYoutubeAndNewsByContentsProvider(m)) 101 | .flatMap(List::stream) 102 | .collect(Collectors.toList()); 103 | 104 | List youtubeAndNewsRecommendList = youtubeAndNewsSubscribeContents.stream() 105 | .filter(m -> m.isContainRecommendKeywords(userRecommendKeywords)) 106 | .collect(Collectors.toList()); 107 | 108 | return youtubeAndNewsRecommendList.stream() 109 | .distinct() 110 | .map(m -> YoutubeAndNewsAlarmDto.convertEntityToDto(m)) 111 | .collect(Collectors.toList()); 112 | } 113 | 114 | public List getUserRecommendAlarmJobContents(long userIdx){ 115 | List userRecommendKeywords = getRecommendKeywords(userIdx); 116 | List userContentsProviderList = subscribeRepository.findContentsProvider(ActiveType.ACTIVE, userIdx, CategoryType.JOB); 117 | 118 | List jobSubscribeContents = userContentsProviderList.stream() 119 | .map(m -> jobRepository.findJobByContentsProvider(m)) 120 | .flatMap(List::stream) 121 | .collect(Collectors.toList()); 122 | 123 | List jobRecommendList = jobSubscribeContents.stream() 124 | .filter(m -> m.isContainRecommendKeywords(userRecommendKeywords)) 125 | .collect(Collectors.toList()); 126 | 127 | return jobRecommendList.stream() 128 | .distinct() 129 | .map(m -> JobAlarmDto.convertEntityToDto(m)) 130 | .collect(Collectors.toList()); 131 | } 132 | 133 | public List getRecommendKeywords(long userIdx){ 134 | List userCustomKeywords = userRepository.findUsersById(userIdx).getJob().getKeywords(); 135 | 136 | Stream.of(RecommendKeywordType.values()) 137 | .forEach(m -> userCustomKeywords.add(m.getName())); 138 | 139 | return userCustomKeywords; 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/ContentsService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.core.type.TypeReference; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.hermes.ithermes.domain.entity.CrawlingContents; 7 | import com.hermes.ithermes.domain.entity.Job; 8 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 9 | import com.hermes.ithermes.domain.exception.JsonParseException; 10 | import com.hermes.ithermes.domain.util.CategoryType; 11 | import com.hermes.ithermes.domain.util.ElasticSearchType; 12 | import com.hermes.ithermes.domain.util.OrderType; 13 | import com.hermes.ithermes.infrastructure.JobRepository; 14 | import com.hermes.ithermes.infrastructure.YoutubeAndNewsRepository; 15 | import com.hermes.ithermes.infrastructure.elastic.JobSearchRepository; 16 | import com.hermes.ithermes.infrastructure.elastic.YoutubeAndNewsSearchRepository; 17 | import com.hermes.ithermes.presentation.dto.contents.*; 18 | import lombok.RequiredArgsConstructor; 19 | import org.springframework.cache.annotation.CacheEvict; 20 | import org.springframework.cache.annotation.Cacheable; 21 | import org.springframework.data.domain.Page; 22 | import org.springframework.data.domain.PageRequest; 23 | import org.springframework.data.domain.Pageable; 24 | import org.springframework.data.domain.Sort; 25 | import org.springframework.data.redis.core.ListOperations; 26 | import org.springframework.data.redis.core.RedisTemplate; 27 | import org.springframework.stereotype.Service; 28 | import org.springframework.transaction.annotation.Transactional; 29 | 30 | import java.util.ArrayList; 31 | import java.util.List; 32 | import java.util.concurrent.TimeUnit; 33 | import java.util.stream.Collectors; 34 | 35 | @Service 36 | @RequiredArgsConstructor 37 | @Transactional 38 | public class ContentsService { 39 | 40 | private final YoutubeAndNewsRepository youtubeAndNewsRepository; 41 | private final JobRepository jobRepository; 42 | private final RedisTemplate cacheRedisTemplate; 43 | private final ObjectMapper objectMapper; 44 | private final YoutubeAndNewsSearchRepository youtubeAndNewsSearchRepository; 45 | private final JobSearchRepository jobSearchRepository; 46 | 47 | @Cacheable("top12ContentsCache") 48 | public List getMainContents(CategoryType type) { 49 | Pageable pageInfo = PageRequest.of(0, 12, Sort.by(OrderType.POPULAR.getOrderQuery()).descending()); 50 | if (type.getTitle().equals("JOB")) { 51 | return convertEntityToDtoList(jobRepository.findJobBy(pageInfo).getContent(), new MainPageContentsDto()); 52 | } 53 | ListOperations stringListValueOperations = cacheRedisTemplate.opsForList(); 54 | if (stringListValueOperations.size("top12") == 0) { 55 | cacheRedisTemplate.expire("top12", 60 * 60 * 3, TimeUnit.SECONDS); 56 | List contentsDtoInterfaces = pageYoutubeAndNewsConvertMainPageContentsDto(pageInfo, type); 57 | stringListValueOperations.rightPushAll("top12", contentsDtoInterfaces); 58 | return contentsDtoInterfaces; 59 | } 60 | Object range = stringListValueOperations.index("top12", 0L); 61 | try { 62 | String writeValueAsString = objectMapper.writeValueAsString(range); 63 | List contentsDtoInterfaceList = new ArrayList<>(); 64 | List mainPageContentsDtoList = objectMapper.readValue(writeValueAsString, new TypeReference<>() { 65 | }); 66 | 67 | mainPageContentsDtoList.stream().forEach(v -> contentsDtoInterfaceList.add(v)); 68 | return contentsDtoInterfaceList; 69 | } catch (JsonProcessingException e) { 70 | throw new JsonParseException(); 71 | } 72 | } 73 | 74 | public List getCategoryContents(CategoryType type, int page, OrderType order) { 75 | Pageable pageInfo = PageRequest.of(page, 12, Sort.by(order.getOrderQuery()).descending()); 76 | 77 | if (type.getTitle().equals("JOB")) { 78 | return convertEntityToDtoList(jobRepository.findJobBy(pageInfo).getContent(), new ContentsDto()); 79 | } 80 | 81 | return convertEntityToDtoList(youtubeAndNewsRepository.findYoutubeAndNewsByCategory(pageInfo, type).getContent(), new ContentsDto()); 82 | } 83 | 84 | private List pageYoutubeAndNewsConvertMainPageContentsDto(Pageable page, CategoryType type) { 85 | Page youtubeAndNewsContents; 86 | 87 | if (type.equals(CategoryType.YOUTUBE_AND_NEWS)) { 88 | youtubeAndNewsContents = youtubeAndNewsRepository.findYoutubeAndNewsBy(page); 89 | } else { 90 | youtubeAndNewsContents = youtubeAndNewsRepository.findYoutubeAndNewsByCategory(page, type); 91 | } 92 | 93 | return convertEntityToDtoList(youtubeAndNewsContents.getContent(), new MainPageContentsDto()); 94 | } 95 | 96 | private List convertEntityToDtoList(List content, ContentsDtoInterface t) { 97 | return content.stream().map(x -> t.convertEntityToDto(x)).collect(Collectors.toList()); 98 | } 99 | 100 | public CategoryCountDto getCategoryCount() { 101 | Long youtubeCnt = youtubeAndNewsRepository.countYoutubeAndNewsByCategory(CategoryType.YOUTUBE); 102 | Long jobCnt = jobRepository.countBy(); 103 | Long newsCnt = youtubeAndNewsRepository.countYoutubeAndNewsByCategory(CategoryType.NEWS); 104 | 105 | return new CategoryCountDto(youtubeCnt, jobCnt, newsCnt); 106 | } 107 | 108 | public SearchContentsDto getSearchContents(String title, CategoryType categoryType) { 109 | if (categoryType == CategoryType.JOB) { 110 | List jobSearchContents = jobSearchRepository.findByTitleContaining(title); 111 | return new SearchContentsDto(jobSearchContents.size(),convertEntityToDtoList(jobSearchContents, new ContentsDto())); 112 | } else { 113 | List youtubeSearchContents = youtubeAndNewsSearchRepository.findByTitleContainingAndCategory(title,categoryType); 114 | return new SearchContentsDto(youtubeSearchContents.size(),convertEntityToDtoList(youtubeSearchContents, new ContentsDto())); 115 | } 116 | } 117 | 118 | @CacheEvict(value = "top12ContentsCache", allEntries = true) 119 | public void deleteContentsCache() { 120 | } 121 | 122 | public void updateElasticsearch(){ 123 | List youtubeAndNewsCrawlingContents = youtubeAndNewsRepository.findByElasticSearchType(ElasticSearchType.READY); 124 | youtubeAndNewsCrawlingContents.stream() 125 | .forEach(v -> { 126 | v.updateElasticSearchType(); 127 | youtubeAndNewsSearchRepository.save(YoutubeAndNews.convertESentity(v)); 128 | }); 129 | 130 | List jobCrawlingContents = jobRepository.findByElasticSearchType(ElasticSearchType.READY); 131 | jobCrawlingContents.stream() 132 | .forEach(v -> { 133 | v.updateElasticSearchType(); 134 | jobSearchRepository.save(Job.convertESEntitiy(v)); 135 | }); 136 | } 137 | 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/CrawlingContentsLastUrlService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContentsLastUrl; 4 | import com.hermes.ithermes.domain.factory.CrawlingContentsLastUrlFactory; 5 | import com.hermes.ithermes.presentation.dto.crawlingcontentslasttitle.CrawlingContentsLastUrlFindAllResponseDto; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | @RequiredArgsConstructor 14 | @Transactional(readOnly = true) 15 | public class CrawlingContentsLastUrlService { 16 | private final CrawlingContentsLastUrlFactory crawlingContentsLastUrlFactory; 17 | 18 | public CrawlingContentsLastUrlFindAllResponseDto findAllCrawlingContentsLastTitle() { 19 | List crawlingContentsLastTitles = crawlingContentsLastUrlFactory.parseAllCrawlingContentsLastTitle(); 20 | return new CrawlingContentsLastUrlFindAllResponseDto(crawlingContentsLastTitles); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/ExternalAlarmClient.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.presentation.dto.alarm.AlarmDtoInterface; 4 | import com.hermes.ithermes.presentation.dto.alarm.JobAlarmDto; 5 | import com.hermes.ithermes.presentation.dto.alarm.YoutubeAndNewsAlarmDto; 6 | 7 | import java.util.List; 8 | 9 | public interface ExternalAlarmClient { 10 | 11 | void sendContentsMessage(List youtubeAlarmDtoList, String telegramId); 12 | void sendJobMessage(List jobAlarmDtoList, String telegramId); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/JobService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContentsLastUrl; 4 | import com.hermes.ithermes.domain.entity.Job; 5 | import com.hermes.ithermes.domain.exception.NoCrawlingDataException; 6 | import com.hermes.ithermes.domain.factory.CrawlingContentsLastUrlFactory; 7 | import com.hermes.ithermes.domain.factory.JobFactory; 8 | import com.hermes.ithermes.domain.util.ContentsProviderType; 9 | import com.hermes.ithermes.domain.util.GradeType; 10 | import com.hermes.ithermes.domain.util.JobType; 11 | import com.hermes.ithermes.infrastructure.CrawlingContentsLastUrlRepository; 12 | import com.hermes.ithermes.infrastructure.JobRepository; 13 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 14 | import com.hermes.ithermes.presentation.dto.job.JobInsertRequestDto; 15 | import lombok.RequiredArgsConstructor; 16 | import org.checkerframework.checker.units.qual.C; 17 | import org.springframework.stereotype.Service; 18 | import org.springframework.transaction.annotation.Transactional; 19 | 20 | import java.util.List; 21 | import java.util.Optional; 22 | 23 | @Service 24 | @RequiredArgsConstructor 25 | @Transactional(readOnly = true) 26 | public class JobService { 27 | private final JobFactory jobFactory; 28 | private final JobRepository jobRepository; 29 | private final CrawlingContentsLastUrlFactory crawlingContentsLastUrlFactory; 30 | private final CrawlingContentsLastUrlRepository crawlingContentsLastUrlRepository; 31 | 32 | @Transactional 33 | public CommonResponseDto insertJob(JobInsertRequestDto jobInsertRequestDto) { 34 | if (jobInsertRequestDto.getJobCrawlingDtoList().isEmpty()) throw new NoCrawlingDataException(); 35 | 36 | List jobList = jobFactory.insertJob(jobInsertRequestDto); 37 | jobList.stream().forEach(v -> jobRepository.save(v)); 38 | 39 | Job recentJob = jobList.get(0); 40 | 41 | ContentsProviderType contentsProvider = recentJob.getContentsProvider(); 42 | GradeType grade = recentJob.getGrade(); 43 | JobType jobType = jobInsertRequestDto.getJob(); 44 | 45 | Optional contentsLastTitle = crawlingContentsLastUrlRepository.findByContentsProviderAndGradeAndJob(contentsProvider, grade, jobType); 46 | CrawlingContentsLastUrl recentCrawlingContentsLastUrl = crawlingContentsLastUrlFactory.parseCrawlingContentsLastUrlToJob(recentJob, jobType); 47 | 48 | contentsLastTitle.ifPresentOrElse( 49 | v -> { 50 | v.updateLastUrl(recentCrawlingContentsLastUrl); 51 | }, 52 | () -> { 53 | crawlingContentsLastUrlRepository.save(recentCrawlingContentsLastUrl); 54 | } 55 | ); 56 | return new CommonResponseDto(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/SubscribeService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.Subscribe; 4 | import com.hermes.ithermes.domain.factory.SubscribeFactory; 5 | import com.hermes.ithermes.infrastructure.SubscribeRepository; 6 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 7 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeContentsDto; 8 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeFindSubscribeRequestDto; 9 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribePutSubscribeRequestDto; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import java.util.List; 15 | 16 | @Service 17 | @RequiredArgsConstructor 18 | @Transactional(readOnly = true) 19 | public class SubscribeService { 20 | private final SubscribeRepository subscribeRepository; 21 | private final SubscribeFactory subscribeFactory; 22 | 23 | @Transactional 24 | public CommonResponseDto putSubscribe(SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto) { 25 | List subscribes = subscribeFactory.parsePutSubscribeDtoToSubscribes(subscribePutSubscribeRequestDto); 26 | subscribes.stream().forEach(v -> subscribeRepository.save(v)); 27 | return new CommonResponseDto(); 28 | } 29 | 30 | public List findSubscribe(SubscribeFindSubscribeRequestDto subscribeFindSubScribeRequestDto) { 31 | List subscribes = subscribeFactory.parseFindSubscribeDtoToSubscribes(subscribeFindSubScribeRequestDto); 32 | List contentsProviderTypes = SubscribeFactory.findActiveContentsProviderType(subscribes); 33 | 34 | return contentsProviderTypes; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/TelegramAlarm.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.infrastructure.*; 4 | import com.hermes.ithermes.presentation.dto.alarm.AlarmDtoInterface; 5 | import com.hermes.ithermes.presentation.dto.alarm.JobAlarmDto; 6 | import com.pengrad.telegrambot.TelegramBot; 7 | import com.pengrad.telegrambot.request.SendMessage; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | 13 | @Component 14 | @RequiredArgsConstructor 15 | public class TelegramAlarm implements ExternalAlarmClient { 16 | private final TelegramBot telegramBot; 17 | 18 | private final UserRepository userRepository; 19 | 20 | @Override 21 | public void sendContentsMessage(List contentsAlarmDtoList, String telegramId) { 22 | 23 | for(int i = 0; i < contentsAlarmDtoList.size(); i++){ 24 | StringBuilder youtubeAlarmMessage = new StringBuilder(); 25 | 26 | youtubeAlarmMessage.append("[유투브 및 뉴스 정보]" + "\n") 27 | .append("[제목]" + contentsAlarmDtoList.get(i).title() + "\n") 28 | .append("[본문]" + contentsAlarmDtoList.get(i).description() + "\n") 29 | .append("[이미지]" + contentsAlarmDtoList.get(i).image() + "\n") 30 | .append("[url]" + contentsAlarmDtoList.get(i).url() + "\n") 31 | .append("[일자]" + contentsAlarmDtoList.get(i).contentsStartAt() + "\n") 32 | .append("[서비스]" + contentsAlarmDtoList.get(i).contentsProvider() + "\n"); 33 | 34 | telegramBot.execute(new SendMessage(telegramId,youtubeAlarmMessage.toString())); 35 | } 36 | 37 | } 38 | 39 | @Override 40 | public void sendJobMessage(List jobAlarmDtoList, String telegramId) { 41 | 42 | for(int i = 0; i < jobAlarmDtoList.size(); i++) { 43 | StringBuilder jobAlarmMessage = new StringBuilder(); 44 | 45 | jobAlarmMessage.append("[채용 정보]" + "\n") 46 | .append("[제목]" + jobAlarmDtoList.get(i).getTitle() + "\n") 47 | .append("[회사]" + jobAlarmDtoList.get(i).getCompany() + "\n") 48 | .append("[위치]" + jobAlarmDtoList.get(i).getLocation() + "\n") 49 | .append("[url]" + jobAlarmDtoList.get(i).getUrl() + "\n") 50 | .append("[서비스]" + jobAlarmDtoList.get(i).getContentsProviderType() + "\n") 51 | .append("[마감일]" + jobAlarmDtoList.get(i).getContentsEndAt()); 52 | 53 | telegramBot.execute(new SendMessage(telegramId,jobAlarmMessage.toString())); 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/UpdateUserChatId.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.User; 4 | import com.hermes.ithermes.infrastructure.UserRepository; 5 | import com.pengrad.telegrambot.TelegramBot; 6 | import com.pengrad.telegrambot.UpdatesListener; 7 | import com.pengrad.telegrambot.model.Update; 8 | import com.pengrad.telegrambot.request.SendMessage; 9 | import lombok.RequiredArgsConstructor; 10 | 11 | import java.util.List; 12 | 13 | @RequiredArgsConstructor 14 | public class UpdateUserChatId { 15 | private final TelegramBot telegramBot; 16 | 17 | public void updateUserChatId(UserRepository userRepository){ 18 | telegramBot.setUpdatesListener(new UpdatesListener() { 19 | @Override 20 | public int process(List updates) { 21 | for(Update update : updates){ 22 | String chatId = update.message().chat().id().toString(); 23 | String userSendMessage = update.message().text(); 24 | 25 | if(userSendMessage.equals("/start")){ 26 | telegramBot.execute(new SendMessage(chatId, "IT-Hermes에서 사용하는 닉네임을 입력해주세요.")); 27 | return UpdatesListener.CONFIRMED_UPDATES_ALL; 28 | } 29 | 30 | if(userRepository.existsUserByNickname(userSendMessage) == false){ 31 | telegramBot.execute(new SendMessage(chatId,"존재하지 않는 유저입니다. 먼저 회원가입을 진행해주세요.")); 32 | return UpdatesListener.CONFIRMED_UPDATES_ALL; 33 | } 34 | 35 | if(userRepository.existsUserByNicknameAndTelegramId(chatId,userSendMessage) == true){ 36 | telegramBot.execute(new SendMessage(chatId,"이미 생성한 봇이 있는 유저입니다.")); 37 | }else{ 38 | User newUser = userRepository.findByNickname(userSendMessage); 39 | newUser.updateTelegramId(chatId); 40 | userRepository.save(newUser); 41 | telegramBot.execute(new SendMessage(chatId,"유저로 등록되었습니다.")); 42 | } 43 | 44 | return UpdatesListener.CONFIRMED_UPDATES_ALL; 45 | } 46 | 47 | return UpdatesListener.CONFIRMED_UPDATES_ALL; 48 | } 49 | 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/UrlRecordService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.Job; 4 | import com.hermes.ithermes.domain.entity.UrlRecord; 5 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 6 | import com.hermes.ithermes.domain.exception.NoCrawlingDataException; 7 | import com.hermes.ithermes.domain.factory.UrlRecordFactory; 8 | import com.hermes.ithermes.infrastructure.JobRepository; 9 | import com.hermes.ithermes.infrastructure.UrlRecordRepository; 10 | import com.hermes.ithermes.infrastructure.YoutubeAndNewsRepository; 11 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 12 | import com.hermes.ithermes.presentation.dto.urlrecord.UrlRecordPutViewCountRequestDto; 13 | import lombok.RequiredArgsConstructor; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.List; 18 | 19 | @Service 20 | @RequiredArgsConstructor 21 | @Transactional(readOnly = true) 22 | public class UrlRecordService { 23 | private final UrlRecordRepository urlRecordRepository; 24 | private final UrlRecordFactory urlRecordFactory; 25 | private final JobRepository jobRepository; 26 | private final YoutubeAndNewsRepository youtubeAndNewsRepository; 27 | 28 | @Transactional 29 | public CommonResponseDto putViewCount(UrlRecordPutViewCountRequestDto urlRecordPutViewCountRequestDto, String ipAddress) { 30 | String url = urlRecordPutViewCountRequestDto.getUrl(); 31 | boolean existsView = urlRecordRepository.existsByUrlAndClientIpAddress(url, ipAddress); 32 | if (existsView) return new CommonResponseDto(); 33 | 34 | UrlRecord urlRecord = urlRecordFactory.parseUrlRecord(urlRecordPutViewCountRequestDto, ipAddress); 35 | urlRecordRepository.save(urlRecord); 36 | List jobList = jobRepository.findByUrl(url).orElseThrow(() -> new NoCrawlingDataException()); 37 | 38 | if (jobList.isEmpty()) { 39 | List youtubeAndNewsList = youtubeAndNewsRepository.findByUrl(url).orElseThrow(() -> new NoCrawlingDataException()); 40 | if (!youtubeAndNewsList.isEmpty()) youtubeAndNewsList.stream().forEach(youtubeAndNews -> youtubeAndNews.updateViewCount()); 41 | } else { 42 | jobList.stream().forEach(job -> job.updateViewCount()); 43 | } 44 | 45 | return new CommonResponseDto(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/UserService.java: -------------------------------------------------------------------------------- 1 | 2 | package com.hermes.ithermes.application; 3 | 4 | import com.hermes.ithermes.domain.entity.Keyword; 5 | import com.hermes.ithermes.domain.entity.User; 6 | import com.hermes.ithermes.domain.entity.UserKeywordRegistry; 7 | import com.hermes.ithermes.domain.exception.*; 8 | import com.hermes.ithermes.domain.factory.KeywordFactory; 9 | import com.hermes.ithermes.domain.factory.RedisFactory; 10 | import com.hermes.ithermes.domain.factory.UserFactory; 11 | import com.hermes.ithermes.domain.factory.UserKeywordRegistryFactory; 12 | import com.hermes.ithermes.infrastructure.UserKeywordRegistryRepository; 13 | import com.hermes.ithermes.infrastructure.UserRepository; 14 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 15 | import com.hermes.ithermes.presentation.dto.user.*; 16 | import com.hermes.ithermes.presentation.security.JwtUtil; 17 | import lombok.RequiredArgsConstructor; 18 | import org.springframework.beans.factory.annotation.Value; 19 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 20 | import org.springframework.stereotype.Service; 21 | import org.springframework.transaction.annotation.Transactional; 22 | 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.Objects; 26 | import java.util.Optional; 27 | 28 | @Service 29 | @RequiredArgsConstructor 30 | @Transactional(readOnly = true) 31 | public class UserService { 32 | @Value("${springboot.jwt.secret}") 33 | private String secretKey = "secretKey"; 34 | 35 | private final UserKeywordRegistryRepository userKeywordRegistryRepository; 36 | private final UserFactory userFactory; 37 | private final KeywordFactory keywordFactory; 38 | private final UserRepository userRepository; 39 | private final UserKeywordRegistryFactory userKeywordRegistryFactory; 40 | private final JwtUtil jwtUtil; 41 | private final BCryptPasswordEncoder encoder; 42 | private final RedisFactory redisFactory; 43 | 44 | @Transactional 45 | public CommonResponseDto joinUser(UserCreateUserRequestDto userLoginRequestDto) { 46 | 47 | Optional.ofNullable(userLoginRequestDto.getPassword().equals(userLoginRequestDto.getPasswordConfirm())) 48 | .filter(v -> v) 49 | .orElseThrow(() -> new UnMatchedPasswordException()); 50 | 51 | String loginId = userLoginRequestDto.getId(); 52 | String password = encoder.encode(userLoginRequestDto.getPassword()); 53 | userLoginRequestDto.encodingPassword(password); 54 | 55 | if (userFactory.existsByLoginId(loginId)) throw new SameIdException(); 56 | User user = userFactory.parseLoginRequestDtoToUser(userLoginRequestDto); 57 | 58 | Arrays.stream(userLoginRequestDto.getKeywordList()) 59 | .filter(v -> Objects.nonNull(v)) 60 | .forEach(v -> { 61 | Keyword keyword = keywordFactory.parseKeywordNameToKeyword(v); 62 | UserKeywordRegistry userKeywordRegistry = userKeywordRegistryFactory.parseUserAndKeyword(user, keyword); 63 | userKeywordRegistryRepository.save(userKeywordRegistry); 64 | }); 65 | 66 | return new CommonResponseDto(); 67 | } 68 | 69 | @Transactional 70 | public UserLoginResponseDto loginUser(UserLoginRequestDto userLoginRequestDto) { 71 | String loginId = userLoginRequestDto.getId(); 72 | String password = userLoginRequestDto.getPassword(); 73 | 74 | User user = userFactory.findLoginId(loginId).orElseThrow(() -> new WrongIdOrPasswordException()); 75 | 76 | if (!encoder.matches(password, user.getPassword())) throw new WrongIdOrPasswordException(); 77 | 78 | String refreshToken = jwtUtil.createRefreshToken(loginId); 79 | redisFactory.setRedisRefreshToken(loginId, refreshToken); 80 | 81 | UserLoginResponseDto userLoginResponseDto = UserLoginResponseDto.builder() 82 | .message("success") 83 | .accessToken(jwtUtil.createAccessToken(loginId)) 84 | .refreshToken(refreshToken) 85 | .build(); 86 | 87 | return userLoginResponseDto; 88 | } 89 | 90 | public CommonResponseDto checkDuplicateNickname(UserDuplicateNicknameRequestDto userDuplicateNicknameRequestDto) { 91 | String nickname = userDuplicateNicknameRequestDto.getNickname(); 92 | if (userRepository.existsByNickname(nickname)) throw new SameNicknameException(); 93 | return new CommonResponseDto(); 94 | } 95 | 96 | public CommonResponseDto checkDuplicateId(UserDuplicateIdRequestDto userDuplicateIdRequestDto) { 97 | String loginId = userDuplicateIdRequestDto.getId(); 98 | if (userFactory.existsByLoginId(loginId)) throw new SameIdException(); 99 | return new CommonResponseDto(); 100 | } 101 | 102 | @Transactional 103 | public CommonResponseDto updateNickname(UserUpdateNicknameRequestDto userUpdateNicknameRequestDto) { 104 | String newNickname = userUpdateNicknameRequestDto.getNickname(); 105 | if (userFactory.existsByNickname(newNickname)) throw new SameNicknameException(); 106 | 107 | User user = userFactory.findLoginId(userUpdateNicknameRequestDto.getId()).orElseThrow(() -> new WrongIdOrPasswordException()); 108 | user.updateNickname(newNickname); 109 | return new CommonResponseDto(); 110 | } 111 | 112 | @Transactional 113 | public CommonResponseDto deleteUser(UserDeleteUserRequestDto userDeleteUserRequestDto) { 114 | User user = userFactory.findLoginId(userDeleteUserRequestDto.getId()).orElseThrow(() -> new WrongIdOrPasswordException()); 115 | 116 | user.isDelete(); 117 | return new CommonResponseDto(); 118 | } 119 | 120 | public UserFindMyDataResponseDto findMyData(UserFindMyDataRequestDto userFindMyDataRequestDto) { 121 | User user = userFactory.findLoginId(userFindMyDataRequestDto.getId()).orElseThrow(() -> new WrongIdOrPasswordException()); 122 | return new UserFindMyDataResponseDto(user.getLoginId(), user.getNickname()); 123 | } 124 | 125 | public UserCheckRefreshTokenResponseDto checkRefreshToken(String refreshToken) { 126 | String token = refreshToken.split(" ")[1]; 127 | boolean validateToken = jwtUtil.validateToken(token, secretKey); 128 | if (!validateToken) { 129 | throw new ExpireTokenException(); 130 | } 131 | String loginId = JwtUtil.getUsername(token, secretKey); 132 | String redisRefreshToken = redisFactory.getRedisRefreshToken(loginId); 133 | /** 레디스 캐쉬 존재 유무 확인 */ 134 | if (!token.equals(redisRefreshToken)) throw new ExpireTokenException(); 135 | 136 | String accessToken = jwtUtil.createAccessToken(loginId); 137 | return UserCheckRefreshTokenResponseDto 138 | .builder() 139 | .accessToken(accessToken) 140 | .message("success") 141 | .build(); 142 | } 143 | 144 | @Transactional 145 | public CommonResponseDto userLogout(String loginId) { 146 | redisFactory.deleteRedisRefreshToken(loginId); 147 | return new CommonResponseDto(); 148 | } 149 | 150 | public List findUserList() { 151 | List userAndSubscribe = userRepository.findUserAndSubscribe(); 152 | return userAndSubscribe.stream().map(user -> UserFactory.parseUserToRequestUserDto(user)).toList(); 153 | } 154 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/application/YoutubeAndNewsService.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContentsLastUrl; 4 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 5 | import com.hermes.ithermes.domain.exception.NoCrawlingDataException; 6 | import com.hermes.ithermes.domain.factory.CrawlingContentsLastUrlFactory; 7 | import com.hermes.ithermes.domain.factory.YoutubeAndNewsFactory; 8 | import com.hermes.ithermes.domain.util.ContentsProviderType; 9 | import com.hermes.ithermes.infrastructure.CrawlingContentsLastUrlRepository; 10 | import com.hermes.ithermes.infrastructure.YoutubeAndNewsRepository; 11 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 12 | import com.hermes.ithermes.presentation.dto.youtubeandnews.YoutubeAndNewsInsertDto; 13 | import lombok.RequiredArgsConstructor; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | 17 | import java.util.List; 18 | import java.util.Optional; 19 | 20 | @Service 21 | @RequiredArgsConstructor 22 | @Transactional(readOnly = true) 23 | public class YoutubeAndNewsService { 24 | private final YoutubeAndNewsFactory youtubeAndNewsFactory; 25 | private final YoutubeAndNewsRepository youtubeAndNewsRepository; 26 | private final CrawlingContentsLastUrlFactory crawlingContentsLastUrlFactory; 27 | private final CrawlingContentsLastUrlRepository crawlingContentsLastUrlRepository; 28 | 29 | @Transactional 30 | public CommonResponseDto insertYoutubeAndNews(YoutubeAndNewsInsertDto youtubeAndNewsCrawlingDtoList) { 31 | if(youtubeAndNewsCrawlingDtoList.getYoutubeAndNewsCrawlingDtoList().isEmpty()) throw new NoCrawlingDataException(); 32 | 33 | List youtubeAndNewsList = youtubeAndNewsFactory.parseYoutubeAndNews(youtubeAndNewsCrawlingDtoList); 34 | youtubeAndNewsList.stream().forEach(v -> youtubeAndNewsRepository.save(v)); 35 | 36 | YoutubeAndNews recentYoutubeAndNews = youtubeAndNewsList.get(0); 37 | 38 | ContentsProviderType contentsProvider = recentYoutubeAndNews.getContentsProvider(); 39 | Optional contentsLastTitle = crawlingContentsLastUrlRepository.findByContentsProvider(contentsProvider); 40 | CrawlingContentsLastUrl recentCrawlingContentsLastUrl = crawlingContentsLastUrlFactory.parseCrawlingContentsLastUrlToYoutubeAndNews(recentYoutubeAndNews); 41 | 42 | contentsLastTitle.ifPresentOrElse( 43 | v -> { 44 | v.updateLastUrl(recentCrawlingContentsLastUrl); 45 | }, 46 | () -> { 47 | crawlingContentsLastUrlRepository.save(recentCrawlingContentsLastUrl); 48 | } 49 | ); 50 | return new CommonResponseDto(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/AlarmSearch.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.hermes.ithermes.domain.util.CategoryType; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | import jakarta.persistence.Id; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import org.springframework.data.elasticsearch.annotations.Document; 11 | 12 | @Getter 13 | @Builder 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Document(indexName = "alarmsearch") 17 | public class AlarmSearch { 18 | 19 | @Id 20 | private String id; 21 | 22 | private ContentsProviderType contentsProvider; 23 | 24 | private Long userId; 25 | 26 | private CategoryType category; 27 | 28 | private String telegramId; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Getter 10 | @MappedSuperclass 11 | @EntityListeners(AuditingEntityListener.class) 12 | public class BaseEntity { 13 | 14 | @Temporal(TemporalType.TIMESTAMP) 15 | private LocalDateTime createdAt; 16 | 17 | @Temporal(TemporalType.TIMESTAMP) 18 | private LocalDateTime updatedAt; 19 | 20 | @PrePersist 21 | public void prePersist() { 22 | var nowTime = LocalDateTime.now(); 23 | this.createdAt = nowTime; 24 | this.updatedAt = nowTime; 25 | } 26 | 27 | public void changeUpdateAt() { 28 | this.updatedAt = LocalDateTime.now(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/ContentsViewMapping.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | @Entity 10 | @Getter 11 | @Builder 12 | @RequiredArgsConstructor 13 | @AllArgsConstructor 14 | public class ContentsViewMapping extends BaseEntity { 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private Long id; 18 | 19 | @Column(nullable = false) 20 | private String url; 21 | 22 | @Column(nullable = false) 23 | private String pc; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/CrawlingContents.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.hermes.ithermes.domain.util.CategoryType; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | 9 | public interface CrawlingContents { 10 | 11 | String findTitle(); 12 | String findImage(); 13 | String findUrl(); 14 | CategoryType findCategoryType(); 15 | ContentsProviderType findContentsProvider(); 16 | LocalDateTime findContentsTime(); 17 | String findDescription(); 18 | Long findViewCount(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/CrawlingContentsLastUrl.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.hermes.ithermes.domain.util.ContentsProviderType; 4 | import com.hermes.ithermes.domain.util.GradeType; 5 | import com.hermes.ithermes.domain.util.JobType; 6 | import jakarta.persistence.*; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Getter; 10 | import lombok.RequiredArgsConstructor; 11 | 12 | @Entity 13 | @Getter 14 | @Builder 15 | @RequiredArgsConstructor 16 | @AllArgsConstructor 17 | public class CrawlingContentsLastUrl { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | 22 | @Enumerated(EnumType.STRING) 23 | @Column(nullable = false) 24 | private ContentsProviderType contentsProvider; 25 | 26 | @Enumerated(EnumType.STRING) 27 | private GradeType grade; 28 | 29 | @Enumerated(EnumType.STRING) 30 | private JobType job; 31 | 32 | @Column(nullable = false, length = 1000) 33 | private String lastUrl; 34 | 35 | public void updateLastUrl(CrawlingContentsLastUrl crawlingContentsLastUrl) { 36 | this.lastUrl = crawlingContentsLastUrl.getLastUrl(); 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/Job.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.hermes.ithermes.domain.util.*; 5 | import jakarta.persistence.*; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | 11 | import java.time.LocalDateTime; 12 | import java.util.List; 13 | 14 | @Entity 15 | @Getter 16 | @Builder 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | public class Job extends BaseEntity implements CrawlingContents { 20 | 21 | @Version 22 | private Integer version; 23 | 24 | @Id 25 | @GeneratedValue(strategy = GenerationType.IDENTITY) 26 | private Long id; 27 | 28 | @Column(nullable = false) 29 | private String title; 30 | 31 | @Column(nullable = false) 32 | private String url; 33 | 34 | @Column(nullable = false) 35 | private String location; 36 | 37 | @Column(nullable = false) 38 | private String company; 39 | 40 | @Temporal(TemporalType.TIMESTAMP) 41 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 42 | @Column(nullable = false) 43 | private LocalDateTime contentsStartAt; 44 | 45 | @Temporal(TemporalType.TIMESTAMP) 46 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 47 | @Column(nullable = false) 48 | private LocalDateTime contentsEndAt; 49 | 50 | @Column(nullable = false) 51 | private Long viewCount; 52 | 53 | @Column(nullable = false) 54 | private Boolean isDelete; 55 | 56 | @Enumerated(EnumType.STRING) 57 | @Column(nullable = false) 58 | private ContentsProviderType contentsProvider; 59 | 60 | @Enumerated(EnumType.STRING) 61 | @Column(nullable = false) 62 | private GradeType grade; 63 | 64 | @Enumerated(EnumType.STRING) 65 | @Column(nullable = false) 66 | private JobType jobType; 67 | 68 | @Enumerated(EnumType.STRING) 69 | @Column(nullable = false, columnDefinition = "READY") 70 | private ElasticSearchType elasticSearchType; 71 | 72 | public void initDefaultData() { 73 | viewCount=0L; 74 | } 75 | 76 | public void updateViewCount() { 77 | this.viewCount+=1L; 78 | } 79 | 80 | public void updateElasticSearchType() {this.elasticSearchType=ElasticSearchType.DONE; } 81 | 82 | @Override 83 | public String findTitle() { 84 | return title; 85 | } 86 | 87 | @Override 88 | public String findImage() { 89 | return null; 90 | } 91 | 92 | @Override 93 | public String findUrl() { 94 | return url; 95 | } 96 | 97 | @Override 98 | public CategoryType findCategoryType() { 99 | return CategoryType.JOB; 100 | } 101 | 102 | @Override 103 | public ContentsProviderType findContentsProvider() { 104 | return contentsProvider; 105 | } 106 | 107 | @Override 108 | public LocalDateTime findContentsTime() { 109 | return contentsEndAt; 110 | } 111 | 112 | @Override 113 | public String findDescription() { 114 | return company; 115 | } 116 | 117 | public boolean isContainRecommendKeywords(List keywordList){ 118 | return keywordList.stream() 119 | .anyMatch(m->m.contains(title)); 120 | } 121 | 122 | @Override 123 | public Long findViewCount() { 124 | return viewCount; 125 | } 126 | 127 | public static JobSearch convertESEntitiy(Job job){ 128 | return JobSearch.builder() 129 | .title(job.getTitle()) 130 | .url(job.getUrl()) 131 | .location(job.getLocation()) 132 | .company(job.getCompany()) 133 | .contentsStartAt(job.getContentsStartAt()) 134 | .contentsEndAt(job.getContentsEndAt()) 135 | .viewCount(job.getViewCount()) 136 | .isDelete(job.getIsDelete()) 137 | .contentsProvider(job.getContentsProvider()) 138 | .grade(job.getGrade()) 139 | .jobType(job.getJobType()) 140 | .build(); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/JobSearch.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.hermes.ithermes.domain.util.*; 5 | import jakarta.persistence.*; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import org.springframework.data.elasticsearch.annotations.DateFormat; 11 | import org.springframework.data.elasticsearch.annotations.Document; 12 | import org.springframework.data.elasticsearch.annotations.Field; 13 | import org.springframework.data.elasticsearch.annotations.FieldType; 14 | 15 | import java.time.LocalDateTime; 16 | 17 | @Getter 18 | @Builder 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @Document(indexName = "jobsearch") 22 | public class JobSearch extends BaseEntity implements CrawlingContents { 23 | 24 | @Id 25 | private String id; 26 | 27 | @Column(nullable = false) 28 | private String title; 29 | 30 | @Column(nullable = false) 31 | private String url; 32 | 33 | @Column(nullable = false) 34 | private String location; 35 | 36 | @Column(nullable = false) 37 | private String company; 38 | 39 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") 40 | @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss") 41 | private LocalDateTime contentsStartAt; 42 | 43 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") 44 | @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss") 45 | private LocalDateTime contentsEndAt; 46 | 47 | @Column(nullable = false) 48 | private Long viewCount; 49 | 50 | @Column(nullable = false) 51 | private Boolean isDelete; 52 | 53 | @Enumerated(EnumType.STRING) 54 | @Column(nullable = false) 55 | private ContentsProviderType contentsProvider; 56 | 57 | @Enumerated(EnumType.STRING) 58 | @Column(nullable = false) 59 | private GradeType grade; 60 | 61 | @Enumerated(EnumType.STRING) 62 | @Column(nullable = false) 63 | private JobType jobType; 64 | 65 | @Enumerated(EnumType.STRING) 66 | private ElasticSearchType elasticSearchType; 67 | 68 | @Override 69 | public String findTitle() { 70 | return title; 71 | } 72 | 73 | @Override 74 | public String findImage() { 75 | return null; 76 | } 77 | 78 | @Override 79 | public String findUrl() { 80 | return url; 81 | } 82 | 83 | @Override 84 | public CategoryType findCategoryType() { 85 | return CategoryType.JOB; 86 | } 87 | 88 | @Override 89 | public ContentsProviderType findContentsProvider() { 90 | return contentsProvider; 91 | } 92 | 93 | @Override 94 | public LocalDateTime findContentsTime() { 95 | return contentsEndAt; 96 | } 97 | 98 | @Override 99 | public String findDescription() { 100 | return company; 101 | } 102 | 103 | @Override 104 | public Long findViewCount() { 105 | return viewCount; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/Keyword.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | @Entity 10 | @Getter 11 | @Builder 12 | @RequiredArgsConstructor 13 | @AllArgsConstructor 14 | public class Keyword extends BaseEntity { 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private Long id; 18 | 19 | @Column(nullable = false) 20 | private String name; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/Subscribe.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.hermes.ithermes.domain.util.ActiveType; 4 | import com.hermes.ithermes.domain.util.CategoryType; 5 | import com.hermes.ithermes.domain.util.ContentsProviderType; 6 | import jakarta.persistence.*; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | 12 | @Entity 13 | @Getter 14 | @Builder 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | 18 | public class Subscribe extends BaseEntity { 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | private Long id; 22 | 23 | @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) 24 | @JoinColumn(name = "userId") 25 | private User user; 26 | 27 | @Enumerated(EnumType.STRING) 28 | @Column(nullable = false) 29 | private ActiveType isActive; 30 | 31 | @Enumerated(EnumType.STRING) 32 | @Column(nullable = false) 33 | private CategoryType category; 34 | 35 | @Enumerated(EnumType.STRING) 36 | @Column(nullable = false) 37 | private ContentsProviderType contentsProvider; 38 | 39 | public void setUser(User user) { 40 | this.user = user; 41 | } 42 | 43 | public void changeUpdateAt(ActiveType activeType) { 44 | this.isActive = activeType; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/UrlRecord.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | @Entity 10 | @Getter 11 | @Builder 12 | @RequiredArgsConstructor 13 | @AllArgsConstructor 14 | public class UrlRecord extends BaseEntity { 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private Long id; 18 | 19 | @Column(nullable = false) 20 | private String url; 21 | 22 | @Column(nullable = false) 23 | private String clientIpAddress; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.hermes.ithermes.domain.util.JobType; 4 | import jakarta.persistence.*; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.RequiredArgsConstructor; 9 | import org.hibernate.annotations.Where; 10 | 11 | import java.util.List; 12 | 13 | @Entity 14 | @Getter 15 | @Builder 16 | @RequiredArgsConstructor 17 | @AllArgsConstructor 18 | @Where(clause = "isDelete = false") 19 | public class User extends BaseEntity { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | private Long id; 24 | 25 | @Column(nullable = false) 26 | private String nickname; 27 | 28 | @Column(nullable = false) 29 | private String loginId; 30 | 31 | @Column(nullable = false) 32 | private String password; 33 | 34 | @Enumerated(EnumType.STRING) 35 | @Column(nullable = false) 36 | private JobType job; 37 | 38 | @Column(nullable = false) 39 | private Integer yearOfExperience; 40 | 41 | private String telegramId; 42 | 43 | @Column(nullable = false) 44 | private Boolean isDelete; 45 | 46 | public void updateNickname(String nickname) { 47 | this.nickname = nickname; 48 | } 49 | 50 | public void isDelete() { 51 | this.isDelete = true; 52 | } 53 | @OneToMany(fetch = FetchType.LAZY) 54 | @JoinColumn(name = "userId") 55 | List subscribe; 56 | 57 | public void setSubscribe(List subscribe) { 58 | this.subscribe = subscribe; 59 | } 60 | 61 | public void updateTelegramId(String telegramId) { 62 | this.telegramId = telegramId; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/UserKeywordRegistry.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | 9 | @Entity 10 | @Getter 11 | @Builder 12 | @RequiredArgsConstructor 13 | @AllArgsConstructor 14 | public class UserKeywordRegistry extends BaseEntity { 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private Long id; 18 | 19 | @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) 20 | @JoinColumn(name = "userId") 21 | private User user; 22 | 23 | public void setUser(User user) { 24 | this.user = user; 25 | } 26 | 27 | @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) 28 | @JoinColumn(name = "keywordId") 29 | private Keyword keyword; 30 | 31 | public void setKeyword(Keyword keyword) { 32 | this.keyword = keyword; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/YoutubeAndNews.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.hermes.ithermes.domain.util.CategoryType; 5 | import com.hermes.ithermes.domain.util.ContentsProviderType; 6 | import com.hermes.ithermes.domain.util.ElasticSearchType; 7 | import jakarta.persistence.*; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Getter; 11 | import lombok.NoArgsConstructor; 12 | 13 | import java.time.LocalDateTime; 14 | import java.util.List; 15 | 16 | @Entity 17 | @Getter 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | public class YoutubeAndNews extends BaseEntity implements CrawlingContents { 22 | 23 | @Version 24 | private Integer version; 25 | 26 | @Id 27 | @GeneratedValue(strategy = GenerationType.IDENTITY) 28 | private Long id; 29 | 30 | @Column(nullable = false) 31 | private String title; 32 | 33 | @Column(nullable = false, length = 1000) 34 | private String description; 35 | 36 | private String image; 37 | 38 | @Column(nullable = false) 39 | private String url; 40 | 41 | @Temporal(TemporalType.TIMESTAMP) 42 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 43 | @Column(nullable = false) 44 | private LocalDateTime contentsStartAt; 45 | 46 | @Column(nullable = false) 47 | private Long viewCount; 48 | 49 | @Column(nullable = false) 50 | private Boolean isDelete; 51 | 52 | @Enumerated(EnumType.STRING) 53 | @Column(nullable = false) 54 | private CategoryType category; 55 | 56 | @Enumerated(EnumType.STRING) 57 | @Column(nullable = false) 58 | private ContentsProviderType contentsProvider; 59 | 60 | @Enumerated(EnumType.STRING) 61 | private ElasticSearchType elasticSearchType; 62 | 63 | public void updateViewCount() { 64 | this.viewCount += +1L; 65 | } 66 | 67 | public void updateElasticSearchType() { this.elasticSearchType=ElasticSearchType.DONE; } 68 | 69 | @Override 70 | public String findTitle() { 71 | return title; 72 | } 73 | 74 | @Override 75 | public String findImage() { 76 | return image; 77 | } 78 | 79 | @Override 80 | public String findUrl() { 81 | return url; 82 | } 83 | 84 | @Override 85 | public CategoryType findCategoryType() { 86 | return category; 87 | } 88 | 89 | @Override 90 | public ContentsProviderType findContentsProvider() { 91 | return contentsProvider; 92 | } 93 | 94 | @Override 95 | public LocalDateTime findContentsTime() { 96 | return contentsStartAt; 97 | } 98 | 99 | @Override 100 | public String findDescription() { 101 | return description; 102 | } 103 | 104 | public boolean isContainRecommendKeywords(List keywordList){ 105 | return keywordList.stream() 106 | .anyMatch(m->m.contains(title)); 107 | } 108 | 109 | @Override 110 | public Long findViewCount() { 111 | return viewCount; 112 | } 113 | 114 | public static YoutubeAndNewsSearch convertESentity(YoutubeAndNews youtubeAndNews){ 115 | return YoutubeAndNewsSearch.builder() 116 | .title(youtubeAndNews.getTitle()) 117 | .description(youtubeAndNews.getDescription()) 118 | .image(youtubeAndNews.getImage()) 119 | .url(youtubeAndNews.getUrl()) 120 | .contentsStartAt(youtubeAndNews.getContentsStartAt()) 121 | .viewCount(youtubeAndNews.getViewCount()) 122 | .isDelete(youtubeAndNews.getIsDelete()) 123 | .category(youtubeAndNews.getCategory()) 124 | .contentsProvider(youtubeAndNews.getContentsProvider()) 125 | .build(); 126 | 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/entity/YoutubeAndNewsSearch.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.entity; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.hermes.ithermes.domain.util.CategoryType; 6 | import com.hermes.ithermes.domain.util.ContentsProviderType; 7 | import jakarta.persistence.*; 8 | import lombok.*; 9 | import org.springframework.data.annotation.Id; 10 | import org.springframework.data.elasticsearch.annotations.DateFormat; 11 | import org.springframework.data.elasticsearch.annotations.Document; 12 | import org.springframework.data.elasticsearch.annotations.Field; 13 | import org.springframework.data.elasticsearch.annotations.FieldType; 14 | 15 | import java.time.LocalDateTime; 16 | 17 | @Getter 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @Document(indexName = "youtubeandnewssearch") 22 | public class YoutubeAndNewsSearch extends BaseEntity implements CrawlingContents { 23 | 24 | @Id 25 | private String id; 26 | 27 | @Column(nullable = false) 28 | private String title; 29 | 30 | @Column(nullable = false, length = 1000) 31 | private String description; 32 | 33 | private String image; 34 | 35 | @Column(nullable = false) 36 | private String url; 37 | 38 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") 39 | @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss") 40 | private LocalDateTime contentsStartAt; 41 | 42 | @Column(nullable = false) 43 | private Long viewCount; 44 | 45 | @Column(nullable = false) 46 | private Boolean isDelete; 47 | 48 | @Enumerated(EnumType.STRING) 49 | @Column(nullable = false) 50 | private CategoryType category; 51 | 52 | @Enumerated(EnumType.STRING) 53 | @Column(nullable = false) 54 | private ContentsProviderType contentsProvider; 55 | 56 | @Override 57 | public String findTitle() { 58 | return title; 59 | } 60 | 61 | @Override 62 | public String findImage() { 63 | return image; 64 | } 65 | 66 | @Override 67 | public String findUrl() { 68 | return url; 69 | } 70 | 71 | @Override 72 | public CategoryType findCategoryType() { 73 | return category; 74 | } 75 | 76 | @Override 77 | public ContentsProviderType findContentsProvider() { 78 | return contentsProvider; 79 | } 80 | 81 | @Override 82 | public LocalDateTime findContentsTime() { 83 | return contentsStartAt; 84 | } 85 | 86 | @Override 87 | public String findDescription() { 88 | return description; 89 | } 90 | 91 | @Override 92 | public Long findViewCount() { 93 | return viewCount; 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/EnumTypeFormatException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class EnumTypeFormatException extends RuntimeException{ 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/ExpireTokenException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class ExpireTokenException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/JsonParseException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class JsonParseException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/NoAlarmDataException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class NoAlarmDataException extends RuntimeException{ 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/NoCrawlingDataException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class NoCrawlingDataException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/NotExistsRequestParamException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class NotExistsRequestParamException extends RuntimeException { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/SameIdException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class SameIdException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/SameNicknameException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class SameNicknameException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/SameUserException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class SameUserException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/UnMatchedPasswordException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class UnMatchedPasswordException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/exception/WrongIdOrPasswordException.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.exception; 2 | 3 | public class WrongIdOrPasswordException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/CrawlingContentsLastUrlFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContentsLastUrl; 4 | import com.hermes.ithermes.domain.entity.Job; 5 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 6 | import com.hermes.ithermes.domain.util.JobType; 7 | import com.hermes.ithermes.infrastructure.CrawlingContentsLastUrlRepository; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | 13 | @Component 14 | @RequiredArgsConstructor 15 | public class CrawlingContentsLastUrlFactory { 16 | private final CrawlingContentsLastUrlRepository crawlingContentsLastUrlRepository; 17 | 18 | public List parseAllCrawlingContentsLastTitle() { 19 | 20 | List crawlingContentsLastUrlRepositoryAll = crawlingContentsLastUrlRepository.findAll(); 21 | return crawlingContentsLastUrlRepositoryAll; 22 | } 23 | 24 | public CrawlingContentsLastUrl parseCrawlingContentsLastUrlToYoutubeAndNews(YoutubeAndNews youtubeAndNews) { 25 | return CrawlingContentsLastUrl.builder() 26 | .lastUrl(youtubeAndNews.getUrl()) 27 | .contentsProvider(youtubeAndNews.getContentsProvider()) 28 | .build(); 29 | } 30 | 31 | public CrawlingContentsLastUrl parseCrawlingContentsLastUrlToJob(Job job, JobType jobType) { 32 | return CrawlingContentsLastUrl.builder() 33 | .lastUrl(job.getUrl()) 34 | .grade(job.getGrade()) 35 | .job(jobType) 36 | .contentsProvider(job.getContentsProvider()) 37 | .build(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/JobFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.Job; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | import com.hermes.ithermes.domain.util.GradeType; 6 | import com.hermes.ithermes.domain.util.JobType; 7 | import com.hermes.ithermes.infrastructure.JobRepository; 8 | import com.hermes.ithermes.presentation.dto.job.JobCrawlingDto; 9 | import com.hermes.ithermes.presentation.dto.job.JobInsertRequestDto; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.time.LocalDateTime; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | @Component 18 | @RequiredArgsConstructor 19 | public class JobFactory { 20 | private final JobRepository jobRepository; 21 | 22 | public List insertJob(JobInsertRequestDto jobInsertRequestDto) { 23 | List jobList = new ArrayList<>(); 24 | List jobCrawlingDtoList = jobInsertRequestDto.getJobCrawlingDtoList(); 25 | ContentsProviderType contentsProvider = jobInsertRequestDto.getContentsProvider(); 26 | GradeType grade = jobInsertRequestDto.getGrade(); 27 | JobType jobType = jobInsertRequestDto.getJob(); 28 | jobCrawlingDtoList.stream().forEach(v -> { 29 | String company = v.getCompany(); 30 | String title = v.getTitle(); 31 | String url = v.getUrl(); 32 | String location = v.getLocation(); 33 | String[] startDateArray = v.getStartDate().split("-"); 34 | String[] endDateArray = v.getStartDate().split("-"); 35 | LocalDateTime startDate = LocalDateTime.of( 36 | Integer.parseInt(startDateArray[0]), 37 | Integer.parseInt(startDateArray[1]), 38 | Integer.parseInt(startDateArray[2]), 39 | Integer.parseInt(startDateArray[3]), 40 | Integer.parseInt(startDateArray[4]), 41 | Integer.parseInt(startDateArray[5])); 42 | 43 | LocalDateTime endDate = LocalDateTime.of( 44 | Integer.parseInt(endDateArray[0]), 45 | Integer.parseInt(endDateArray[1]), 46 | Integer.parseInt(endDateArray[2]), 47 | Integer.parseInt(endDateArray[3]), 48 | Integer.parseInt(endDateArray[4]), 49 | Integer.parseInt(endDateArray[5])); 50 | 51 | Job job = Job 52 | .builder() 53 | .company(company) 54 | .title(title) 55 | .url(url) 56 | .location(location) 57 | .grade(grade) 58 | .contentsStartAt(startDate) 59 | .contentsEndAt(endDate) 60 | .isDelete(false) 61 | .viewCount(0L) 62 | .contentsProvider(contentsProvider) 63 | .jobType(jobType) 64 | .build(); 65 | 66 | jobList.add(job); 67 | }); 68 | return jobList; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/KeywordFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.Keyword; 4 | import lombok.Builder; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Builder 8 | @Component 9 | public class KeywordFactory { 10 | public Keyword parseKeywordNameToKeyword(String keywordName) { 11 | Keyword keyword = Keyword.builder().name(keywordName).build(); 12 | return keyword; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/RedisFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.data.redis.core.RedisTemplate; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @RequiredArgsConstructor 9 | public class RedisFactory { 10 | 11 | private final RedisTemplate redisTemplate; 12 | 13 | public String setRedisRefreshToken(String key, String value) { 14 | redisTemplate.opsForValue().set(key, value); 15 | return value; 16 | } 17 | 18 | public String getRedisRefreshToken(String key) { 19 | return redisTemplate.opsForValue().get(key); 20 | } 21 | 22 | public void deleteRedisRefreshToken(String key) { 23 | redisTemplate.delete(key); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/SubscribeFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.Subscribe; 4 | import com.hermes.ithermes.domain.entity.User; 5 | import com.hermes.ithermes.domain.exception.EnumTypeFormatException; 6 | import com.hermes.ithermes.domain.exception.WrongIdOrPasswordException; 7 | import com.hermes.ithermes.domain.util.ActiveType; 8 | import com.hermes.ithermes.domain.util.CategoryType; 9 | import com.hermes.ithermes.domain.util.ContentsProviderType; 10 | import com.hermes.ithermes.infrastructure.SubscribeRepository; 11 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeContentsDto; 12 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeFindSubscribeRequestDto; 13 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribePutSubscribeRequestDto; 14 | import lombok.Builder; 15 | import lombok.RequiredArgsConstructor; 16 | import org.springframework.stereotype.Component; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Optional; 21 | import java.util.stream.Collectors; 22 | 23 | @Builder 24 | @Component 25 | @RequiredArgsConstructor 26 | public class SubscribeFactory { 27 | private final SubscribeRepository subscribeRepository; 28 | private final UserFactory userFactory; 29 | 30 | public List parsePutSubscribeDtoToSubscribes(SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto) { 31 | List subscribes = new ArrayList<>(); 32 | String loginId = subscribePutSubscribeRequestDto.getId(); 33 | User user = userFactory.findLoginId(loginId).orElseThrow(() -> new WrongIdOrPasswordException()); 34 | ArrayList subscribeContentsList = subscribePutSubscribeRequestDto.getSubscribeContentsList(); 35 | boolean isEdit = existsByUserId(user.getId()); 36 | 37 | subscribeContentsList.stream().forEach(v -> { 38 | ContentsProviderType contentsProviderType = ContentsProviderType.valueOf(v.getContentsProvider()); 39 | CategoryType categoryType = CategoryType.findByContentsProviderType(contentsProviderType); 40 | ActiveType activeType = ActiveType.valueOf(v.getIsActive()); 41 | 42 | Subscribe subscribe = CategoryType.parseSubscribe(user, categoryType, contentsProviderType, activeType); 43 | if (isEdit) { 44 | Subscribe editSubscribe = subscribeRepository.findByContentsProvider(ContentsProviderType.valueOf(v.getContentsProvider())).orElseThrow(() -> new EnumTypeFormatException()); 45 | editSubscribe.changeUpdateAt(ActiveType.valueOf(v.getIsActive())); 46 | } else { 47 | subscribes.add(subscribe); 48 | } 49 | 50 | }); 51 | return subscribes; 52 | } 53 | 54 | public List parseFindSubscribeDtoToSubscribes(SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto) { 55 | String loginId = subscribeFindSubscribeRequestDto.getId(); 56 | User user = userFactory.findLoginId(loginId).orElseThrow(() -> new WrongIdOrPasswordException()); 57 | Long userId = user.getId(); 58 | return findSubscribeByUserId(userId).orElseThrow(null); 59 | } 60 | 61 | public static List findActiveContentsProviderType(List subscribes) { 62 | return subscribes.stream().map(v -> new SubscribeContentsDto(v.getContentsProvider().getTitle(), v.getIsActive().getTitle())).collect(Collectors.toList()); 63 | } 64 | 65 | public Optional> findSubscribeByUserId(Long userId) { 66 | return subscribeRepository.findByUserId(userId); 67 | } 68 | 69 | public boolean existsByUserId(Long userId) { 70 | return subscribeRepository.existsByUserId(userId); 71 | } 72 | } 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/UrlRecordFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.UrlRecord; 4 | import com.hermes.ithermes.infrastructure.UrlRecordRepository; 5 | import com.hermes.ithermes.presentation.dto.urlrecord.UrlRecordPutViewCountRequestDto; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | @RequiredArgsConstructor 11 | public class UrlRecordFactory { 12 | private final UrlRecordRepository urlRecordRepository; 13 | 14 | public UrlRecord parseUrlRecord(UrlRecordPutViewCountRequestDto urlRecordPutViewCountRequestDto, String ipAddress) { 15 | UrlRecord urlRecord = UrlRecord 16 | .builder() 17 | .url(urlRecordPutViewCountRequestDto.getUrl()) 18 | .clientIpAddress(ipAddress) 19 | .build(); 20 | 21 | return urlRecord; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/UserFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.User; 4 | import com.hermes.ithermes.infrastructure.UserRepository; 5 | import com.hermes.ithermes.presentation.dto.user.UserCreateUserRequestDto; 6 | import com.hermes.ithermes.presentation.dto.user.UserFindUserListResponseDto; 7 | import lombok.Builder; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.Optional; 12 | 13 | @Builder 14 | @Component 15 | @RequiredArgsConstructor 16 | public class UserFactory { 17 | private final UserRepository userRepository; 18 | 19 | public User parseLoginRequestDtoToUser(UserCreateUserRequestDto userLoginRequestDto) { 20 | User user = User.builder() 21 | .loginId(userLoginRequestDto.getId()) 22 | .password(userLoginRequestDto.getPassword()) 23 | .nickname(userLoginRequestDto.getNickname()) 24 | .job(userLoginRequestDto.getJob()) 25 | .yearOfExperience(Integer.parseInt(userLoginRequestDto.getYearOfExperience())) 26 | .isDelete(false) 27 | .build(); 28 | return user; 29 | } 30 | 31 | public Optional findLoginId(String userId) { 32 | return userRepository.findByLoginId(userId); 33 | } 34 | 35 | public boolean existsByLoginId(String userId) { 36 | return userRepository.existsByLoginId(userId); 37 | } 38 | 39 | public boolean existsByNickname(String nickname) { 40 | return userRepository.existsByNickname(nickname); 41 | } 42 | 43 | public static UserFindUserListResponseDto parseUserToRequestUserDto(User user) { 44 | 45 | return UserFindUserListResponseDto.builder() 46 | .loginId(user.getLoginId()) 47 | .nickname(user.getNickname()) 48 | .jobType(user.getJob().name()) 49 | .yearOfExperience(user.getYearOfExperience()) 50 | .subscribeList(SubscribeFactory.findActiveContentsProviderType(user.getSubscribe())) 51 | .build(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/UserKeywordRegistryFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.Keyword; 4 | import com.hermes.ithermes.domain.entity.User; 5 | import com.hermes.ithermes.domain.entity.UserKeywordRegistry; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class UserKeywordRegistryFactory { 10 | 11 | public UserKeywordRegistry parseUserAndKeyword(User user, Keyword keyword) { 12 | UserKeywordRegistry userKeywordRegistry = UserKeywordRegistry.builder() 13 | .user(user) 14 | .keyword(keyword) 15 | .build(); 16 | return userKeywordRegistry; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/factory/YoutubeAndNewsFactory.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.factory; 2 | 3 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 4 | import com.hermes.ithermes.domain.util.CategoryType; 5 | import com.hermes.ithermes.domain.util.ContentsProviderType; 6 | import com.hermes.ithermes.infrastructure.YoutubeAndNewsRepository; 7 | import com.hermes.ithermes.presentation.dto.youtubeandnews.YoutubeAndNewsCrawlingDto; 8 | import com.hermes.ithermes.presentation.dto.youtubeandnews.YoutubeAndNewsInsertDto; 9 | import lombok.RequiredArgsConstructor; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.time.LocalDateTime; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | @Component 17 | @RequiredArgsConstructor 18 | public class YoutubeAndNewsFactory { 19 | private final YoutubeAndNewsRepository youtubeAndNewsRepository; 20 | 21 | public List parseYoutubeAndNews(YoutubeAndNewsInsertDto youtubeAndNewsCrawlingDtoList) { 22 | List youtubeAndNewsList = new ArrayList<>(); 23 | ArrayList crawlingList = youtubeAndNewsCrawlingDtoList.getYoutubeAndNewsCrawlingDtoList(); 24 | CategoryType categoryType = youtubeAndNewsCrawlingDtoList.getCategory(); 25 | ContentsProviderType contentsProvider = youtubeAndNewsCrawlingDtoList.getContentsProvider(); 26 | crawlingList.stream().forEach(v -> { 27 | String title = v.getTitle(); 28 | String description = v.getDescription(); 29 | String thumbnail = v.getThumbnail(); 30 | String url = v.getUrl(); 31 | String[] dateArray = v.getDate().split("-"); 32 | LocalDateTime date = LocalDateTime.of( 33 | Integer.parseInt(dateArray[0]), 34 | Integer.parseInt(dateArray[1]), 35 | Integer.parseInt(dateArray[2]), 36 | Integer.parseInt(dateArray[3]), 37 | Integer.parseInt(dateArray[4]), 38 | Integer.parseInt(dateArray[5])); 39 | 40 | YoutubeAndNews youtubeAndNews = YoutubeAndNews 41 | .builder() 42 | .description(description) 43 | .title(title) 44 | .image(thumbnail) 45 | .url(url) 46 | .contentsStartAt(date) 47 | .isDelete(false) 48 | .viewCount(0L) 49 | .category(categoryType) 50 | .contentsProvider(contentsProvider) 51 | .build(); 52 | youtubeAndNewsList.add(youtubeAndNews); 53 | }); 54 | return youtubeAndNewsList; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/ActiveType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum ActiveType { 7 | ACTIVE("ACTIVE"), 8 | NOT_ACTIVE("NOT_ACTIVE"); 9 | 10 | private String title; 11 | 12 | ActiveType(String title) { 13 | this.title = title; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/CategoryType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.hermes.ithermes.domain.entity.Subscribe; 5 | import com.hermes.ithermes.domain.entity.User; 6 | import com.hermes.ithermes.domain.exception.EnumTypeFormatException; 7 | import lombok.Getter; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | @Getter 13 | public enum CategoryType { 14 | JOB("JOB", Arrays.asList(ContentsProviderType.SARAMIN, ContentsProviderType.WANTED)), 15 | NEWS("NEWS", Arrays.asList(ContentsProviderType.CODING_WORLD, ContentsProviderType.YOZM)), 16 | YOUTUBE("YOUTUBE", Arrays.asList( 17 | ContentsProviderType.NOMAD_CODERS, ContentsProviderType.DREAM_CODING, 18 | ContentsProviderType.WHITESHIP,ContentsProviderType.FI,ContentsProviderType.LINE_DEVELOP, 19 | ContentsProviderType.DEVELOP_FOOT, ContentsProviderType.NULLNULL_DEVELOP, ContentsProviderType.DONGBINNA, 20 | ContentsProviderType.POPE, ContentsProviderType.WOOWA_COURSE 21 | )), 22 | YOUTUBE_AND_NEWS("YOUTUBE_AND_NEWS",Arrays.asList(ContentsProviderType.NOMAD_CODERS,ContentsProviderType.DREAM_CODING, 23 | ContentsProviderType.CODING_WORLD,ContentsProviderType.YOZM, 24 | ContentsProviderType.WHITESHIP,ContentsProviderType.FI,ContentsProviderType.LINE_DEVELOP, 25 | ContentsProviderType.DEVELOP_FOOT, ContentsProviderType.NULLNULL_DEVELOP, ContentsProviderType.DONGBINNA, 26 | ContentsProviderType.POPE, ContentsProviderType.WOOWA_COURSE 27 | )); 28 | 29 | private String title; 30 | private List contentsProviderTypes; 31 | 32 | CategoryType(String title, List contentsProviderTypes) { 33 | this.title = title; 34 | this.contentsProviderTypes = contentsProviderTypes; 35 | } 36 | 37 | public static CategoryType findByContentsProviderType(ContentsProviderType contentsProviderType) { 38 | return Arrays.stream(CategoryType.values()) 39 | .filter(categoryType -> categoryType.matchContentsProviderType(contentsProviderType)) 40 | .findAny() 41 | .orElseThrow(() -> new EnumTypeFormatException()); 42 | } 43 | 44 | public boolean matchContentsProviderType(ContentsProviderType contentsProviderType) { 45 | return contentsProviderTypes.stream() 46 | .anyMatch(contentsProviderTypeList -> contentsProviderTypeList.equals(contentsProviderType)); 47 | } 48 | 49 | public static Subscribe parseSubscribe(User user, CategoryType categoryType, ContentsProviderType contentsProviderType, ActiveType activeType) { 50 | return Subscribe.builder() 51 | .user(user) 52 | .category(categoryType) 53 | .contentsProvider(contentsProviderType) 54 | .isActive(activeType) 55 | .build(); 56 | } 57 | 58 | @JsonCreator 59 | public static CategoryType fromValue(String category) { 60 | return CategoryType.valueOf(category.toUpperCase()); 61 | } 62 | 63 | public static boolean isContainCategoryType(String title){ 64 | for(CategoryType c: CategoryType.values()){ 65 | if(c.getTitle().equals(title)){ 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/ContentsProviderType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public enum ContentsProviderType { 8 | SARAMIN("SARAMIN"), 9 | WANTED("WANTED"), 10 | CODING_WORLD("CODING_WORLD"), 11 | YOZM("YOZM"), 12 | NOMAD_CODERS("NOMAD_CODERS"), 13 | DREAM_CODING("DREAM_CODING"), 14 | WHITESHIP("WHITESHIP"), 15 | FI("FI"), 16 | LINE_DEVELOP("LINE_DEVELOP"), 17 | DEVELOP_FOOT("DEVELOP_FOOT"), 18 | NULLNULL_DEVELOP("NULLNULL_DEVELOP"), 19 | DONGBINNA("DONGBINNA"), 20 | POPE("POPE"), 21 | WOOWA_COURSE("WOOWA_COURSE"); 22 | 23 | private String title; 24 | 25 | ContentsProviderType(String title) { 26 | this.title = title; 27 | } 28 | 29 | @JsonCreator 30 | public static ContentsProviderType fromValue(String contentsProvider) { 31 | return ContentsProviderType.valueOf(contentsProvider.toUpperCase()); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/ElasticSearchType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public enum ElasticSearchType { 8 | READY("READY"), 9 | DONE("DONE"); 10 | 11 | private String text; 12 | 13 | ElasticSearchType(String text) { 14 | this.text = text; 15 | } 16 | 17 | @JsonCreator 18 | public static ElasticSearchType fromValue(String text) { 19 | return ElasticSearchType.valueOf(text); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/GradeType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | 5 | public enum GradeType { 6 | BEGINNER("BEGINNER", 0, 0), 7 | JUNIOR("JUNIOR", 1, 4), 8 | INTERMEDIATE("INTERMEDIATE", 5, 9), 9 | SENIOR("SENIOR", 10, 30); 10 | 11 | private String name; 12 | private int minExperience; 13 | private int maxExperience; 14 | 15 | GradeType(String name, int minExperience, int maxExperience) { 16 | this.name = name; 17 | this.minExperience = minExperience; 18 | this.maxExperience = maxExperience; 19 | } 20 | 21 | public static GradeType checkGradleType(int experience) { 22 | if (experience < BEGINNER.minExperience) return GradeType.BEGINNER; 23 | else if (experience > 0 && experience <= 4) return GradeType.JUNIOR; 24 | else if (experience > 4 && experience < 10) return GradeType.INTERMEDIATE; 25 | else return GradeType.SENIOR; 26 | } 27 | 28 | @JsonCreator 29 | public static JobType fromValue(String grade) { 30 | return JobType.valueOf(grade.toUpperCase()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/JobType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import lombok.Getter; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @Getter 10 | public enum JobType { 11 | FRONT("FRONT", Arrays.asList("UIUX","React","Vue","HTML","CSS")), 12 | BACKEND("BACKEND",Arrays.asList("데이터베이스","API")), 13 | MOBILE("MOBILE",Arrays.asList("iOS","안드로이드")); 14 | 15 | private String title; 16 | private List keywords; 17 | 18 | JobType(String title, List keywords) { 19 | this.title = title; 20 | this.keywords = keywords; 21 | } 22 | 23 | @JsonCreator 24 | public static JobType fromValue(String job) { 25 | return JobType.valueOf(job.toUpperCase()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/OrderType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderType { 7 | 8 | ID("ID","createdAt"), 9 | RECENT("RECENT","contentsStartAt"), 10 | POPULAR("POPULAR","viewCount"); 11 | 12 | private String name; 13 | private String orderQuery; 14 | 15 | OrderType(String name, String orderQuery) { 16 | this.name = name; 17 | this.orderQuery = orderQuery; 18 | } 19 | 20 | public static boolean isContainOrderType(String type){ 21 | for(OrderType o: OrderType.values()){ 22 | if(o.getName().equals(type)){ 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/domain/util/RecommendKeywordType.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.domain.util; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum RecommendKeywordType { 7 | 8 | MachineLearning("머신러닝"), 9 | BigData("빅데이터"), 10 | Security("보안"), 11 | OpenSource("오픈소스"), 12 | Cloud("클라우드"), 13 | Framework("프레임워크"); 14 | 15 | private String name; 16 | 17 | RecommendKeywordType(String name) { 18 | this.name = name; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/CrawlingContentsLastUrlRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContentsLastUrl; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | import com.hermes.ithermes.domain.util.GradeType; 6 | import com.hermes.ithermes.domain.util.JobType; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.repository.query.Param; 9 | import org.springframework.stereotype.Repository; 10 | 11 | import java.util.List; 12 | import java.util.Optional; 13 | 14 | @Repository 15 | public interface CrawlingContentsLastUrlRepository extends JpaRepository { 16 | List findAll(); 17 | Optional findByContentsProvider(@Param("contentsProvider")ContentsProviderType contentsProvider); 18 | Optional findByContentsProviderAndGradeAndJob(@Param("contentsProvider")ContentsProviderType contentsProvider, @Param("grade")GradeType grade, @Param("job") JobType job); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/JobRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import java.util.List; 4 | 5 | import com.hermes.ithermes.domain.entity.CrawlingContents; 6 | import com.hermes.ithermes.domain.entity.Job; 7 | import com.hermes.ithermes.domain.util.ContentsProviderType; 8 | import com.hermes.ithermes.domain.util.ElasticSearchType; 9 | import com.hermes.ithermes.domain.util.GradeType; 10 | import com.hermes.ithermes.domain.util.JobType; 11 | import org.springframework.data.domain.Page; 12 | import org.springframework.data.domain.Pageable; 13 | import org.springframework.data.jpa.repository.JpaRepository; 14 | import org.springframework.data.jpa.repository.Query; 15 | import org.springframework.data.repository.query.Param; 16 | import org.springframework.stereotype.Repository; 17 | 18 | import java.util.Optional; 19 | 20 | @Repository 21 | public interface JobRepository extends JpaRepository { 22 | 23 | Page findJobBy(Pageable pageable); 24 | List findByTitleContaining(String searchKeyword); 25 | @Query("select jn from Job jn where jn.id<(select innerjn.id from Job innerjn where innerjn.url=:url and innerjn.contentsProvider=:contentsProviderType and innerjn.grade=:GradeType and innerjn.jobType=:JobType) and jn.contentsProvider=:contentsProviderType and jn.grade=:GradeType and jn.jobType=:JobType") 26 | List findJobByUrlGreater(@Param("url") String url, @Param("contentsProviderType") ContentsProviderType contentsProvider, @Param("GradeType") GradeType gradeType, @Param("JobType")JobType jobType); 27 | List findJobByContentsProvider(ContentsProviderType contentsProviderType); 28 | Optional> findByUrl(@Param("url") String url); 29 | Long countBy(); 30 | List findByElasticSearchType(ElasticSearchType elasticSearchType); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/KeywordRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.Keyword; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface KeywordRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/SubscribeRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.Subscribe; 4 | import com.hermes.ithermes.domain.util.ActiveType; 5 | import com.hermes.ithermes.domain.util.CategoryType; 6 | import com.hermes.ithermes.domain.util.ContentsProviderType; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Query; 9 | import org.springframework.data.repository.query.Param; 10 | 11 | import java.util.List; 12 | import java.util.Optional; 13 | 14 | public interface SubscribeRepository extends JpaRepository { 15 | Optional> findByUserId(@Param("userId") Long userId); 16 | 17 | @Query("select s.contentsProvider from Subscribe s where s.isActive = :active and s.user.id = :userId and s.category = :category") 18 | List findContentsProvider(@Param("active") ActiveType active, @Param("userId") Long userId, @Param("category") CategoryType categoryType); 19 | 20 | boolean existsByUserId(@Param("userId") Long userId); 21 | 22 | Optional findByContentsProvider(@Param("contentsProvider") ContentsProviderType contentsProvider); 23 | 24 | List findByUserIdAndCategoryAndIsActive(@Param("userId") Long userId, @Param("category") CategoryType categoryType, @Param("active") ActiveType active); 25 | 26 | Subscribe findByUserIdAndContentsProvider(Long userId, ContentsProviderType contentsProviderType); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/UrlRecordRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.UrlRecord; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.repository.query.Param; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface UrlRecordRepository extends JpaRepository { 10 | boolean existsByUrlAndClientIpAddress(@Param("url") String url, @Param("clientIpAddress") String clientIpAddress); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/UserKeywordRegistryRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.UserKeywordRegistry; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface UserKeywordRegistryRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.data.repository.query.Param; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | @Repository 13 | public interface UserRepository extends JpaRepository { 14 | 15 | @Query("SELECT u FROM User u JOIN FETCH u.subscribe") 16 | List findUserAndSubscribe(); 17 | 18 | Optional findByLoginId(@Param("loginId") String loginId); 19 | 20 | boolean existsByNickname(@Param("nickname") String nickname); 21 | 22 | boolean existsByLoginId(@Param("loginId") String loginId); 23 | 24 | Boolean existsUserByNicknameAndTelegramId(String nickname,String telegramId); 25 | 26 | Boolean existsUserByNickname(String nickname); 27 | 28 | @Query("SELECT u.id FROM User u where u.telegramId is not null and u.isDelete=false") 29 | List findUserId(); 30 | 31 | @Query("SELECT u.telegramId FROM User u where u.id=:id") 32 | String findTelegramIdByUserId(@Param("id") Long id); 33 | 34 | User findByNickname(String nickname); 35 | 36 | User findUsersById(Long id); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/YoutubeAndNewsRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContents; 4 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 5 | import com.hermes.ithermes.domain.util.CategoryType; 6 | import com.hermes.ithermes.domain.util.ContentsProviderType; 7 | import com.hermes.ithermes.domain.util.ElasticSearchType; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.Pageable; 10 | import org.springframework.data.jpa.repository.JpaRepository; 11 | import org.springframework.data.jpa.repository.Query; 12 | import org.springframework.data.repository.query.Param; 13 | import org.springframework.stereotype.Repository; 14 | 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | @Repository 19 | public interface YoutubeAndNewsRepository extends JpaRepository { 20 | 21 | Page findYoutubeAndNewsBy(Pageable pageable); 22 | Page findYoutubeAndNewsByCategory(Pageable pageable, CategoryType type); 23 | List findByTitleContainingAndCategory(String searchKeyword,CategoryType type); 24 | @Query("select yn from YoutubeAndNews yn where yn.id<(select inneryn.id from YoutubeAndNews inneryn where inneryn.url=:url and inneryn.contentsProvider=:contentsProviderType) and yn.contentsProvider=:contentsProviderType") 25 | List findYoutubeAndNewsByUrlGreater(@Param("url") String url,@Param("contentsProviderType") ContentsProviderType contentsProviderType); 26 | List findYoutubeAndNewsByContentsProvider(ContentsProviderType contentsProvider); 27 | Optional> findByUrl(@Param("url") String url); 28 | Long countYoutubeAndNewsByCategory(@Param("category") CategoryType category); 29 | List findByElasticSearchType(ElasticSearchType elasticSearchType); 30 | 31 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/elastic/AlarmSearchRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure.elastic; 2 | 3 | import com.hermes.ithermes.domain.entity.AlarmSearch; 4 | import com.hermes.ithermes.domain.util.CategoryType; 5 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | @Repository 12 | public interface AlarmSearchRepository extends ElasticsearchRepository { 13 | 14 | Optional> findByCategory(CategoryType categoryType); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/elastic/JobSearchRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure.elastic; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContents; 4 | import com.hermes.ithermes.domain.entity.JobSearch; 5 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface JobSearchRepository extends ElasticsearchRepository { 12 | List findByTitleContaining(String title); 13 | void save(JobSearch jobSearch); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/infrastructure/elastic/YoutubeAndNewsSearchRepository.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.infrastructure.elastic; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContents; 4 | import com.hermes.ithermes.domain.entity.YoutubeAndNewsSearch; 5 | import com.hermes.ithermes.domain.util.CategoryType; 6 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import java.util.List; 10 | 11 | @Repository 12 | public interface YoutubeAndNewsSearchRepository extends ElasticsearchRepository { 13 | List findByTitleContainingAndCategory(String title, CategoryType categoryType); 14 | void save(YoutubeAndNewsSearch youtubeAndNewsSearch); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation; 2 | 3 | import com.hermes.ithermes.domain.exception.*; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.MethodArgumentNotValidException; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; 9 | @RestControllerAdvice 10 | public class GlobalExceptionHandler { 11 | 12 | @ExceptionHandler(NotExistsRequestParamException.class) 13 | public ResponseEntity NotExistsRequestValue(){ 14 | return new ResponseEntity<>("잘못된 요청 파라미터 값입니다.", HttpStatus.BAD_REQUEST); 15 | } 16 | 17 | @ExceptionHandler(SameIdException.class) 18 | public ResponseEntity handleLSameIdException() { 19 | return new ResponseEntity<>("이미 존재하는 아이디", HttpStatus.BAD_REQUEST); 20 | } 21 | 22 | @ExceptionHandler(SameNicknameException.class) 23 | public ResponseEntity handleLSameNicknameException() { 24 | return new ResponseEntity<>("동일한 닉네임 회원 존재", HttpStatus.BAD_REQUEST); 25 | } 26 | 27 | @ExceptionHandler(UnMatchedPasswordException.class) 28 | public ResponseEntity handleUnMatchedPasswordException() { 29 | return new ResponseEntity<>("비밀번호와 비밀번호 확인 데이터 불일치", HttpStatus.BAD_REQUEST); 30 | } 31 | 32 | @ExceptionHandler(WrongIdOrPasswordException.class) 33 | public ResponseEntity handleWrongIdOrPasswordException() { 34 | return new ResponseEntity<>("아이디 또는 비밀번호 불일치", HttpStatus.BAD_REQUEST); 35 | } 36 | 37 | @ExceptionHandler(SameUserException.class) 38 | public ResponseEntity handleSameUserException() { 39 | return new ResponseEntity<>("이미 존재하는 회원", HttpStatus.BAD_REQUEST); 40 | } 41 | 42 | @ExceptionHandler(EnumTypeFormatException.class) 43 | public ResponseEntity enumTypeFormatException() { 44 | return new ResponseEntity<>("서버에 존재하지 않는 유효하지 않는 데이터", HttpStatus.BAD_REQUEST); 45 | } 46 | @ExceptionHandler(value = MethodArgumentNotValidException.class) 47 | public ResponseEntity methodArgumentNotValidException(MethodArgumentNotValidException e){ 48 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); 49 | } 50 | 51 | @ExceptionHandler(value = NoCrawlingDataException.class) 52 | public ResponseEntity noCrawlingDataException(){ 53 | return new ResponseEntity<>("크롤링 데이터가 존재하지 않음", HttpStatus.BAD_REQUEST); 54 | } 55 | 56 | @ExceptionHandler(value = JsonParseException.class) 57 | public ResponseEntity jsonParseException(){ 58 | return new ResponseEntity<>("JSON 데이터 파싱 중 오류 발생", HttpStatus.BAD_REQUEST); 59 | } 60 | 61 | @ExceptionHandler(value = ExpireTokenException.class) 62 | public ResponseEntity expireRefreshTokenException(){ 63 | return new ResponseEntity<>("인증 토큰 만료 혹은 유효하지 않음", HttpStatus.UNAUTHORIZED); 64 | } 65 | 66 | @ExceptionHandler(value = NoAlarmDataException.class) 67 | public ResponseEntity noAlarmDataException(){ 68 | return new ResponseEntity<>("알림데이터가 존재하지 않습니다,", HttpStatus.NOT_FOUND); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/aop/ControllerLogAop.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.aop; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.aspectj.lang.ProceedingJoinPoint; 5 | import org.aspectj.lang.annotation.Around; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.util.StopWatch; 9 | 10 | @Aspect 11 | @Component 12 | @Slf4j 13 | public class ControllerLogAop { 14 | @Around("within(com.hermes.ithermes.presentation.controller.*)") 15 | public Object checkLog(ProceedingJoinPoint joinPoint) throws Throwable { 16 | StopWatch stopWatch = new StopWatch(); 17 | try { 18 | stopWatch.start(); 19 | return joinPoint.proceed(); 20 | } finally { 21 | stopWatch.stop(); 22 | String className = joinPoint.getTarget().getClass().getName(); 23 | String methodName = joinPoint.getSignature().getName() + "()"; 24 | log.info("className : {} | methodName : {} server | transaction Processing Time : {} ms", className, methodName, stopWatch.getLastTaskTimeMillis()); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/aop/ServiceLogAop.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.aop; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.aspectj.lang.ProceedingJoinPoint; 5 | import org.aspectj.lang.annotation.Around; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.util.StopWatch; 9 | 10 | @Aspect 11 | @Component 12 | @Slf4j 13 | public class ServiceLogAop { 14 | @Around("within(com.hermes.ithermes.application.*)") 15 | public Object checkLog(ProceedingJoinPoint joinPoint) throws Throwable { 16 | StopWatch stopWatch = new StopWatch(); 17 | try { 18 | stopWatch.start(); 19 | return joinPoint.proceed(); 20 | } finally { 21 | stopWatch.stop(); 22 | String className = joinPoint.getTarget().getClass().getName(); 23 | String methodName = joinPoint.getSignature().getName() + "()"; 24 | log.info("className : {} | methodName : {} server | transaction Processing Time : {} ms", className, methodName, stopWatch.getLastTaskTimeMillis()); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/config/AbstractElasticsearchConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.config; 2 | 3 | import org.elasticsearch.client.RestHighLevelClient; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport; 6 | import org.springframework.data.elasticsearch.core.ElasticsearchOperations; 7 | import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; 8 | import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; 9 | 10 | public abstract class AbstractElasticsearchConfiguration extends ElasticsearchConfigurationSupport { 11 | 12 | @Bean 13 | public abstract RestHighLevelClient elasticsearchClient(); 14 | 15 | @Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" }) 16 | public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter, 17 | RestHighLevelClient elasticsearchClient) { 18 | 19 | ElasticsearchRestTemplate template = new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter); 20 | template.setRefreshPolicy(refreshPolicy()); 21 | 22 | return template; 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/config/ElasticSearchConfig.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.config; 2 | 3 | import com.hermes.ithermes.infrastructure.elastic.JobSearchRepository; 4 | import com.hermes.ithermes.infrastructure.elastic.YoutubeAndNewsSearchRepository; 5 | import org.elasticsearch.client.RestHighLevelClient; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.elasticsearch.client.ClientConfiguration; 9 | import org.springframework.data.elasticsearch.client.RestClients; 10 | import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; 11 | 12 | @Configuration 13 | @EnableElasticsearchRepositories(basePackageClasses = {YoutubeAndNewsSearchRepository.class, JobSearchRepository.class}) 14 | public class ElasticSearchConfig extends AbstractElasticsearchConfiguration { 15 | 16 | @Value("${spring.elasticSearch.ipAddress}") 17 | private String ipAddress; 18 | @Value("${spring.elasticSearch.port}") 19 | private String port; 20 | 21 | @Override 22 | public RestHighLevelClient elasticsearchClient() { 23 | ClientConfiguration clientConfiguration = ClientConfiguration.builder() 24 | .connectedTo(ipAddress + ":" + port) 25 | .build(); 26 | return RestClients.create(clientConfiguration).rest(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/AlarmController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.AlarmService; 4 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | @RequiredArgsConstructor 13 | @RequestMapping("/api/alarm") 14 | public class AlarmController { 15 | 16 | private final AlarmService alarmService; 17 | 18 | @RequestMapping(value = "/subscription",method = RequestMethod.GET) 19 | public ResponseEntity alarmSubscribeContents(){ 20 | return ResponseEntity.ok(alarmService.sendSubscribeAlarm()); 21 | } 22 | 23 | @RequestMapping(value = "/recommend",method = RequestMethod.GET) 24 | public ResponseEntity alarmRecommendContents(){ 25 | return ResponseEntity.ok(alarmService.sendRecommendAlarm()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/ContentsController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.ContentsService; 4 | import com.hermes.ithermes.domain.exception.NotExistsRequestParamException; 5 | import com.hermes.ithermes.domain.util.CategoryType; 6 | import com.hermes.ithermes.domain.util.OrderType; 7 | import com.hermes.ithermes.presentation.dto.contents.CategoryCountDto; 8 | import com.hermes.ithermes.presentation.dto.contents.ContentsDtoInterface; 9 | import com.hermes.ithermes.presentation.dto.contents.SearchContentsDto; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import java.util.List; 15 | 16 | @RestController 17 | @RequestMapping("/api/contents") 18 | @RequiredArgsConstructor 19 | public class ContentsController { 20 | 21 | private final ContentsService contentsService; 22 | 23 | @RequestMapping(value = "/main",method = RequestMethod.GET) 24 | public ResponseEntity> getMainContents(@RequestParam(value = "type") CategoryType type){ 25 | if(!CategoryType.isContainCategoryType(type.getTitle())){ 26 | throw new NotExistsRequestParamException(); 27 | } 28 | return ResponseEntity.ok(contentsService.getMainContents(type)); 29 | } 30 | 31 | @RequestMapping(value = "/category",method = RequestMethod.GET) 32 | public ResponseEntity> getCategoryContents(@RequestParam(value = "type") CategoryType type, @RequestParam(value = "page")int page, 33 | @RequestParam(value = "order",required = false)OrderType order){ 34 | if(!CategoryType.isContainCategoryType(type.getTitle())||!OrderType.isContainOrderType(order.getName())){ 35 | throw new NotExistsRequestParamException(); 36 | } 37 | return ResponseEntity.ok(contentsService.getCategoryContents(type, page,order)); 38 | } 39 | 40 | @RequestMapping(value = "/count",method = RequestMethod.GET) 41 | public ResponseEntity getCategoryCount(){ 42 | return ResponseEntity.ok(contentsService.getCategoryCount()); 43 | } 44 | 45 | @RequestMapping(value = "/search", method = RequestMethod.GET) 46 | public ResponseEntity getSearchContents(@RequestParam(value = "type")CategoryType type, @RequestParam(value = "search")String search){ 47 | return ResponseEntity.ok(contentsService.getSearchContents(search,type)); 48 | } 49 | 50 | @RequestMapping(value = "/deleteCache",method = RequestMethod.GET) 51 | public ResponseEntity deleteCacheContents(){ 52 | contentsService.deleteContentsCache(); 53 | return ResponseEntity.ok("success"); 54 | } 55 | 56 | @RequestMapping(value = "/elasticsearch",method = RequestMethod.GET) 57 | public ResponseEntity updateContentsElasticSearch(){ 58 | contentsService.updateElasticsearch(); 59 | return ResponseEntity.ok("success"); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/CrawlingContentsLastUrlController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.CrawlingContentsLastUrlService; 4 | import com.hermes.ithermes.presentation.dto.crawlingcontentslasttitle.CrawlingContentsLastUrlFindAllResponseDto; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | @RequiredArgsConstructor 13 | @RequestMapping("/api/crawling-contents-last-title") 14 | public class CrawlingContentsLastUrlController { 15 | 16 | private final CrawlingContentsLastUrlService crawlingContentsLastUrlService; 17 | 18 | @RequestMapping(value = "/",method = RequestMethod.GET) 19 | public ResponseEntity findAllCrawlingContentsLastTitle() { 20 | CrawlingContentsLastUrlFindAllResponseDto crawlingContentsLastUrlFindAllResponseDto = crawlingContentsLastUrlService.findAllCrawlingContentsLastTitle(); 21 | return ResponseEntity.ok(crawlingContentsLastUrlFindAllResponseDto); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/JobController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.JobService; 4 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 5 | import com.hermes.ithermes.presentation.dto.job.JobInsertRequestDto; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import java.net.URI; 14 | 15 | @RestController 16 | @RequiredArgsConstructor 17 | @RequestMapping("/api/job") 18 | public class JobController { 19 | private final JobService jobService; 20 | 21 | @RequestMapping(value = "/",method = RequestMethod.POST) 22 | public ResponseEntity insertJob(@RequestBody JobInsertRequestDto jobInsertRequestDto){ 23 | CommonResponseDto commonResponseDto = jobService.insertJob(jobInsertRequestDto); 24 | return ResponseEntity.created(URI.create("/api/job")).body(commonResponseDto); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/SubscribeController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.SubscribeService; 4 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 5 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeContentsDto; 6 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeFindSubscribeRequestDto; 7 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribePutSubscribeRequestDto; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestMethod; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.validation.Valid; 16 | import java.util.List; 17 | 18 | @RestController 19 | @RequestMapping("/api/subscribe") 20 | public class SubscribeController { 21 | private final SubscribeService subscribeService; 22 | 23 | @Autowired 24 | public SubscribeController(SubscribeService subscribeService) { 25 | this.subscribeService = subscribeService; 26 | } 27 | 28 | @RequestMapping(value = "/", method = RequestMethod.PUT) 29 | public ResponseEntity putSubscribe(@Valid @RequestBody SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto) { 30 | 31 | CommonResponseDto commonResponseDto = subscribeService.putSubscribe(subscribePutSubscribeRequestDto); 32 | return ResponseEntity.ok(commonResponseDto); 33 | } 34 | 35 | @RequestMapping(value = "/", method = RequestMethod.POST) 36 | public ResponseEntity> findSubscribe(@Valid @RequestBody SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto) { 37 | 38 | List subscribe = subscribeService.findSubscribe(subscribeFindSubscribeRequestDto); 39 | return ResponseEntity.ok(subscribe); 40 | } 41 | 42 | @RequestMapping(value = "/elasticsearch", method = RequestMethod.GET) 43 | public ResponseEntity updateSubscribeElasticSearch(){ 44 | return ResponseEntity.ok("success"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/UrlRecordController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.UrlRecordService; 4 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 5 | import com.hermes.ithermes.presentation.dto.urlrecord.UrlRecordPutViewCountRequestDto; 6 | import jakarta.servlet.http.HttpServletRequest; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.net.URISyntaxException; 15 | 16 | @RestController 17 | @RequiredArgsConstructor 18 | @RequestMapping("/api/url-record") 19 | public class UrlRecordController { 20 | private final UrlRecordService urlRecordService; 21 | 22 | @RequestMapping(value = "/", method = RequestMethod.POST) 23 | public ResponseEntity putViewCount(@RequestBody UrlRecordPutViewCountRequestDto urlRecordPutViewCountRequestDto, HttpServletRequest httpServletRequest) throws URISyntaxException { 24 | String ipAddress = httpServletRequest.getRemoteAddr(); 25 | CommonResponseDto responseDto = urlRecordService.putViewCount(urlRecordPutViewCountRequestDto, ipAddress); 26 | return ResponseEntity.ok(responseDto); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.UserService; 4 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 5 | import com.hermes.ithermes.presentation.dto.user.*; 6 | import jakarta.servlet.http.HttpServletRequest; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestMethod; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.validation.Valid; 16 | import java.net.URI; 17 | import java.util.List; 18 | 19 | @RestController() 20 | @RequestMapping("/api/user") 21 | public class UserController { 22 | 23 | private final UserService userService; 24 | 25 | @Autowired 26 | public UserController(UserService userService) { 27 | this.userService = userService; 28 | } 29 | 30 | @RequestMapping(value = "/join", method = RequestMethod.POST) 31 | public ResponseEntity joinUser(@Valid @RequestBody UserCreateUserRequestDto userCreateUserRequestDto) { 32 | userService.joinUser(userCreateUserRequestDto); 33 | URI uri = URI.create("/api/user/join/"); 34 | 35 | return ResponseEntity.created(uri).body(userCreateUserRequestDto); 36 | } 37 | 38 | @RequestMapping(value = "/login", method = RequestMethod.POST) 39 | public ResponseEntity loginUser(@Valid @RequestBody UserLoginRequestDto userLoginRequestDto) { 40 | UserLoginResponseDto userLoginResponseDto = userService.loginUser(userLoginRequestDto); 41 | return ResponseEntity.ok().body(userLoginResponseDto); 42 | } 43 | 44 | @RequestMapping(value = "/duplicate-nickname", method = RequestMethod.POST) 45 | public ResponseEntity checkDuplicateNickname(@Valid @RequestBody UserDuplicateNicknameRequestDto userDuplicateNicknameRequestDto) { 46 | CommonResponseDto userDuplicateNicknameResponseDto = userService.checkDuplicateNickname(userDuplicateNicknameRequestDto); 47 | return ResponseEntity.ok(userDuplicateNicknameResponseDto); 48 | } 49 | 50 | @RequestMapping(value = "/duplicate-id", method = RequestMethod.POST) 51 | public ResponseEntity checkDuplicateNickname(@Valid @RequestBody UserDuplicateIdRequestDto userDuplicateIdRequestDto) { 52 | CommonResponseDto userDuplicateIdResponseDto = userService.checkDuplicateId(userDuplicateIdRequestDto); 53 | return ResponseEntity.ok(userDuplicateIdResponseDto); 54 | } 55 | 56 | @RequestMapping(value = "/nickname", method = RequestMethod.PUT) 57 | public ResponseEntity checkDuplicateNickname(@Valid @RequestBody UserUpdateNicknameRequestDto userUpdateNicknameRequestDto) { 58 | CommonResponseDto userUpdateNicknameResponseDto = userService.updateNickname(userUpdateNicknameRequestDto); 59 | return ResponseEntity.ok(userUpdateNicknameResponseDto); 60 | } 61 | 62 | @RequestMapping(value = "/user-list", method = RequestMethod.GET) 63 | public ResponseEntity> findUserList() { 64 | List userList = userService.findUserList(); 65 | return ResponseEntity.ok(userList); 66 | } 67 | 68 | @RequestMapping(value = "/", method = RequestMethod.PUT) 69 | public ResponseEntity deleteUser(@Valid @RequestBody UserDeleteUserRequestDto userDeleteUserRequestDto) { 70 | CommonResponseDto commonResponseDto = userService.deleteUser(userDeleteUserRequestDto); 71 | return ResponseEntity.ok(commonResponseDto); 72 | } 73 | 74 | @RequestMapping(value = "/my-page", method = RequestMethod.POST) 75 | public ResponseEntity findMyData(@Valid @RequestBody UserFindMyDataRequestDto userFindMyDataRequestDto) { 76 | UserFindMyDataResponseDto userFindMyDataResponseDto = userService.findMyData(userFindMyDataRequestDto); 77 | return ResponseEntity.ok(userFindMyDataResponseDto); 78 | } 79 | 80 | @RequestMapping(value = "/refresh-token", method = RequestMethod.GET) 81 | public ResponseEntity checkRefreshToken(HttpServletRequest request) { 82 | String refreshToken = request.getHeader("HERMES-REFRESH-TOKEN"); 83 | UserCheckRefreshTokenResponseDto userCheckRefreshTokenResponseDto = userService.checkRefreshToken(refreshToken); 84 | return ResponseEntity.ok(userCheckRefreshTokenResponseDto); 85 | } 86 | 87 | @RequestMapping(value = "/logout", method = RequestMethod.GET) 88 | public ResponseEntity logoutUser(Authentication authentication) { 89 | String loginId = authentication.getName(); 90 | CommonResponseDto commonResponseDto = userService.userLogout(loginId); 91 | return ResponseEntity.ok(commonResponseDto); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/controller/YoutubeAndNewsController.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.hermes.ithermes.application.YoutubeAndNewsService; 4 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 5 | import com.hermes.ithermes.presentation.dto.youtubeandnews.YoutubeAndNewsInsertDto; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import java.net.URI; 14 | 15 | @RestController 16 | @RequiredArgsConstructor 17 | @RequestMapping("/api/youtube-and-news") 18 | public class YoutubeAndNewsController { 19 | private final YoutubeAndNewsService youtubeAndNewsService; 20 | 21 | @RequestMapping(value = "/",method = RequestMethod.POST) 22 | public ResponseEntity parseYoutubeAndNews(@RequestBody YoutubeAndNewsInsertDto youtubeAndNewsCrawlingDtoList){ 23 | CommonResponseDto commonResponseDto = youtubeAndNewsService.insertYoutubeAndNews(youtubeAndNewsCrawlingDtoList); 24 | return ResponseEntity.created(URI.create("/api/youtube-and-news")).body(commonResponseDto); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/CommonResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class CommonResponseDto { 7 | 8 | private String message; 9 | 10 | public CommonResponseDto() { 11 | this.message = "success"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/alarm/AlarmDtoInterface.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.alarm; 2 | 3 | import com.hermes.ithermes.domain.util.ContentsProviderType; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | public interface AlarmDtoInterface { 8 | 9 | String title(); 10 | String description(); 11 | String image(); 12 | String url(); 13 | LocalDateTime contentsStartAt(); 14 | ContentsProviderType contentsProvider(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/alarm/JobAlarmDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.alarm; 2 | 3 | import com.hermes.ithermes.domain.entity.Job; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @Getter 12 | @Builder 13 | @AllArgsConstructor 14 | public class JobAlarmDto{ 15 | 16 | private String title; 17 | 18 | private String location; 19 | 20 | private String company; 21 | 22 | private String url; 23 | 24 | private LocalDateTime contentsEndAt; 25 | 26 | private ContentsProviderType contentsProviderType; 27 | 28 | public static JobAlarmDto convertEntityToDto(Job job){ 29 | return JobAlarmDto.builder() 30 | .title(job.getTitle()) 31 | .location(job.getLocation()) 32 | .company(job.getCompany()) 33 | .url(job.getUrl()) 34 | .contentsEndAt(job.getContentsEndAt()) 35 | .contentsProviderType(job.getContentsProvider()) 36 | .build(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/alarm/YoutubeAndNewsAlarmDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.alarm; 2 | 3 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @Getter 12 | @AllArgsConstructor 13 | @Builder 14 | public class YoutubeAndNewsAlarmDto implements AlarmDtoInterface{ 15 | 16 | private String title; 17 | 18 | private String description; 19 | 20 | private String image; 21 | 22 | private String url; 23 | 24 | private LocalDateTime contentsStartAt; 25 | 26 | private ContentsProviderType contentsProviderType; 27 | 28 | public static YoutubeAndNewsAlarmDto convertEntityToDto(YoutubeAndNews youtubeAndNews){ 29 | return YoutubeAndNewsAlarmDto.builder() 30 | .title(youtubeAndNews.getTitle()) 31 | .description(youtubeAndNews.getDescription()) 32 | .image(youtubeAndNews.getImage()) 33 | .url(youtubeAndNews.getUrl()) 34 | .contentsStartAt(youtubeAndNews.getContentsStartAt()) 35 | .contentsProviderType(youtubeAndNews.getContentsProvider()) 36 | .build(); 37 | } 38 | 39 | @Override 40 | public String title() { 41 | return title; 42 | } 43 | 44 | @Override 45 | public String description() { 46 | return description; 47 | } 48 | 49 | @Override 50 | public String image() { 51 | return image; 52 | } 53 | 54 | @Override 55 | public String url() { 56 | return url; 57 | } 58 | 59 | @Override 60 | public LocalDateTime contentsStartAt() { 61 | return contentsStartAt; 62 | } 63 | 64 | @Override 65 | public ContentsProviderType contentsProvider() { 66 | return contentsProviderType; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/contents/CategoryCountDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.contents; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class CategoryCountDto { 11 | private long youtubeCnt; 12 | private long jobCnt; 13 | private long newsCnt; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/contents/ContentsDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.contents; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 6 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; 7 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 8 | import com.hermes.ithermes.domain.entity.CrawlingContents; 9 | import com.hermes.ithermes.domain.util.CategoryType; 10 | import com.hermes.ithermes.domain.util.ContentsProviderType; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Builder; 13 | import lombok.Getter; 14 | import lombok.NoArgsConstructor; 15 | 16 | import java.io.Serializable; 17 | import java.time.LocalDateTime; 18 | 19 | @Getter 20 | @Builder 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | public class ContentsDto implements ContentsDtoInterface, Serializable { 24 | 25 | public String title; 26 | 27 | public String image; 28 | 29 | public String url; 30 | 31 | public CategoryType category; 32 | 33 | public ContentsProviderType contentProvider; 34 | 35 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 36 | @JsonSerialize(using = LocalDateTimeSerializer.class) 37 | @JsonDeserialize(using = LocalDateTimeDeserializer.class) 38 | public LocalDateTime contentsDate; 39 | 40 | public String description; 41 | 42 | public Long viewCnt; 43 | 44 | public ContentsDto(CrawlingContents crawlingContents){ 45 | this.title = crawlingContents.findTitle(); 46 | this.image = crawlingContents.findImage(); 47 | this.url = crawlingContents.findUrl(); 48 | this.category = crawlingContents.findCategoryType(); 49 | this.contentProvider = crawlingContents.findContentsProvider(); 50 | this.contentsDate = crawlingContents.findContentsTime(); 51 | this.description = crawlingContents.findDescription(); 52 | this.viewCnt = crawlingContents.findViewCount(); 53 | } 54 | 55 | @Override 56 | public ContentsDto convertEntityToDto(CrawlingContents crawlingContents) { 57 | return new ContentsDto(crawlingContents); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/contents/ContentsDtoInterface.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.contents; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContents; 4 | 5 | public interface ContentsDtoInterface { 6 | 7 | ContentsDtoInterface convertEntityToDto(CrawlingContents crawlingContents); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/contents/MainPageContentsDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.contents; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 6 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; 7 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 8 | import com.hermes.ithermes.domain.entity.CrawlingContents; 9 | import com.hermes.ithermes.domain.util.CategoryType; 10 | import com.hermes.ithermes.domain.util.ContentsProviderType; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Builder; 13 | import lombok.Getter; 14 | import lombok.NoArgsConstructor; 15 | 16 | import java.io.Serializable; 17 | import java.time.LocalDateTime; 18 | 19 | @Getter 20 | @AllArgsConstructor 21 | @Builder 22 | @NoArgsConstructor 23 | public class MainPageContentsDto implements ContentsDtoInterface, Serializable { 24 | 25 | public String title; 26 | 27 | public String image; 28 | 29 | public String url; 30 | 31 | public CategoryType category; 32 | 33 | public ContentsProviderType contentsProviderType; 34 | 35 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 36 | @JsonSerialize(using = LocalDateTimeSerializer.class) 37 | @JsonDeserialize(using = LocalDateTimeDeserializer.class) 38 | public LocalDateTime contentsDate; 39 | 40 | public Long viewCnt; 41 | 42 | public MainPageContentsDto(CrawlingContents crawlingContents) { 43 | this.title = crawlingContents.findTitle(); 44 | this.image = crawlingContents.findImage(); 45 | this.url = crawlingContents.findUrl(); 46 | this.category = crawlingContents.findCategoryType(); 47 | this.contentsProviderType = crawlingContents.findContentsProvider(); 48 | this.contentsDate = crawlingContents.findContentsTime(); 49 | this.viewCnt = crawlingContents.findViewCount(); 50 | } 51 | 52 | @Override 53 | public MainPageContentsDto convertEntityToDto(CrawlingContents crawlingContents) { 54 | return new MainPageContentsDto(crawlingContents); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/contents/SearchContentsDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.contents; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | @Getter 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class SearchContentsDto { 15 | 16 | public int count; 17 | 18 | public List searchContentsList; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/crawlingcontentslasttitle/CrawlingContentsLastUrlFindAllResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.crawlingcontentslasttitle; 2 | 3 | import com.hermes.ithermes.domain.entity.CrawlingContentsLastUrl; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Getter 13 | public class CrawlingContentsLastUrlFindAllResponseDto { 14 | List crawlingContentsLastUrlDtoList; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/error/EntryPointErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.error; 2 | 3 | import lombok.*; 4 | 5 | @Data 6 | @NoArgsConstructor 7 | @AllArgsConstructor 8 | public class EntryPointErrorResponse { 9 | private String msg; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/error/UserErrorDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.error; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class UserErrorDto { 7 | private String message; 8 | private String errorData; 9 | 10 | public UserErrorDto(String message, String errorData) { 11 | this.message = message; 12 | this.errorData = errorData; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/job/JobCrawlingDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.job; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class JobCrawlingDto { 11 | private String company; 12 | private String title; 13 | private String url; 14 | private String location; 15 | private String startDate; 16 | private String endDate; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/job/JobInsertRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.job; 2 | 3 | import com.hermes.ithermes.domain.util.ContentsProviderType; 4 | import com.hermes.ithermes.domain.util.GradeType; 5 | import com.hermes.ithermes.domain.util.JobType; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.util.List; 11 | 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Getter 15 | public class JobInsertRequestDto { 16 | private ContentsProviderType contentsProvider; 17 | private GradeType grade; 18 | private JobType job; 19 | private List jobCrawlingDtoList; 20 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/subscribe/SubscribeContentsDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.subscribe; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class SubscribeContentsDto { 11 | private String contentsProvider; 12 | private String isActive; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/subscribe/SubscribeFindSubscribeRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.subscribe; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | @Getter 11 | public class SubscribeFindSubscribeRequestDto { 12 | @NotBlank(message = "아이디는 필수 입력사항 입니다.") 13 | private String id; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/subscribe/SubscribeFindSubscribeResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.subscribe; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | @Getter 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class SubscribeFindSubscribeResponseDto { 15 | /** 서비스 구독 활성화 정보 */ 16 | private List keywordList; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/subscribe/SubscribePutSubscribeRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.subscribe; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotEmpty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.ArrayList; 10 | 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Getter 14 | public class SubscribePutSubscribeRequestDto { 15 | 16 | @NotBlank(message = "아이디는 필수 입력사항 입니다.") 17 | private String id; 18 | 19 | /** 20 | * 서비스 구독 활성화 정보, 비활성화 시, 배열에 "NON_ACTIVE" 삽입 21 | */ 22 | @NotEmpty(message = "서비스정보는 필수 입력사항 입니다.") 23 | private ArrayList subscribeContentsList; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/urlrecord/UrlRecordPutViewCountRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.urlrecord; 2 | 3 | import com.hermes.ithermes.domain.util.ContentsProviderType; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | @Getter 11 | public class UrlRecordPutViewCountRequestDto { 12 | private String url; 13 | private ContentsProviderType contentsProviderType; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserCheckRefreshTokenResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | 7 | @Getter 8 | @Builder 9 | @AllArgsConstructor 10 | public class UserCheckRefreshTokenResponseDto { 11 | private String message; 12 | private String accessToken; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserCreateUserRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import com.hermes.ithermes.domain.util.JobType; 4 | import jakarta.validation.constraints.NotBlank; 5 | import jakarta.validation.constraints.NotEmpty; 6 | import jakarta.validation.constraints.Pattern; 7 | import jakarta.validation.constraints.Size; 8 | import lombok.*; 9 | 10 | 11 | @Getter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class UserCreateUserRequestDto { 15 | @NonNull 16 | @NotBlank(message = "아이디는 필수 입력사항 입니다.") 17 | private String id; 18 | @Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}", 19 | message = "비밀번호는 영문 대,소문자와 숫자, 특수기호가 적어도 1개 이상씩 포함된 8자 ~ 20자의 비밀번호여야 합니다.") 20 | private String password; 21 | @NonNull 22 | @NotBlank(message = "비밀번호 확인은 필수 입력사항 입니다.") 23 | private String passwordConfirm; 24 | @NonNull 25 | @NotBlank(message = "닉네임은 필수 입력사항 입니다.") 26 | @Size(min = 2, max = 10, message = "닉네임은 2~10자만 가능 합니다.") 27 | private String nickname; 28 | @NonNull 29 | private JobType job; 30 | @NonNull 31 | @NotBlank(message = "경력은 필수 입력사항 입니다.") 32 | private String yearOfExperience; 33 | /** 34 | * 키워드는 최대 5개, 5개 이하 일 시, 배열에 null 삽입 35 | */ 36 | @NonNull 37 | @NotEmpty(message = "키워드는 필수 입력사항 입니다.") 38 | private String[] keywordList; 39 | 40 | public void encodingPassword(final String password) { 41 | this.password = password; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserDeleteUserRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.NonNull; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | @RequiredArgsConstructor 9 | @NoArgsConstructor 10 | @Getter 11 | public class UserDeleteUserRequestDto { 12 | @NonNull 13 | private String id; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserDuplicateIdRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.Getter; 4 | import lombok.NonNull; 5 | 6 | @Getter 7 | public class UserDuplicateIdRequestDto { 8 | @NonNull 9 | private String id; 10 | 11 | public UserDuplicateIdRequestDto() { 12 | 13 | } 14 | 15 | public UserDuplicateIdRequestDto(@NonNull String id) { 16 | this.id = id; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserDuplicateNicknameRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.Getter; 4 | import lombok.NonNull; 5 | 6 | @Getter 7 | public class UserDuplicateNicknameRequestDto { 8 | @NonNull 9 | private String nickname; 10 | 11 | public UserDuplicateNicknameRequestDto() { 12 | 13 | } 14 | 15 | public UserDuplicateNicknameRequestDto(@NonNull String nickname) { 16 | this.nickname = nickname; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserFindMyDataRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.NonNull; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | @RequiredArgsConstructor 9 | @NoArgsConstructor 10 | @Getter 11 | public class UserFindMyDataRequestDto { 12 | @NonNull 13 | private String id; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserFindMyDataResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.NonNull; 6 | import lombok.RequiredArgsConstructor; 7 | 8 | @RequiredArgsConstructor 9 | @NoArgsConstructor 10 | @Getter 11 | public class UserFindMyDataResponseDto { 12 | @NonNull 13 | String id; 14 | @NonNull 15 | String nickname; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserFindUserListResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeContentsDto; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Getter 15 | public class UserFindUserListResponseDto { 16 | String loginId; 17 | String nickname; 18 | String jobType; 19 | int yearOfExperience; 20 | List subscribeList; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserLoginRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.NonNull; 7 | 8 | @Getter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | public class UserLoginRequestDto { 12 | @NonNull 13 | private String id; 14 | @NonNull 15 | private String password; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserLoginResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Getter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @Builder 12 | public class UserLoginResponseDto { 13 | private String message; 14 | private String accessToken; 15 | private String refreshToken; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/user/UserUpdateNicknameRequestDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.user; 2 | 3 | import lombok.Getter; 4 | import lombok.NonNull; 5 | 6 | @Getter 7 | public class UserUpdateNicknameRequestDto { 8 | @NonNull 9 | private String id; 10 | @NonNull 11 | private String nickname; 12 | 13 | public UserUpdateNicknameRequestDto() { 14 | 15 | } 16 | 17 | public UserUpdateNicknameRequestDto(String id, String nickname) { 18 | this.id = id; 19 | this.nickname = nickname; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/youtubeandnews/YoutubeAndNewsCrawlingDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.youtubeandnews; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class YoutubeAndNewsCrawlingDto { 11 | private String title; 12 | private String url; 13 | private String description; 14 | private String thumbnail; 15 | private String date; 16 | } -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/dto/youtubeandnews/YoutubeAndNewsInsertDto.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.dto.youtubeandnews; 2 | 3 | import com.hermes.ithermes.domain.util.CategoryType; 4 | import com.hermes.ithermes.domain.util.ContentsProviderType; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.ArrayList; 10 | 11 | @Getter 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class YoutubeAndNewsInsertDto { 15 | private CategoryType category; 16 | private ContentsProviderType contentsProvider; 17 | ArrayList youtubeAndNewsCrawlingDtoList; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/security/CustomAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.security; 2 | 3 | import com.hermes.ithermes.domain.exception.WrongIdOrPasswordException; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.security.access.AccessDeniedException; 7 | import org.springframework.security.web.access.AccessDeniedHandler; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class CustomAccessDeniedHandler implements AccessDeniedHandler { 12 | 13 | @Override 14 | public void handle(HttpServletRequest request, HttpServletResponse response, 15 | AccessDeniedException accessDeniedException) { 16 | throw new WrongIdOrPasswordException(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/security/CustomAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.security; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.hermes.ithermes.presentation.dto.error.EntryPointErrorResponse; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.web.AuthenticationEntryPoint; 9 | 10 | import java.io.IOException; 11 | 12 | public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { 13 | 14 | @Override 15 | public void commence(HttpServletRequest request, HttpServletResponse response, 16 | AuthenticationException authException) throws IOException { 17 | String exception = request.getAttribute("exception").toString(); 18 | 19 | if(exception.equals(SecurityErrorCode.WRONG_TYPE_TOKEN.getCode())) { 20 | setResponse(response, exception); 21 | return; 22 | } 23 | 24 | if(exception.equals(SecurityErrorCode.EXPIRED_TOKEN.getCode())) { 25 | setResponse(response, exception); 26 | return; 27 | } 28 | 29 | if(exception.equals(null)) { 30 | setResponse(response, "인증실패"); 31 | } 32 | } 33 | 34 | private void setResponse(HttpServletResponse response, String message) throws IOException { 35 | ObjectMapper objectMapper = new ObjectMapper(); 36 | EntryPointErrorResponse entryPointErrorResponse = new EntryPointErrorResponse(); 37 | entryPointErrorResponse.setMsg(message); 38 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 39 | response.setContentType("application/json;charset=UTF-8"); 40 | response.setCharacterEncoding("utf-8"); 41 | response.getWriter().write(objectMapper.writeValueAsString(entryPointErrorResponse)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/security/JwtFilter.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.security; 2 | 3 | import jakarta.servlet.FilterChain; 4 | import jakarta.servlet.ServletException; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 9 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 10 | import org.springframework.security.core.context.SecurityContextHolder; 11 | import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; 12 | import org.springframework.web.filter.OncePerRequestFilter; 13 | 14 | import java.io.IOException; 15 | import java.util.List; 16 | 17 | @RequiredArgsConstructor 18 | public class JwtFilter extends OncePerRequestFilter { 19 | private final String secretKey; 20 | 21 | @Override 22 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 23 | FilterChain filterChain) throws ServletException, IOException { 24 | final String authentication = request.getHeader("HERMES-ACCESS-TOKEN"); 25 | 26 | if (authentication == null || !authentication.startsWith("Bearer ")) { 27 | request.setAttribute("exception", SecurityErrorCode.WRONG_TYPE_TOKEN); 28 | filterChain.doFilter(request, response); 29 | return; 30 | } 31 | 32 | String token = authentication.split(" ")[1]; 33 | 34 | if (!JwtUtil.validateToken(token, secretKey)) { 35 | logger.error("Token 만료"); 36 | request.setAttribute("exception", SecurityErrorCode.EXPIRED_TOKEN); 37 | filterChain.doFilter(request, response); 38 | return; 39 | } 40 | 41 | String userName = JwtUtil.getUsername(token, secretKey); 42 | 43 | UsernamePasswordAuthenticationToken authenticationToken = 44 | new UsernamePasswordAuthenticationToken(userName, null, List.of(new SimpleGrantedAuthority("USER"))); 45 | 46 | authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); 47 | SecurityContextHolder.getContext().setAuthentication(authenticationToken); 48 | filterChain.doFilter(request, response); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/security/JwtUtil.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.security; 2 | 3 | import io.jsonwebtoken.Claims; 4 | import io.jsonwebtoken.Jws; 5 | import io.jsonwebtoken.Jwts; 6 | import io.jsonwebtoken.SignatureAlgorithm; 7 | import jakarta.annotation.PostConstruct; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.nio.charset.StandardCharsets; 12 | import java.util.Base64; 13 | import java.util.Date; 14 | 15 | @Component 16 | public class JwtUtil { 17 | 18 | @Value("${springboot.jwt.secret}") 19 | private String secretKey = "secretKey"; 20 | private final long tokenValidMillisecond = 1000L * 60 * 60; 21 | 22 | @PostConstruct 23 | protected void init() { 24 | secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)); 25 | } 26 | 27 | public String createAccessToken(String userName) { 28 | Claims claims = Jwts.claims(); 29 | claims.put("userName",userName); 30 | Date now = new Date(); 31 | 32 | String token = Jwts.builder() 33 | .setHeaderParam("type", "jwt") 34 | .setClaims(claims) 35 | .setIssuedAt(now) 36 | .setExpiration(new Date(now.getTime() + tokenValidMillisecond)) 37 | .signWith(SignatureAlgorithm.HS256, secretKey) 38 | .compact(); 39 | 40 | return token; 41 | } 42 | 43 | public String createRefreshToken(String userName) { 44 | Claims claims = Jwts.claims(); 45 | claims.put("userName",userName); 46 | Date now = new Date(); 47 | 48 | String token = Jwts.builder() 49 | .setHeaderParam("type", "jwt") 50 | .setClaims(claims) 51 | .setIssuedAt(now) 52 | .setExpiration(new Date(now.getTime() + tokenValidMillisecond*72)) 53 | .signWith(SignatureAlgorithm.HS256, secretKey) 54 | .compact(); 55 | 56 | return token; 57 | } 58 | 59 | public static String getUsername(String token, String secretKey) { 60 | secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)); 61 | String info = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().get("userName",String.class); 62 | return info; 63 | } 64 | 65 | public static boolean validateToken(String token, String secretKey) { 66 | try { 67 | secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)); 68 | Jws claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); 69 | return !claims.getBody().getExpiration().before(new Date()); 70 | } catch (Exception e) { 71 | return false; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/security/SecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.security; 2 | 3 | import com.hermes.ithermes.application.UserService; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; 12 | import org.springframework.security.config.http.SessionCreationPolicy; 13 | import org.springframework.security.web.SecurityFilterChain; 14 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 15 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 16 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 17 | 18 | @Configuration 19 | @RequiredArgsConstructor 20 | @EnableWebSecurity 21 | @EnableMethodSecurity 22 | public class SecurityConfiguration { 23 | 24 | public static final String ALLOWED_METHOD_NAMES = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,PATCH"; 25 | private final UserService userService; 26 | 27 | @Value("${springboot.jwt.secret}") 28 | private String secretKey; 29 | 30 | @Bean 31 | public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { 32 | return httpSecurity 33 | .httpBasic().disable() 34 | .csrf().disable() 35 | .cors().and() 36 | .sessionManagement() 37 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 38 | .and() 39 | .authorizeHttpRequests().requestMatchers("/user/login", "/user/join","/user/duplicate-id","/user/duplicate-nickname","/user/refresh-token").permitAll() 40 | .and() 41 | .authorizeHttpRequests().requestMatchers("/api/user/login", "/api/user/join","/api/user/duplicate-id","/api/user/duplicate-nickname","/api/user/refresh-token").permitAll() 42 | .and() 43 | .authorizeHttpRequests().requestMatchers("/youtube-and-news/", "/job/","/crawling-contents-last-title/","/api/alarm/recommend").permitAll() 44 | .and() 45 | .authorizeHttpRequests().requestMatchers("/api/youtube-and-news/", "/api/job/","/api/crawling-contents-last-title/","/api/alarm/subscription").permitAll() 46 | .and() 47 | .authorizeHttpRequests().requestMatchers("/contents/main","/url-record/","/contents/count").permitAll() 48 | .and() 49 | .authorizeHttpRequests().requestMatchers("/api/contents/main","/api/url-record/","/api/contents/count","/api/contents/search","/api/contents/refreshCache","/api/contents/elasticsearch").permitAll() 50 | .and() 51 | .authorizeHttpRequests().requestMatchers("/**").authenticated() 52 | .and() 53 | .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler()) 54 | .and() 55 | .exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint()) 56 | .and() 57 | .addFilterBefore(new JwtFilter(secretKey), UsernamePasswordAuthenticationFilter.class) 58 | .build(); 59 | } 60 | 61 | @Bean 62 | public WebSecurityCustomizer webSecurityCustomizer(){ 63 | return (web) -> web.ignoring().requestMatchers("/favicon.ico"); 64 | } 65 | 66 | @Bean 67 | public WebMvcConfigurer corsConfigurer() { 68 | return new WebMvcConfigurer() { 69 | @Override 70 | public void addCorsMappings(CorsRegistry registry) { 71 | registry.addMapping("/**").allowedOrigins("http://localhost:5500"); 72 | registry.addMapping("/**").allowedOrigins("http://127.0.0.1:5500"); 73 | registry.addMapping("/**").allowedOrigins("http://127.0.0.1:80"); 74 | registry.addMapping("/**").allowedOrigins("http://localhost:80"); 75 | registry.addMapping("/**").allowedMethods(ALLOWED_METHOD_NAMES.split(",")); 76 | } 77 | }; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/hermes/ithermes/presentation/security/SecurityErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.security; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum SecurityErrorCode { 7 | WRONG_TYPE_TOKEN("WRONG_TYPE_TOKEN"), 8 | EXPIRED_TOKEN("EXPIRED_TOKEN"); 9 | 10 | private String code; 11 | 12 | SecurityErrorCode(String code) { 13 | this.code = code; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/application-eun.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: com.mysql.cj.jdbc.Driver 4 | url: jdbc:mysql://10.41.82.229:3306/ithermes?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC&allowPublicKeyRetrieval=true 5 | username: root 6 | password: ${PASSWORD} 7 | redis: 8 | ipAddress: 10.41.82.229 9 | elasticSearch: 10 | ipAddress: 10.41.82.229 11 | port: 9200 12 | 13 | jpa: 14 | open-in-view: true 15 | hibernate: 16 | ddl-auto: update 17 | naming: 18 | physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 19 | show-sql: true 20 | properties: 21 | hibernate.format_sql: true 22 | dialect: org.hibernate.dialect.MySQL8InnoDBDialect 23 | defer-datasource-initialization: true 24 | sql: 25 | init: 26 | mode: always 27 | 28 | springboot: 29 | jwt: 30 | secret: ${JWT_KEY} 31 | 32 | logging: 33 | level: 34 | org.hibernate.SQL: debug 35 | springframework.data.elasticsearch.client.WIRE: TRACE 36 | 37 | telegram-key: ${TELEGRAM_KEY} -------------------------------------------------------------------------------- /src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: com.mysql.cj.jdbc.Driver 4 | url: jdbc:mysql://localhost:3307/test_schema?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC&allowPublicKeyRetrieval=true 5 | username: ${username} 6 | password: ${password} 7 | redis: 8 | ipAddress: localhost 9 | elasticSearch: 10 | ipAddress: localhost 11 | port: 9200 12 | 13 | jpa: 14 | open-in-view: true 15 | hibernate: 16 | ddl-auto: update 17 | naming: 18 | physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 19 | show-sql: false 20 | properties: 21 | hibernate.format_sql: true 22 | dialect: org.hibernate.dialect.MySQL8InnoDBDialect 23 | defer-datasource-initialization: true 24 | sql: 25 | init: 26 | mode: always 27 | 28 | springboot: 29 | jwt: 30 | secret: ${jwt-key} 31 | 32 | logging: 33 | level: 34 | org.hibernate.SQL: debug 35 | springframework.data.elasticsearch.client.WIRE: TRACE 36 | 37 | telegram-key: ${telegram-key} -------------------------------------------------------------------------------- /src/main/resources/application-seung.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: com.mysql.cj.jdbc.Driver 4 | url: jdbc:mysql://10.41.4.73:3306/ithermes?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC&allowPublicKeyRetrieval=true 5 | username: ${DATASOURCE_USERNAME} 6 | password: ${DATASOURCE_PASSWORD} 7 | redis: 8 | ipAddress: 10.41.4.73 9 | elasticSearch: 10 | ipAddress: 10.41.4.73 11 | port: 9200 12 | 13 | jpa: 14 | open-in-view: true 15 | hibernate: 16 | ddl-auto: update 17 | naming: 18 | physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 19 | show-sql: true 20 | properties: 21 | hibernate.format_sql: true 22 | dialect: org.hibernate.dialect.MySQL8InnoDBDialect 23 | defer-datasource-initialization: true 24 | sql: 25 | init: 26 | mode: always 27 | 28 | springboot: 29 | jwt: 30 | secret: ${JWT_KEY} 31 | 32 | logging: 33 | level: 34 | org.hibernate.SQL: debug 35 | springframework.data.elasticsearch.client.WIRE: TRACE 36 | 37 | telegram-key: ${TELEGRAM_KEY} -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: com.mysql.cj.jdbc.Driver 4 | url: jdbc:mysql://10.41.4.73:3306/ithermes?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC&allowPublicKeyRetrieval=true 5 | username: ithermes 6 | password: ithermes1221 7 | redis: 8 | ipAddress: localhost 9 | elasticSearch: 10 | ipAddress: localhost 11 | port: 9200 12 | 13 | jpa: 14 | open-in-view: true 15 | hibernate: 16 | ddl-auto: update 17 | naming: 18 | physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 19 | show-sql: true 20 | properties: 21 | hibernate.format_sql: true 22 | dialect: org.hibernate.dialect.MySQL8InnoDBDialect 23 | defer-datasource-initialization: true 24 | sql: 25 | init: 26 | mode: always 27 | 28 | springboot: 29 | jwt: 30 | secret: test123!@# 31 | 32 | logging: 33 | level: 34 | org.hibernate.SQL: debug 35 | springframework.data.elasticsearch.client.WIRE: TRACE 36 | 37 | telegram-key: 5810579378:AAGNSVQz1Mzn1FjMkBuL1x-5UUz9u-jXdXc 38 | -------------------------------------------------------------------------------- /src/main/resources/ehcache.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/test/java/com/hermes/ithermes/application/ContentsServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | 4 | import com.hermes.ithermes.domain.entity.CrawlingContents; 5 | import com.hermes.ithermes.domain.entity.YoutubeAndNews; 6 | import com.hermes.ithermes.domain.util.CategoryType; 7 | import com.hermes.ithermes.domain.util.ContentsProviderType; 8 | import com.hermes.ithermes.infrastructure.YoutubeAndNewsRepository; 9 | import com.hermes.ithermes.presentation.dto.contents.ContentsDtoInterface; 10 | import jakarta.transaction.Transactional; 11 | import org.junit.jupiter.api.Assertions; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.DisplayName; 14 | import org.junit.jupiter.api.Test; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.data.domain.PageRequest; 18 | import org.springframework.data.domain.Pageable; 19 | 20 | import java.time.LocalDateTime; 21 | import java.util.List; 22 | /* 23 | @SpringBootTest 24 | @Transactional 25 | class ContentsServiceTest { 26 | 27 | @Autowired 28 | private ContentsService contentsService; 29 | 30 | @Autowired 31 | private YoutubeAndNewsRepository youtubeAndNewsRepository; 32 | 33 | @BeforeEach 34 | void setUp() { 35 | for(int i=0; i<12; i++){ 36 | YoutubeAndNews youtubeAndNews = new YoutubeAndNews((long)i,"안녕하세요","ㅎㅎㅎㅎㅎ","이미지 url","그냥 url", LocalDateTime.now(),123L,false,CategoryType.YOUTUBE, ContentsProviderType.DREAM_CODING); 37 | youtubeAndNewsRepository.save(youtubeAndNews); 38 | } 39 | } 40 | 41 | @Test 42 | @DisplayName("main contents를 11개 반환하는지 테스트") 43 | void checkMainContentsCount(){ 44 | List results = contentsService.getMainContents(CategoryType.YOUTUBE); 45 | Assertions.assertEquals(11, results.size()); 46 | } 47 | 48 | @Test 49 | @DisplayName("category contents 페이징 처리 테스트") 50 | void checkpaging() { 51 | Pageable pageInfo = PageRequest.of(0,2); 52 | List youtubeContents = youtubeAndNewsRepository.findYoutubeAndNewsByCategory(pageInfo, CategoryType.YOUTUBE).getContent(); 53 | 54 | Assertions.assertEquals(2,youtubeContents.size()); 55 | } 56 | 57 | }*/ 58 | 59 | -------------------------------------------------------------------------------- /src/test/java/com/hermes/ithermes/application/SubscribeServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.Subscribe; 4 | import com.hermes.ithermes.domain.entity.User; 5 | import com.hermes.ithermes.domain.exception.WrongIdOrPasswordException; 6 | import com.hermes.ithermes.domain.factory.SubscribeFactory; 7 | import com.hermes.ithermes.domain.util.ActiveType; 8 | import com.hermes.ithermes.domain.util.CategoryType; 9 | import com.hermes.ithermes.domain.util.ContentsProviderType; 10 | import com.hermes.ithermes.domain.util.JobType; 11 | import com.hermes.ithermes.infrastructure.SubscribeRepository; 12 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 13 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeContentsDto; 14 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeFindSubscribeRequestDto; 15 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribePutSubscribeRequestDto; 16 | import org.junit.jupiter.api.BeforeEach; 17 | import org.junit.jupiter.api.DisplayName; 18 | import org.junit.jupiter.api.Test; 19 | import org.junit.jupiter.api.extension.ExtendWith; 20 | import org.mockito.InjectMocks; 21 | import org.mockito.Mock; 22 | import org.mockito.junit.jupiter.MockitoExtension; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | import static org.junit.jupiter.api.Assertions.assertThrows; 29 | import static org.mockito.ArgumentMatchers.any; 30 | import static org.mockito.Mockito.when; 31 | 32 | @ExtendWith(MockitoExtension.class) 33 | class SubscribeServiceTest { 34 | @InjectMocks 35 | private SubscribeService subscribeService; 36 | @Mock 37 | private SubscribeRepository subscribeRepository; 38 | @Mock 39 | private SubscribeFactory subscribeFactory; 40 | 41 | private Subscribe subscribe; 42 | private User user; 43 | ArrayList subscribeContentsList; 44 | 45 | @BeforeEach 46 | void setUp() { 47 | user = User.builder() 48 | .loginId("test").nickname("김승기") 49 | .password("test1234").job(JobType.BACKEND) 50 | .yearOfExperience(1) 51 | .build(); 52 | 53 | subscribe = Subscribe.builder() 54 | .user(user) 55 | .category(CategoryType.JOB) 56 | .contentsProvider(ContentsProviderType.SARAMIN) 57 | .isActive(ActiveType.ACTIVE) 58 | .build(); 59 | 60 | subscribeContentsList = new ArrayList<>(); 61 | subscribeContentsList.add(new SubscribeContentsDto("SARAMIN","ACTIVE")); 62 | subscribeContentsList.add(new SubscribeContentsDto("WANTED","ACTIVE")); 63 | subscribeContentsList.add(new SubscribeContentsDto("CODING_WORLD","ACTIVE")); 64 | subscribeContentsList.add(new SubscribeContentsDto("NAVER","ACTIVE")); 65 | subscribeContentsList.add(new SubscribeContentsDto("YOZM","ACTIVE")); 66 | subscribeContentsList.add(new SubscribeContentsDto("NOMAD_CODERS","NON_ACTIVE")); 67 | subscribeContentsList.add(new SubscribeContentsDto("DREAM_CODING","ACTIVE")); 68 | 69 | } 70 | 71 | @Test 72 | @DisplayName("구독 데이터를 입력 시, 구독 테이블에 요청 된 정보 등록 혹은 수정 성공") 73 | void 구독_PUT_정상처리() { 74 | SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto = new SubscribePutSubscribeRequestDto("test", subscribeContentsList); 75 | assertEquals(new CommonResponseDto().getMessage(), subscribeService.putSubscribe(subscribePutSubscribeRequestDto).getMessage()); 76 | } 77 | 78 | @Test 79 | @DisplayName("구독 데이터 중 로그인 아이디를 잘못 입력할 시, WrongIdOrPasswordException 던지며 구독 정보 등록 혹은 수정 실패") 80 | void 구독_PUT_실패처리() { 81 | SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto = new SubscribePutSubscribeRequestDto("test", subscribeContentsList); 82 | 83 | when(subscribeFactory.parsePutSubscribeDtoToSubscribes(any())).thenThrow(new WrongIdOrPasswordException()); 84 | 85 | assertThrows(WrongIdOrPasswordException.class, () -> subscribeService.putSubscribe(subscribePutSubscribeRequestDto).getMessage()); 86 | } 87 | 88 | @Test 89 | @DisplayName("유저의 아이디를 요청할 시, 유저 정보와 일치하는 구독 테이블 정보가 있다면 조회 성공") 90 | void 구독조회_존재하는_구독데이터_조회() { 91 | SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto = new SubscribeFindSubscribeRequestDto("test"); 92 | List list = new ArrayList<>(); 93 | list.add(subscribe); 94 | when(subscribeFactory.parseFindSubscribeDtoToSubscribes(any())).thenReturn(list); 95 | 96 | List responseSubscribe = subscribeService.findSubscribe(subscribeFindSubscribeRequestDto); 97 | for (int i = 0; i < responseSubscribe.size(); i++) { 98 | assertEquals(subscribeContentsList.get(i).getIsActive(), responseSubscribe.get(i).getIsActive()); 99 | } 100 | } 101 | 102 | @Test 103 | @DisplayName("유저의 아이디를 요청할 시, 유저 정보와 일치하는 구독 테이블 정보가 있다면 비활성화 데이터를 보내며 조회 성공") 104 | void 구독조회_존재하지않는_구독데이터_조회() { 105 | SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto = new SubscribeFindSubscribeRequestDto("test"); 106 | List list = new ArrayList<>(); 107 | when(subscribeFactory.parseFindSubscribeDtoToSubscribes(any())).thenReturn(list); 108 | 109 | List responseSubscribe = subscribeService.findSubscribe(subscribeFindSubscribeRequestDto); 110 | assertEquals(list.size(), responseSubscribe.size()); 111 | } 112 | 113 | @Test 114 | @DisplayName("유저의 아이디를 요청할 시, 유저의 아이디 정보가 테이블에 없다면 WrongIdOrPasswordException 던지며 구독 정보 등록 혹은 수정 실패") 115 | void 구독조회_로그인_실패처리() { 116 | SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto = new SubscribeFindSubscribeRequestDto("aaaa"); 117 | when(subscribeFactory.parseFindSubscribeDtoToSubscribes(any())).thenThrow(new WrongIdOrPasswordException()); 118 | assertThrows(WrongIdOrPasswordException.class, () -> subscribeService.findSubscribe(subscribeFindSubscribeRequestDto)); 119 | } 120 | } -------------------------------------------------------------------------------- /src/test/java/com/hermes/ithermes/application/UserServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.application; 2 | 3 | import com.hermes.ithermes.domain.entity.Keyword; 4 | import com.hermes.ithermes.domain.entity.User; 5 | import com.hermes.ithermes.domain.entity.UserKeywordRegistry; 6 | import com.hermes.ithermes.domain.exception.SameIdException; 7 | import com.hermes.ithermes.domain.exception.SameNicknameException; 8 | import com.hermes.ithermes.domain.exception.UnMatchedPasswordException; 9 | import com.hermes.ithermes.domain.exception.WrongIdOrPasswordException; 10 | import com.hermes.ithermes.domain.factory.KeywordFactory; 11 | import com.hermes.ithermes.domain.factory.RedisFactory; 12 | import com.hermes.ithermes.domain.factory.UserFactory; 13 | import com.hermes.ithermes.domain.factory.UserKeywordRegistryFactory; 14 | import com.hermes.ithermes.domain.util.JobType; 15 | import com.hermes.ithermes.infrastructure.UserKeywordRegistryRepository; 16 | import com.hermes.ithermes.presentation.dto.CommonResponseDto; 17 | import com.hermes.ithermes.presentation.dto.user.UserCreateUserRequestDto; 18 | import com.hermes.ithermes.presentation.dto.user.UserFindMyDataRequestDto; 19 | import com.hermes.ithermes.presentation.dto.user.UserLoginRequestDto; 20 | import com.hermes.ithermes.presentation.dto.user.UserUpdateNicknameRequestDto; 21 | import com.hermes.ithermes.presentation.security.JwtUtil; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.DisplayName; 24 | import org.junit.jupiter.api.Test; 25 | import org.junit.jupiter.api.extension.ExtendWith; 26 | import org.mockito.InjectMocks; 27 | import org.mockito.Mock; 28 | import org.mockito.junit.jupiter.MockitoExtension; 29 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 30 | 31 | import java.util.Optional; 32 | 33 | import static org.junit.jupiter.api.Assertions.assertEquals; 34 | import static org.junit.jupiter.api.Assertions.assertThrows; 35 | import static org.mockito.ArgumentMatchers.any; 36 | import static org.mockito.Mockito.when; 37 | 38 | @ExtendWith(MockitoExtension.class) 39 | class UserServiceTest { 40 | 41 | @InjectMocks 42 | private UserService userService; 43 | @Mock 44 | private UserKeywordRegistryRepository userKeywordRegistryRepository; 45 | @Mock 46 | private UserKeywordRegistryFactory userKeywordRegistryFactory; 47 | @Mock 48 | private UserFactory userFactory; 49 | @Mock 50 | private KeywordFactory keywordFactory; 51 | @Mock 52 | private BCryptPasswordEncoder encoder; 53 | @Mock 54 | private JwtUtil jwtUtil; 55 | @Mock 56 | private RedisFactory redisFactory; 57 | 58 | 59 | private UserCreateUserRequestDto userCreateUserRequestDto; 60 | private User user; 61 | private UserKeywordRegistry userKeywordRegistry; 62 | private Keyword keyword; 63 | 64 | @BeforeEach 65 | void setUp() { 66 | user = User.builder() 67 | .loginId("test").nickname("김승기") 68 | .password("test1234!").job(JobType.BACKEND) 69 | .yearOfExperience(1) 70 | .build(); 71 | 72 | keyword = Keyword.builder().name("머신러닝").build(); 73 | 74 | userKeywordRegistry = UserKeywordRegistry.builder() 75 | .user(user) 76 | .keyword(keyword) 77 | .build(); 78 | } 79 | 80 | @Test 81 | @DisplayName("회원가입 시 회원정보, 키워드가 테이블에 저장되어 회원가입 성공") 82 | void 회원가입_정상처리() { 83 | userCreateUserRequestDto = new UserCreateUserRequestDto("test", "test1234!", 84 | "test1234!", "김승기", JobType.BACKEND, "1", new String[]{"프론트", "백엔드", "인공지능", null, null}); 85 | 86 | when(userFactory.existsByLoginId(any())).thenReturn(false); 87 | when(userFactory.parseLoginRequestDtoToUser(any())).thenReturn(user); 88 | when(userKeywordRegistryFactory.parseUserAndKeyword(any(), any())).thenReturn(userKeywordRegistry); 89 | 90 | assertEquals(new CommonResponseDto().getMessage(), userService.joinUser(userCreateUserRequestDto).getMessage()); 91 | } 92 | 93 | @Test 94 | @DisplayName("회원가입 시 아이디가 유저테이블에 저장 된 데이터와 일치 할 시 SameIdException 던지며 회원가입 실패") 95 | void 회원가입_이미존재하는회원() { 96 | UserCreateUserRequestDto userCreateUserRequestDtoTest = new UserCreateUserRequestDto("test", "1q2w3e4r", 97 | "1q2w3e4r", "김승기", JobType.BACKEND, "1" 98 | , new String[]{"프론트", "백엔드", "인공지능", "빅데이터", "머신러닝"}); 99 | 100 | when(userFactory.existsByLoginId(any())).thenReturn(true); 101 | 102 | assertThrows(SameIdException.class, () -> userService.joinUser(userCreateUserRequestDtoTest)); 103 | 104 | } 105 | 106 | @Test 107 | @DisplayName("회원가입 시 입력한 비밀번호와 비밀번호확인 데이터가 다를 경우 UnMatchedPasswordException 던지며 회원가입 실패") 108 | void 회원가입_비밀번호불일치() { 109 | UserCreateUserRequestDto userCreateUserRequestDtoTest = new UserCreateUserRequestDto("test", "1q2w3e4r", 110 | "1q2w3e4r!!", "김승기", JobType.BACKEND, "1" 111 | , new String[]{"프론트", "백엔드", "인공지능", "빅데이터", "머신러닝"}); 112 | 113 | assertThrows(UnMatchedPasswordException.class, () -> userService.joinUser(userCreateUserRequestDtoTest)); 114 | } 115 | 116 | @Test 117 | @DisplayName("유저 테이블에 존재하지 하는 아이디 패스워드를 입력하는 경우 로그인 성공") 118 | void 로그인_정상처리() { 119 | //Given 120 | String id = "kimsk"; 121 | String password = "kimsk1234"; 122 | UserLoginRequestDto userLoginRequestDto = new UserLoginRequestDto(id, password); 123 | 124 | //When 125 | when(userFactory.findLoginId(any())).thenReturn(Optional.ofNullable(user)); 126 | when(jwtUtil.createAccessToken(any())).thenReturn("1q2w3e4r!"); 127 | when(jwtUtil.createRefreshToken(any())).thenReturn("1q2w3e4r!"); 128 | when(encoder.matches(any(), any())).thenReturn(true); 129 | when(redisFactory.setRedisRefreshToken(any(),any())).thenReturn("1q2w3e4r!"); 130 | //Then 131 | assertEquals("success", userService.loginUser(userLoginRequestDto).getMessage()); 132 | } 133 | 134 | @Test 135 | @DisplayName("유저 테이블에 존재하지 않은 아이디 패스워드를 입력하는 경우 WrongIdOrPasswordException 던지며 로그인 실패") 136 | void 로그인_회원정보불일치() { 137 | //Given 138 | String id = "kimsk"; 139 | String password = "kimsk1234"; 140 | UserLoginRequestDto userLoginRequestDto = new UserLoginRequestDto(id, password); 141 | 142 | //When 143 | when(userFactory.findLoginId(any())).thenThrow(new WrongIdOrPasswordException()); 144 | 145 | //Then 146 | assertThrows(WrongIdOrPasswordException.class, () -> userService.loginUser(userLoginRequestDto)); 147 | } 148 | 149 | @Test 150 | @DisplayName("유저테이블에 입력한 닉네임이 존재하지 않을 경우 닉네임 수정 성공") 151 | void 닉네임수정_정상처리() { 152 | //Given 153 | String loginId = "kimsk"; 154 | String nickname = "kimsk123"; 155 | 156 | UserUpdateNicknameRequestDto userUpdateNicknameRequestDto = new UserUpdateNicknameRequestDto(loginId, nickname); 157 | 158 | when(userFactory.existsByNickname(any())).thenReturn(false); 159 | when(userFactory.findLoginId(any())).thenReturn(Optional.of(user)); 160 | //Then 161 | assertEquals(new CommonResponseDto().getMessage(), userService.updateNickname(userUpdateNicknameRequestDto).getMessage()); 162 | } 163 | 164 | @Test 165 | @DisplayName("유저테이블에 입력한 닉네임이 존재할 경우 SameNicknameException 던지며 닉네임 수정 실패") 166 | void 닉네임수정_닉네임중복() { 167 | //Given 168 | String loginId = "test"; 169 | String nickname = "김승기"; 170 | 171 | //When 172 | UserUpdateNicknameRequestDto userUpdateNicknameRequestDto = new UserUpdateNicknameRequestDto(loginId, nickname); 173 | when(userFactory.existsByNickname(nickname)).thenReturn(true); 174 | 175 | //Then 176 | assertThrows(SameNicknameException.class, () -> userService.updateNickname(userUpdateNicknameRequestDto)); 177 | } 178 | 179 | @Test 180 | @DisplayName("유저 테이블에 존재하는 아이디를 입력했을 경우 유저 데이터 조회 성공") 181 | void 마이페이지_정상처리() { 182 | //Given 183 | String loginId = "test"; 184 | UserFindMyDataRequestDto userFindMyDataRequestDto = new UserFindMyDataRequestDto(loginId); 185 | 186 | //When 187 | when(userFactory.findLoginId(any())).thenReturn(Optional.of(user)); 188 | 189 | //Then 190 | assertEquals(loginId, userService.findMyData(userFindMyDataRequestDto).getId()); 191 | assertEquals("김승기", userService.findMyData(userFindMyDataRequestDto).getNickname()); 192 | 193 | } 194 | 195 | @Test 196 | @DisplayName("유저 테이블에 존재하지 않는 아이디를 입력했을 경우 WrongIdOrPasswordException 던지며 유저 데이터 조회 실패") 197 | void 마이페이지_존재하지않는회원() { 198 | //Given 199 | String loginId = "dfjerioghjeruiojgheruih"; 200 | UserFindMyDataRequestDto userFindMyDataRequestDto = new UserFindMyDataRequestDto(loginId); 201 | 202 | //When 203 | when(userFactory.findLoginId(any())).thenReturn(Optional.ofNullable(null)); 204 | 205 | //Then 206 | assertThrows(WrongIdOrPasswordException.class, () -> userService.findMyData(userFindMyDataRequestDto)); 207 | } 208 | } -------------------------------------------------------------------------------- /src/test/java/com/hermes/ithermes/presentation/controller/SubscribeControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.hermes.ithermes.presentation.controller; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.hermes.ithermes.application.SubscribeService; 5 | import com.hermes.ithermes.domain.exception.WrongIdOrPasswordException; 6 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeContentsDto; 7 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribeFindSubscribeRequestDto; 8 | import com.hermes.ithermes.presentation.dto.subscribe.SubscribePutSubscribeRequestDto; 9 | import org.junit.jupiter.api.DisplayName; 10 | import org.junit.jupiter.api.Test; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa; 13 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 14 | import org.springframework.boot.test.mock.mockito.MockBean; 15 | import org.springframework.http.MediaType; 16 | import org.springframework.security.test.context.support.WithMockUser; 17 | import org.springframework.test.web.servlet.MockMvc; 18 | 19 | import java.util.ArrayList; 20 | 21 | import static org.mockito.ArgumentMatchers.any; 22 | import static org.mockito.Mockito.when; 23 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; 24 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 25 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; 26 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 27 | 28 | @WebMvcTest(controllers = SubscribeController.class) 29 | @AutoConfigureDataJpa 30 | class SubscribeControllerTest { 31 | 32 | @MockBean 33 | private SubscribeService subscribeService; 34 | 35 | @Autowired 36 | private MockMvc mockMvc; 37 | 38 | @Autowired 39 | ObjectMapper objectMapper; 40 | 41 | @Test 42 | @DisplayName("구독_PUT_정상처리") 43 | @WithMockUser 44 | void 구독_PUT_정상처리() throws Exception { 45 | ArrayList subscribeContentsList = new ArrayList<>(); 46 | subscribeContentsList.add(new SubscribeContentsDto("SARAMIN","ACTIVE")); 47 | subscribeContentsList.add(new SubscribeContentsDto("WANTED","ACTIVE")); 48 | subscribeContentsList.add(new SubscribeContentsDto("CODING_WORLD","ACTIVE")); 49 | subscribeContentsList.add(new SubscribeContentsDto("NAVER","ACTIVE")); 50 | subscribeContentsList.add(new SubscribeContentsDto("YOZM","ACTIVE")); 51 | subscribeContentsList.add(new SubscribeContentsDto("NOMAD_CODERS","NON_ACTIVE")); 52 | subscribeContentsList.add(new SubscribeContentsDto("DREAM_CODING","ACTIVE")); 53 | 54 | SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto = new SubscribePutSubscribeRequestDto("test",subscribeContentsList); 55 | 56 | mockMvc.perform(put("/api/subscribe/") 57 | .with(csrf()) 58 | .contentType(MediaType.APPLICATION_JSON) 59 | .content(objectMapper.writeValueAsString(subscribePutSubscribeRequestDto))) 60 | .andExpect(status().isOk()); // 추후 201로 수정필요! 61 | } 62 | 63 | @Test 64 | @DisplayName("구독_PUT_실패처리") 65 | @WithMockUser 66 | void 구독_PUT_실패처리() throws Exception { 67 | ArrayList subscribeContentsList = new ArrayList<>(); 68 | subscribeContentsList.add(new SubscribeContentsDto("SARAMIN","ACTIVE")); 69 | subscribeContentsList.add(new SubscribeContentsDto("WANTED","ACTIVE")); 70 | subscribeContentsList.add(new SubscribeContentsDto("CODING_WORLD","ACTIVE")); 71 | subscribeContentsList.add(new SubscribeContentsDto("NAVER","ACTIVE")); 72 | subscribeContentsList.add(new SubscribeContentsDto("YOZM","ACTIVE")); 73 | subscribeContentsList.add(new SubscribeContentsDto("NOMAD_CODERS","NON_ACTIVE")); 74 | subscribeContentsList.add(new SubscribeContentsDto("DREAM_CODING","ACTIVE")); 75 | 76 | SubscribePutSubscribeRequestDto subscribePutSubscribeRequestDto = new SubscribePutSubscribeRequestDto("test",subscribeContentsList); 77 | 78 | when(subscribeService.putSubscribe(any())).thenThrow(new WrongIdOrPasswordException()); 79 | 80 | mockMvc.perform(put("/api/subscribe/") 81 | .with(csrf()) 82 | .contentType(MediaType.APPLICATION_JSON) 83 | .content(objectMapper.writeValueAsString(subscribePutSubscribeRequestDto))) 84 | .andExpect(status().isBadRequest()); 85 | } 86 | 87 | @Test 88 | @DisplayName("구독조회_성공처리") 89 | @WithMockUser 90 | void 구독조회_성공처리() throws Exception { 91 | SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto = new SubscribeFindSubscribeRequestDto("test"); 92 | 93 | mockMvc.perform(post("/api/subscribe/") 94 | .with(csrf()) 95 | .contentType(MediaType.APPLICATION_JSON) 96 | .content(objectMapper.writeValueAsString(subscribeFindSubscribeRequestDto))) 97 | .andExpect(status().isOk()); 98 | } 99 | 100 | @Test 101 | @DisplayName("구독조회_실패처리") 102 | @WithMockUser 103 | void 구독조회_실패처리() throws Exception { 104 | SubscribeFindSubscribeRequestDto subscribeFindSubscribeRequestDto = new SubscribeFindSubscribeRequestDto("test"); 105 | 106 | when(subscribeService.findSubscribe(any())).thenThrow(new WrongIdOrPasswordException()); 107 | 108 | mockMvc.perform(post("/api/subscribe/") 109 | .with(csrf()) 110 | .contentType(MediaType.APPLICATION_JSON) 111 | .content(objectMapper.writeValueAsString(subscribeFindSubscribeRequestDto))) 112 | .andExpect(status().isBadRequest()); 113 | } 114 | } -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: org.h2.Driver 4 | url: jdbc:h2:mem:hermes;MODE=MYSQL 5 | username: sa 6 | password: 7 | redis: 8 | ipAddress: localhost 9 | h2: 10 | console: 11 | enabled: true 12 | 13 | jpa: 14 | hibernate: 15 | ddl-auto: create 16 | properties: 17 | hibernate: 18 | show_sql: true 19 | format_sql: true 20 | jdbc: 21 | time_zone: Asia/Seoul 22 | defer-datasource-initialization: true 23 | 24 | springboot: 25 | jwt: 26 | secret: test123!@# 27 | 28 | logging: 29 | level: 30 | org.hibernate.SQL: debug 31 | 32 | telegram-key: "5810579378:AAGNSVQz1Mzn1FjMkBuL1x-5UUz9u-jXdXc" --------------------------------------------------------------------------------