diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..252cdf9
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+target
+build
+!build/libs/*.jar
+.gradle
+.git
+*.md
+*.env
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..8648833
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,8 @@
+FROM openjdk:17-jdk-slim
+
+# JAR 파일 복사
+COPY build/libs/*.jar app.jar
+
+ENTRYPOINT ["java", "-jar", "/app.jar"]
+
+EXPOSE 8080
diff --git a/MYREADME.md b/MYREADME.md
new file mode 100644
index 0000000..9788b47
--- /dev/null
+++ b/MYREADME.md
@@ -0,0 +1,94 @@
+## 구현내용
+
+### API 디자인
+- 버저닝 적용(현재 v1)
+
+---
+
+### API 응답값
+ - createErrorResponse() 메서드를 사용하여 모든 에러 응답을 통일
+ - GlobalExceptionHandler에서 예외를 전역적으로 처리하여 일관성 유지
+
+ #### 성공 응답
+ | 상태 코드 | 설명 |
+ |------------|--------------------------|
+ | `200 OK` | 주식 정보 정상 응답 |
+
+ #### 오류 응답
+ | 상태 코드 | 설명 |
+ |-----------------|----------------------------------------|
+ | `400 Bad Request` | 필수 파라미터(`companyCode`, `startDate`, `endDate`)가 누락된 경우 |
+ | `400 Bad Request` | API Key가 요청에 포함되지 않은 경우 |
+ | `403 Forbidden` | 제공된 API Key가 유효하지 않은 경우 |
+ | `404 Not Found` | 존재하지 않는 API 엔드포인트 요청 시 |
+
+---
+
+### 유효성 검사
+1) API 유효성 검사
+ - 헤더(x-api-key) 또는 쿼리 파라미터(apikey) 로 제공되지 않으면 400 Bad Request
+ - API Key 값이 올바르지 않으면 403 Forbidden
+2) 필수 파라미터 검증
+ - 누락된 필수 파라미터가 있다면 각각 다른 메시지로 400 Bad Request 반환
+3) 날짜 형식 검증
+ - startDate와 endDate는 @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)으로 yyyy-MM-dd 으로 변환되도록 처리
+ - 잘못된 날짜 형식이면 자동으로 400 Bad Request
+4) 존재하지않는 API 요청
+ - Spring Boot의 GlobalExceptionHandler에서 처리
+
+---
+
+### Custom Exception, log rotation
+application.properties(기본지원)과 logback-spring.xml 중 application.properties 선택
+이유 : 간단하게 설정 가능하며 다른 XML 설정이 불필요하였기 때문.
+but 세부적인 로그 설정이 필요하면 logback-spring.xml을 사용할 예정
+
+📌 **설정 내용**
+- **로그 파일 최대 크기**: 10MB 이상이면 자동으로 새로운 파일 생성
+- **로그 보관 기간**: 30일간 로그 유지 (이후 자동 삭제)
+- **전체 로그 저장 용량**: 1GB를 초과하면 오래된 로그부터 삭제
+- **로그 파일 저장 경로**: `logs/app.log`
+
+---
+
+### 응답형식
+사용자가 원하는 응답 포맷을 선택할 수 있도록 쿼리파라미터를 활용하여 자동 변환 지원
+
+- /api/v1/stocks?format=json → JSON 응답
+- /api/v1/stocks?format=xml → XML 응답
+- 별도 지정이 없으면 기본 JSON 응답
+
+#### 💣 트러블 슈팅 💣
+**[문제]**
+- 예외 발생 시 **JSON으로만 응답이 반환됨**
+- `/api/v1/stocks?format=xml` 요청 시에도 **XML 응답이 나오지 않음**
+- `GlobalExceptionHandler`에서 정의한 **커스텀 예외 처리(`ErrorResponseDTO`)가 무시됨**
+
+**[해결 방법]**
+- `application.properties`에서 **Spring Boot의 자동 예외 처리를 비활성화**
+ ```properties
+ spring.mvc.problemdetails.enabled=false
+ ```
+
+---
+
+### 배포
+- docker, dockerhub를 사용하였고 AWS ec2에 pull받아서 배포
+- 환경변수는 .env파일로 주입
+
+.env
+```
+DB_HOST=
+DB_PORT=
+DB_NAME=
+DB_USER=
+DB_PASSWORD=
+
+API_KEY=
+```
+도커 이미지 : ahnsojeong/stock-api:v3
+실행 명령어 : docker run -d -p 80:8080 --name stock-api --env-file .env ahnsojeong/stock-api:v3
+
+요청 주소 : http://43.201.95.193
+
+---
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..157741c
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,34 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '3.4.2'
+ id 'io.spring.dependency-management' version '1.1.7'
+}
+
+group = 'com.example'
+version = '0.0.1-SNAPSHOT'
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(17)
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-web' // REST API 개발
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // JPA ORM 기능
+ implementation 'org.mariadb.jdbc:mariadb-java-client' // MariaDB 드라이버
+ implementation 'org.projectlombok:lombok' // Getter, Setter 자동 생성
+// implementation 'io.github.cdimascio:dotenv-java:3.0.0' // .env 로드
+ annotationProcessor 'org.projectlombok:lombok'
+ implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.3' //XML을 위한 JAXB 라이브러리 추가
+ implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml' // XML 지원 추가
+ testImplementation 'org.springframework.boot:spring-boot-starter-test' // 테스트 지원
+}
+
+tasks.named('test') {
+ useJUnitPlatform()
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..a4b76b9
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e18bc25
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..f5feea6
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..9d21a21
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/logs/app.log b/logs/app.log
new file mode 100644
index 0000000..0a423c9
--- /dev/null
+++ b/logs/app.log
@@ -0,0 +1,351 @@
+2025-02-17T01:07:52.852+09:00 INFO 92900 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Starting StockApiApplication using Java 17.0.14 with PID 92900 (/Users/goorm/IdeaProjects/stockAPI/build/classes/java/main started by goorm in /Users/goorm/IdeaProjects/stockAPI)
+2025-02-17T01:07:52.855+09:00 INFO 92900 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : No active profile set, falling back to 1 default profile: "default"
+2025-02-17T01:07:53.176+09:00 INFO 92900 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2025-02-17T01:07:53.203+09:00 INFO 92900 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 22 ms. Found 2 JPA repository interfaces.
+2025-02-17T01:07:53.435+09:00 INFO 92900 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
+2025-02-17T01:07:53.442+09:00 INFO 92900 --- [stockAPI] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2025-02-17T01:07:53.442+09:00 INFO 92900 --- [stockAPI] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.34]
+2025-02-17T01:07:53.471+09:00 INFO 92900 --- [stockAPI] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2025-02-17T01:07:53.471+09:00 INFO 92900 --- [stockAPI] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 595 ms
+2025-02-17T01:07:53.548+09:00 INFO 92900 --- [stockAPI] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
+2025-02-17T01:07:53.597+09:00 INFO 92900 --- [stockAPI] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.5.Final
+2025-02-17T01:07:53.622+09:00 INFO 92900 --- [stockAPI] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
+2025-02-17T01:07:53.822+09:00 INFO 92900 --- [stockAPI] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
+2025-02-17T01:07:53.840+09:00 INFO 92900 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
+2025-02-17T01:07:54.856+09:00 WARN 92900 --- [stockAPI] [main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: null
+2025-02-17T01:07:54.857+09:00 ERROR 92900 --- [stockAPI] [main] o.h.engine.jdbc.spi.SqlExceptionHelper : Incorrect port value : ${DB_PORT}
+2025-02-17T01:07:54.858+09:00 WARN 92900 --- [stockAPI] [main] o.h.e.j.e.i.JdbcEnvironmentInitiator : HHH000342: Could not obtain connection to query metadata
+
+org.hibernate.exception.GenericJDBCException: unable to obtain isolated JDBC connection [Incorrect port value : ${DB_PORT}] [n/a]
+ at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:63) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:116) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:320) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:129) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:81) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.boot.model.relational.Database.(Database.java:45) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:226) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.(InFlightMetadataCollectorImpl.java:194) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:171) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1431) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1502) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) ~[spring-orm-6.2.2.jar:6.2.2]
+ at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:390) ~[spring-orm-6.2.2.jar:6.2.2]
+ at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:419) ~[spring-orm-6.2.2.jar:6.2.2]
+ at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:400) ~[spring-orm-6.2.2.jar:6.2.2]
+ at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:366) ~[spring-orm-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1859) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1808) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:307) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:970) ~[spring-context-6.2.2.jar:6.2.2]
+ at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) ~[spring-context-6.2.2.jar:6.2.2]
+ at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) ~[spring-boot-3.4.2.jar:3.4.2]
+ at com.example.stockapi.StockApiApplication.main(StockApiApplication.java:9) ~[main/:na]
+Caused by: java.sql.SQLException: Incorrect port value : ${DB_PORT}
+ at org.mariadb.jdbc.HostAddress.getPort(HostAddress.java:195) ~[mariadb-java-client-3.4.1.jar:na]
+ at org.mariadb.jdbc.HostAddress.parseSimpleHostAddress(HostAddress.java:173) ~[mariadb-java-client-3.4.1.jar:na]
+ at org.mariadb.jdbc.HostAddress.parse(HostAddress.java:141) ~[mariadb-java-client-3.4.1.jar:na]
+ at org.mariadb.jdbc.Configuration.parseInternal(Configuration.java:851) ~[mariadb-java-client-3.4.1.jar:na]
+ at org.mariadb.jdbc.Configuration.parse(Configuration.java:773) ~[mariadb-java-client-3.4.1.jar:na]
+ at org.mariadb.jdbc.Driver.connect(Driver.java:87) ~[mariadb-java-client-3.4.1.jar:na]
+ at org.mariadb.jdbc.Driver.connect(Driver.java:26) ~[mariadb-java-client-3.4.1.jar:na]
+ at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:137) ~[HikariCP-5.1.0.jar:na]
+ at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:360) ~[HikariCP-5.1.0.jar:na]
+ at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:202) ~[HikariCP-5.1.0.jar:na]
+ at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:461) ~[HikariCP-5.1.0.jar:na]
+ at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:550) ~[HikariCP-5.1.0.jar:na]
+ at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:98) ~[HikariCP-5.1.0.jar:na]
+ at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111) ~[HikariCP-5.1.0.jar:na]
+ at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:126) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:467) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:61) ~[hibernate-core-6.6.5.Final.jar:6.6.5.Final]
+ ... 35 common frames omitted
+
+2025-02-17T01:07:54.878+09:00 WARN 92900 --- [stockAPI] [main] org.hibernate.orm.deprecation : HHH90000025: MariaDBDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
+2025-02-17T01:07:54.886+09:00 INFO 92900 --- [stockAPI] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (null)']
+ Database driver: undefined/unknown
+ Database version: 10.4
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2025-02-17T01:07:55.353+09:00 INFO 92900 --- [stockAPI] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2025-02-17T01:07:55.355+09:00 INFO 92900 --- [stockAPI] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:07:55.576+09:00 WARN 92900 --- [stockAPI] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stockController': Injection of autowired dependencies failed
+2025-02-17T01:07:55.577+09:00 INFO 92900 --- [stockAPI] [main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:07:55.580+09:00 INFO 92900 --- [stockAPI] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
+2025-02-17T01:07:55.588+09:00 INFO 92900 --- [stockAPI] [main] .s.b.a.l.ConditionEvaluationReportLogger :
+
+Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
+2025-02-17T01:07:55.598+09:00 ERROR 92900 --- [stockAPI] [main] o.s.boot.SpringApplication : Application run failed
+
+org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stockController': Injection of autowired dependencies failed
+ at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:515) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1445) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:307) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1122) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1093) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1030) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987) ~[spring-context-6.2.2.jar:6.2.2]
+ at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) ~[spring-context-6.2.2.jar:6.2.2]
+ at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) ~[spring-boot-3.4.2.jar:3.4.2]
+ at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) ~[spring-boot-3.4.2.jar:3.4.2]
+ at com.example.stockapi.StockApiApplication.main(StockApiApplication.java:9) ~[main/:na]
+Caused by: org.springframework.util.PlaceholderResolutionException: Could not resolve placeholder 'API_KEY' in value "${API_KEY}" <-- "${api.key}"
+ at org.springframework.util.PlaceholderResolutionException.withValue(PlaceholderResolutionException.java:81) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.util.PlaceholderParser$ParsedValue.resolve(PlaceholderParser.java:416) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.util.PlaceholderParser.replacePlaceholders(PlaceholderParser.java:128) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:118) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:114) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:255) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:226) ~[spring-core-6.2.2.jar:6.2.2]
+ at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:201) ~[spring-context-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:963) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1541) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1519) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:785) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:768) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:146) ~[spring-beans-6.2.2.jar:6.2.2]
+ at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:509) ~[spring-beans-6.2.2.jar:6.2.2]
+ ... 19 common frames omitted
+
+2025-02-17T01:08:32.674+09:00 INFO 93364 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Starting StockApiApplication using Java 17.0.14 with PID 93364 (/Users/goorm/IdeaProjects/stockAPI/build/classes/java/main started by goorm in /Users/goorm/IdeaProjects/stockAPI)
+2025-02-17T01:08:32.676+09:00 INFO 93364 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : No active profile set, falling back to 1 default profile: "default"
+2025-02-17T01:08:32.961+09:00 INFO 93364 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2025-02-17T01:08:32.987+09:00 INFO 93364 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 21 ms. Found 2 JPA repository interfaces.
+2025-02-17T01:08:33.219+09:00 INFO 93364 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
+2025-02-17T01:08:33.228+09:00 INFO 93364 --- [stockAPI] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2025-02-17T01:08:33.228+09:00 INFO 93364 --- [stockAPI] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.34]
+2025-02-17T01:08:33.262+09:00 INFO 93364 --- [stockAPI] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2025-02-17T01:08:33.262+09:00 INFO 93364 --- [stockAPI] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 568 ms
+2025-02-17T01:08:33.350+09:00 INFO 93364 --- [stockAPI] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
+2025-02-17T01:08:33.382+09:00 INFO 93364 --- [stockAPI] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.5.Final
+2025-02-17T01:08:33.401+09:00 INFO 93364 --- [stockAPI] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
+2025-02-17T01:08:33.556+09:00 INFO 93364 --- [stockAPI] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
+2025-02-17T01:08:33.572+09:00 INFO 93364 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
+2025-02-17T01:08:33.749+09:00 INFO 93364 --- [stockAPI] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.mariadb.jdbc.Connection@236861da
+2025-02-17T01:08:33.751+09:00 INFO 93364 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
+2025-02-17T01:08:33.781+09:00 WARN 93364 --- [stockAPI] [main] org.hibernate.dialect.Dialect : HHH000511: The 8.0.41 version for [org.hibernate.dialect.MariaDBDialect] is no longer supported, hence certain features may not work properly. The minimum supported version is 10.4.0. Check the community dialects project for available legacy versions.
+2025-02-17T01:08:33.784+09:00 WARN 93364 --- [stockAPI] [main] org.hibernate.orm.deprecation : HHH90000025: MariaDBDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
+2025-02-17T01:08:33.809+09:00 INFO 93364 --- [stockAPI] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
+ Database driver: undefined/unknown
+ Database version: 8.0.41
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2025-02-17T01:08:34.265+09:00 INFO 93364 --- [stockAPI] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2025-02-17T01:08:34.267+09:00 INFO 93364 --- [stockAPI] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:08:34.453+09:00 WARN 93364 --- [stockAPI] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
+2025-02-17T01:08:34.648+09:00 INFO 93364 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
+2025-02-17T01:08:34.655+09:00 INFO 93364 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Started StockApiApplication in 2.171 seconds (process running for 2.415)
+2025-02-17T01:08:48.008+09:00 INFO 93364 --- [stockAPI] [http-nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2025-02-17T01:08:48.008+09:00 INFO 93364 --- [stockAPI] [http-nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2025-02-17T01:08:48.009+09:00 INFO 93364 --- [stockAPI] [http-nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
+2025-02-17T01:08:48.027+09:00 ERROR 93364 --- [stockAPI] [http-nio-8080-exec-2] c.e.s.exception.GlobalExceptionHandler : Unexpected Exception: No static resource api/v2/stocks.
+
+org.springframework.web.servlet.resource.NoResourceFoundException: No static resource api/v2/stocks.
+ at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.34.jar:6.0]
+ at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.34.jar:6.0]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
+
+2025-02-17T01:09:30.108+09:00 INFO 93364 --- [stockAPI] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
+2025-02-17T01:09:30.116+09:00 INFO 93364 --- [stockAPI] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
+2025-02-17T01:09:30.122+09:00 INFO 93364 --- [stockAPI] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:09:30.126+09:00 INFO 93364 --- [stockAPI] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
+2025-02-17T01:09:30.146+09:00 INFO 93364 --- [stockAPI] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
+2025-02-17T01:09:32.021+09:00 INFO 93978 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Starting StockApiApplication using Java 17.0.14 with PID 93978 (/Users/goorm/IdeaProjects/stockAPI/build/classes/java/main started by goorm in /Users/goorm/IdeaProjects/stockAPI)
+2025-02-17T01:09:32.022+09:00 INFO 93978 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : No active profile set, falling back to 1 default profile: "default"
+2025-02-17T01:09:32.360+09:00 INFO 93978 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2025-02-17T01:09:32.389+09:00 INFO 93978 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 25 ms. Found 2 JPA repository interfaces.
+2025-02-17T01:09:32.620+09:00 INFO 93978 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
+2025-02-17T01:09:32.626+09:00 INFO 93978 --- [stockAPI] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2025-02-17T01:09:32.626+09:00 INFO 93978 --- [stockAPI] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.34]
+2025-02-17T01:09:32.656+09:00 INFO 93978 --- [stockAPI] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2025-02-17T01:09:32.656+09:00 INFO 93978 --- [stockAPI] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 616 ms
+2025-02-17T01:09:32.752+09:00 INFO 93978 --- [stockAPI] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
+2025-02-17T01:09:32.784+09:00 INFO 93978 --- [stockAPI] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.5.Final
+2025-02-17T01:09:32.801+09:00 INFO 93978 --- [stockAPI] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
+2025-02-17T01:09:32.938+09:00 INFO 93978 --- [stockAPI] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
+2025-02-17T01:09:32.953+09:00 INFO 93978 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
+2025-02-17T01:09:33.102+09:00 INFO 93978 --- [stockAPI] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.mariadb.jdbc.Connection@11abd6c
+2025-02-17T01:09:33.104+09:00 INFO 93978 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
+2025-02-17T01:09:33.133+09:00 WARN 93978 --- [stockAPI] [main] org.hibernate.dialect.Dialect : HHH000511: The 8.0.41 version for [org.hibernate.dialect.MariaDBDialect] is no longer supported, hence certain features may not work properly. The minimum supported version is 10.4.0. Check the community dialects project for available legacy versions.
+2025-02-17T01:09:33.136+09:00 WARN 93978 --- [stockAPI] [main] org.hibernate.orm.deprecation : HHH90000025: MariaDBDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
+2025-02-17T01:09:33.160+09:00 INFO 93978 --- [stockAPI] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
+ Database driver: undefined/unknown
+ Database version: 8.0.41
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2025-02-17T01:09:33.595+09:00 INFO 93978 --- [stockAPI] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2025-02-17T01:09:33.596+09:00 INFO 93978 --- [stockAPI] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:09:33.773+09:00 WARN 93978 --- [stockAPI] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
+2025-02-17T01:09:33.967+09:00 INFO 93978 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
+2025-02-17T01:09:33.974+09:00 INFO 93978 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Started StockApiApplication in 2.217 seconds (process running for 2.509)
+2025-02-17T01:09:36.767+09:00 INFO 93978 --- [stockAPI] [http-nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2025-02-17T01:09:36.767+09:00 INFO 93978 --- [stockAPI] [http-nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2025-02-17T01:09:36.768+09:00 INFO 93978 --- [stockAPI] [http-nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
+2025-02-17T01:09:36.782+09:00 ERROR 93978 --- [stockAPI] [http-nio-8080-exec-2] c.e.s.exception.GlobalExceptionHandler : Unexpected Exception: No static resource api/v2/stocks.
+
+org.springframework.web.servlet.resource.NoResourceFoundException: No static resource api/v2/stocks.
+ at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.34.jar:6.0]
+ at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.2.2.jar:6.2.2]
+ at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.34.jar:6.0]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.2.jar:6.2.2]
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
+ at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
+
+2025-02-17T01:11:07.351+09:00 INFO 93978 --- [stockAPI] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
+2025-02-17T01:11:07.360+09:00 INFO 93978 --- [stockAPI] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
+2025-02-17T01:11:07.365+09:00 INFO 93978 --- [stockAPI] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:11:07.369+09:00 INFO 93978 --- [stockAPI] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
+2025-02-17T01:11:07.387+09:00 INFO 93978 --- [stockAPI] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
+2025-02-17T01:11:08.933+09:00 INFO 94986 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Starting StockApiApplication using Java 17.0.14 with PID 94986 (/Users/goorm/IdeaProjects/stockAPI/build/classes/java/main started by goorm in /Users/goorm/IdeaProjects/stockAPI)
+2025-02-17T01:11:08.935+09:00 INFO 94986 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : No active profile set, falling back to 1 default profile: "default"
+2025-02-17T01:11:09.257+09:00 INFO 94986 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2025-02-17T01:11:09.283+09:00 INFO 94986 --- [stockAPI] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 21 ms. Found 2 JPA repository interfaces.
+2025-02-17T01:11:09.531+09:00 INFO 94986 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
+2025-02-17T01:11:09.549+09:00 INFO 94986 --- [stockAPI] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2025-02-17T01:11:09.549+09:00 INFO 94986 --- [stockAPI] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.34]
+2025-02-17T01:11:09.574+09:00 INFO 94986 --- [stockAPI] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2025-02-17T01:11:09.574+09:00 INFO 94986 --- [stockAPI] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 616 ms
+2025-02-17T01:11:09.649+09:00 INFO 94986 --- [stockAPI] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
+2025-02-17T01:11:09.676+09:00 INFO 94986 --- [stockAPI] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.5.Final
+2025-02-17T01:11:09.691+09:00 INFO 94986 --- [stockAPI] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled
+2025-02-17T01:11:09.840+09:00 INFO 94986 --- [stockAPI] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
+2025-02-17T01:11:09.863+09:00 INFO 94986 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
+2025-02-17T01:11:10.017+09:00 INFO 94986 --- [stockAPI] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.mariadb.jdbc.Connection@77ce88c4
+2025-02-17T01:11:10.018+09:00 INFO 94986 --- [stockAPI] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
+2025-02-17T01:11:10.044+09:00 WARN 94986 --- [stockAPI] [main] org.hibernate.dialect.Dialect : HHH000511: The 8.0.41 version for [org.hibernate.dialect.MariaDBDialect] is no longer supported, hence certain features may not work properly. The minimum supported version is 10.4.0. Check the community dialects project for available legacy versions.
+2025-02-17T01:11:10.048+09:00 WARN 94986 --- [stockAPI] [main] org.hibernate.orm.deprecation : HHH90000025: MariaDBDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
+2025-02-17T01:11:10.072+09:00 INFO 94986 --- [stockAPI] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
+ Database driver: undefined/unknown
+ Database version: 8.0.41
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2025-02-17T01:11:10.767+09:00 INFO 94986 --- [stockAPI] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2025-02-17T01:11:10.768+09:00 INFO 94986 --- [stockAPI] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:11:10.941+09:00 WARN 94986 --- [stockAPI] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
+2025-02-17T01:11:11.133+09:00 INFO 94986 --- [stockAPI] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
+2025-02-17T01:11:11.139+09:00 INFO 94986 --- [stockAPI] [main] c.example.stockapi.StockApiApplication : Started StockApiApplication in 2.413 seconds (process running for 2.736)
+2025-02-17T01:11:12.497+09:00 INFO 94986 --- [stockAPI] [http-nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2025-02-17T01:11:12.498+09:00 INFO 94986 --- [stockAPI] [http-nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2025-02-17T01:11:12.499+09:00 INFO 94986 --- [stockAPI] [http-nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
+2025-02-17T01:11:12.506+09:00 WARN 94986 --- [stockAPI] [http-nio-8080-exec-1] o.s.web.servlet.PageNotFound : No mapping for GET /api/v2/stocks
+2025-02-17T01:11:12.512+09:00 WARN 94986 --- [stockAPI] [http-nio-8080-exec-1] c.e.s.exception.GlobalExceptionHandler : API Not Found
+2025-02-17T01:11:20.864+09:00 WARN 94986 --- [stockAPI] [http-nio-8080-exec-3] o.s.web.servlet.PageNotFound : No mapping for GET /api/v2/stocks
+2025-02-17T01:11:20.866+09:00 WARN 94986 --- [stockAPI] [http-nio-8080-exec-3] c.e.s.exception.GlobalExceptionHandler : API Not Found
+2025-02-17T01:11:28.279+09:00 WARN 94986 --- [stockAPI] [http-nio-8080-exec-4] c.e.s.exception.GlobalExceptionHandler : Business Exception: API Key is required (either in header or query param).
+2025-02-17T01:12:45.677+09:00 WARN 94986 --- [stockAPI] [http-nio-8080-exec-10] c.e.s.exception.GlobalExceptionHandler : Invalid Parameter: Invalid date format. Please use 'yyyy-MM-dd'.
+2025-02-17T01:12:57.888+09:00 INFO 94986 --- [stockAPI] [SpringApplicationShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
+2025-02-17T01:12:57.894+09:00 INFO 94986 --- [stockAPI] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
+2025-02-17T01:12:57.897+09:00 INFO 94986 --- [stockAPI] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
+2025-02-17T01:12:57.899+09:00 INFO 94986 --- [stockAPI] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
+2025-02-17T01:12:57.918+09:00 INFO 94986 --- [stockAPI] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
diff --git a/logs/app.log.2025-02-16.0.gz b/logs/app.log.2025-02-16.0.gz
new file mode 100644
index 0000000..f3752da
Binary files /dev/null and b/logs/app.log.2025-02-16.0.gz differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..62b05ac
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'stockAPI'
diff --git a/src/main/java/com/example/stockapi/StockApiApplication.java b/src/main/java/com/example/stockapi/StockApiApplication.java
new file mode 100644
index 0000000..832c867
--- /dev/null
+++ b/src/main/java/com/example/stockapi/StockApiApplication.java
@@ -0,0 +1,18 @@
+package com.example.stockapi;
+
+//import io.github.cdimascio.dotenv.Dotenv;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class StockApiApplication {
+ public static void main(String[] args) {
+// // 환경 변수 로드
+// Dotenv dotenv = Dotenv.load();
+//
+// // 시스템 환경 변수로 설정
+// dotenv.entries().forEach(entry -> System.setProperty(entry.getKey(), entry.getValue()));
+
+ SpringApplication.run(StockApiApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/example/stockapi/controller/StockController.java b/src/main/java/com/example/stockapi/controller/StockController.java
new file mode 100644
index 0000000..7f46309
--- /dev/null
+++ b/src/main/java/com/example/stockapi/controller/StockController.java
@@ -0,0 +1,74 @@
+package com.example.stockapi.controller;
+
+import com.example.stockapi.dto.StockListResponseDTO;
+import com.example.stockapi.dto.StockResponseDTO;
+import com.example.stockapi.exception.BusinessException;
+import com.example.stockapi.service.StockService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.http.MediaType;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/v1/stocks")
+public class StockController {
+
+ private final StockService stockService;
+
+ @Value("${api.key}")
+ private String validApiKey;
+
+ public StockController(StockService stockService) {
+ this.stockService = stockService;
+ }
+
+ // JSON, XML 응답지원
+ @GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
+ public ResponseEntity> getStockData(
+ @RequestParam String companyCode,
+ @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
+ @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
+ @RequestHeader(value = "x-api-key", required = false) String headerApiKey,
+ @RequestParam(value = "apikey", required = false) String queryApiKey,
+ @RequestParam(value = "format", required = false, defaultValue = "json") String format
+ ) {
+ // API Key 검증
+ if (headerApiKey == null && queryApiKey == null) {
+ throw new BusinessException("API Key is required (either in header or query param).", HttpStatus.BAD_REQUEST);
+ }
+
+ String apiKey = (headerApiKey != null) ? headerApiKey : queryApiKey;
+ if (!validApiKey.equals(apiKey)) {
+ throw new BusinessException("Invalid API Key.", HttpStatus.FORBIDDEN);
+ }
+
+ // 필수 파라미터 검증
+ if (companyCode.isEmpty()) {
+ throw new BusinessException("Missing required parameter: companyCode.", HttpStatus.BAD_REQUEST);
+ }
+ if (startDate == null || endDate == null) {
+ throw new BusinessException("Missing required date parameters.", HttpStatus.BAD_REQUEST);
+ }
+
+ // 주식 정보 조회
+ List stocks = stockService.getStockData(companyCode, startDate, endDate);
+
+ // XML 또는 JSON 응답 처리
+ StockListResponseDTO response = new StockListResponseDTO(stocks);
+
+ HttpHeaders headers = new HttpHeaders();
+ if ("xml".equalsIgnoreCase(format)) {
+ headers.setContentType(MediaType.APPLICATION_XML);
+ return ResponseEntity.ok().headers(headers).body(response);
+ } else {
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ return ResponseEntity.ok().headers(headers).body(response);
+ }
+ }
+}
diff --git a/src/main/java/com/example/stockapi/dto/ErrorResponseDTO.java b/src/main/java/com/example/stockapi/dto/ErrorResponseDTO.java
new file mode 100644
index 0000000..3efb72c
--- /dev/null
+++ b/src/main/java/com/example/stockapi/dto/ErrorResponseDTO.java
@@ -0,0 +1,23 @@
+package com.example.stockapi.dto;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@XmlRootElement(name = "errorResponse") // XML 변환 지원
+@XmlAccessorType(XmlAccessType.FIELD) // JAXB 필드 접근
+public class ErrorResponseDTO {
+ @XmlElement
+ private String error;
+ @XmlElement
+ private String message;
+}
diff --git a/src/main/java/com/example/stockapi/dto/StockListResponseDTO.java b/src/main/java/com/example/stockapi/dto/StockListResponseDTO.java
new file mode 100644
index 0000000..86d88f3
--- /dev/null
+++ b/src/main/java/com/example/stockapi/dto/StockListResponseDTO.java
@@ -0,0 +1,24 @@
+package com.example.stockapi.dto;
+
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@XmlRootElement(name = "stocks") // XML 루트 요소 지정
+@XmlAccessorType(XmlAccessType.FIELD)
+public class StockListResponseDTO {
+
+ @XmlElement(name = "stock") // 개별 요소
+ private List stocks;
+}
diff --git a/src/main/java/com/example/stockapi/dto/StockResponseDTO.java b/src/main/java/com/example/stockapi/dto/StockResponseDTO.java
new file mode 100644
index 0000000..8add350
--- /dev/null
+++ b/src/main/java/com/example/stockapi/dto/StockResponseDTO.java
@@ -0,0 +1,40 @@
+package com.example.stockapi.dto;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@XmlRootElement(name = "stock") // XML 지원을 위해 추가
+@XmlAccessorType(XmlAccessType.FIELD) // JAXB 필드 접근
+public class StockResponseDTO {
+ @XmlElement
+ private String companyName;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
+ @XmlElement
+ private LocalDate tradeDate;
+
+ @XmlElement
+ private Float openPrice;
+ @XmlElement
+ private Float highPrice;
+ @XmlElement
+ private Float lowPrice;
+ @XmlElement
+ private Float closingPrice;
+ @XmlElement
+ private Float volume;
+}
diff --git a/src/main/java/com/example/stockapi/entity/Company.java b/src/main/java/com/example/stockapi/entity/Company.java
new file mode 100644
index 0000000..9bb9522
--- /dev/null
+++ b/src/main/java/com/example/stockapi/entity/Company.java
@@ -0,0 +1,19 @@
+package com.example.stockapi.entity;
+
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.Setter;
+
+@Entity
+@Getter
+@Setter
+@Table(name = "company")
+public class Company {
+ @Id
+ @Column(name = "company_code", length = 10, nullable = false)
+ private String companyCode;
+
+ @Column(name = "company_name", length = 100, nullable = false)
+ private String companyName;
+}
+
diff --git a/src/main/java/com/example/stockapi/entity/StockHistory.java b/src/main/java/com/example/stockapi/entity/StockHistory.java
new file mode 100644
index 0000000..c7b83a5
--- /dev/null
+++ b/src/main/java/com/example/stockapi/entity/StockHistory.java
@@ -0,0 +1,42 @@
+package com.example.stockapi.entity;
+
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+
+@Entity
+@Getter
+@Setter
+@Table(name = "stocks_history")
+@IdClass(StockHistoryId.class) // 복합 키 사용
+public class StockHistory {
+ @Id
+ @Column(name = "company_code", length = 10, nullable = false)
+ private String companyCode;
+
+ @Id
+ @Column(name = "trade_date", nullable = false)
+ private LocalDate tradeDate;
+
+ @Column(name = "open_price", nullable = false)
+ private Float openPrice;
+
+ @Column(name = "high_price", nullable = false)
+ private Float highPrice;
+
+ @Column(name = "low_price", nullable = false)
+ private Float lowPrice;
+
+ @Column(name = "close_price", nullable = false)
+ private Float closePrice;
+
+ @Column(name = "volume", nullable = false)
+ private Float volume;
+
+ @ManyToOne
+ @JoinColumn(name = "company_code", referencedColumnName = "company_code", insertable = false, updatable = false)
+ private Company company;
+}
+
diff --git a/src/main/java/com/example/stockapi/entity/StockHistoryId.java b/src/main/java/com/example/stockapi/entity/StockHistoryId.java
new file mode 100644
index 0000000..1cd8b21
--- /dev/null
+++ b/src/main/java/com/example/stockapi/entity/StockHistoryId.java
@@ -0,0 +1,16 @@
+package com.example.stockapi.entity;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+public class StockHistoryId implements Serializable {
+ private String companyCode;
+ private LocalDate tradeDate;
+}
+
diff --git a/src/main/java/com/example/stockapi/exception/BusinessException.java b/src/main/java/com/example/stockapi/exception/BusinessException.java
new file mode 100644
index 0000000..16da390
--- /dev/null
+++ b/src/main/java/com/example/stockapi/exception/BusinessException.java
@@ -0,0 +1,15 @@
+package com.example.stockapi.exception;
+
+import org.springframework.http.HttpStatus;
+import lombok.Getter;
+
+@Getter
+public class BusinessException extends RuntimeException {
+ private final HttpStatus status;
+
+ public BusinessException(String message, HttpStatus status) {
+ super(message);
+ this.status = status;
+ }
+}
+
diff --git a/src/main/java/com/example/stockapi/exception/GlobalExceptionHandler.java b/src/main/java/com/example/stockapi/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..19d2ec3
--- /dev/null
+++ b/src/main/java/com/example/stockapi/exception/GlobalExceptionHandler.java
@@ -0,0 +1,75 @@
+package com.example.stockapi.exception;
+
+import com.example.stockapi.dto.ErrorResponseDTO;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+ private ResponseEntity createErrorResponse(String error, String message, HttpStatus status, HttpServletRequest request) {
+ String format = request.getParameter("format");
+ String acceptHeader = request.getHeader(HttpHeaders.ACCEPT);
+
+ MediaType responseType = MediaType.APPLICATION_JSON;
+ if ("xml".equalsIgnoreCase(format) || (acceptHeader != null && acceptHeader.contains("xml"))) {
+ responseType = MediaType.APPLICATION_XML;
+ }
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(responseType);
+
+ return new ResponseEntity<>(new ErrorResponseDTO(error, message), headers, status);
+ }
+
+ // 비즈니스 예외 처리 (400, 403)
+ @ExceptionHandler(BusinessException.class)
+ public ResponseEntity handleBusinessException(BusinessException ex, HttpServletRequest request) {
+ log.warn("Business Exception: {}", ex.getMessage());
+ return createErrorResponse("Business Error", ex.getMessage(), ex.getStatus(), request);
+ }
+
+ // 시스템 예외 처리 (500)
+ @ExceptionHandler(SystemException.class)
+ public ResponseEntity handleSystemException(SystemException ex, HttpServletRequest request) {
+ log.error("System Exception: {}", ex.getMessage(), ex);
+ return createErrorResponse("System Error", ex.getMessage(), ex.getStatus(), request);
+ }
+
+ // 잘못된 요청 파라미터 (400 Bad Request) - 날짜 형식 오류 포함
+ @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+ public ResponseEntity handleTypeMismatchException(MethodArgumentTypeMismatchException ex, HttpServletRequest request) {
+ String message = "Invalid request parameter: " + ex.getName();
+
+ if (ex.getRequiredType() != null && ex.getRequiredType().equals(java.time.LocalDate.class)) {
+ message = "Invalid date format. Please use 'yyyy-MM-dd'.";
+ }
+
+ log.warn("Invalid Parameter: {}", message);
+ return createErrorResponse("Bad Request", message, HttpStatus.BAD_REQUEST, request);
+ }
+
+ // 존재하지 않는 API 요청 (404 Not Found)
+ @ExceptionHandler(org.springframework.web.servlet.NoHandlerFoundException.class)
+ public ResponseEntity handleNotFoundException(HttpServletRequest request) {
+ log.warn("API Not Found");
+ return createErrorResponse("API Not Found", "API does not exist..", HttpStatus.NOT_FOUND, request);
+ }
+
+ // 기타 예외 처리 (500 Internal Server Error)
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleGeneralException(Exception ex, HttpServletRequest request) {
+ log.error("Unexpected Exception: {}", ex.getMessage(), ex);
+ return createErrorResponse("Internal Server Error", "Unexpected error occurred.", HttpStatus.INTERNAL_SERVER_ERROR, request);
+ }
+}
diff --git a/src/main/java/com/example/stockapi/exception/SystemException.java b/src/main/java/com/example/stockapi/exception/SystemException.java
new file mode 100644
index 0000000..7a4ed85
--- /dev/null
+++ b/src/main/java/com/example/stockapi/exception/SystemException.java
@@ -0,0 +1,14 @@
+package com.example.stockapi.exception;
+
+import org.springframework.http.HttpStatus;
+import lombok.Getter;
+
+@Getter
+public class SystemException extends RuntimeException {
+ private final HttpStatus status;
+
+ public SystemException(String message, HttpStatus status) {
+ super(message);
+ this.status = status;
+ }
+}
diff --git a/src/main/java/com/example/stockapi/repository/CompanyRepository.java b/src/main/java/com/example/stockapi/repository/CompanyRepository.java
new file mode 100644
index 0000000..9a1c3aa
--- /dev/null
+++ b/src/main/java/com/example/stockapi/repository/CompanyRepository.java
@@ -0,0 +1,10 @@
+package com.example.stockapi.repository;
+
+import com.example.stockapi.entity.Company;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface CompanyRepository extends JpaRepository {
+ Company findByCompanyCode(String companyCode);
+}
+
+
diff --git a/src/main/java/com/example/stockapi/repository/StockHistoryRepository.java b/src/main/java/com/example/stockapi/repository/StockHistoryRepository.java
new file mode 100644
index 0000000..49fb2aa
--- /dev/null
+++ b/src/main/java/com/example/stockapi/repository/StockHistoryRepository.java
@@ -0,0 +1,13 @@
+package com.example.stockapi.repository;
+
+import com.example.stockapi.entity.StockHistory;
+import com.example.stockapi.entity.StockHistoryId;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public interface StockHistoryRepository extends JpaRepository {
+ List findByCompanyCodeAndTradeDateBetween(String companyCode, LocalDate startDate, LocalDate endDate);
+}
+
diff --git a/src/main/java/com/example/stockapi/service/StockService.java b/src/main/java/com/example/stockapi/service/StockService.java
new file mode 100644
index 0000000..bde0275
--- /dev/null
+++ b/src/main/java/com/example/stockapi/service/StockService.java
@@ -0,0 +1,45 @@
+package com.example.stockapi.service;
+
+import com.example.stockapi.dto.StockResponseDTO;
+import com.example.stockapi.entity.Company;
+import com.example.stockapi.entity.StockHistory;
+import com.example.stockapi.repository.CompanyRepository;
+import com.example.stockapi.repository.StockHistoryRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class StockService {
+ private final StockHistoryRepository stockHistoryRepository;
+ private final CompanyRepository companyRepository;
+
+ public StockService(StockHistoryRepository stockHistoryRepository, CompanyRepository companyRepository) {
+ this.stockHistoryRepository = stockHistoryRepository;
+ this.companyRepository = companyRepository;
+ }
+
+ @Transactional(readOnly = true)
+ public List getStockData(String companyCode, LocalDate startDate, LocalDate endDate) {
+ Company company = companyRepository.findByCompanyCode(companyCode);
+ if (company == null) {
+ throw new IllegalArgumentException("Invalid company code");
+ }
+
+ return stockHistoryRepository.findByCompanyCodeAndTradeDateBetween(companyCode, startDate, endDate)
+ .stream()
+ .map(stock -> new StockResponseDTO(
+ company.getCompanyName(),
+ stock.getTradeDate(),
+ stock.getOpenPrice(),
+ stock.getHighPrice(),
+ stock.getLowPrice(),
+ stock.getClosePrice(),
+ stock.getVolume()
+ ))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..c6f66dd
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,30 @@
+spring.application.name=stockAPI
+
+server.port=8080
+api.key=${API_KEY}
+
+spring.datasource.url=jdbc:mariadb://${DB_HOST}:${DB_PORT}/${DB_NAME}
+spring.datasource.username=${DB_USER}
+spring.datasource.password=${DB_PASSWORD}
+spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
+
+spring.jpa.database-platform=org.hibernate.dialect.MariaDBDialect
+# DB ?? ?? ??
+spring.datasource.hikari.maximum-pool-size=5
+spring.jpa.hibernate.ddl-auto=none
+
+logging.file.name=logs/app.log
+logging.logback.rollingpolicy.max-file-size=10MB
+logging.logback.rollingpolicy.max-history=30
+logging.logback.rollingpolicy.total-size-cap=1GB
+logging.level.root=INFO
+
+# ?? ?? ??? JSON?? ??
+spring.mvc.problemdetails.enabled=false
+spring.mvc.converters.preferred-json-mapper=jackson
+spring.jackson.serialization.indent_output=true
+spring.xml.enabled=true
+
+# ?? ??? ?? ????
+spring.web.resources.add-mappings=false
+
diff --git a/src/test/java/com/example/stockapi/StockApiApplicationTests.java b/src/test/java/com/example/stockapi/StockApiApplicationTests.java
new file mode 100644
index 0000000..7c8f794
--- /dev/null
+++ b/src/test/java/com/example/stockapi/StockApiApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.stockapi;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class StockApiApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}