├── .gitignore ├── .prettierrc ├── README.md ├── build.gradle.kts ├── docker ├── docker-compose-jenkins.yml ├── docker-compose-mariadb.yml ├── docker-compose-redis.yml ├── master_db │ └── config │ │ └── my.cnf └── slave_db │ └── config │ └── my.cnf ├── document └── Swagger Annotations Changes ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── http ├── http-client.env.json └── reactive │ └── MethodArgumentExample.http ├── mvc ├── build.gradle.kts └── src │ ├── main │ ├── java │ │ └── studio │ │ │ └── thinkground │ │ │ └── aroundhub │ │ │ └── mvc │ │ │ ├── Application.java │ │ │ ├── common │ │ │ ├── CommonResponse.java │ │ │ ├── Constants.java │ │ │ ├── annotation │ │ │ │ ├── FieldAnnotation.java │ │ │ │ ├── MethodAnnotation.java │ │ │ │ ├── TypeAnnotation.java │ │ │ │ └── ValidationAnnotation.java │ │ │ ├── exception │ │ │ │ ├── AroundHubException.java │ │ │ │ └── AroundHubExceptionHandler.java │ │ │ └── valid │ │ │ │ ├── ParameterValidator.java │ │ │ │ └── TempDto.java │ │ │ ├── config │ │ │ ├── JasyptConfig.java │ │ │ ├── JpaAuditingConfiguration.java │ │ │ ├── OpenAPIConfiguration.java │ │ │ ├── ProfileManager.java │ │ │ ├── WebMvcConfig.java │ │ │ └── cache │ │ │ │ ├── CacheConfig.java │ │ │ │ └── RedisCacheConfig.java │ │ │ ├── controller │ │ │ ├── ConditionController.java │ │ │ ├── DeleteController.java │ │ │ ├── GetController.java │ │ │ ├── HelloController.java │ │ │ ├── ListenerController.java │ │ │ ├── PostController.java │ │ │ ├── ProductController.java │ │ │ ├── PutController.java │ │ │ ├── RestTemplateController.java │ │ │ └── ShortUrlController.java │ │ │ ├── data │ │ │ ├── dao │ │ │ │ ├── ProductDAO.java │ │ │ │ ├── ShortUrlDAO.java │ │ │ │ └── impl │ │ │ │ │ ├── ProductDAOImpl.java │ │ │ │ │ └── ShortUrlDaoImpl.java │ │ │ ├── dto │ │ │ │ ├── MemberDTO.java │ │ │ │ ├── NaverUriDto.java │ │ │ │ ├── ProductDto.java │ │ │ │ └── ShortUrlResponseDto.java │ │ │ ├── entity │ │ │ │ ├── BaseEntity.java │ │ │ │ ├── Listener.java │ │ │ │ ├── Product.java │ │ │ │ ├── ShortUrl.java │ │ │ │ └── listener │ │ │ │ │ └── CustomListener.java │ │ │ ├── handler │ │ │ │ ├── ProductDataHandler.java │ │ │ │ └── impl │ │ │ │ │ └── ProductDataHandlerImpl.java │ │ │ └── repository │ │ │ │ ├── ListenerRepository.java │ │ │ │ ├── ProductRepository.java │ │ │ │ ├── ShortUrlRedisRepository.java │ │ │ │ └── ShortUrlRepository.java │ │ │ ├── interceptor │ │ │ └── HttpInterceptor.java │ │ │ ├── service │ │ │ ├── ListenerService.java │ │ │ ├── ProductService.java │ │ │ ├── RestClientService.java │ │ │ ├── RestTemplateService.java │ │ │ ├── ShortUrlService.java │ │ │ └── impl │ │ │ │ ├── ListenerServiceImpl.java │ │ │ │ ├── ProductServiceImpl.java │ │ │ │ ├── RestClientServiceImpl.java │ │ │ │ ├── RestTemplateServiceImpl.java │ │ │ │ └── ShortUrlServiceImpl.java │ │ │ └── util │ │ │ ├── KakaoPortalApi.java │ │ │ ├── NaverPortalApi.java │ │ │ ├── PortalApi.java │ │ │ └── PortalApiConfig.java │ └── resources │ │ ├── application.yml │ │ └── logback-spring.xml │ └── test │ └── java │ └── studio │ └── thinkground │ └── aroundhub │ └── mvc │ ├── ApplicationTests.java │ ├── config │ └── JasyptTest.java │ ├── controller │ └── ProductControllerTest.java │ ├── impl │ └── ProductServiceImplTest.java │ ├── repository │ ├── DevProductRepositoryTest.java │ ├── LocalProductRepositoryTest.java │ └── ProductRepositoryTest.java │ └── test │ └── TestLifeCycle.java ├── reactive ├── build.gradle.kts └── src │ └── main │ ├── java │ └── studio │ │ └── thinkground │ │ └── reactive │ │ ├── Application.java │ │ ├── basic │ │ ├── BasicController.java │ │ ├── BasicRouter.java │ │ └── MethodArgumentExample.java │ │ ├── common │ │ └── config │ │ │ └── ApplicationConfig.java │ │ └── user │ │ ├── User.java │ │ ├── UserHandler.java │ │ ├── UserRouterConfig.java │ │ └── UserService.java │ └── resources │ ├── application.yml │ └── logback-spring.xml └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### docker ### 23 | !**/docker/ 24 | **/docker/master_db 25 | **/docker/slave_db 26 | 27 | ### NetBeans ### 28 | /nbproject/private/ 29 | /nbbuild/ 30 | /dist/ 31 | /nbdist/ 32 | /.nb-gradle/ 33 | build/ 34 | !**/src/main/**/build/ 35 | !**/src/test/**/build/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | 40 | .gradle -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | useTabs: false 2 | tabWidth: 2 3 | endOfLine: lf 4 | semi: true 5 | trailingComma: es5 6 | singleQuote: true 7 | printWidth: 120 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![header](https://capsule-render.vercel.app/api?type=waving&color=auto) 2 | 3 | 4 | ## Around Hub Studio 'Spring Boot' 5 | 6 |

유튜브(YouTube)에서 스프링 부트 강의를 진행하면서 사용한 예제 코드를 공유하고 있습니다.

7 |

핵심 코드만 공유하는 것이 아니라 '실행 가능한' 형태로 공유하고 있어 그대로 사용하실 수 있습니다.

8 |

도움이 되셨으면 좋겠습니다 :)

9 | 10 |
11 | 12 | ### Contents 13 | 14 |

스프링 부트 강의 영상에 맞춰 매번 코드가 변경될 수 있습니다.

15 |

최대한 변경된 내용을 커밋 코멘트에 남기지만 넓은 범위로 변경될 경우 일치하지 않을 수 있습니다.

16 |
17 | 18 | #### Docker 사용법 19 |

1. ./docker 경로에 있는 docker-compose-*.yml 파일을 관리에 용이한 디렉토리에 복사합니다.

20 |

2. 아래와 같이 실행합니다.

21 |
22 | 
23 | ## 파일마다 아래와 같은 커맨드로 실행합니다.
24 | docker-compose -f {파일명}.yml up -d
25 | 
26 | 
27 | 28 | ### Around Hub Studio & ThinkGround 29 | 30 |

I'm Flature

31 |

Around Hub StudioThinkGround 는 제가 운영하는 포트폴리오 사이트와 유튜브 채널입니다.

32 |

어라운드 허브 스튜디오는 IT 기술 정보를 공유하는 채널입니다.

33 |

대부분의 소스코드는 ThinkGround 와 Around Hub Studio가 소유하고 있습니다.

34 | 35 | 36 |



37 | 38 |

39 | YouTube

40 | 41 |

42 | 43 |

44 | Major Skill Stack

45 | 46 | 47 | 48 |

49 | 50 |

51 | Minor Skill Stack

52 | 53 | 54 | 55 | 56 |

57 | 58 |


