새 과제 프로젝트를 clone한 뒤 애플리케이션을 실행했는데 서버가 정상적으로 실행되지 않았다.
처음 실행했을 때 아래와 같은 에러가 발생했다.
ApplicationContextException: Unable to start web server
처음에는 단순히 서버 실행 문제라고 생각했지만, 에러 로그를 아래로 내려보니 진짜 원인은 따로 있었다.
Could not resolve placeholder 'jwt.secret.key' in value "${jwt.secret.key}"
즉, Spring Boot가 실행되는 과정에서 jwt.secret.key 값을 찾지 못해서 JwtUtil Bean 생성에 실패하고 있었다.
프로젝트의 JwtUtil 클래스에서는 JWT Secret Key 값을 설정 파일에서 주입받고 있었다.
@Value("${jwt.secret.key}")
private String secretKey;
하지만 프로젝트를 처음 열었을 때 src/main/resources/application.properties 파일이 존재하지 않았다.
즉, Spring Boot 입장에서는 아래 값을 읽어와야 하는데,
jwt.secret.key=...
해당 설정 자체가 없었기 때문에 애플리케이션 실행에 실패한 것이다.
먼저 src/main/resources 폴더를 만들고, 그 안에 application.properties 파일을 생성했다.
그리고 아래처럼 JWT Secret Key 값을 추가했다.
jwt.secret.key=sparta-spring-advanced-secret-key-2026-must-be-at-least-32-bytes
하지만 다시 실행해보니 또 다른 에러가 발생했다.
Illegal base64 character 2d
이번 에러는 jwt.secret.key 값이 없어서 발생한 문제가 아니라, Secret Key의 형식이 잘못되어 발생한 문제였다.
JwtUtil 내부에서 Secret Key를 Base64로 디코딩하고 있었기 때문에 일반 문자열을 넣으면 안 됐다.
처음 넣은 값에는 - 하이픈이 포함되어 있었고, 이 문자는 Base64 디코딩 과정에서 문제가 되었다.
그래서 Secret Key 값을 Base64 형식의 문자열로 변경했다.
jwt.secret.key=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=
이후 JWT 관련 에러는 해결되었다.
하지만 이번에는 DB 설정 관련 에러가 발생했다.
Failed to configure a DataSource: 'url' attribute is not specified
build.gradle을 확인해보니 MySQL 의존성이 추가되어 있었다.
runtimeOnly 'com.mysql:mysql-connector-j'
즉, 이 프로젝트는 MySQL DB 연결이 필요한 프로젝트였다.
하지만 application.properties에 DB 연결 정보가 없었기 때문에 Spring Boot가 어떤 DB에 연결해야 하는지 알 수 없었다.
MySQL에 사용할 데이터베이스를 생성했다.
CREATE DATABASE spring_advanced;
그리고 application.properties에 MySQL 연결 설정을 추가했다.
spring.datasource.url=jdbc:mysql://localhost:3306/spring_advanced
spring.datasource.username=root
spring.datasource.password=내 MySQL 비밀번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
최종적으로 application.properties에는 JWT 설정과 DB 설정이 함께 들어가게 되었다.
jwt.secret.key=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=
spring.datasource.url=jdbc:mysql://localhost:3306/spring_advanced
spring.datasource.username=root
spring.datasource.password=내 MySQL 비밀번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
다시 애플리케이션을 실행하니 서버가 정상적으로 실행되었다.
Tomcat started on port 8080
Started ExpertApplication
또한 Hibernate가 필요한 테이블들도 정상적으로 생성했다.
create table users
create table todos
create table comments
create table managers
application.properties에는 MySQL 비밀번호 같은 민감한 정보가 들어간다.
그래서 GitHub에 올라가지 않도록 반드시 .gitignore 적용 여부를 확인했다.
git check-ignore -v src/main/resources/application.properties
확인 결과 아래처럼 .gitignore에 의해 무시되고 있었다.
.gitignore:40:*.properties src/main/resources/application.properties
즉, DB 비밀번호가 GitHub에 올라가지 않는 안전한 상태였다.
이번 트러블 슈팅을 통해 Spring Boot 프로젝트 실행 실패 로그를 볼 때는 가장 위의 에러만 볼 것이 아니라, 아래쪽의 Caused by를 따라가며 진짜 원인을 찾아야 한다는 것을 알게 되었다.
또한 @Value("${...}")로 주입받는 설정값은 반드시 application.properties 또는 application.yml에 존재해야 한다.
JWT Secret Key처럼 내부에서 Base64 디코딩을 수행하는 값은 단순 문자열이 아니라 Base64 형식으로 넣어야 한다는 점도 알게 되었다.
마지막으로 MySQL 의존성이 있는 프로젝트에서는 DataSource 설정이 없으면 애플리케이션 실행 단계에서 실패할 수 있다는 것도 확인했다.
이번 문제의 흐름은 다음과 같았다.
1. 프로젝트 실행 실패
2. jwt.secret.key 설정 누락 확인
3. application.properties 생성
4. JWT Secret Key 추가
5. Base64 형식 문제 해결
6. DataSource 설정 누락 확인
7. MySQL DB 생성 및 연결 설정 추가
8. 서버 정상 실행
단순히 에러 메시지만 보고 해결하려고 하기보다, 로그의 원인을 단계별로 따라가면서 해결하는 것이 중요하다는 것을 배웠다.