Spring Data JPA로 DB에 데이터를 조회하는 과정에서 이슈 하나가 발생하였는데 어떤 이슈인지 원인과 해결 방법은 무엇인지 말씀드리겠습니다. 이슈 JPQL이 아닌 직접 SQL을 작성 후 데이터를 조회하는 과정에서 Enum 타입의 파라미터가 정상적으로 바인딩이 되지 않는 이슈였습니다. 현상 테스트코드는 간단합니다. Member 객체를 생성 후 DB에 저장하고 type으로 다시 조회해 오는 코드입니다. type으로 조회해 오는 코드는 다음과 같습니다. 이제 데이터를 조회해 보겠습니다. insert는 정상적으로 실행되었는데 select에서는 예외가 발생합니다. 원인은 NullPointerException인데 jdbcMapping 이라는 변수가 null이라 그런 것 같습니다. 왜 NullPointerE..
Spring Boot 3.0.4 환경에서 OAuth2-Client 라이브러리를 적용 후 소셜 로그인을 구현하면서 이슈 하나가 발생하였는데 어떤 이슈인지 문제 원인은 무엇이고 어떻게 해결해야 하는지 말씀드리겠습니다. 이슈 OAuth2-Client 라이브러리를 적용 후 Access Token을 조회하려면 application.yml 파일에 spring.security.oauth2.client.registration.[id].client-authentication-method 프로퍼티에 POST를 적어줘야 하는데 POST를 적어도 401 예외가 발생합니다. 원인 client-authentication-method 프로퍼티에 POST로 정의하면 해당 조건문이 false가 되어 Access Token 발급 API..
회사에서 소셜 로그인을 구현해야 할 업무가 생겼는데 마침 진행하고 있는 프로젝트의 Spring Boot 버전이 3.0.4여서 Spring Boot 3.x 버전에서 OAuth2 라이브러리를 이용하여 카카오 로그인을 구현하고 동작 원리를 살펴보겠습니다. 제가 정리한 내용을 순차적으로 진행하시면 문제없이 카카오 로그인을 구현하실 수 있습니다. Kakao Developers 설정 카카오 디벨로퍼 사이트에 접속하셔서 로그인하시고 우측상단에 보이는 '내 애플리케이션'을 클릭하고 애플리케이션을 생성합니다. 앱 설정 > 요약정보 페이지에 가시면 4가지의 앱 키가 있는데 REST API 키를 복사해 둡니다. 이 키가 서버에서 사용할 client-id 값이 됩니다. client-id 값은 밑에서 다시 설명하겠습니다. 앱 ..
Spring WebFlux로 API를 만드는 과정에서 이슈가 발생하였습니다. Flux 타입을 응답할 때 당연히 JSON Array로 직렬화되어서 응답하는 줄 알았는데 반드시 그런 건 아니었습니다. Flux 타입일 경우 JSON Array로 직렬화가 되지 않은 이슈를 겪었는데요. 코드로 함께 살펴보겠습니다. 예제코드 Flux와 Flux을 반환하는 두 개의 API가 있습니다. Flux를 반환하는 API에 요청을 보내면 Content-Type이 application/json, Body는 JSON Array로 응답합니다. 하지만 Flux을 반환하는 API에 요청을 보내면 Content-Type은 application/json이 아닌 text/plain으로 응답하고 Body 또한 JSON Array가 아니라 Ar..
얼마 전에 Amazon EventBridge Scheduler가 한국 리전에 출시되었습니다. Amazon EventBridge Scheduler는 Amazon EventBridge 규칙과 기능이 거의 흡사합니다. Amazon EventBridge 규칙은 이벤트 기반 애플리케이션을 구성할 수 있게끔 해주며 Lambda, SNS, SQS와 통합하여 애플리케이션을 보다 확장성 있게 설계할 수 있습니다. 만약 매일 오후 1시에 외부 API를 호출하여 조회한 데이터를 DB에 저장하는 기능을 개발해야 한다고 가정하면 다음처럼 구성할 수 있습니다. 1. Amazon EventBridge 규칙에 매일 오후1시에 이벤트가 트리거 되게끔 설정합니다. 2. 트리거 대상을 Lambda 함수로 설정해둡니다. 3. 매일 오후 1..
얼마 전에 AWS SES + Spring Boot를 이용해서 이메일 발송하는 예제를 작성했었는데요. 이번에는 파일을 첨부하여 발송하는 기능까지 알아보겠습니다. 이미 AWS SES 공식 문서 맨 하단에 Java로 작성된 예제코드가 작성돼있는데요. 핵심 부분만 잠시 살펴보겠습니다. AWS SES 공식문서 예제코드 HTML 삽입 미리보기할 수 없는 소스 예제코드이지만 코드가 너무 길고 가독성이 좋지 못한데요. Spring Mail 라이브러리에서는 이러한 코드를 더욱 쉽게 사용할 수 있게 제공하는데 좀 더 자세히 알아보겠습니다. 예제코드 HTML 삽입 미리보기할 수 없는 소스 spring-boot-starter-mail, aws ses 두 라이브러리를 추가해줍니다. AWS SES 공식 문서에서 제공된 예제코드는..
클라이언트에서 전달받은 날짜 포맷의 데이터를 @JsonFormat을 이용하여 ZonedDateTime 타입의 변수에 바인딩할 때주의할 점에 대해 알아보겠습니다. 일단 클라이언트에서 전달받은 날짜 포맷의 데이터를 ZoneDateTime 타입으로 받을 때 UTC로 변환되는 이슈가 있었는데요. 예제코드 (1)을 통해 함께 알아보겠습니다. 예제코드 (1) ZonedDateTime 타입의 필드를 가진 Product 클래스가 있고 이 필드 위에는 다음과 같은 어노테이션이 선언돼있습니다. 위 예제에서의 @JsonFormat 역할은 "yyyy-MM-dd HH:mm:ss" 패턴의 String 데이터를 ZonedDateTime 타입으로 역직렬화를 해주는 코드이며 Timezone은 Asia/Seoul로 세팅하는 코드입니다...
저번 글에서는 Spring Boot와 Spring Cloud AWS 라이브러리를 이용하여 AWS SQS에 대해 간단히 알아보았습니다. 이번에는 Spring Cloud AWS SQS에서 제공해주는 두 가지 내용들에 대해 주의할 점에 대해 알아보겠습니다. 살펴볼 내용은 다음과 같습니다. 1. MappingJackson2MessageConverter 2. ThreadPoolTaskExecutor (@SqsListener Multiple 구성 시 주의할 점) 1. MappingJackson2MessageConverter Spring Cloud AWS SQS의 코어 기능들은 Spring Cloud AWS Messaging 라이브러리에 포함되어 있으며 Spring Cloud AWS Messaging 라이브러리 내부..
Spring Boot와 AWS SQS를 활용한 간단한 애플리케이션을 만들고자 합니다. 제목에 Spring Boot 2.4.x 이상 환경이라고 말씀드린 이유는 여기에서 확인해보실 수 있습니다. 대략 내용을 말씀드리자면 Spring Cloud AWS 2.3 버전이 출시되었는데 Spring Boot 2.4.x 이상 버전과 함께 사용할 수 있다고 합니다. 기존에 Spring Cloud AWS 관련 라이브러리를 사용할 때 org.springframework.cloud.aws 라이브러리를 사용했지만 지금은 업데이트가 중단되었습니다. Spring Boot 2.4.x 이상 환경에서 호환되는 Spring Cloud AWS 2.3에서는 org.springframework.cloud.aws 패키지에 있던 모든 클래스들이 i..
클래스 및 메서드에 Proxy 기반으로 동작하는 어노테이션을 선언해주면 해당 클래스의 메서드에 부가 기능이 추가되어 실행됩니다. 대표적으로 @Transactional이 있습니다. 이번 글에서는 Proxy 기반으로 동작하는 어노테이션을 AspectJ 모듈과 함께 사용할 경우 주의할 점에 대해 알아보겠습니다. 예제코드를 함께 살펴보겠습니다. 예제코드 위 코드는 DB에서 데이터를 조회한 후 JPA Dirty Checking으로 Entity의 상태를 변경하는 단순한 코드입니다. update 쿼리가 정상적으로 실행된 걸 확인할 수 있습니다. 이 쿼리가 실행되는 이유는 JPA의 영속성 컨텍스트의 스코프는 기본적으로 @Transactional이 선언된 메서드가 호출되어 종료될 때까지 유효합니다. 해당 Entity가 ..
Spring Configuration을 구성할 때 @Configuration 클래스 내부의 메서드에다가 @Bean을 선언하여 구성합니다. 만일 동일한 타입의 @Bean이 여러 개이고 환경별로 다르게 동작하게끔 구성하기 위해서는 @Profile을 사용해 처리할 수 있습니다. 그런데 이 @Profile을 사용할 때 주의해야 할 점이 있는데요. 예제코드와 함께 살펴보겠습니다. 예제코드 위 코드는 AWS SES를 이용하기 위해 AmazonSimpleEmailService 타입의 Bean을 생성하는 코드입니다. local 환경에서는 설정 파일에 있는 access-key, secret-key 정보로 credentials 정보를 생성하여 이용할 수 있도록, dev 환경은 EC2에 배포되니 IMDS를 이용하여 EC2에..
AWS SES를 이용하여 사용자에게 이메일을 발송할 때 발신자 정보는 기본적으로 발신자 이메일로 설정됩니다. 그런데 발신자 정보를 발신자 이메일이 아닌 다른 값으로 세팅해줘야 하는 상황이 있을 수 있는데요. 그 방법에 대해 예제코드로 알아보도록 하겠습니다. 예제코드 HTML 삽입 미리보기할 수 없는 소스 AWS SES SDK를 이용하여 사용자에게 이메일을 발송하는 예제코드입니다. HTML 삽입 미리보기할 수 없는 소스 이메일을 발송하는 예제 테스트 코드입니다. 이제 테스트 코드를 실행하여 이메일을 발송해보겠습니다. 정상적으로 발송되었지만 보낸 사람은 발신자 이메일 주소로 표기되었습니다. 이제 이 부분을 변경해보도록 하겠습니다. 발신자 정보 변경 (영문) HTML 삽입 미리보기할 수 없는 소스 발신자 정보..
ThreadLocal과 InheritableThreadLocal에 대해 많이 들어보신 분도 계시겠지만 생소하신 분도 계실 것 같습니다. 두 클래스는 Java 1.2에 등장한 클래스이며 ThreadLocal과 InheritableThreadLocal에 대해 한번 알아보겠습니다. ThreadLocal 쓰레드 로컬 변수를 제공하며 이 로컬 변수는 get 또는 set 메서드를 통해 액세스 하거나 변경할 수 있으며 쓰레드 마다 독립적으로 갖고있는 변수를 말합니다. ThreadLocal의 설명을 해석하자면 위와 같습니다. 즉, ThreadLocal에 할당된 변수는 각 쓰레드마다 고유하게 할당되므로 멀티쓰레드 간 쓰레드 세이프 하게 프로그램을 작성할 수 있습니다. 예제코드를 함께 살펴보겠습니다. ThreadLocal..
사용자에게 메일을 발송할 때 기존에는 Daum에서 제공하는 SMTP 서비스를 사용했었습니다. 근데 간헐적으로 메일발송이 되지 않거나 10~20분 후 발송되는 현상이 있어서 SMTP 서비스를 AWS SES로 바꾸기로 하였습니다. 그래서 이번 글에서는 AWS SES와 Spring Boot로 이메일 전송기능을 만드는 작업을 정리해보겠습니다. 위에서부터 순서대로 진행하시면 문제없이 만드실 수 있습니다. AWS SES 세팅 AWS 계정을 만들고 SES 서비스를 처음 이용하면 해당 계정은 샌드박스에 있습니다. 이 샌드박스에 있으면 다음과 같은 활동이 제한됩니다. - 자격증명된 이메일로만 메일을 보낼 수 있습니다. - 24시간 동안 최대 200개의 메세지를 보낼 수 있습니다. - 초당 최대 1개의 메세지를 보낼 수 ..
Java의 Functional Interface란 단 1개의 추상메서드를 가진 인터페이스를 얘기합니다. 이번 글에서는 Functional Interface에 대해 새롭게 알게 된 내용을 공유하고자 합니다. 예제 위 소스를 보시면 반환 타입이 int인 1개의 추상메서드가 있고 @FunctionalInterface가 선언되어 있습니다. @FunctionalInterface를 선언하면 컴파일러에게 이 인터페이스는 단 1개의 추상메서드만 허용하는 Functional Interface라는걸 알립니다. 만약에 추상메서드를 2개 이상 작성할 경우 위와 같은 컴파일 에러를 내뱉게 됩니다. 이번에는 num2() 라는 추상메서드를 지우고 또 다른 추상메서드를 추가해보도록 하겠습니다. 이번엔 아까처럼 컴파일 에러가 발생하지..
Spring Boot로 개발환경을 구성할 때 Gradle을 빌드도구로 많이 사용하는데요. 이번 글에는 build.gradle에 라이브러리를 동적으로 추가하는 방법에 대해 알아보겠습니다. build.gradle build.gradle의 일부입니다. Gradle로 build 할 때 property를 넘겨줄 수 있는데 profile이라는 property가 존재하지 않을 경우 local을 기본값으로 두고 profile이 local일 경우 spring-data-jpa 라이브러리를 추가하는 코드입니다. 로컬환경에서 build 할 때는 따로 property를 주입해줄 케이스는 없다보니 기본값으로 local을 적용하였습니다. 커맨드라인은 아래처럼 입력하시면 됩니다. gradle clean build -Pprofile=..
Spring 웹 애플리케이션에서 AWS SDK를 이용하여 AWS 리소스에 액세스하기 위해서는 accessKey와 secretKey로 AWS Credentials 자격증명을 관리하는 객체를 생성해서 액세스할 수 있습니다. 그런데 이러한 웹 애플리케이션이 EC2에 배포가 된다면 accessKey와 secretKey를 발급하지 않고도 IAM에 역할을 부여하고 인스턴스 메타데이터를 이용하여 액세스할 수 있는 방법도 있습니다. 그런데 인스턴스 메타데이터를 이용하여 AWS 리소스에 액세스할 경우 주의해야 할 점이 있는데요. 지금부터 천천히 알아보도록 하겠습니다. 애플리케이션 코드 HTML 삽입 미리보기할 수 없는 소스 위 코드는 인스턴스 메타데이터를 이용하여 EC2에 부여된 IAM 역할을 기반으로 credentia..
안녕하세요. 오랜만에 글을 작성하게 되었습니다. 방송통신대와 직장 때문에 여유가 없어서 글을 못올리고 있었는데 이번 주 일요일이 드디어 방송통신대 종강입니다. 다음 주부터는 시간적인 여유가 많이 생겨서 예전처럼 활발하게 활동할 수 있을 것 같습니다. 자격증 및 뱃지 제가 얼마전에 AWS Solutions Architect - Associate (SAA-C03) 자격증을 취득하였습니다. 위 사진은 자격증을 취득하게 되면 받을 수 있는 AWS SAA 뱃지입니다. 자격증을 취득하게된 이유 (1) 2023년 2월에 방송통신대를 졸업하며 학사학위를 취득합니다. 졸업요건은 130학점과 졸업논문을 작성해야 하는데 졸업논문 대신 자격증으로 대체할 수 있습니다. (2) 회사에서 Java, Spring Framework ..
Spring Boot에 starter-test 라이브러리를 추가하면 JUnit API를 이용하여 테스트 코드를 작성할 수 있습니다. 테스트 코드를 작성하고 검증할 때 검증하고자 하는 값이 실행환경에 따라 동적으로 변경된다면 그 실행환경에 맞게끔 설정을 해줘야 합니다. Spring에서는 ActiveProfilesResolver 라는 인터페이스를 제공해주는데 이 인터페이스를 활용하여 처리할 수 있습니다. 간단히 예제코드를 보면서 내용을 살펴보도록 하겠습니다. 테스트 환경 Spring Boot Gradle 테스트 코드 위 코드는 ActiveProfiles 라는 어노테이션을 통해 테스트 코드를 실행할 Spring Profile을 지정해주고 해당 Profile에 맞는 Property를 조회해오는 코드입니다. 결과..
현 회사에 JAVA 백엔드 개발자로 입사한 지 8개월차로 접어들었습니다. 입사 초반에는 백엔드 개발업무를 주로 하다가Amazon Web Service (AWS)도 다뤄볼 수 있는 기회를 얻게 되었습니다. 기존에는 제 개인계정으로 EC2, RDS, S3 등 간단하게 프리티어로 이용해본게 전부인데 실무에서 잘 할 수 있을지 걱정이 많았지만 일단 해보기로 했습니다. AWS 계정을 받고 처음 딱 접속을 해보니 저희 회사는 AWS의 많은 서비스를 이용하고 있었고 그 중에는 실질적으로 쓰이지 않고 리소스만 점유하고 있는 자원들도 굉장히 많았고 24시간 풀로 가동되지 않아도 될 서비스들도 24시간 풀로 서비스 되고있는 자원도 많았습니다. 그걸보고 느낀점은 사용하지 않는 자원, 또는 효율적이지 못한 자원을 제거하면서 ..
웹 애플리케이션 개발을 하다보면 피해갈 수 없는 문제 중 하나가 바로 타임존(Timezone) 이다. 데이터베이스를 통해 받아온 날짜형식의 데이터를 원하는 Timezone에 맞춰서 보여줘야 하는데 제대로 동작이 안되는 경우를 한번쯤은 겪어봤을 것이다. 지금부터 필자와 함께 어떻게 설정을 해줘야 하는지 코드를 통해 알아보자. 환경 Spring Boot 2.6.8 Java 17 (Timezone = Asia/Seoul) MySQL 8.0.27 (Timezone = UTC) MySQL Connector/J 8.0.29 예제코드 현재 Timezone이 UTC인 MySQL 서버를 띄웠고 Java 애플리케이션에서 JDBC API를 통해 Connection을 맺은 후 현재시간을 조회해오는 SQL을 작성 후 결과값을 ..
Spring으로 웹 애플리케이션 개발을 진행하다보면 이미지, 파일 등 정적 리소스를 저장할 저장소가 필요하게 된다. 가장 많이 쓰여지는 것 중 하나가 AWS에서 제공하는 S3가 있는데 이걸 이용하려면 credentials 인증을 어플리케이션에서 해줘야 한다. credentials 인증 방식은 많이 있지만 사람들이 제일 많이 쓰는 방법 중 하나가 application.properties 파일같은 설정파일에 accessKey와 secretAccessKey를 넣어서 사용하는데 이는 보안에 매우 취약하다. 만약 github에 accessKey, secretAccessKey를 그대로 올리기라도 하면 큰 피해를 입을 수 있으며 실제로 그런 사례가 많이 있다. 그래서 이번에는 accessKey와 secretAcces..
AWS의 스토리지 서비스인 S3와 관계형 데이터베이스 서비스인 Aurora MySQL를 연동하여 S3 버킷에 있는 CSV 파일로 Aurora MySQL에 대량 insert 하는 방법과 Aurora MySQL에 저장된 데이터를 S3 버킷에 CSV 파일로 추출 하는 방법에 대해 알아보자. 순서대로 진행하면 문제없이 진행할 수 있다. 환경 Amazon RDS Aurora MySQL (Private - us-east-2) Amazon EC2 (Private - us-east-2) Amazon S3 (Private - us-east-2) IAM Role 생성 Aurora MySQL에서 S3에 파일을 읽어드리고 쓰기위해 AmazonS3FullAccess 정책을 가진 Role을 생성해준다. 그리고 위사진의 ARN값을..
sudo vi /etc/sysconfig/jenkins 위 경로에 있는 파일은 Jenkins 환경설정 파일인데 여기에 JENKINS_PORT 번호를 변경 후 재시작하면 변경된 port번호로 시작 되어야 하는데 변경된 포트가 적용 되지않고 기본포트(8080)로 시작되는 이슈를 겪었다. 추측을 해보자면 Jenkins 환경설정 파일내에 정의된 JENKINS_PORT 변수보다 더 우선적으로 적용되는 무언가가 있는 것 같다. 그래서 Jenkins Service 파일을 확인해봤다. sudo vi /usr/lib/systemd/system/jenkins.service 위 파일을 확인해보니 환경변수로 JENKINS_PORT가 정의되있다. 이 값을 9090으로 한번 변경 후 재시작 해보자. sudo systemctl d..
CI/CD는 애플리케이션 개발 단계부터 배포 단계까지 자동화 하여 개발한 애플리케이션을 사용자에게 빠르게 제공하는 방법이다. CI CI는 Continuous Integration의 약자이며 지속적 통합 이란 뜻이다. 여러 개발자가 작성한 코드를 Github, Bitbucket과 같은 코드 형상관리 툴을 이용하여 Repository에 통합하고 빌드 및 테스트가 정상적으로 이뤄지는지 확인하는 과정을 얘기한다. Repository에 개발한 코드들의 변경사항에 대해 주기적으로 변경함으로써 모든 개발자들에게 동일한 작업환경을 제공함으로써 버그를 사전에 미리 발견하고 소프트웨어 품질을 개선하는 장점이 있다. CD CD는 Continuous Delivery or Continuous Deployment 두 용어의 약자..
MFA는 Multi Factor Authentication의 약자로 우리말로 해석하면 다중 인증 이라고 부른다. MFA는 사용자 인증 프로세스에 보호 계층을 추가하는 방법으로써 계정에 액세스 할 때 지문이나 전화로 한번 더 인증절차를 거치게 된다. MFA를 적용하지 않게되면 사용자의 계정정보가 유출되었을 때 언제든지 해킹당할 우려가 있다. Amazon에서는 AWS를 사용하고 있는 기업들에 대해 자주하는 10가지 실수를 발표한 적이 있는데 그 중 하나로 MFA를 설정하지 않은 문제를 얘기할 정도로 MFA 설정을 필수로 권장하고 있다. MFA 적용하기 AWS Console에 들어가서 IAM 메뉴로 들어간다. 그리고 좌측에 있는 사용자 메뉴를 클릭하여 MFA를 적용할 사용자를 클릭한다. 그리고 보안 자격 증명..
Spring에서 file, classpath에 위치한 리소스를 제공해주는 Resource 라는 추상화된 인터페이스를 제공해준다. 이번글에서는 Resource 인터페이스의 구현체인 ClassPathResource와 PathMatchingResourcePatternResolver를 이용하여 classpath에 위치한 resource를 가져오는 5가지의 방법을 알아보도록 한다. classpath resource 현재 classpath의 resource에는 다음과 같은 디렉토리 및 파일들이 존재한다. classpath resource 조회 ClassPathResource 생성자 또는 PathMatchingResourcePatternResolver 클래스의 getResource 메서드로 classpath에 위치한..
이번글에서는 Spring Boot에서 Database Replication이 구성된 AWS RDS쪽으로 Read와 Write의 부하를 분산하게끔 구성을 해보려고 한다. 그전에 Database Replication에 대해 간단한 개념을 짚고 가자. Database Replication Replication의 사전적 의미는 복제다. 그렇다면 Database Replication은 데이터베이스를 복제하는걸 말하는데 기준이 되는 서버를 Primary라 불리우며 복제된 서버는 Secondary라고 부른다. 기준이 되는 Primary는 1대로 구성되며 복제된 Secondary는 N대로 구성된다. Database Replication 구성하는 이유 트래픽이 급증할 경우 1대의 데이터베이스에 쓰기(insert, upd..
현재 회사에서는 스테이지용 EC2 인스턴스 8개, RDS 인스턴스 1개 총 9개가 있습니다. 인스턴스들이 24시간 가동되어 비용이 적지 않게 나오고 있는데 어떻게 하면 비용을 줄일 수 있을까 고민을 했습니다. 그래서 개발자들이 업무하는 시간대에만 가동하고 퇴근 후에는 중지해놓으면 비용을 절감할 수 있다고 생각했습니다. 하지만 매번 수동으로 하게되면 리소스가 상당히 소모될 수 있습니다. AWS에서는 AWS Instance-Scheduler 라는 솔루션을 제안하는데 이 솔루션을 활용하면 EC2, RDS를 원하는 시간대에 시작 및 중지를 할 수 있게끔 해줍니다. 위 공식 문서에서는 Amazon CloudWatch, AWS CloudFormation, AWS DynomoDB, AWS Lambda 4개의 서비스를..
Spring Boot 프로젝트를 생성 후 .java파일을 제외한 애플리케이션 개발 시 필요한 리소스 파일을 src/main/resources 디렉토리 하위에 위치해두는데 대표적으로 application.properties(yml) 파일이 있다. 그리고 application.properties(yml) 파일에는 애플리케이션이 배포 될 환경별로 환경에 맞는 값을 세팅해두거나 (ex. DB정보) 로깅용 xml 파일을 세팅해두는데 이러한 리소스 파일들을 효율적으로 관리하는 방법에 대해 알아보자. 참고로 이 방법은 필자가 개인적으로 생각했을 때 효율적이라고 판단되서 작성하는 것.. 프로젝트 환경 Spring Boot Maven Gradle 예제 src/main/resources 디렉토리와 src/main/reso..