-------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("org.springframework.boot") version "3.2.4" 4 | id("io.spring.dependency-management") version "1.1.0" 5 | id("io.freefair.lombok") version "6.6.1" 6 | id("com.diffplug.spotless") version "6.25.0" 7 | } 8 | 9 | group = "studio.thinkground" 10 | version = "1.0.0" 11 | description = "around-hub-spring-boot" 12 | java.sourceCompatibility = JavaVersion.VERSION_17 13 | 14 | repositories { 15 | mavenLocal() 16 | maven { 17 | url = uri("https://repo.maven.apache.org/maven2/") 18 | } 19 | } 20 | 21 | subprojects { 22 | apply(plugin = "java") 23 | apply(plugin = "org.springframework.boot") 24 | apply(plugin = "io.spring.dependency-management") 25 | apply(plugin = "com.diffplug.spotless") 26 | apply(plugin = "io.freefair.lombok") 27 | } 28 | -------------------------------------------------------------------------------- /docker/docker-compose-jenkins.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | jenkins: 4 | image: jenkins/jenkins:lts 5 | restart: always 6 | build: 7 | context: . 8 | container_name: jenkins 9 | user: root 10 | privileged: true 11 | ports: 12 | - 9090:8080 13 | - 50000:50000 14 | volumes: 15 | - ./jenkins_home:/var/jenkins_home 16 | - /var/run/docker.sock:/var/run/docker.sock 17 | -------------------------------------------------------------------------------- /docker/docker-compose-mariadb.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | db_master: 5 | image: mariadb:10.6 # mariadb 10.6 버전 이미지 사용 6 | container_name: db_master # container 이름 설정 7 | restart: always 8 | environment: 9 | MARIADB_ROOT_PASSWORD: aroundhub12# # container 생성 후 root의 비밀번호를 저장한 파일을 설정함으로서 root 비밀번호를 설정 10 | MARIADB_DATABASE: springboot 11 | MARIADB_USER: flature 12 | MARIADB_PASSWORD: aroundhub12# 13 | volumes: 14 | - ./master_db/data:/var/lib/mysql # 각종 log와 index등이 volume이 저장되는 디렉토리 15 | - ./master_db/config/:/etc/mysql/conf.d # 이전에 나왔던 ./master/config/my.cnf 를 써줌으써 설정을 reference해줍니다. 16 | ports: 17 | - '3306:3306' # 이 옵션은 docker engine에게 각 container에게 포트를 수동으로 설정하게 해줍니다. 18 | 19 | db_slave: 20 | image: mariadb:10.6 # mariadb 10.6 버전 이미지 사용 21 | container_name: db_slave # container 이름 설정 22 | restart: always 23 | environment: 24 | MARIADB_ROOT_PASSWORD: aroundhub12# 25 | MARIADB_DATABASE: springboot 26 | MARIADB_USER: flature 27 | MARIADB_PASSWORD: aroundhub12# 28 | volumes: 29 | - ./slave_db/data:/var/lib/mysql 30 | - ./slave_db/config/:/etc/mysql/conf.d 31 | ports: 32 | - '3307:3306' 33 | depends_on: 34 | - db_master # depends_on은 실행 순서에 대한 정의입니다. 다만 서비스가 온전히 실행됐는지 검증하진 않아 별도 처리가 필요할 수 있습니다. 35 | 36 | # docker-compose -f docker-compose-mariadb.yml up -d 37 | -------------------------------------------------------------------------------- /docker/docker-compose-redis.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | aroundhub_redis: 5 | image: redis:7.0.0 6 | restart: always 7 | ports: 8 | - '6379:6379' 9 | # docker-compose -f docker-compose-redis.yml up -d 10 | -------------------------------------------------------------------------------- /docker/master_db/config/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | server-id=1 3 | log-bin=mysql-bin 4 | log-basename=master1 -------------------------------------------------------------------------------- /docker/slave_db/config/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | server-id=2 3 | log-bin=mysql-bin 4 | log-basename=master1 5 | report-host=slave1 -------------------------------------------------------------------------------- /document/Swagger Annotations Changes: -------------------------------------------------------------------------------- 1 | 2 | @Api -> @Tag 3 | @ApiIgnore -> @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden 4 | @ApiImplicitParam -> @Parameter 5 | @ApiImplicitParams -> @Parameters 6 | @ApiModel -> @Schema 7 | @ApiModelProperty(hidden = true) -> @Schema(accessMode = READ_ONLY) 8 | @ApiModelProperty -> @Schema 9 | @ApiOperation(value = "foo", notes = "bar") -> @Operation(summary = "foo", description = "bar") 10 | @ApiParam -> @Parameter 11 | @ApiResponse(code = 404, message = "foo") -> @ApiResponse(responseCode = "404", description = "foo") -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Around-Hub-Studio/around-hub-spring-boot/f773d68fadb56668da96b93ce6463f97edf7fd49/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: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Stop when "xargs" is not available. 209 | if ! command -v xargs >/dev/null 2>&1 210 | then 211 | die "xargs is not available" 212 | fi 213 | 214 | # Use "xargs" to parse quoted args. 215 | # 216 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 217 | # 218 | # In Bash we could simply go: 219 | # 220 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 221 | # set -- "${ARGS[@]}" "$@" 222 | # 223 | # but POSIX shell has neither arrays nor command substitution, so instead we 224 | # post-process each arg (as a line of input to sed) to backslash-escape any 225 | # character that might be a shell metacharacter, then use eval to reverse 226 | # that process (while maintaining the separation between arguments), and wrap 227 | # the whole thing up as a single "set" statement. 228 | # 229 | # This will of course break if any of these variables contains a newline or 230 | # an unmatched quote. 231 | # 232 | 233 | eval "set -- $( 234 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 235 | xargs -n1 | 236 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 237 | tr '\n' ' ' 238 | )" '"$@"' 239 | 240 | exec "$JAVACMD" "$@" 241 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /http/http-client.env.json: -------------------------------------------------------------------------------- 1 | { 2 | "env123": { 3 | "base-url": "http://localhost:8080" 4 | }, 5 | 6 | "env124": { 7 | "base-url": "http://localhost:8080" 8 | } 9 | } -------------------------------------------------------------------------------- /http/reactive/MethodArgumentExample.http: -------------------------------------------------------------------------------- 1 | ### /user-gent 2 | GET {{base-url}}/argument/user-agent 3 | 4 | ### /echo 5 | POST http://localhost:8080/argument/echo 6 | Content-Type: application/json 7 | 8 | { 9 | "name": "flature", 10 | "org": "around hub studio" 11 | } 12 | 13 | ### /custom-response 14 | GET http://localhost:8080/argument/custom-response -------------------------------------------------------------------------------- /mvc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = "studio.thinkground.aroundhub.mvc" 2 | version = "1.0.0" 3 | java.sourceCompatibility = JavaVersion.VERSION_17 4 | 5 | spotless { 6 | format("yaml") { 7 | target("**.*.yaml", "**/*.yml") 8 | prettier().configFile("${rootDir}/.prettierrc") 9 | } 10 | java { 11 | removeUnusedImports() 12 | googleJavaFormat() 13 | importOrder( 14 | "java", 15 | "jakarta", 16 | "lombok", 17 | "org.springframework", 18 | "", 19 | "\\#", 20 | "studio.thinkground", 21 | "\\#studio.thinkground" 22 | ) 23 | indentWithTabs(2) 24 | indentWithSpaces(2) 25 | trimTrailingWhitespace() 26 | endWithNewline() 27 | } 28 | } 29 | 30 | repositories { 31 | mavenLocal() 32 | maven { 33 | url = uri("https://repo.maven.apache.org/maven2/") 34 | } 35 | } 36 | 37 | dependencies { 38 | implementation("org.springframework.boot:spring-boot-starter-web") 39 | implementation("org.springframework.boot:spring-boot-starter-data-jpa") 40 | implementation("org.springframework.boot:spring-boot-starter-validation") 41 | implementation("org.springframework.boot:spring-boot-starter-data-redis") 42 | 43 | // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui 44 | implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.4.0") 45 | 46 | implementation("com.google.code.gson:gson:2.10.1") 47 | implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5") 48 | 49 | implementation("org.mariadb.jdbc:mariadb-java-client") 50 | 51 | testImplementation("org.springframework.boot:spring-boot-starter-test") 52 | } 53 | 54 | tasks.withType() { 55 | options.encoding = "UTF-8" 56 | } 57 | 58 | tasks.test { 59 | useJUnitPlatform() 60 | systemProperties["spring.profiles.active"] = "test" 61 | } -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/Application.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/CommonResponse.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common; 2 | 3 | public enum CommonResponse { 4 | SUCCESS(0, "Success"), 5 | FAIL(-1, "Fail"); 6 | 7 | int code; 8 | String msg; 9 | 10 | CommonResponse(int code, String msg) { 11 | this.code = code; 12 | this.msg = msg; 13 | } 14 | 15 | public int getCode() { 16 | return code; 17 | } 18 | 19 | public String getMsg() { 20 | return msg; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/Constants.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common; 2 | 3 | public class Constants { 4 | 5 | public enum ExceptionClass { 6 | PRODUCT("Product"), 7 | SIGN("Sign"); 8 | 9 | private String exceptionClass; 10 | 11 | ExceptionClass(String exceptionClass) { 12 | this.exceptionClass = exceptionClass; 13 | } 14 | 15 | public String getExceptionClass() { 16 | return exceptionClass; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return getExceptionClass() + " Exception. "; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/annotation/FieldAnnotation.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.FIELD) 10 | public @interface FieldAnnotation { 11 | String name(); 12 | 13 | String value(); 14 | } 15 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/annotation/MethodAnnotation.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface MethodAnnotation { 11 | String name(); 12 | 13 | String value() default "I'm Method"; 14 | } 15 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/annotation/TypeAnnotation.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.TYPE) 10 | public @interface TypeAnnotation { 11 | String name(); 12 | 13 | String value(); 14 | } 15 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/annotation/ValidationAnnotation.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import jakarta.validation.Constraint; 9 | import jakarta.validation.Payload; 10 | 11 | import studio.thinkground.aroundhub.mvc.common.valid.ParameterValidator; 12 | 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.FIELD) 15 | @Constraint(validatedBy = ParameterValidator.class) 16 | public @interface ValidationAnnotation { 17 | String message() default "Invalid Value. It should be 'hello'"; 18 | 19 | Class[] groups() default {}; 20 | 21 | Class[] payload() default {}; 22 | } 23 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/exception/AroundHubException.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | import studio.thinkground.aroundhub.mvc.common.Constants; 6 | 7 | public class AroundHubException extends Exception { 8 | 9 | private static final long serialVersionUID = 4663380430591151694L; 10 | 11 | private Constants.ExceptionClass exceptionClass; 12 | private HttpStatus httpStatus; 13 | 14 | public AroundHubException( 15 | Constants.ExceptionClass exceptionClass, HttpStatus httpStatus, String message) { 16 | super(exceptionClass.toString() + message); 17 | this.exceptionClass = exceptionClass; 18 | this.httpStatus = httpStatus; 19 | } 20 | 21 | public Constants.ExceptionClass getExceptionClass() { 22 | return exceptionClass; 23 | } 24 | 25 | public int getHttpStatusCode() { 26 | return httpStatus.value(); 27 | } 28 | 29 | public String getHttpStatusType() { 30 | return httpStatus.getReasonPhrase(); 31 | } 32 | 33 | public HttpStatus getHttpStatus() { 34 | return httpStatus; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/exception/AroundHubExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.exception; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.http.HttpHeaders; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.RestControllerAdvice; 11 | 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | @RestControllerAdvice 16 | public class AroundHubExceptionHandler { 17 | 18 | private final Logger LOGGER = LoggerFactory.getLogger(AroundHubExceptionHandler.class); 19 | 20 | @ExceptionHandler(value = Exception.class) 21 | public ResponseEntity> ExceptionHandler(Exception e) { 22 | HttpHeaders responseHeaders = new HttpHeaders(); 23 | // responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json"); 24 | HttpStatus httpStatus = HttpStatus.BAD_REQUEST; 25 | 26 | LOGGER.error("Advice 내 ExceptionHandler 호출, {}, {}", e.getCause(), e.getMessage()); 27 | 28 | Map map = new HashMap<>(); 29 | map.put("error type", httpStatus.getReasonPhrase()); 30 | map.put("code", "400"); 31 | map.put("message", "에러 발생"); 32 | 33 | return new ResponseEntity<>(map, responseHeaders, httpStatus); 34 | } 35 | 36 | @ExceptionHandler(value = AroundHubException.class) 37 | public ResponseEntity> ExceptionHandler(AroundHubException e) { 38 | HttpHeaders responseHeaders = new HttpHeaders(); 39 | 40 | Map map = new HashMap<>(); 41 | map.put("error type", e.getHttpStatusType()); 42 | map.put( 43 | "error code", 44 | Integer.toString(e.getHttpStatusCode())); // Map로 설정하면 toString 불필요 45 | map.put("message", e.getMessage()); 46 | 47 | return new ResponseEntity<>(map, responseHeaders, e.getHttpStatus()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/valid/ParameterValidator.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.valid; 2 | 3 | import jakarta.validation.ConstraintValidator; 4 | import jakarta.validation.ConstraintValidatorContext; 5 | 6 | import studio.thinkground.aroundhub.mvc.common.annotation.ValidationAnnotation; 7 | 8 | public class ParameterValidator implements ConstraintValidator { 9 | @Override 10 | public void initialize(ValidationAnnotation constraintAnnotation) { 11 | ConstraintValidator.super.initialize(constraintAnnotation); 12 | } 13 | 14 | @Override 15 | public boolean isValid(String value, ConstraintValidatorContext context) { 16 | return value != null && value.equals("hello"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/common/valid/TempDto.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.common.valid; 2 | 3 | import lombok.Getter; 4 | 5 | import studio.thinkground.aroundhub.mvc.common.annotation.ValidationAnnotation; 6 | 7 | @Getter 8 | public class TempDto { 9 | @ValidationAnnotation private String value; 10 | } 11 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/JasyptConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import org.jasypt.encryption.StringEncryptor; 7 | import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; 8 | import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; 9 | 10 | /** GitHub : https://github.com/ulisesbocchio/jasypt-spring-boot */ 11 | @Configuration 12 | public class JasyptConfig { 13 | 14 | @Bean(name = "jasyptStringEncryptor") 15 | public StringEncryptor stringEncryptor() { 16 | String password = "around_hub_studio"; 17 | PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); 18 | 19 | SimpleStringPBEConfig config = new SimpleStringPBEConfig(); 20 | config.setPassword(password); // 암호화할 때 사용하는 키 21 | config.setAlgorithm("PBEWithMD5AndDES"); // 암호화 알고리즘 22 | config.setKeyObtentionIterations("1000"); // 반복할 해싱 회수 23 | config.setPoolSize("1"); // 인스턴스 pool 24 | config.setProviderName("SunJCE"); 25 | config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); // salt 생성 클래스 26 | config.setStringOutputType("base64"); // 인코딩 방식 27 | 28 | encryptor.setConfig(config); 29 | return encryptor; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/JpaAuditingConfiguration.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 5 | 6 | @Configuration 7 | @EnableJpaAuditing 8 | public class JpaAuditingConfiguration {} 9 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/OpenAPIConfiguration.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import io.swagger.v3.oas.models.OpenAPI; 7 | import io.swagger.v3.oas.models.info.Info; 8 | 9 | /** 10 | * @package : studio.thinkground.aroundhub.config 11 | * @name : OpenAPIConfiguration.java 12 | * @date : 2022-01-28 오후 4:34 13 | * @author : Flature 14 | * @version : 1.0.0 15 | */ 16 | @Configuration 17 | public class OpenAPIConfiguration { 18 | 19 | private static final String API_NAME = "Around Hub Studion"; 20 | private static final String API_VERSION = "1.0.0"; 21 | private static final String API_DESCRIPTION = "어라운드 허브 스튜디오 스프링 부트 레포지토리입니다."; 22 | 23 | @Bean 24 | public OpenAPI OpenAPIConfig() { 25 | return new OpenAPI() 26 | .info(new Info().title(API_NAME).description(API_DESCRIPTION).version(API_VERSION)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/ProfileManager.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.core.env.Environment; 5 | import org.springframework.stereotype.Component; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * PackageName : studio.thinkground.aroundhub.config FileName : ProfileManager Author : Flature Date 12 | * : 2022-05-11 Description : 13 | */ 14 | @Component 15 | public class ProfileManager { 16 | 17 | private final Logger LOGGER = LoggerFactory.getLogger(ProfileManager.class); 18 | private final Environment environment; 19 | 20 | @Autowired 21 | public ProfileManager(Environment environment) { 22 | this.environment = environment; 23 | } 24 | 25 | public void printActiveProfiles() { 26 | LOGGER.info( 27 | "[printActiveProfiles] active Profiles size : {}", environment.getActiveProfiles().length); 28 | for (String profile : environment.getActiveProfiles()) { 29 | LOGGER.info("[printActiveProfiles] profile : {}", profile); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 6 | 7 | import studio.thinkground.aroundhub.mvc.interceptor.HttpInterceptor; 8 | 9 | /** 10 | * PackageName : studio.thinkground.aroundhub.config FileName : WebMvcConfig Author : Flature Date : 11 | * 2022-06-05 Description : 12 | */ 13 | @Configuration 14 | public class WebMvcConfig implements WebMvcConfigurer { 15 | 16 | @Override 17 | public void addInterceptors(InterceptorRegistry registry) { 18 | registry 19 | .addInterceptor(new HttpInterceptor()) 20 | .addPathPatterns("/**") 21 | .excludePathPatterns("/hello"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/cache/CacheConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config.cache; 2 | 3 | /** 4 | * PackageName : studio.thinkground.aroundhub.config.cache FileName : CacheConfig Author : Flature 5 | * Date : 2022-05-19 Description : 6 | */ 7 | public interface CacheConfig {} 8 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/config/cache/RedisCacheConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config.cache; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 8 | import org.springframework.data.redis.core.RedisTemplate; 9 | 10 | /** 11 | * PackageName : studio.thinkground.aroundhub.config.cache FileName : RedisCacheConfig Author : 12 | * Flature Date : 2022-05-19 Description : 13 | */ 14 | @Configuration 15 | public class RedisCacheConfig implements CacheConfig { 16 | 17 | @Value("${spring.data.redis.host}") 18 | private String host; 19 | 20 | @Value("${spring.data.redis.port}") 21 | private int port; 22 | 23 | @Bean 24 | public RedisConnectionFactory redisConnectionFactory() { 25 | return new LettuceConnectionFactory(host, port); 26 | } 27 | 28 | @Bean 29 | public RedisTemplate redisTemplate() { 30 | RedisTemplate redisTemplate = new RedisTemplate<>(); 31 | redisTemplate.setConnectionFactory(redisConnectionFactory()); 32 | return redisTemplate; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/ConditionController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import studio.thinkground.aroundhub.mvc.util.PortalApi; 10 | 11 | @RestController 12 | @RequiredArgsConstructor 13 | @RequestMapping("/condition") 14 | public class ConditionController { 15 | private final PortalApi portalApi; 16 | 17 | @GetMapping 18 | public String integratePortal() { 19 | return portalApi.integrate(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/DeleteController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import org.springframework.web.bind.annotation.DeleteMapping; 4 | import org.springframework.web.bind.annotation.PathVariable; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequestMapping("/api/v1/get-api") 10 | public class DeleteController { 11 | 12 | // http://localhost:8080/api/v1/get-api/variable1/{String 값} 13 | @DeleteMapping(value = "/delete/{variable}") 14 | public String DeleteVariable(@PathVariable String variable) { 15 | return variable; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/GetController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 13 | 14 | @RestController 15 | @RequestMapping("/api/v1/get-api") 16 | public class GetController { 17 | 18 | // http://localhost:8080/api/v1/get-api/hello 19 | @RequestMapping(value = "/hello", method = RequestMethod.GET) 20 | public String getHello() { 21 | return "Hello Around Hub Studio!"; 22 | } 23 | 24 | // http://localhost:8080/api/v1/get-api/name 25 | @GetMapping(value = "/name") 26 | public String getName() { 27 | return "Flature"; 28 | } 29 | 30 | // http://localhost:8080/api/v1/get-api/variable1/{String 값} 31 | @GetMapping(value = "/variable1/{variable}") 32 | public String getVariable1(@PathVariable String variable) { 33 | return variable; 34 | } 35 | 36 | // http://localhost:8080/api/v1/get-api/variable2/{String 값} 37 | @GetMapping(value = "/variable2/{variable}") 38 | public String getVariable2(@PathVariable("variable") String var) { 39 | return var; 40 | } 41 | 42 | // http://localhost:8080/api/v1/get-api/request1?name=flature&email=thinkground.flature@gmail.com&organization=thinkground 43 | @GetMapping(value = "/request1") 44 | public String getRequestParam1( 45 | @RequestParam String name, @RequestParam String email, @RequestParam String organization) { 46 | return name + " " + email + " " + organization; 47 | } 48 | 49 | // http://localhost:8080/api/v1/get-api/request2?key1=value1&key2=value2 50 | @GetMapping(value = "/request2") 51 | public String getRequestParam2(@RequestParam Map param) { 52 | StringBuilder sb = new StringBuilder(); 53 | 54 | param 55 | .entrySet() 56 | .forEach( 57 | map -> { 58 | sb.append(map.getKey() + " : " + map.getValue() + "\n"); 59 | }); 60 | 61 | /* 62 | param.forEach((key, value) -> sb.append(key).append(" : ").append(value).append("\n")); 63 | */ 64 | 65 | return sb.toString(); 66 | } 67 | 68 | // http://localhost:8080/api/v1/get-api/request3?name=flature&email=thinkground.flature@gmail.com&organization=thinkground 69 | @GetMapping(value = "/request3") 70 | public String getRequestParam3(MemberDTO memberDTO) { 71 | // return memberDTO.getName() + " " + memberDTO.getEmail() + " " + memberDTO.getOrganization(); 72 | return memberDTO.toString(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/HelloController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Method; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import jakarta.validation.Valid; 9 | 10 | import org.springframework.http.HttpHeaders; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.ExceptionHandler; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.RequestBody; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import studio.thinkground.aroundhub.mvc.common.annotation.FieldAnnotation; 23 | import studio.thinkground.aroundhub.mvc.common.annotation.MethodAnnotation; 24 | import studio.thinkground.aroundhub.mvc.common.annotation.TypeAnnotation; 25 | import studio.thinkground.aroundhub.mvc.common.valid.TempDto; 26 | 27 | @RestController 28 | @TypeAnnotation(name = "Hello?", value = "World") 29 | public class HelloController { 30 | @FieldAnnotation(name = "returnValue", value = "Bye World!") 31 | public String returnValue = "Hello World!"; 32 | 33 | private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); 34 | 35 | @RequestMapping("/hello") 36 | public String hello() { 37 | return "Hello World!"; 38 | } 39 | 40 | @RequestMapping("/hello1") 41 | @MethodAnnotation(name = "Hello1", value = "World1") 42 | public String hello1() throws NoSuchMethodException { 43 | Method method = this.getClass().getMethod("hello1"); 44 | Annotation[] annotations = method.getDeclaredAnnotations(); 45 | 46 | for (Annotation annotation : annotations) { 47 | if (annotation instanceof MethodAnnotation) { 48 | MethodAnnotation methodAnnotation = (MethodAnnotation) annotation; 49 | return methodAnnotation.name() + ", " + methodAnnotation.value(); 50 | } 51 | } 52 | return "Hello World!"; 53 | } 54 | 55 | @RequestMapping("/hello2") 56 | public String hello2(@RequestBody @Valid TempDto dto) { 57 | return "Valid value : " + dto.getValue(); 58 | } 59 | 60 | @PostMapping("log-test") 61 | public void logTest() { 62 | 63 | LOGGER.trace("Trace Log"); 64 | LOGGER.debug("Debug Log"); 65 | LOGGER.info("Info Log"); 66 | LOGGER.warn("Warn Log"); 67 | LOGGER.error("Error Log"); 68 | } 69 | 70 | @PostMapping("/exception") 71 | public void exceptionTest() throws Exception { 72 | throw new Exception(); 73 | } 74 | 75 | @ExceptionHandler(value = Exception.class) 76 | public ResponseEntity> ExceptionHandler(Exception e) { 77 | HttpHeaders responseHeaders = new HttpHeaders(); 78 | // responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json"); 79 | HttpStatus httpStatus = HttpStatus.BAD_REQUEST; 80 | 81 | LOGGER.info(e.getMessage()); 82 | LOGGER.info("Controller 내 ExceptionHandler 호출"); 83 | 84 | Map map = new HashMap<>(); 85 | map.put("error type", httpStatus.getReasonPhrase()); 86 | map.put("code", "400"); 87 | map.put("message", "에러 발생"); 88 | 89 | return new ResponseEntity<>(map, responseHeaders, httpStatus); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/ListenerController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.DeleteMapping; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.PutMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import studio.thinkground.aroundhub.mvc.data.entity.Listener; 12 | import studio.thinkground.aroundhub.mvc.service.ListenerService; 13 | 14 | @RestController 15 | @RequestMapping("/listener") 16 | public class ListenerController { 17 | 18 | private ListenerService listenerService; 19 | 20 | @Autowired 21 | public ListenerController(ListenerService listenerService) { 22 | this.listenerService = listenerService; 23 | } 24 | 25 | @GetMapping 26 | public String getListener(Long id) { 27 | listenerService.getEntity(id); 28 | 29 | return "OK"; 30 | } 31 | 32 | @PostMapping 33 | public void saveListener(String name) { 34 | Listener listener = new Listener(); 35 | listener.setName(name); 36 | 37 | listenerService.saveEntity(listener); 38 | } 39 | 40 | @PutMapping 41 | public void updateListener(Long id, String name) { 42 | Listener listener = new Listener(); 43 | listener.setId(id); 44 | listener.setName(name); 45 | 46 | listenerService.updateEntity(listener); 47 | } 48 | 49 | @DeleteMapping 50 | public void deleteListener(Long id) { 51 | Listener listener = listenerService.getEntity(id); 52 | 53 | listenerService.removeEntity(listener); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/PostController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 11 | 12 | @RestController 13 | @RequestMapping("/api/v1/post-api") 14 | public class PostController { 15 | 16 | // http://localhost:8080/api/v1/post-api/default 17 | @PostMapping(value = "/default") 18 | public String postMethod() { 19 | return "Hello World!"; 20 | } 21 | 22 | // http://localhost:8080/api/v1/post-api/member 23 | @PostMapping(value = "/member") 24 | public String postMember(@RequestBody Map postData) { 25 | StringBuilder sb = new StringBuilder(); 26 | 27 | postData 28 | .entrySet() 29 | .forEach( 30 | map -> { 31 | sb.append(map.getKey() + " : " + map.getValue() + "\n"); 32 | }); 33 | 34 | /* 35 | param.forEach((key, value) -> sb.append(key).append(" : ").append(value).append("\n")); 36 | */ 37 | 38 | return sb.toString(); 39 | } 40 | 41 | // http://localhost:8080/api/v1/post-api/member2 42 | @PostMapping(value = "/member2") 43 | public String postMemberDto(@RequestBody MemberDTO memberDTO) { 44 | return memberDTO.toString(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/ProductController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import jakarta.validation.Valid; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.DeleteMapping; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import io.swagger.v3.oas.annotations.Parameter; 17 | import io.swagger.v3.oas.annotations.Parameters; 18 | import io.swagger.v3.oas.annotations.enums.ParameterIn; 19 | import io.swagger.v3.oas.annotations.media.Schema; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import studio.thinkground.aroundhub.mvc.common.Constants; 24 | import studio.thinkground.aroundhub.mvc.common.exception.AroundHubException; 25 | import studio.thinkground.aroundhub.mvc.data.dto.ProductDto; 26 | import studio.thinkground.aroundhub.mvc.service.ProductService; 27 | 28 | @RestController 29 | @RequestMapping("/api/v1/product-api") 30 | public class ProductController { 31 | 32 | private final Logger LOGGER = LoggerFactory.getLogger(ProductController.class); 33 | private final ProductService productService; 34 | 35 | @Autowired 36 | public ProductController(ProductService productService) { 37 | this.productService = productService; 38 | } 39 | 40 | // http://localhost:8080/api/v1/product-api/product/{productId} 41 | @GetMapping(value = "/product/{productId}") 42 | public ProductDto getProduct(@PathVariable String productId) { 43 | 44 | long startTime = System.currentTimeMillis(); 45 | LOGGER.info("[getProduct] perform {} of Around Hub API.", "getProduct"); 46 | 47 | ProductDto productDto = productService.getProduct(productId); 48 | 49 | LOGGER.info( 50 | "[getProduct] Response :: productId = {}, productName = {}, productPrice = {}, productStock = {}, Response Time = {}ms", 51 | productDto.getProductId(), 52 | productDto.getProductName(), 53 | productDto.getProductPrice(), 54 | productDto.getProductStock(), 55 | (System.currentTimeMillis() - startTime)); 56 | return productDto; 57 | } 58 | 59 | // http://localhost:8080/api/v1/product-api/product 60 | @Parameters({ 61 | @Parameter( 62 | name = "X-AUTH-TOKEN", 63 | description = "로그인 성공 후 access_token", 64 | required = true, 65 | schema = @Schema(implementation = String.class), 66 | in = ParameterIn.HEADER) 67 | }) 68 | @PostMapping(value = "/product") 69 | public ResponseEntity createProduct(@Valid @RequestBody ProductDto productDto) { 70 | 71 | LOGGER.info("[createProduct] perform {} of Around Hub API.", "createProduct"); 72 | 73 | // Validation Code Example 74 | if (productDto.getProductId().equals("") || productDto.getProductId().isEmpty()) { 75 | LOGGER.error("[createProduct] failed Response :: productId is Empty"); 76 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(productDto); 77 | } 78 | 79 | String productId = productDto.getProductId(); 80 | String productName = productDto.getProductName(); 81 | int productPrice = productDto.getProductPrice(); 82 | int productStock = productDto.getProductStock(); 83 | 84 | ProductDto response = 85 | productService.saveProduct(productId, productName, productPrice, productStock); 86 | 87 | LOGGER.info( 88 | "[createProduct] Response >> productId : {}, productName : {}, productPrice : {}, productStock : {}", 89 | response.getProductId(), 90 | response.getProductName(), 91 | response.getProductPrice(), 92 | response.getProductStock()); 93 | return ResponseEntity.status(HttpStatus.OK).body(response); 94 | } 95 | 96 | // http://localhost:8080/api/v1/product-api/product/{productId} 97 | @Parameters({ 98 | @Parameter( 99 | name = "X-AUTH-TOKEN", 100 | description = "로그인 성공 후 access_token", 101 | required = true, 102 | schema = @Schema(implementation = String.class), 103 | in = ParameterIn.HEADER) 104 | }) 105 | @DeleteMapping(value = "/product/{productId}") 106 | public ProductDto deleteProduct(@PathVariable String productId) { 107 | return null; 108 | } 109 | 110 | @PostMapping(value = "/product/exception") 111 | public void exceptionTest() throws AroundHubException { 112 | throw new AroundHubException( 113 | Constants.ExceptionClass.PRODUCT, HttpStatus.FORBIDDEN, "접근이 금지되었습니다."); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/PutController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.PutMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 13 | 14 | @RestController 15 | @RequestMapping("/api/v1/put-api") 16 | public class PutController { 17 | 18 | // http://localhost:8080/api/v1/put-api/default 19 | @PutMapping(value = "/default") 20 | public String putMethod() { 21 | return "Hello World!"; 22 | } 23 | 24 | // http://localhost:8080/api/v1/put-api/member 25 | @PutMapping(value = "/member") 26 | public String postMember(@RequestBody Map putData) { 27 | StringBuilder sb = new StringBuilder(); 28 | 29 | putData 30 | .entrySet() 31 | .forEach( 32 | map -> { 33 | sb.append(map.getKey() + " : " + map.getValue() + "\n"); 34 | }); 35 | 36 | /* 37 | param.forEach((key, value) -> sb.append(key).append(" : ").append(value).append("\n")); 38 | */ 39 | 40 | return sb.toString(); 41 | } 42 | 43 | // http://localhost:8080/api/v1/put-api/member2 44 | @PutMapping(value = "/member1") 45 | public String postMemberDto1(@RequestBody MemberDTO memberDTO) { 46 | return memberDTO.toString(); 47 | } 48 | 49 | // http://localhost:8080/api/v1/put-api/member2 50 | @PutMapping(value = "/member2") 51 | public MemberDTO postMemberDto2(@RequestBody MemberDTO memberDTO) { 52 | return memberDTO; 53 | } 54 | 55 | // http://localhost:8080/api/v1/put-api/member2 56 | @PutMapping(value = "/member3") 57 | public ResponseEntity postMemberDto3(@RequestBody MemberDTO memberDTO) { 58 | return ResponseEntity.status(HttpStatus.ACCEPTED).body(memberDTO); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/RestTemplateController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 11 | import studio.thinkground.aroundhub.mvc.service.RestTemplateService; 12 | 13 | @RestController 14 | @RequestMapping("/api/rest-template") 15 | public class RestTemplateController { 16 | 17 | RestTemplateService restTemplateService; 18 | 19 | @Autowired 20 | public RestTemplateController(RestTemplateService restTemplateService) { 21 | this.restTemplateService = restTemplateService; 22 | } 23 | 24 | @GetMapping(value = "/around-hub") 25 | public String getAroundHub() { 26 | return restTemplateService.getAroundHub(); 27 | } 28 | 29 | @GetMapping(value = "/name") 30 | public String getName() { 31 | return restTemplateService.getName(); 32 | } 33 | 34 | @GetMapping(value = "/name2") 35 | public String getName2() { 36 | return restTemplateService.getName2(); 37 | } 38 | 39 | @PostMapping(value = "/dto") 40 | public ResponseEntity postDto() { 41 | return restTemplateService.postDto(); 42 | } 43 | 44 | @PostMapping(value = "/add-header") 45 | public ResponseEntity addHeader() { 46 | return restTemplateService.addHeader(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/controller/ShortUrlController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.DeleteMapping; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.PutMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import studio.thinkground.aroundhub.mvc.data.dto.ShortUrlResponseDto; 18 | import studio.thinkground.aroundhub.mvc.service.ShortUrlService; 19 | 20 | @RestController 21 | @RequestMapping("/api/v1/short-url") 22 | public class ShortUrlController { 23 | 24 | private final Logger LOGGER = LoggerFactory.getLogger(ShortUrlController.class); 25 | 26 | @Value("${around.hub.short.url.id}") 27 | private String CLIENT_ID; 28 | 29 | @Value("${around.hub.short.url.secret}") 30 | private String CLIENT_SECRET; 31 | 32 | ShortUrlService shortUrlService; 33 | 34 | @Autowired 35 | public ShortUrlController(ShortUrlService shortUrlService) { 36 | this.shortUrlService = shortUrlService; 37 | } 38 | 39 | @PostMapping() 40 | public ShortUrlResponseDto generateShortUrl(String originalUrl) { 41 | LOGGER.info( 42 | "[generateShortUrl] perform API. CLIENT_ID : {}, CLIENT_SECRET : {}", 43 | CLIENT_ID, 44 | CLIENT_SECRET); 45 | 46 | return shortUrlService.generateShortUrl(CLIENT_ID, CLIENT_SECRET, originalUrl); 47 | } 48 | 49 | @GetMapping() 50 | public ShortUrlResponseDto getShortUrl(String originalUrl) { 51 | long startTime = System.currentTimeMillis(); 52 | ShortUrlResponseDto shortUrlResponseDto = 53 | shortUrlService.getShortUrl(CLIENT_ID, CLIENT_SECRET, originalUrl); 54 | long endTime = System.currentTimeMillis(); 55 | 56 | LOGGER.info("[getShortUrl] response Time : {}ms", (endTime - startTime)); 57 | 58 | return shortUrlResponseDto; 59 | } 60 | 61 | @PutMapping("/") 62 | public ShortUrlResponseDto updateShortUrl(String originalUrl) { 63 | return null; 64 | } 65 | 66 | @DeleteMapping("/") 67 | public ResponseEntity deleteShortUrl(String url) { 68 | try { 69 | shortUrlService.deleteShortUrl(url); 70 | } catch (RuntimeException e) { 71 | e.printStackTrace(); 72 | } 73 | 74 | return ResponseEntity.status(HttpStatus.OK).body("정상적으로 삭제되었습니다."); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dao/ProductDAO.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dao; 2 | 3 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 4 | 5 | public interface ProductDAO { 6 | 7 | Product saveProduct(Product product); 8 | 9 | Product getProduct(String productId); 10 | } 11 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dao/ShortUrlDAO.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dao; 2 | 3 | import studio.thinkground.aroundhub.mvc.data.entity.ShortUrl; 4 | 5 | public interface ShortUrlDAO { 6 | 7 | ShortUrl saveShortUrl(ShortUrl shortUrl); 8 | 9 | ShortUrl getShortUrl(String originalUrl); 10 | 11 | ShortUrl getOriginalUrl(String shortUrl); 12 | 13 | ShortUrl updateShortUrl(ShortUrl newShortUrl); 14 | 15 | void deleteByShortUrl(String shortUrl); 16 | 17 | void deleteByOriginalUrl(String originalUrl); 18 | } 19 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dao/impl/ProductDAOImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dao.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import studio.thinkground.aroundhub.mvc.data.dao.ProductDAO; 10 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 11 | import studio.thinkground.aroundhub.mvc.data.repository.ProductRepository; 12 | 13 | @Service 14 | public class ProductDAOImpl implements ProductDAO { 15 | 16 | private final Logger LOGGER = LoggerFactory.getLogger(ProductDAOImpl.class); 17 | 18 | ProductRepository productRepository; 19 | 20 | @Autowired 21 | public ProductDAOImpl(ProductRepository productRepository) { 22 | this.productRepository = productRepository; 23 | } 24 | 25 | @Override 26 | public Product saveProduct(Product product) { 27 | LOGGER.info("[saveProduct] product 정보 저장. productId : {}", product.getId()); 28 | Product product1 = productRepository.save(product); 29 | LOGGER.info("[saveProduct] product 정보 저장완료. productId : {}", product1.getId()); 30 | return product1; 31 | } 32 | 33 | @Override 34 | public Product getProduct(String productId) { 35 | LOGGER.info("[getProduct] product 정보 요청. productId : {}", productId); 36 | Product product = productRepository.getById(productId); 37 | LOGGER.info("[getProduct] product 정보 요청 완료. productId : {}", product.getId()); 38 | return product; 39 | } 40 | 41 | /** Repository에서 기본적으로 제공하는 대표적인 메소드 */ 42 | private void testRepositoryMethod() { 43 | /* productRepository.save(); 44 | productRepository.getById(); 45 | productRepository.delete(); 46 | productRepository.deleteAll(); 47 | productRepository.findAll(); 48 | productRepository.saveAll();*/ 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dao/impl/ShortUrlDaoImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dao.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Component; 5 | 6 | import studio.thinkground.aroundhub.mvc.data.dao.ShortUrlDAO; 7 | import studio.thinkground.aroundhub.mvc.data.entity.ShortUrl; 8 | import studio.thinkground.aroundhub.mvc.data.repository.ShortUrlRepository; 9 | 10 | @Component 11 | public class ShortUrlDaoImpl implements ShortUrlDAO { 12 | 13 | private final ShortUrlRepository shortUrlRepository; 14 | 15 | @Autowired 16 | public ShortUrlDaoImpl(ShortUrlRepository shortUrlRepository) { 17 | this.shortUrlRepository = shortUrlRepository; 18 | } 19 | 20 | @Override 21 | public ShortUrl saveShortUrl(ShortUrl shortUrl) { 22 | ShortUrl foundShortUrl = shortUrlRepository.save(shortUrl); 23 | return foundShortUrl; 24 | } 25 | 26 | @Override 27 | public ShortUrl getShortUrl(String originalUrl) { 28 | ShortUrl foundShortUrl = shortUrlRepository.findByOrgUrl(originalUrl); 29 | return foundShortUrl; 30 | } 31 | 32 | @Override 33 | public ShortUrl getOriginalUrl(String shortUrl) { 34 | ShortUrl foundShortUrl = shortUrlRepository.findByUrl(shortUrl); 35 | return foundShortUrl; 36 | } 37 | 38 | @Override 39 | public ShortUrl updateShortUrl(ShortUrl newShortUrl) { 40 | ShortUrl foundShortUrl = shortUrlRepository.findByOrgUrl(newShortUrl.getOrgUrl()); 41 | 42 | foundShortUrl.setUrl(newShortUrl.getUrl()); 43 | 44 | ShortUrl savedShortUrl = shortUrlRepository.save(foundShortUrl); 45 | 46 | return savedShortUrl; 47 | } 48 | 49 | @Override 50 | public void deleteByShortUrl(String shortUrl) { 51 | ShortUrl foundShortUrl = shortUrlRepository.findByUrl(shortUrl); 52 | shortUrlRepository.delete(foundShortUrl); 53 | } 54 | 55 | @Override 56 | public void deleteByOriginalUrl(String originalUrl) { 57 | ShortUrl foundShortUrl = shortUrlRepository.findByOrgUrl(originalUrl); 58 | shortUrlRepository.delete(foundShortUrl); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dto/MemberDTO.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.ToString; 6 | 7 | @Getter 8 | @Setter 9 | @ToString 10 | public class MemberDTO { 11 | 12 | private String name; 13 | private String email; 14 | private String organization; 15 | } 16 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dto/NaverUriDto.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | import lombok.ToString; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @ToString 15 | @Builder 16 | public class NaverUriDto { 17 | 18 | private String message; 19 | 20 | private String code; 21 | 22 | private Result result; 23 | 24 | @Getter 25 | @Setter 26 | public static class Result { 27 | 28 | private String hash; 29 | 30 | private String url; 31 | 32 | private String orgUrl; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dto/ProductDto.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dto; 2 | 3 | import jakarta.validation.constraints.Max; 4 | import jakarta.validation.constraints.Min; 5 | import jakarta.validation.constraints.NotNull; 6 | 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | import lombok.ToString; 12 | 13 | import org.springframework.data.annotation.Id; 14 | import org.springframework.data.redis.core.RedisHash; 15 | 16 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 17 | 18 | @Data 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @ToString 22 | @Builder 23 | @RedisHash(value = "product", timeToLive = 60) 24 | public class ProductDto { 25 | 26 | // @Size(min = 8, max = 8) // abcdefg 27 | @NotNull private String productId; 28 | 29 | @NotNull @Id private String productName; 30 | 31 | @NotNull 32 | @Min(value = 500) 33 | @Max(value = 3000000) 34 | private int productPrice; 35 | 36 | @NotNull 37 | @Min(value = 0) 38 | @Max(value = 9999) 39 | private int productStock; 40 | 41 | public Product toEntity() { 42 | return Product.builder() 43 | .id(productId) 44 | .name(productName) 45 | .price(productPrice) 46 | .stock(productStock) 47 | .build(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/dto/ShortUrlResponseDto.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.dto; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | import lombok.ToString; 10 | 11 | import org.springframework.data.annotation.Id; 12 | import org.springframework.data.redis.core.RedisHash; 13 | 14 | @Data 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @ToString 18 | @Builder 19 | @RedisHash(value = "shortUrl", timeToLive = 60) 20 | public class ShortUrlResponseDto implements Serializable { 21 | 22 | private static final long serialVersionUID = -214490344996507077L; 23 | 24 | @Id private String orgUrl; 25 | 26 | private String shortUrl; 27 | } 28 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.entity; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.EntityListeners; 7 | import jakarta.persistence.MappedSuperclass; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | import org.springframework.data.annotation.CreatedDate; 13 | import org.springframework.data.annotation.LastModifiedDate; 14 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 15 | 16 | @Getter 17 | @Setter 18 | @MappedSuperclass 19 | @EntityListeners(AuditingEntityListener.class) 20 | public class BaseEntity { 21 | 22 | @CreatedDate 23 | @Column(updatable = false) 24 | private LocalDateTime createdAt; 25 | 26 | /* 27 | @CreatedBy 28 | @Column(updatable = false) 29 | private String createdBy; 30 | */ 31 | 32 | @LastModifiedDate private LocalDateTime updatedAt; 33 | 34 | /* 35 | @LastModifiedBy 36 | private String updatedBy; 37 | */ 38 | 39 | } 40 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/entity/Listener.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.EntityListeners; 5 | import jakarta.persistence.GeneratedValue; 6 | import jakarta.persistence.GenerationType; 7 | import jakarta.persistence.Id; 8 | import jakarta.persistence.Table; 9 | 10 | import lombok.AllArgsConstructor; 11 | import lombok.Builder; 12 | import lombok.Getter; 13 | import lombok.NoArgsConstructor; 14 | import lombok.Setter; 15 | 16 | import studio.thinkground.aroundhub.mvc.data.entity.listener.CustomListener; 17 | 18 | @Entity 19 | @Getter 20 | @Setter 21 | @NoArgsConstructor 22 | @AllArgsConstructor 23 | @Builder 24 | @Table(name = "listener") 25 | @EntityListeners(CustomListener.class) 26 | public class Listener { 27 | 28 | @Id 29 | @GeneratedValue(strategy = GenerationType.IDENTITY) 30 | private Long id; 31 | 32 | private String name; 33 | } 34 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/entity/Product.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Table; 6 | 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | import lombok.ToString; 13 | 14 | import studio.thinkground.aroundhub.mvc.data.dto.ProductDto; 15 | 16 | @Entity 17 | @Getter 18 | @Setter 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @Builder 22 | @ToString 23 | @Table(name = "product") 24 | public class Product extends BaseEntity { 25 | 26 | @Id String id; 27 | 28 | String name; 29 | 30 | Integer price; 31 | 32 | Integer stock; 33 | 34 | /* 35 | @Column 36 | String sellerId; 37 | 38 | @Column 39 | String sellerPhoneNumber; 40 | */ 41 | 42 | public ProductDto toDto() { 43 | return ProductDto.builder() 44 | .productId(id) 45 | .productName(name) 46 | .productPrice(price) 47 | .productStock(stock) 48 | .build(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/entity/ShortUrl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.entity; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.GeneratedValue; 6 | import jakarta.persistence.GenerationType; 7 | import jakarta.persistence.Id; 8 | import jakarta.persistence.Table; 9 | 10 | import lombok.AllArgsConstructor; 11 | import lombok.Builder; 12 | import lombok.Getter; 13 | import lombok.NoArgsConstructor; 14 | import lombok.Setter; 15 | 16 | @Entity 17 | @Getter 18 | @Setter 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @Builder 22 | @Table(name = "short_url") 23 | public class ShortUrl extends BaseEntity { 24 | 25 | @Id 26 | @GeneratedValue(strategy = GenerationType.IDENTITY) 27 | private Long id; 28 | 29 | @Column(nullable = false, unique = true) 30 | private String hash; 31 | 32 | @Column(nullable = false, unique = true) 33 | private String url; 34 | 35 | @Column(nullable = false, unique = true) 36 | private String orgUrl; 37 | } 38 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/entity/listener/CustomListener.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.entity.listener; 2 | 3 | import jakarta.persistence.PostLoad; 4 | import jakarta.persistence.PostPersist; 5 | import jakarta.persistence.PostRemove; 6 | import jakarta.persistence.PostUpdate; 7 | import jakarta.persistence.PrePersist; 8 | import jakarta.persistence.PreRemove; 9 | import jakarta.persistence.PreUpdate; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import studio.thinkground.aroundhub.mvc.data.entity.Listener; 15 | 16 | public class CustomListener { 17 | 18 | private final Logger LOGGER = LoggerFactory.getLogger(CustomListener.class); 19 | 20 | @PostLoad 21 | public void postLoad(Listener entity) { 22 | LOGGER.info("[postLoad] called!!"); 23 | } 24 | 25 | @PrePersist 26 | public void prePersist(Listener entity) { 27 | LOGGER.info("[prePersist] called!!"); 28 | } 29 | 30 | @PostPersist 31 | public void postPersist(Listener entity) { 32 | LOGGER.info("[postPersist] called!!"); 33 | } 34 | 35 | @PreUpdate 36 | public void preUpdate(Listener entity) { 37 | LOGGER.info("[preUpdate] called!!"); 38 | } 39 | 40 | @PostUpdate 41 | public void postUpdate(Listener entity) { 42 | LOGGER.info("[postUpdate] called!!"); 43 | } 44 | 45 | @PreRemove 46 | public void preRemove(Listener entity) { 47 | LOGGER.info("[preRemove] called!!"); 48 | } 49 | 50 | @PostRemove 51 | public void postRemove(Listener entity) { 52 | LOGGER.info("[postRemove] called!!"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/handler/ProductDataHandler.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.handler; 2 | 3 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 4 | 5 | public interface ProductDataHandler { 6 | 7 | Product saveProductEntity( 8 | String productId, String productName, int productPrice, int productStock); 9 | 10 | Product getProductEntity(String productId); 11 | } 12 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/handler/impl/ProductDataHandlerImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.handler.impl; 2 | 3 | import jakarta.transaction.Transactional; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import studio.thinkground.aroundhub.mvc.data.dao.ProductDAO; 12 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 13 | import studio.thinkground.aroundhub.mvc.data.handler.ProductDataHandler; 14 | 15 | @Service 16 | @Transactional 17 | public class ProductDataHandlerImpl implements ProductDataHandler { 18 | 19 | private final Logger LOGGER = LoggerFactory.getLogger(ProductDataHandlerImpl.class); 20 | 21 | ProductDAO productDAO; 22 | 23 | @Autowired 24 | public ProductDataHandlerImpl(ProductDAO productDAO) { 25 | this.productDAO = productDAO; 26 | } 27 | 28 | @Override 29 | public Product saveProductEntity( 30 | String productId, String productName, int productPrice, int productStock) { 31 | 32 | LOGGER.debug("[saveProductEntity] 매개변수를 통해 Entity 객체 생성"); 33 | Product product = new Product(productId, productName, productPrice, productStock); 34 | 35 | LOGGER.info("[saveProductEntity] productDAO로 Product 정보 저장 요청. productId : {}", productId); 36 | return productDAO.saveProduct(product); 37 | } 38 | 39 | @Override 40 | public Product getProductEntity(String productId) { 41 | LOGGER.info("[saveProductEntity] productDAO로 Product 정보 요청. productId : {}", productId); 42 | return productDAO.getProduct(productId); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/repository/ListenerRepository.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import studio.thinkground.aroundhub.mvc.data.entity.Listener; 6 | 7 | public interface ListenerRepository extends JpaRepository {} 8 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.repository; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.domain.Sort; 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 studio.thinkground.aroundhub.mvc.data.entity.Product; 12 | 13 | public interface ProductRepository extends JpaRepository { 14 | 15 | /* 쿼리 메소드의 주제 키워드 */ 16 | 17 | // 조회 18 | List findByName(String name); 19 | 20 | List queryByName(String name); 21 | 22 | // 존재 유무 23 | boolean existsByName(String name); 24 | 25 | // 쿼리 결과 개수 26 | long countByName(String name); 27 | 28 | // 삭제 29 | void deleteByName(String name); 30 | 31 | long removeByName(String name); 32 | 33 | // 값 개수 제한 34 | List findFirst5ByName(String name); 35 | 36 | List findTop3ByName(String name); 37 | 38 | /* 쿼리 메소드의 조건자 키워드 */ 39 | 40 | // Is, Equals (생략 가능) 41 | // Logical Keyword : IS , Keyword Expressions : Is, Equals, (or no keyword) 42 | // findByNumber 메소드와 동일하게 동작 43 | Product findByIdIs(String id); 44 | 45 | Product findByIdEquals(String id); 46 | 47 | // (Is)Not 48 | List findByIdNot(String id); 49 | 50 | List findByIdIsNot(String id); 51 | 52 | // (Is)Null, (Is)NotNull 53 | List findByStockIsNull(); 54 | 55 | List findByStockIsNotNull(); 56 | 57 | // And, Or 58 | List findTopByIdAndName(String id, String name); 59 | 60 | // (Is)GreaterThan, (Is)LessThan, (Is)Between 61 | List findByPriceGreaterThan(Integer price); 62 | 63 | // (Is)Like, (Is)Containing, (Is)StartingWith, (Is)EndingWith 64 | List findByNameContaining(String name); 65 | 66 | /* 정렬과 페이징 */ 67 | 68 | // Asc : 오름차순, Desc : 내림차순 69 | List findByNameContainingOrderByStockAsc(String name); 70 | 71 | List findByNameContainingOrderByStockDesc(String name); 72 | 73 | // 여러 정렬 기준 사용 74 | List findByNameContainingOrderByPriceAscStockDesc(String name); 75 | 76 | // 매개변수를 활용한 정렬 77 | List findByNameContaining(String name, Sort sort); 78 | 79 | // 페이징 처리하기 80 | List findByPriceGreaterThan(Integer price, Pageable pageable); 81 | 82 | /* @Query 사용하기 */ 83 | 84 | @Query("SELECT p FROM Product p WHERE p.price > 2000") 85 | List findByPriceBasis(); 86 | 87 | @Query(value = "SELECT * FROM product p WHERE p.price > 2000", nativeQuery = true) 88 | List findByPriceBasisNativeQuery(); 89 | 90 | @Query("SELECT p FROM Product p WHERE p.price > ?1") 91 | List findByPriceWithParameter(Integer price); 92 | 93 | @Query("SELECT p FROM Product p WHERE p.price > :price") 94 | List findByPriceWithParameterNaming(Integer price); 95 | 96 | @Query("SELECT p FROM Product p WHERE p.price > :pri") 97 | List findByPriceWithParameterNaming2(@Param("pri") Integer price); 98 | 99 | @Query( 100 | value = "SELECT * FROM product WHERE price > :price", 101 | countQuery = "SELECT count(*) FROM product WHERE price > ?1", 102 | nativeQuery = true) 103 | List findByPriceWithParameterPaging(Integer price, Pageable pageable); 104 | } 105 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/repository/ShortUrlRedisRepository.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.repository; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | import studio.thinkground.aroundhub.mvc.data.dto.ShortUrlResponseDto; 6 | 7 | /** 8 | * PackageName : studio.thinkground.aroundhub.data.repository FileName : ShortUrlRedisRepository 9 | * Author : Flature Date : 2022-05-21 Description : 10 | */ 11 | public interface ShortUrlRedisRepository extends CrudRepository {} 12 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/data/repository/ShortUrlRepository.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.data.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import studio.thinkground.aroundhub.mvc.data.entity.ShortUrl; 6 | 7 | public interface ShortUrlRepository extends JpaRepository { 8 | 9 | ShortUrl findByUrl(String url); 10 | 11 | ShortUrl findByOrgUrl(String originalUrl); 12 | } 13 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/interceptor/HttpInterceptor.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.interceptor; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.servlet.HandlerInterceptor; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | /** 14 | * PackageName : studio.thinkground.aroundhub.interceptor FileName : HttpInterceptor Author : 15 | * Flature Date : 2022-06-04 Description : 16 | */ 17 | @Component 18 | public class HttpInterceptor implements HandlerInterceptor { 19 | 20 | private final Logger LOGGER = LoggerFactory.getLogger(HttpInterceptor.class); 21 | 22 | @Override 23 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 24 | throws Exception { 25 | LOGGER.info("[preHandle] preHandle is performed"); 26 | /* LOGGER.info("[preHandle] request : {}", request); 27 | LOGGER.info("[preHandle] request path info : {}", request.getPathInfo()); 28 | LOGGER.info("[preHandle] request header names : {}", request.getHeaderNames()); 29 | LOGGER.info("[preHandle] request request URL : {}", request.getRequestURL()); 30 | LOGGER.info("[preHandle] request request URI: {}", request.getRequestURI()); 31 | LOGGER.info("[preHandle] request Requested Session Id : {}", request.getRequestedSessionId());*/ 32 | 33 | // TODO HttpServletRequestWrapper 구현하여 Body 값 확인할 수 있게 코드 추가 34 | 35 | return true; 36 | } 37 | 38 | @Override 39 | public void postHandle( 40 | HttpServletRequest request, 41 | HttpServletResponse response, 42 | Object handler, 43 | ModelAndView modelAndView) 44 | throws Exception { 45 | LOGGER.info("[postHandle] postHandle is performed"); 46 | /*LOGGER.info("[postHandle] request : {}", request); 47 | LOGGER.info("[postHandle] response : {}", response); 48 | LOGGER.info("[postHandle] response : {}", response.getHeaderNames());*/ 49 | } 50 | 51 | @Override 52 | public void afterCompletion( 53 | HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 54 | throws Exception { 55 | LOGGER.info("[afterCompletion] afterCompletion is performed"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/ListenerService.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service; 2 | 3 | import studio.thinkground.aroundhub.mvc.data.entity.Listener; 4 | 5 | public interface ListenerService { 6 | 7 | Listener getEntity(Long id); 8 | 9 | void saveEntity(Listener listener); 10 | 11 | void updateEntity(Listener listener); 12 | 13 | void removeEntity(Listener listener); 14 | } 15 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service; 2 | 3 | import studio.thinkground.aroundhub.mvc.data.dto.ProductDto; 4 | 5 | public interface ProductService { 6 | 7 | ProductDto saveProduct(String productId, String productName, int productPrice, int productStock); 8 | 9 | ProductDto getProduct(String productId); 10 | } 11 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/RestClientService.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | 5 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 6 | 7 | public interface RestClientService { 8 | 9 | String getName(); 10 | 11 | String getNameWithPathVariable(); 12 | 13 | String getNameWithParameter(); 14 | 15 | ResponseEntity postWithParamAndBody(); 16 | 17 | ResponseEntity postWithHeader(); 18 | } 19 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/RestTemplateService.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | 5 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 6 | 7 | public interface RestTemplateService { 8 | 9 | public String getAroundHub(); 10 | 11 | public String getName(); 12 | 13 | public String getName2(); 14 | 15 | public ResponseEntity postDto(); 16 | 17 | public ResponseEntity addHeader(); 18 | } 19 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/ShortUrlService.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service; 2 | 3 | import studio.thinkground.aroundhub.mvc.data.dto.ShortUrlResponseDto; 4 | 5 | public interface ShortUrlService { 6 | 7 | ShortUrlResponseDto getShortUrl(String clientId, String clientSecret, String originalUrl); 8 | 9 | ShortUrlResponseDto generateShortUrl(String clientId, String clientSecret, String originalUrl); 10 | 11 | ShortUrlResponseDto updateShortUrl(String clientId, String clientSecret, String originalUrl); 12 | 13 | void deleteShortUrl(String url); 14 | } 15 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/impl/ListenerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | 6 | import studio.thinkground.aroundhub.mvc.data.entity.Listener; 7 | import studio.thinkground.aroundhub.mvc.data.repository.ListenerRepository; 8 | import studio.thinkground.aroundhub.mvc.service.ListenerService; 9 | 10 | @Service 11 | public class ListenerServiceImpl implements ListenerService { 12 | 13 | private ListenerRepository listenerRepository; 14 | 15 | @Autowired 16 | public ListenerServiceImpl(ListenerRepository listenerRepository) { 17 | this.listenerRepository = listenerRepository; 18 | } 19 | 20 | @Override 21 | public Listener getEntity(Long id) { 22 | return listenerRepository.findById(id).get(); 23 | } 24 | 25 | @Override 26 | public void saveEntity(Listener listener) { 27 | listenerRepository.save(listener); 28 | } 29 | 30 | @Override 31 | public void updateEntity(Listener listener) { 32 | Listener foundListener = listenerRepository.findById(listener.getId()).get(); 33 | foundListener.setName(listener.getName()); 34 | 35 | listenerRepository.save(foundListener); 36 | } 37 | 38 | @Override 39 | public void removeEntity(Listener listener) { 40 | listenerRepository.delete(listener); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/impl/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import studio.thinkground.aroundhub.mvc.data.dto.ProductDto; 10 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 11 | import studio.thinkground.aroundhub.mvc.data.handler.ProductDataHandler; 12 | import studio.thinkground.aroundhub.mvc.service.ProductService; 13 | 14 | @Service 15 | public class ProductServiceImpl implements ProductService { 16 | 17 | private final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class); 18 | 19 | ProductDataHandler productDataHandler; 20 | 21 | @Autowired 22 | public ProductServiceImpl(ProductDataHandler productDataHandler) { 23 | this.productDataHandler = productDataHandler; 24 | } 25 | 26 | @Override 27 | public ProductDto saveProduct( 28 | String productId, String productName, int productPrice, int productStock) { 29 | 30 | LOGGER.info("[saveProduct] productDataHandler 로 상품 정보 저장 요청"); 31 | Product product = 32 | productDataHandler.saveProductEntity(productId, productName, productPrice, productStock); 33 | 34 | LOGGER.info("[saveProduct] Entity 객체를 DTO 객체로 변환 작업. productId : {}", product.getId()); 35 | ProductDto productDto = 36 | new ProductDto(product.getId(), product.getName(), product.getPrice(), product.getStock()); 37 | 38 | return productDto; 39 | } 40 | 41 | @Override 42 | public ProductDto getProduct(String productId) { 43 | 44 | LOGGER.info("[getProduct] productDataHandler 로 상품 정보 조회 요청"); 45 | Product product = productDataHandler.getProductEntity(productId); 46 | 47 | LOGGER.info("[getProduct] Entity 객체를 DTO 객체로 변환 작업. productId : {}", product.getId()); 48 | ProductDto productDto = 49 | new ProductDto(product.getId(), product.getName(), product.getPrice(), product.getStock()); 50 | 51 | return productDto; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/impl/RestClientServiceImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service.impl; 2 | 3 | import org.springframework.http.HttpHeaders; 4 | import org.springframework.http.HttpStatusCode; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.web.client.RestClient; 9 | 10 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 11 | import studio.thinkground.aroundhub.mvc.service.RestClientService; 12 | 13 | @Service 14 | public class RestClientServiceImpl implements RestClientService { 15 | 16 | public String getName() { 17 | RestClient restClient = 18 | RestClient.builder() 19 | .baseUrl("http://localhost:9090") 20 | .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 21 | .build(); 22 | 23 | return restClient.get().uri("/api/v1/crud-api").retrieve().body(String.class); 24 | } 25 | 26 | public String getNameWithPathVariable() { 27 | RestClient restClient = RestClient.create("http://localhost:9090"); 28 | 29 | ResponseEntity responseEntity = 30 | restClient 31 | .get() 32 | .uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/{name}").build("Flature")) 33 | .retrieve() 34 | .toEntity(String.class); 35 | 36 | ResponseEntity responseEntity1 = 37 | restClient 38 | .get() 39 | .uri("/api/v1/crud-api/{name}", "Flature") 40 | .retrieve() 41 | .toEntity(String.class); 42 | 43 | return responseEntity.getBody(); 44 | } 45 | 46 | public String getNameWithParameter() { 47 | RestClient restClient = RestClient.create("http://localhost:9090"); 48 | 49 | return restClient 50 | .get() 51 | .uri( 52 | uriBuilder -> 53 | uriBuilder.path("/api/v1/crud-api/param").queryParam("name", "Flature").build()) 54 | .retrieve() 55 | .onStatus( 56 | HttpStatusCode::is4xxClientError, 57 | (request, response) -> { 58 | throw new RuntimeException("400 Error occurred"); 59 | }) 60 | .onStatus( 61 | HttpStatusCode::is5xxServerError, 62 | (request, response) -> { 63 | throw new RuntimeException("500 Error occurred"); 64 | }) 65 | .body(String.class); 66 | } 67 | 68 | public ResponseEntity postWithParamAndBody() { 69 | RestClient restClient = 70 | RestClient.builder() 71 | .baseUrl("http://localhost:9090") 72 | .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 73 | .build(); 74 | 75 | MemberDTO memberDTO = new MemberDTO(); 76 | memberDTO.setName("flature!!"); 77 | memberDTO.setEmail("flature@gmail.com"); 78 | memberDTO.setOrganization("Around Hub Studio"); 79 | 80 | return restClient 81 | .post() 82 | .uri( 83 | uriBuilder -> 84 | uriBuilder 85 | .path("/api/v1/crud-api") 86 | .queryParam("name", "Flature") 87 | .queryParam("email", "flature@wikibooks.co.kr") 88 | .queryParam("organization", "Wikibooks") 89 | .build()) 90 | .body(memberDTO) 91 | .retrieve() 92 | .toEntity(MemberDTO.class); 93 | } 94 | 95 | public ResponseEntity postWithHeader() { 96 | RestClient restClient = 97 | RestClient.builder() 98 | .baseUrl("http://localhost:9090") 99 | .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 100 | .build(); 101 | 102 | MemberDTO memberDTO = new MemberDTO(); 103 | memberDTO.setName("flature!!"); 104 | memberDTO.setEmail("flature@gmail.com"); 105 | memberDTO.setOrganization("Around Hub Studio"); 106 | 107 | return restClient 108 | .post() 109 | .uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/add-header").build()) 110 | .body(memberDTO) 111 | .header("my-header", "Wikibooks API") 112 | .retrieve() 113 | .toEntity(MemberDTO.class); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/impl/RestTemplateServiceImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service.impl; 2 | 3 | import java.net.URI; 4 | 5 | import org.springframework.http.RequestEntity; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.web.client.RestTemplate; 9 | import org.springframework.web.util.UriComponentsBuilder; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import studio.thinkground.aroundhub.mvc.data.dto.MemberDTO; 15 | import studio.thinkground.aroundhub.mvc.service.RestTemplateService; 16 | 17 | @Service 18 | public class RestTemplateServiceImpl implements RestTemplateService { 19 | 20 | private final Logger LOGGER = LoggerFactory.getLogger(RestTemplateServiceImpl.class); 21 | 22 | @Override 23 | public String getAroundHub() { 24 | URI uri = 25 | UriComponentsBuilder.fromUriString("http://localhost:9090") 26 | .path("/api/server/around-hub") 27 | .encode() 28 | .build() 29 | .toUri(); 30 | 31 | RestTemplate restTemplate = new RestTemplate(); 32 | ResponseEntity responseEntity = restTemplate.getForEntity(uri, String.class); 33 | 34 | LOGGER.info("status code : {}", responseEntity.getStatusCode()); 35 | LOGGER.info("body : {}", responseEntity.getBody()); 36 | 37 | return responseEntity.getBody(); 38 | } 39 | 40 | @Override 41 | public String getName() { 42 | 43 | URI uri = 44 | UriComponentsBuilder.fromUriString("http://localhost:9090") 45 | .path("/api/server/name") 46 | .queryParam("name", "Flature") 47 | .encode() 48 | .build() 49 | .toUri(); 50 | 51 | RestTemplate restTemplate = new RestTemplate(); 52 | ResponseEntity responseEntity = restTemplate.getForEntity(uri, String.class); 53 | 54 | LOGGER.info("status code : {}", responseEntity.getStatusCode()); 55 | LOGGER.info("body : {}", responseEntity.getBody()); 56 | 57 | return responseEntity.getBody(); 58 | } 59 | 60 | @Override 61 | public String getName2() { 62 | URI uri = 63 | UriComponentsBuilder.fromUriString("http://localhost:9090") 64 | .path("/api/server/path-variable/{name}") 65 | .encode() 66 | .build() 67 | .expand("Flature") // 복수의 값을 넣어야할 경우 , 를 추가하여 구분 68 | .toUri(); 69 | 70 | RestTemplate restTemplate = new RestTemplate(); 71 | ResponseEntity responseEntity = restTemplate.getForEntity(uri, String.class); 72 | 73 | LOGGER.info("status code : {}", responseEntity.getStatusCode()); 74 | LOGGER.info("body : {}", responseEntity.getBody()); 75 | 76 | return responseEntity.getBody(); 77 | } 78 | 79 | @Override 80 | public ResponseEntity postDto() { 81 | URI uri = 82 | UriComponentsBuilder.fromUriString("http://localhost:9090") 83 | .path("/api/server/member") 84 | .queryParam("name", "Flature") 85 | .queryParam("email", "jjj@jjj.com") 86 | .queryParam("organization", "Around Hub Studio") 87 | .encode() 88 | .build() 89 | .toUri(); 90 | 91 | MemberDTO memberDTO = new MemberDTO(); 92 | memberDTO.setName("flature!!"); 93 | memberDTO.setEmail("aaa@aaa.com"); 94 | memberDTO.setOrganization("Around Hub Studio!!"); 95 | 96 | RestTemplate restTemplate = new RestTemplate(); 97 | ResponseEntity responseEntity = 98 | restTemplate.postForEntity(uri, memberDTO, MemberDTO.class); 99 | 100 | LOGGER.info("status code : {}", responseEntity.getStatusCode()); 101 | LOGGER.info("body : {}", responseEntity.getBody()); 102 | 103 | return responseEntity; 104 | } 105 | 106 | @Override 107 | public ResponseEntity addHeader() { 108 | URI uri = 109 | UriComponentsBuilder.fromUriString("http://localhost:9090") 110 | .path("/api/server/add-header") 111 | .encode() 112 | .build() 113 | .toUri(); 114 | 115 | MemberDTO memberDTO = new MemberDTO(); 116 | memberDTO.setName("flature"); 117 | memberDTO.setEmail("jjj@jjj.com"); 118 | memberDTO.setOrganization("Around Hub Studio"); 119 | 120 | RequestEntity requestEntity = 121 | RequestEntity.post(uri).header("around-header", "Around Hub Studio").body(memberDTO); 122 | 123 | RestTemplate restTemplate = new RestTemplate(); 124 | ResponseEntity responseEntity = 125 | restTemplate.exchange(requestEntity, MemberDTO.class); 126 | 127 | LOGGER.info("status code : {}", responseEntity.getStatusCode()); 128 | LOGGER.info("body : {}", responseEntity.getBody()); 129 | 130 | return responseEntity; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/service/impl/ShortUrlServiceImpl.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.service.impl; 2 | 3 | import java.net.URI; 4 | import java.util.Arrays; 5 | import java.util.Optional; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpEntity; 9 | import org.springframework.http.HttpHeaders; 10 | import org.springframework.http.HttpMethod; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.stereotype.Service; 14 | import org.springframework.web.client.RestTemplate; 15 | import org.springframework.web.util.UriComponentsBuilder; 16 | 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import studio.thinkground.aroundhub.mvc.data.dao.ShortUrlDAO; 21 | import studio.thinkground.aroundhub.mvc.data.dto.NaverUriDto; 22 | import studio.thinkground.aroundhub.mvc.data.dto.ShortUrlResponseDto; 23 | import studio.thinkground.aroundhub.mvc.data.entity.ShortUrl; 24 | import studio.thinkground.aroundhub.mvc.data.repository.ShortUrlRedisRepository; 25 | import studio.thinkground.aroundhub.mvc.service.ShortUrlService; 26 | 27 | @Service 28 | public class ShortUrlServiceImpl implements ShortUrlService { 29 | 30 | private final Logger LOGGER = LoggerFactory.getLogger(ShortUrlServiceImpl.class); 31 | private final ShortUrlDAO shortUrlDAO; 32 | private final ShortUrlRedisRepository shortUrlRedisRepository; 33 | 34 | @Autowired 35 | public ShortUrlServiceImpl( 36 | ShortUrlDAO shortUrlDAO, ShortUrlRedisRepository shortUrlRedisRepository) { 37 | this.shortUrlDAO = shortUrlDAO; 38 | this.shortUrlRedisRepository = shortUrlRedisRepository; 39 | } 40 | 41 | @Override 42 | public ShortUrlResponseDto getShortUrl(String clientId, String clientSecret, String originalUrl) { 43 | LOGGER.info("[getShortUrl] request data : {}", originalUrl); 44 | 45 | // Cache Logic 46 | Optional foundResponseDto = shortUrlRedisRepository.findById(originalUrl); 47 | if (foundResponseDto.isPresent()) { 48 | LOGGER.info("[getShortUrl] Cache Data existed."); 49 | return foundResponseDto.get(); 50 | } else { 51 | LOGGER.info("[getShortUrl] Cache Data does not existed."); 52 | } 53 | 54 | ShortUrl getShortUrl = shortUrlDAO.getShortUrl(originalUrl); 55 | 56 | String orgUrl; 57 | String shortUrl; 58 | 59 | if (getShortUrl == null) { 60 | LOGGER.info("[getShortUrl] No Entity in Database."); 61 | ResponseEntity responseEntity = 62 | requestShortUrl(clientId, clientSecret, originalUrl); 63 | 64 | orgUrl = responseEntity.getBody().getResult().getOrgUrl(); 65 | shortUrl = responseEntity.getBody().getResult().getUrl(); 66 | String hash = responseEntity.getBody().getResult().getHash(); 67 | 68 | ShortUrl shortUrlEntity = new ShortUrl(); 69 | shortUrlEntity.setOrgUrl(orgUrl); 70 | shortUrlEntity.setUrl(shortUrl); 71 | shortUrlEntity.setHash(hash); 72 | 73 | shortUrlDAO.saveShortUrl(shortUrlEntity); 74 | 75 | } else { 76 | orgUrl = getShortUrl.getOrgUrl(); 77 | shortUrl = getShortUrl.getUrl(); 78 | } 79 | 80 | ShortUrlResponseDto shortUrlResponseDto = new ShortUrlResponseDto(orgUrl, shortUrl); 81 | 82 | shortUrlRedisRepository.save(shortUrlResponseDto); 83 | 84 | LOGGER.info("[getShortUrl] Response DTO : {}", shortUrlResponseDto); 85 | return shortUrlResponseDto; 86 | } 87 | 88 | @Override 89 | public ShortUrlResponseDto generateShortUrl( 90 | String clientId, String clientSecret, String originalUrl) { 91 | 92 | LOGGER.info("[generateShortUrl] request data : {}", originalUrl); 93 | 94 | if (originalUrl.contains("me2.do")) { 95 | throw new RuntimeException(); 96 | } 97 | 98 | ResponseEntity responseEntity = 99 | requestShortUrl(clientId, clientSecret, originalUrl); 100 | 101 | String orgUrl = responseEntity.getBody().getResult().getOrgUrl(); 102 | String shortUrl = responseEntity.getBody().getResult().getUrl(); 103 | String hash = responseEntity.getBody().getResult().getHash(); 104 | 105 | ShortUrl shortUrlEntity = new ShortUrl(); 106 | shortUrlEntity.setOrgUrl(orgUrl); 107 | shortUrlEntity.setUrl(shortUrl); 108 | shortUrlEntity.setHash(hash); 109 | 110 | shortUrlDAO.saveShortUrl(shortUrlEntity); 111 | 112 | ShortUrlResponseDto shortUrlResponseDto = new ShortUrlResponseDto(orgUrl, shortUrl); 113 | 114 | // Cache Logic 115 | shortUrlRedisRepository.save(shortUrlResponseDto); 116 | 117 | LOGGER.info("[generateShortUrl] Response DTO : {}", shortUrlResponseDto); 118 | return shortUrlResponseDto; 119 | } 120 | 121 | @Override 122 | public ShortUrlResponseDto updateShortUrl( 123 | String clientId, String clientSecret, String originalUrl) { 124 | return null; 125 | } 126 | 127 | @Override 128 | public void deleteShortUrl(String url) { 129 | if (url.contains("me2.do")) { 130 | LOGGER.info("[deleteShortUrl] Request Url is 'ShortUrl'."); 131 | deleteByShortUrl(url); 132 | } else { 133 | LOGGER.info("[deleteShortUrl] Request Url is 'OriginalUrl'."); 134 | deleteByOriginalUrl(url); 135 | } 136 | } 137 | 138 | private void deleteByShortUrl(String url) { 139 | LOGGER.info("[deleteByShortUrl] delete record"); 140 | shortUrlDAO.deleteByShortUrl(url); 141 | } 142 | 143 | private void deleteByOriginalUrl(String url) { 144 | LOGGER.info("[deleteByOriginalUrl] delete record"); 145 | shortUrlDAO.deleteByOriginalUrl(url); 146 | } 147 | 148 | private ResponseEntity requestShortUrl( 149 | String clientId, String clientSecret, String originalUrl) { 150 | LOGGER.info( 151 | "[requestShortUrl] client ID : ***, client Secret : ***, original URL : {}", originalUrl); 152 | 153 | URI uri = 154 | UriComponentsBuilder.fromUriString("https://openapi.naver.com") 155 | .path("/v1/util/shorturl") 156 | .queryParam("url", originalUrl) 157 | .encode() 158 | .build() 159 | .toUri(); 160 | 161 | LOGGER.info("[requestShortUrl] set HTTP Request Header"); 162 | HttpHeaders headers = new HttpHeaders(); 163 | headers.setAccept(Arrays.asList(new MediaType[] {MediaType.APPLICATION_JSON})); 164 | headers.setContentType(MediaType.APPLICATION_JSON); 165 | headers.set("X-Naver-Client-Id", clientId); 166 | headers.set("X-Naver-Client-Secret", clientSecret); 167 | 168 | HttpEntity entity = new HttpEntity<>("", headers); 169 | 170 | RestTemplate restTemplate = new RestTemplate(); 171 | 172 | LOGGER.info("[requestShortUrl] request by restTemplate"); 173 | ResponseEntity responseEntity = 174 | restTemplate.exchange(uri, HttpMethod.GET, entity, NaverUriDto.class); 175 | 176 | LOGGER.info("[requestShortUrl] request has been successfully complete."); 177 | 178 | return responseEntity; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/util/KakaoPortalApi.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | @Slf4j 6 | public class KakaoPortalApi implements PortalApi { 7 | public KakaoPortalApi() { 8 | log.info("[PortalApi] Kakao Portal API"); 9 | } 10 | 11 | @Override 12 | public String integrate() { 13 | return "Kakao integration succeeded"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/util/NaverPortalApi.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | @Slf4j 6 | public class NaverPortalApi implements PortalApi { 7 | public NaverPortalApi() { 8 | log.info("[PortalApi] Naver Portal API"); 9 | } 10 | 11 | @Override 12 | public String integrate() { 13 | return "Naver integration succeeded"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/util/PortalApi.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.util; 2 | 3 | public interface PortalApi { 4 | String integrate(); 5 | } 6 | -------------------------------------------------------------------------------- /mvc/src/main/java/studio/thinkground/aroundhub/mvc/util/PortalApiConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.util; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class PortalApiConfig { 9 | @Bean 10 | @ConditionalOnProperty(prefix = "around.hub", name = "portal", havingValue = "naver") 11 | public PortalApi naverPortalApi() { 12 | return new NaverPortalApi(); 13 | } 14 | 15 | @Bean 16 | @ConditionalOnProperty(prefix = "around.hub", name = "portal", havingValue = "kakao") 17 | public PortalApi kakaoPortalApi() { 18 | return new KakaoPortalApi(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mvc/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8090 3 | spring: 4 | mvc: 5 | pathmatch: 6 | matching-strategy: ant_path_matcher 7 | datasource: 8 | driverClassName: org.mariadb.jdbc.Driver 9 | url: jdbc:mariadb://localhost:3306/springboot 10 | username: ENC(LdsY1or+HixRvd/oLzeD0Q==) 11 | password: ENC(ocjxUpU0Aq6GM0WtxG9zhQEq7RlpTQey) 12 | ## JPA 설정 13 | # create : SessionFactory가 올라갈 때 테이블을 지우고 새로 만듬. (sql문을 별도로 만들어서 데이터를 넣는 용도로도 사용가능하다.) 14 | # create-drop : create와 동일하지만, SessionFactory가 내려가면 해당 테이블을 drop시킨다. 15 | # update : SessionFactory가 올라갈 때 Object를 검사하여 테이블을 alter 시킨다. 데이터는 유지됨. 16 | # validate : update처럼 Object를 검사하지만, 스키마는 아무것도 건드리지 않고, Object와 스키마의 정보가 다르다면 에러를 발생시킨다. 17 | # none : 사용하지 않음 18 | jpa: 19 | hibernate.ddl-auto: create 20 | show-sql: true 21 | properties: 22 | hibernate: 23 | format_sql: true 24 | data: 25 | redis: 26 | host: localhost 27 | port: 6379 28 | jasypt: # 프로퍼티 암호화 설정 29 | encryptor: 30 | bean: jasyptStringEncryptor 31 | around: 32 | hub: 33 | short: 34 | url: 35 | id: ENC(ZJtn8I8tSMNBtlUhuF9l4gPmSt5cEbvEaTDREJq31PQ=) 36 | secret: ENC(tWXd8DA35z/XD28NuFNrvNRY4xJTU+v0) 37 | ## ConditionalOnProperty Sample 38 | portal: naver 39 | 40 | --- 41 | spring: 42 | config: 43 | activate: 44 | on-profile: local 45 | --- 46 | spring: 47 | config: 48 | activate: 49 | on-profile: dev 50 | --- 51 | spring: 52 | config: 53 | activate: 54 | on-profile: prod 55 | --- 56 | spring: 57 | config: 58 | activate: 59 | on-profile: test 60 | -------------------------------------------------------------------------------- /mvc/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | DEBUG 17 | 18 | 19 | %green([%d{yyyy-MM-dd HH:mm:ss.SSS}]) %magenta([%-5level]) %highlight([%thread]) %cyan(%logger{30}) %yellow(%msg%n) 20 | 21 | 22 | 23 | 24 | 25 | 26 | DEBUG 27 | 28 | ${logdir}/${moduleId}/${logback}/debug_${type}.log 29 | true 30 | 31 | ${logdir}/${moduleId}/${logback}/debug_${type}.%d{yyyy-MM-dd}.gz 32 | 30 33 | 34 | 35 | [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n 36 | 37 | 38 | 39 | 40 | 41 | INFO 42 | 43 | ${logdir}/${moduleId}/${logback}/info_${type}.log 44 | true 45 | 46 | ${logdir}/${moduleId}/${logback}/info_${type}.%d{yyyy-MM-dd}.gz 47 | 30 48 | 49 | 50 | [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n 51 | 52 | 53 | 54 | 85 | 86 | 87 | 88 | 89 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | @SpringBootTest 8 | class ApplicationTests { 9 | 10 | @Test 11 | void contextLoads() {} 12 | } 13 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/config/JasyptTest.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.config; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | 5 | import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; 6 | import org.junit.jupiter.api.Test; 7 | 8 | @SpringBootTest 9 | public class JasyptTest { 10 | 11 | @Test 12 | void encryptTest() { 13 | String id = "ddd"; 14 | String password = "ddd"; 15 | 16 | System.out.println(jasyptEncoding(id)); 17 | System.out.println(jasyptEncoding(password)); 18 | } 19 | 20 | public String jasyptEncoding(String value) { 21 | String key = "around_hub_studio"; 22 | StandardPBEStringEncryptor pbeEnc = new StandardPBEStringEncryptor(); 23 | pbeEnc.setAlgorithm("PBEWithMD5AndDES"); 24 | pbeEnc.setPassword(key); 25 | return pbeEnc.encrypt(value); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/controller/ProductControllerTest.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 5 | import org.springframework.boot.test.mock.mockito.MockBean; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.test.web.servlet.MockMvc; 8 | 9 | import com.google.gson.Gson; 10 | import org.junit.jupiter.api.DisplayName; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import static org.mockito.BDDMockito.given; 14 | import static org.mockito.Mockito.verify; 15 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 16 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 17 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 18 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 20 | 21 | import studio.thinkground.aroundhub.mvc.data.dto.ProductDto; 22 | import studio.thinkground.aroundhub.mvc.service.ProductService; 23 | 24 | @WebMvcTest(ProductController.class) 25 | public class ProductControllerTest { 26 | 27 | @Autowired private MockMvc mockMvc; 28 | @MockBean ProductService productService; 29 | 30 | // http://localhost:8080/api/v1/product-api/product/{productId} 31 | @Test 32 | @DisplayName("Product 데이터 가져오기 테스트") 33 | void getProductTest() throws Exception { 34 | 35 | // given : Mock 객체가 특정 상황에서 해야하는 행위를 정의하는 메소드 36 | given(productService.getProduct("12315")) 37 | .willReturn(new ProductDto("15871", "pen", 5000, 2000)); 38 | 39 | String productId = "12315"; 40 | 41 | // andExpect : 기대하는 값이 나왔는지 체크해볼 수 있는 메소드 42 | mockMvc 43 | .perform(get("/api/v1/product-api/product/" + productId)) 44 | .andExpect(status().isOk()) 45 | .andExpect( 46 | jsonPath("$.productId").exists()) // json path의 depth가 깊어지면 .을 추가하여 탐색할 수 있음 (ex : 47 | // $.productId.productIdName) 48 | .andExpect(jsonPath("$.productName").exists()) 49 | .andExpect(jsonPath("$.productPrice").exists()) 50 | .andExpect(jsonPath("$.productStock").exists()) 51 | .andDo(print()); 52 | 53 | // verify : 해당 객체의 메소드가 실행되었는지 체크해줌 54 | verify(productService).getProduct("12315"); 55 | } 56 | 57 | // http://localhost:8080/api/v1/product-api/product 58 | @Test 59 | @DisplayName("Product 데이터 생성 테스트") 60 | void createProductTest() throws Exception { 61 | // Mock 객체에서 특정 메소드가 실행되는 경우 실제 Return을 줄 수 없기 때문에 아래와 같이 가정 사항을 만들어줌 62 | given(productService.saveProduct("15871", "pen", 5000, 2000)) 63 | .willReturn(new ProductDto("15871", "pen", 5000, 2000)); 64 | 65 | ProductDto productDto = 66 | ProductDto.builder() 67 | .productId("15871") 68 | .productName("pen") 69 | .productPrice(5000) 70 | .productStock(2000) 71 | .build(); 72 | Gson gson = new Gson(); 73 | String content = gson.toJson(productDto); 74 | 75 | // 아래 코드로 json 형태 변경 작업을 대체할 수 있음 76 | // String json = new ObjectMapper().writeValueAsString(productDto); 77 | 78 | mockMvc 79 | .perform( 80 | post("/api/v1/product-api/product") 81 | .content(content) 82 | .contentType(MediaType.APPLICATION_JSON)) 83 | .andExpect(status().isOk()) 84 | .andExpect(jsonPath("$.productId").exists()) 85 | .andExpect(jsonPath("$.productName").exists()) 86 | .andExpect(jsonPath("$.productPrice").exists()) 87 | .andExpect(jsonPath("$.productStock").exists()) 88 | .andDo(print()); 89 | 90 | verify(productService).saveProduct("15871", "pen", 5000, 2000); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/impl/ProductServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.test.mock.mockito.MockBean; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.test.context.junit.jupiter.SpringExtension; 7 | 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.mockito.Mockito; 12 | 13 | import static org.mockito.Mockito.verify; 14 | 15 | import studio.thinkground.aroundhub.mvc.data.dto.ProductDto; 16 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 17 | import studio.thinkground.aroundhub.mvc.data.handler.impl.ProductDataHandlerImpl; 18 | import studio.thinkground.aroundhub.mvc.service.impl.ProductServiceImpl; 19 | 20 | // @SpringBootTest(classes = {ProductDataHandlerImpl.class, ProductServiceImpl.class}) 21 | @ExtendWith(SpringExtension.class) 22 | @Import({ProductDataHandlerImpl.class, ProductServiceImpl.class}) 23 | public class ProductServiceImplTest { 24 | 25 | @MockBean ProductDataHandlerImpl productDataHandler; 26 | 27 | @Autowired ProductServiceImpl productService; 28 | 29 | @Test 30 | public void getProductTest() { 31 | // given 32 | Mockito.when(productDataHandler.getProductEntity("123")) 33 | .thenReturn(new Product("123", "pen", 2000, 3000)); 34 | 35 | ProductDto productDto = productService.getProduct("123"); 36 | 37 | Assertions.assertEquals(productDto.getProductId(), "123"); 38 | Assertions.assertEquals(productDto.getProductName(), "pen"); 39 | Assertions.assertEquals(productDto.getProductPrice(), 2000); 40 | Assertions.assertEquals(productDto.getProductStock(), 3000); 41 | 42 | verify(productDataHandler).getProductEntity("123"); 43 | } 44 | 45 | @Test 46 | public void saveProductTest() { 47 | // given 48 | Mockito.when(productDataHandler.saveProductEntity("123", "pen", 2000, 3000)) 49 | .thenReturn(new Product("123", "pen", 2000, 3000)); 50 | 51 | ProductDto productDto = productService.saveProduct("123", "pen", 2000, 3000); 52 | 53 | Assertions.assertEquals(productDto.getProductId(), "123"); 54 | Assertions.assertEquals(productDto.getProductName(), "pen"); 55 | Assertions.assertEquals(productDto.getProductPrice(), 2000); 56 | Assertions.assertEquals(productDto.getProductStock(), 3000); 57 | 58 | verify(productDataHandler).saveProductEntity("123", "pen", 2000, 3000); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/repository/DevProductRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.repository; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | import org.springframework.test.context.ActiveProfiles; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 10 | import studio.thinkground.aroundhub.mvc.data.repository.ProductRepository; 11 | 12 | /** 13 | * PackageName : studio.thinkground.aroundhub.data.repository FileName : DevProductRepositoryTest 14 | * Author : Flature Date : 2022-05-11 Description : 15 | */ 16 | @SpringBootTest 17 | @ActiveProfiles("dev") 18 | public class DevProductRepositoryTest { 19 | 20 | @Autowired ProductRepository productRepository; 21 | 22 | @Test 23 | void devTest() { 24 | Product product = 25 | Product.builder().id("testProduct").name("testP").price(1000).stock(500).build(); 26 | 27 | productRepository.save(product); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/repository/LocalProductRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.repository; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | import org.springframework.test.context.ActiveProfiles; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 10 | import studio.thinkground.aroundhub.mvc.data.repository.ProductRepository; 11 | 12 | /** 13 | * PackageName : studio.thinkground.aroundhub.data.repository FileName : LocalProductRepositoryTest 14 | * Author : Flature Date : 2022-05-11 Description : 15 | */ 16 | @SpringBootTest 17 | @ActiveProfiles("local") 18 | public class LocalProductRepositoryTest { 19 | 20 | @Autowired ProductRepository productRepository; 21 | 22 | @Test 23 | void devTest() { 24 | Product product = 25 | Product.builder().id("testProduct").name("testP").price(1000).stock(500).build(); 26 | 27 | productRepository.save(product); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/repository/ProductRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.repository; 2 | 3 | import java.util.List; 4 | 5 | import jakarta.transaction.Transactional; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.data.domain.PageRequest; 10 | import org.springframework.data.domain.Sort; 11 | import org.springframework.data.domain.Sort.Order; 12 | 13 | import org.assertj.core.api.Assertions; 14 | import org.junit.jupiter.api.BeforeEach; 15 | import org.junit.jupiter.api.Test; 16 | 17 | import studio.thinkground.aroundhub.mvc.data.entity.Product; 18 | import studio.thinkground.aroundhub.mvc.data.repository.ProductRepository; 19 | 20 | @SpringBootTest 21 | class ProductRepositoryTest { 22 | 23 | @Autowired ProductRepository productRepository; 24 | 25 | private Product getProduct(String id, int nameNumber, int price, int stock) { 26 | return new Product(id, "상품" + nameNumber, price, stock); 27 | } 28 | 29 | @Test 30 | void findTest() { 31 | List foundAll = productRepository.findAll(); 32 | System.out.println("====↓↓ Test Data ↓↓===="); 33 | for (Product product : foundAll) { 34 | System.out.println(product.toString()); 35 | } 36 | System.out.println("====↑↑ Test Data ↑↑===="); 37 | 38 | List foundEntities = productRepository.findByName("상품4"); 39 | 40 | for (Product product : foundEntities) { 41 | System.out.println(product.toString()); 42 | } 43 | 44 | List queryEntities = productRepository.queryByName("상품4"); 45 | 46 | for (Product product : queryEntities) { 47 | System.out.println(product.toString()); 48 | } 49 | } 50 | 51 | @Test 52 | void existTest() { 53 | List foundAll = productRepository.findAll(); 54 | System.out.println("====↓↓ Test Data ↓↓===="); 55 | for (Product product : foundAll) { 56 | System.out.println(product.toString()); 57 | } 58 | System.out.println("====↑↑ Test Data ↑↑===="); 59 | 60 | System.out.println(productRepository.existsByName("상품4")); 61 | System.out.println(productRepository.existsByName("상품2")); 62 | } 63 | 64 | @Test 65 | void countTest() { 66 | List foundAll = productRepository.findAll(); 67 | System.out.println("====↓↓ Test Data ↓↓===="); 68 | for (Product product : foundAll) { 69 | System.out.println(product.toString()); 70 | } 71 | System.out.println("====↑↑ Test Data ↑↑===="); 72 | 73 | System.out.println(productRepository.countByName("상품4")); 74 | } 75 | 76 | @Test 77 | @Transactional 78 | void deleteTest() { 79 | System.out.println("before : " + productRepository.count()); 80 | 81 | productRepository.deleteByName("상품1"); 82 | productRepository.removeByName("상품9"); 83 | 84 | System.out.println("After : " + productRepository.count()); 85 | } 86 | 87 | @Test 88 | void topTest() { 89 | productRepository.save(getProduct("109", 123, 1500, 5000)); 90 | productRepository.save(getProduct("101", 123, 2500, 5000)); 91 | productRepository.save(getProduct("102", 123, 3500, 5000)); 92 | productRepository.save(getProduct("103", 123, 4500, 5000)); 93 | productRepository.save(getProduct("104", 123, 1000, 5000)); 94 | productRepository.save(getProduct("105", 123, 2000, 5000)); 95 | productRepository.save(getProduct("106", 123, 3000, 5000)); 96 | productRepository.save(getProduct("107", 123, 4000, 5000)); 97 | 98 | List foundEntities = productRepository.findFirst5ByName("상품123"); 99 | for (Product product : foundEntities) { 100 | System.out.println(product.toString()); 101 | } 102 | 103 | List foundEntities2 = productRepository.findTop3ByName("상품123"); 104 | for (Product product : foundEntities2) { 105 | System.out.println(product.toString()); 106 | } 107 | } 108 | 109 | /* ↓↓ 조건자 키워드 테스트 ↓↓ */ 110 | 111 | @Test 112 | void isEqualsTest() { 113 | List foundAll = productRepository.findAll(); 114 | System.out.println("====↓↓ Test Data ↓↓===="); 115 | for (Product product : foundAll) { 116 | System.out.println(product.toString()); 117 | } 118 | System.out.println("====↑↑ Test Data ↑↑===="); 119 | 120 | System.out.println(productRepository.findByIdIs("1")); 121 | System.out.println(productRepository.findByIdEquals("1")); 122 | } 123 | 124 | @Test 125 | void notTest() { 126 | List foundAll = productRepository.findAll(); 127 | System.out.println("====↓↓ Test Data ↓↓===="); 128 | for (Product product : foundAll) { 129 | System.out.println(product.toString()); 130 | } 131 | System.out.println("====↑↑ Test Data ↑↑===="); 132 | 133 | List foundEntities = productRepository.findByIdNot("1"); 134 | for (Product product : foundEntities) { 135 | System.out.println(product); 136 | } 137 | // System.out.println(productRepository.findByProductIdNot("1")); 138 | System.out.println(productRepository.findByIdIsNot("1")); 139 | } 140 | 141 | @Test 142 | void nullTest() { 143 | List foundAll = productRepository.findAll(); 144 | System.out.println("====↓↓ Test Data ↓↓===="); 145 | for (Product product : foundAll) { 146 | System.out.println(product.toString()); 147 | } 148 | System.out.println("====↑↑ Test Data ↑↑===="); 149 | 150 | System.out.println(productRepository.findByStockIsNull()); 151 | System.out.println(productRepository.findByStockIsNotNull()); 152 | } 153 | 154 | @Test 155 | void andTest() { 156 | List foundAll = productRepository.findAll(); 157 | System.out.println("====↓↓ Test Data ↓↓===="); 158 | for (Product product : foundAll) { 159 | System.out.println(product.toString()); 160 | } 161 | System.out.println("====↑↑ Test Data ↑↑===="); 162 | 163 | System.out.println(productRepository.findTopByIdAndName("1", "상품1")); 164 | } 165 | 166 | @Test 167 | void greaterTest() { 168 | List foundAll = productRepository.findAll(); 169 | System.out.println("====↓↓ Test Data ↓↓===="); 170 | for (Product product : foundAll) { 171 | System.out.println(product.toString()); 172 | } 173 | System.out.println("====↑↑ Test Data ↑↑===="); 174 | 175 | List productEntities = productRepository.findByPriceGreaterThan(5000); 176 | 177 | for (Product product : productEntities) { 178 | System.out.println(product); 179 | } 180 | } 181 | 182 | @Test 183 | void containTest() { 184 | List foundAll = productRepository.findAll(); 185 | System.out.println("====↓↓ Test Data ↓↓===="); 186 | for (Product product : foundAll) { 187 | System.out.println(product.toString()); 188 | } 189 | System.out.println("====↑↑ Test Data ↑↑===="); 190 | 191 | System.out.println(productRepository.findByNameContaining("상품1")); 192 | } 193 | 194 | /* 정렬과 페이징 */ 195 | @Test 196 | void orderByTest() { 197 | List foundAll = productRepository.findAll(); 198 | System.out.println("====↓↓ Test Data ↓↓===="); 199 | for (Product product : foundAll) { 200 | System.out.println(product.toString()); 201 | } 202 | System.out.println("====↑↑ Test Data ↑↑===="); 203 | 204 | List foundProducts = productRepository.findByNameContainingOrderByStockAsc("상품"); 205 | for (Product product : foundProducts) { 206 | System.out.println(product); 207 | } 208 | 209 | foundProducts = productRepository.findByNameContainingOrderByStockDesc("상품"); 210 | for (Product product : foundProducts) { 211 | System.out.println(product); 212 | } 213 | } 214 | 215 | @Test 216 | void multiOrderByTest() { 217 | List foundAll = productRepository.findAll(); 218 | System.out.println("====↓↓ Test Data ↓↓===="); 219 | for (Product product : foundAll) { 220 | System.out.println(product.toString()); 221 | } 222 | System.out.println("====↑↑ Test Data ↑↑===="); 223 | 224 | List foundProducts = 225 | productRepository.findByNameContainingOrderByPriceAscStockDesc("상품"); 226 | for (Product product : foundProducts) { 227 | System.out.println(product); 228 | } 229 | } 230 | 231 | @Test 232 | void orderByWithParameterTest() { 233 | List foundAll = productRepository.findAll(); 234 | System.out.println("====↓↓ Test Data ↓↓===="); 235 | for (Product product : foundAll) { 236 | System.out.println(product.toString()); 237 | } 238 | System.out.println("====↑↑ Test Data ↑↑===="); 239 | 240 | List foundProducts = 241 | productRepository.findByNameContaining("상품", Sort.by(Order.asc("price"))); 242 | for (Product product : foundProducts) { 243 | System.out.println(product); 244 | } 245 | 246 | foundProducts = 247 | productRepository.findByNameContaining( 248 | "상품", Sort.by(Order.asc("price"), Order.asc("stock"))); 249 | for (Product product : foundProducts) { 250 | System.out.println(product); 251 | } 252 | } 253 | 254 | @Test 255 | void pagingTest() { 256 | List foundAll = productRepository.findAll(); 257 | System.out.println("====↓↓ Test Data ↓↓===="); 258 | for (Product product : foundAll) { 259 | System.out.println(product.toString()); 260 | } 261 | System.out.println("====↑↑ Test Data ↑↑===="); 262 | 263 | List foundProducts = 264 | productRepository.findByPriceGreaterThan(200, PageRequest.of(0, 2)); 265 | for (Product product : foundProducts) { 266 | System.out.println(product); 267 | } 268 | 269 | foundProducts = productRepository.findByPriceGreaterThan(200, PageRequest.of(4, 2)); 270 | for (Product product : foundProducts) { 271 | System.out.println(product); 272 | } 273 | } 274 | 275 | @Test 276 | public void queryTest() { 277 | List foundAll = productRepository.findAll(); 278 | System.out.println("====↓↓ Test Data ↓↓===="); 279 | for (Product product : foundAll) { 280 | System.out.println(product.toString()); 281 | } 282 | System.out.println("====↑↑ Test Data ↑↑===="); 283 | 284 | List foundProducts = productRepository.findByPriceBasis(); 285 | for (Product product : foundProducts) { 286 | System.out.println(product); 287 | } 288 | } 289 | 290 | @Test 291 | public void nativeQueryTest() { 292 | List foundAll = productRepository.findAll(); 293 | System.out.println("====↓↓ Test Data ↓↓===="); 294 | for (Product product : foundAll) { 295 | System.out.println(product.toString()); 296 | } 297 | System.out.println("====↑↑ Test Data ↑↑===="); 298 | 299 | List foundProducts = productRepository.findByPriceBasisNativeQuery(); 300 | for (Product product : foundProducts) { 301 | System.out.println(product); 302 | } 303 | } 304 | 305 | @Test 306 | public void parameterQueryTest() { 307 | List foundAll = productRepository.findAll(); 308 | System.out.println("====↓↓ Test Data ↓↓===="); 309 | for (Product product : foundAll) { 310 | System.out.println(product.toString()); 311 | } 312 | System.out.println("====↑↑ Test Data ↑↑===="); 313 | 314 | List foundProducts = productRepository.findByPriceWithParameter(2000); 315 | for (Product product : foundProducts) { 316 | System.out.println(product); 317 | } 318 | } 319 | 320 | @Test 321 | public void parameterNamingQueryTest() { 322 | List foundAll = productRepository.findAll(); 323 | System.out.println("====↓↓ Test Data ↓↓===="); 324 | for (Product product : foundAll) { 325 | System.out.println(product.toString()); 326 | } 327 | System.out.println("====↑↑ Test Data ↑↑===="); 328 | 329 | List foundProducts = productRepository.findByPriceWithParameterNaming(2000); 330 | for (Product product : foundProducts) { 331 | System.out.println(product); 332 | } 333 | } 334 | 335 | @Test 336 | public void parameterNamingQueryTest2() { 337 | List foundAll = productRepository.findAll(); 338 | System.out.println("====↓↓ Test Data ↓↓===="); 339 | for (Product product : foundAll) { 340 | System.out.println(product.toString()); 341 | } 342 | System.out.println("====↑↑ Test Data ↑↑===="); 343 | 344 | List foundProducts = productRepository.findByPriceWithParameterNaming2(2000); 345 | for (Product product : foundProducts) { 346 | System.out.println(product); 347 | } 348 | } 349 | 350 | @Test 351 | public void nativeQueryPagingTest() { 352 | List foundAll = productRepository.findAll(); 353 | System.out.println("====↓↓ Test Data ↓↓===="); 354 | for (Product product : foundAll) { 355 | System.out.println(product.toString()); 356 | } 357 | System.out.println("====↑↑ Test Data ↑↑===="); 358 | 359 | List foundProducts = 360 | productRepository.findByPriceWithParameterPaging(2000, PageRequest.of(2, 2)); 361 | for (Product product : foundProducts) { 362 | System.out.println(product); 363 | } 364 | } 365 | 366 | @Test 367 | public void basicCRUDTest() { 368 | /* create */ 369 | // given 370 | Product product = 371 | Product.builder().id("testProduct").name("testP").price(1000).stock(500).build(); 372 | 373 | // when 374 | Product savedEntity = productRepository.save(product); 375 | 376 | // then 377 | Assertions.assertThat(savedEntity.getId()).isEqualTo(product.getId()); 378 | Assertions.assertThat(savedEntity.getName()).isEqualTo(product.getName()); 379 | Assertions.assertThat(savedEntity.getPrice()).isEqualTo(product.getPrice()); 380 | Assertions.assertThat(savedEntity.getStock()).isEqualTo(product.getStock()); 381 | 382 | /* read */ 383 | // when 384 | Product selectedEntity = 385 | productRepository.findById("testProduct").orElseThrow(RuntimeException::new); 386 | 387 | // then 388 | Assertions.assertThat(selectedEntity.getId()).isEqualTo(product.getId()); 389 | Assertions.assertThat(selectedEntity.getName()).isEqualTo(product.getName()); 390 | Assertions.assertThat(selectedEntity.getPrice()).isEqualTo(product.getPrice()); 391 | Assertions.assertThat(selectedEntity.getStock()).isEqualTo(product.getStock()); 392 | } 393 | 394 | @BeforeEach 395 | void GenerateData() { 396 | int count = 1; 397 | productRepository.save(getProduct(Integer.toString(count), count++, 2000, 3000)); 398 | productRepository.save(getProduct(Integer.toString(count), count++, 3000, 3000)); 399 | productRepository.save(getProduct(Integer.toString(--count), count = count + 2, 1500, 200)); 400 | productRepository.save(getProduct(Integer.toString(count), count++, 4000, 3000)); 401 | productRepository.save(getProduct(Integer.toString(count), count++, 10000, 1500)); 402 | productRepository.save(getProduct(Integer.toString(count), count++, 10000, 1000)); 403 | productRepository.save(getProduct(Integer.toString(count), count++, 500, 10000)); 404 | productRepository.save(getProduct(Integer.toString(count), count++, 8500, 3500)); 405 | productRepository.save(getProduct(Integer.toString(count), count++, 1000, 2000)); 406 | productRepository.save(getProduct(Integer.toString(count), count, 5100, 1700)); 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /mvc/src/test/java/studio/thinkground/aroundhub/mvc/test/TestLifeCycle.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.aroundhub.mvc.test; 2 | 3 | import org.junit.jupiter.api.AfterAll; 4 | import org.junit.jupiter.api.AfterEach; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Disabled; 8 | import org.junit.jupiter.api.DisplayName; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public class TestLifeCycle { 12 | 13 | @BeforeAll 14 | static void beforeAll() { 15 | System.out.println("## BeforeAll Annotation 호출 ##"); 16 | System.out.println(); 17 | } 18 | 19 | @AfterAll 20 | static void afterAll() { 21 | System.out.println("## afterAll Annotation 호출 ##"); 22 | System.out.println(); 23 | } 24 | 25 | @BeforeEach 26 | void beforeEach() { 27 | System.out.println("## beforeEach Annotation 호출 ##"); 28 | System.out.println(); 29 | } 30 | 31 | @AfterEach 32 | void afterEach() { 33 | System.out.println("## afterEach Annotation 호출 ##"); 34 | System.out.println(); 35 | } 36 | 37 | @Test 38 | void test1() { 39 | System.out.println("## test1 시작 ##"); 40 | System.out.println(); 41 | } 42 | 43 | @Test 44 | @DisplayName("Test Case 2!!!") 45 | void test2() { 46 | System.out.println("## test2 시작 ##"); 47 | System.out.println(); 48 | } 49 | 50 | @Test 51 | @Disabled 52 | // Disabled Annotation : 테스트를 실행하지 않게 설정하는 어노테이션 53 | void test3() { 54 | System.out.println("## test3 시작 ##"); 55 | System.out.println(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /reactive/build.gradle.kts: -------------------------------------------------------------------------------- 1 | group = "studio.thinkground.aroundhub.reactive" 2 | version = "1.0.0" 3 | java.sourceCompatibility = JavaVersion.VERSION_17 4 | 5 | spotless { 6 | format("yaml") { 7 | target("**.*.yaml", "**/*.yml") 8 | prettier().configFile("${rootDir}/.prettierrc") 9 | } 10 | java { 11 | removeUnusedImports() 12 | googleJavaFormat() 13 | importOrder( 14 | "java", 15 | "jakarta", 16 | "lombok", 17 | "org.springframework", 18 | "", 19 | "\\#", 20 | "studio.thinkground", 21 | "\\#studio.thinkground" 22 | ) 23 | indentWithTabs(2) 24 | indentWithSpaces(2) 25 | trimTrailingWhitespace() 26 | endWithNewline() 27 | } 28 | } 29 | 30 | repositories { 31 | mavenLocal() 32 | maven { 33 | url = uri("https://repo.maven.apache.org/maven2/") 34 | } 35 | } 36 | 37 | dependencies { 38 | implementation("org.springframework.boot:spring-boot-starter-webflux") 39 | testImplementation("org.springframework.boot:spring-boot-starter-test") 40 | } 41 | 42 | tasks.withType() { 43 | options.encoding = "UTF-8" 44 | } 45 | 46 | tasks.test { 47 | useJUnitPlatform() 48 | systemProperties["spring.profiles.active"] = "test" 49 | } -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/Application.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/basic/BasicController.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.basic; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestHeader; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import reactor.core.publisher.Mono; 14 | 15 | import studio.thinkground.reactive.user.User; 16 | 17 | @RestController 18 | @RequestMapping("/api/controller") 19 | public class BasicController { 20 | 21 | @GetMapping("/hello") 22 | public Mono hello() { 23 | return Mono.just("Hello, Around Hub Studio!"); 24 | } 25 | 26 | @GetMapping("/hello/{name}") 27 | public Mono hello(@PathVariable String name) { 28 | return Mono.just("Hello, " + name + "!"); 29 | } 30 | 31 | @GetMapping("/greet") 32 | public Mono greet(@RequestParam(defaultValue = "Guest") String name) { 33 | return Mono.just("Hello, " + name + "!"); 34 | } 35 | 36 | @GetMapping("/check-header") 37 | public Mono checkHeader( 38 | @RequestHeader(name = "X-Request-ID", required = false) String requestId) { 39 | if (requestId == null) { 40 | return Mono.just("X-Request-ID is null"); 41 | } 42 | return Mono.just("Request Id: " + requestId); 43 | } 44 | 45 | @PostMapping("/create") 46 | public Mono> create(@RequestBody Mono userMono) { 47 | return userMono.map(user -> ResponseEntity.ok("User created: " + user.getName())); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/basic/BasicRouter.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.basic; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.server.RouterFunction; 6 | import org.springframework.web.reactive.function.server.RouterFunctions; 7 | import org.springframework.web.reactive.function.server.ServerResponse; 8 | 9 | import studio.thinkground.reactive.user.User; 10 | 11 | @Configuration 12 | public class BasicRouter { 13 | 14 | @Bean 15 | public RouterFunction basicRoute() { 16 | return RouterFunctions.route() 17 | .GET( 18 | "/api/router/hello", 19 | request -> ServerResponse.ok().bodyValue("Hello, Around Hub Studio!")) 20 | .GET( 21 | "/api/router/hello/{name}", 22 | request -> { 23 | String name = request.pathVariable("name"); 24 | return ServerResponse.ok().bodyValue("Hello, " + name + "!"); 25 | }) 26 | .GET( 27 | "/api/router/greet", 28 | request -> { 29 | String name = request.queryParam("name").orElse("Guest"); 30 | return ServerResponse.ok().bodyValue("Hello, " + name + "!"); 31 | }) 32 | .GET( 33 | "/api/router/check-header", 34 | request -> { 35 | String requestId = request.headers().firstHeader("X-Request-Id"); 36 | String response = 37 | (requestId == null) ? "No Request Id found" : "Request Id: " + requestId; 38 | return ServerResponse.ok().bodyValue(response); 39 | }) 40 | .POST( 41 | "/api/router/create", 42 | request -> 43 | request 44 | .bodyToMono(User.class) 45 | .flatMap( 46 | user -> ServerResponse.ok().bodyValue("User Created: " + user.getName()))) 47 | .build(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/basic/MethodArgumentExample.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.basic; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.http.server.reactive.ServerHttpRequest; 10 | import org.springframework.http.server.reactive.ServerHttpResponse; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | import org.springframework.web.server.ServerWebExchange; 16 | 17 | import reactor.core.publisher.Mono; 18 | 19 | @Slf4j 20 | @RestController 21 | @RequestMapping("/argument") 22 | public class MethodArgumentExample { 23 | 24 | // ServerHttpRequest의 getBody()를 사용하여 요청 바디를 읽고 반환 25 | @PostMapping("/echo") 26 | public Mono echo(ServerHttpRequest request) { 27 | return request 28 | .getBody() 29 | .map( 30 | dataBuffer -> { 31 | byte[] bytes = new byte[dataBuffer.readableByteCount()]; 32 | dataBuffer.read(bytes); 33 | return new String(bytes, StandardCharsets.UTF_8); 34 | }) 35 | .collectList() 36 | .map(list -> String.join("", list)); 37 | } 38 | 39 | // ServerHttpResponse를 사용하여 직접 응답을 작성하고 JSON 반환 40 | @GetMapping("/custom-response") 41 | public Mono customResponse(ServerHttpResponse response) { 42 | response.setStatusCode(HttpStatus.ACCEPTED); 43 | response.getHeaders().setContentType(MediaType.APPLICATION_JSON); 44 | response.getHeaders().add("X-Custom-Header", "Custom-Header"); 45 | 46 | String json = "{\"message\": \"Hello, WebFlux!\"}"; 47 | return response.writeWith( 48 | Mono.just(response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8)))); 49 | } 50 | 51 | // ServerWebExchange를 사용하여 User-Agent 헤더 값을 읽고 응답 52 | @GetMapping("/user-agent") 53 | public Mono getUserAgent(ServerWebExchange exchange) { 54 | String userAgent = exchange.getRequest().getHeaders().getFirst("User-Agent"); 55 | return Mono.just("User-Agent: " + (userAgent != null ? userAgent : "Unknown")); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/common/config/ApplicationConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.common.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.reactive.config.EnableWebFlux; 5 | 6 | @Configuration 7 | @EnableWebFlux 8 | public class ApplicationConfig {} 9 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/user/User.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.user; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Getter 9 | @Builder 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class User { 13 | 14 | private Long id; 15 | 16 | private String name; 17 | 18 | private int age; 19 | } 20 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/user/UserHandler.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.user; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | 5 | import org.springframework.http.MediaType; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.reactive.function.server.ServerRequest; 8 | import org.springframework.web.reactive.function.server.ServerResponse; 9 | 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | 13 | @Component 14 | @RequiredArgsConstructor 15 | public class UserHandler { 16 | 17 | private final UserService userService; 18 | 19 | public Mono getAllUsers(ServerRequest request) { 20 | Flux users = userService.getAllUsers(); 21 | return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users, User.class); 22 | } 23 | 24 | public Mono getUserById(ServerRequest request) { 25 | String id = request.pathVariable("id"); 26 | return userService 27 | .getUserById(Long.parseLong(id)) 28 | .flatMap( 29 | user -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(user)) 30 | .switchIfEmpty(ServerResponse.notFound().build()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/user/UserRouterConfig.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.user; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.server.RouterFunction; 6 | import org.springframework.web.reactive.function.server.ServerResponse; 7 | 8 | import static org.springframework.web.reactive.function.server.RequestPredicates.GET; 9 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 10 | 11 | @Configuration 12 | public class UserRouterConfig { 13 | 14 | @Bean 15 | public RouterFunction userRoutes(UserHandler userHandler) { 16 | return route(GET("/users"), userHandler::getAllUsers) 17 | .andRoute(GET("/users/{id}"), userHandler::getUserById); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /reactive/src/main/java/studio/thinkground/reactive/user/UserService.java: -------------------------------------------------------------------------------- 1 | package studio.thinkground.reactive.user; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import lombok.RequiredArgsConstructor; 7 | 8 | import org.springframework.stereotype.Service; 9 | 10 | import reactor.core.publisher.Flux; 11 | import reactor.core.publisher.Mono; 12 | 13 | @Service 14 | @RequiredArgsConstructor 15 | public class UserService { 16 | 17 | private final Map users = 18 | new HashMap<>( 19 | Map.of( 20 | 1L, 21 | User.builder().id(1L).name("flature").age(20).build(), 22 | 2L, 23 | User.builder().id(2L).name("around").age(21).build(), 24 | 3L, 25 | User.builder().id(3L).name("hub").age(22).build(), 26 | 4L, 27 | User.builder().id(4L).name("studio").age(23).build())); 28 | 29 | public Flux getAllUsers() { 30 | return Flux.fromStream(users.values().stream()); 31 | } 32 | 33 | public Mono getUserById(Long id) { 34 | return Mono.just(users.get(id)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /reactive/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | logging: 5 | level: 6 | root: INFO 7 | -------------------------------------------------------------------------------- /reactive/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %green(%logger{36}) - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | UTC 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "around-hub-spring-boot" 2 | include("mvc") 3 | include("reactive") 4 | --------------------------------------------------------------------------------