From f57d550c2e2fcd2293829bf481fded3d94360e12 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Mon, 25 Aug 2025 17:58:53 +0900 Subject: [PATCH 01/12] =?UTF-8?q?fix:=20postgre=20password=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docker-compose.yml에 설정되어있는 password로 변경 - docker-compose.yml에 설정되어있는 password와 application-develop.yml에 설정되어있는 password 통일 시킴 --- .../main/resources/application-develop.yml | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/apps/user-service/src/main/resources/application-develop.yml b/apps/user-service/src/main/resources/application-develop.yml index fb8125bd..8cae624c 100644 --- a/apps/user-service/src/main/resources/application-develop.yml +++ b/apps/user-service/src/main/resources/application-develop.yml @@ -8,7 +8,7 @@ spring: datasource: url: jdbc:postgresql://localhost:5432/pre_process username: postgres - password: password123 + password: qwer1234 driver-class-name: org.postgresql.Driver hikari: @@ -19,21 +19,27 @@ spring: minimum-idle: 5 pool-name: HikariCP-MyBatis - # JPA/Hibernate 설정 - jpa: - hibernate: - ddl-auto: update # create, create-drop, update, validate, none - show-sql: true - format-sql: true - database: postgresql - database-platform: org.hibernate.dialect.PostgreSQLDialect - properties: - hibernate: - format_sql: true - use_sql_comments: true - jdbc: - lob: - non_contextual_creation: true +# # JPA/Hibernate 설정 +# jpa: +# hibernate: +# ddl-auto: update # create, create-drop, update, validate, none +# show-sql: true +# format-sql: true +# database: postgresql +# database-platform: org.hibernate.dialect.PostgreSQLDialect +# properties: +# hibernate: +# format_sql: true +# use_sql_comments: true +# jdbc: +# lob: +# non_contextual_creation: true + +mybatis: + mapper-locations: classpath:mybatis/mapper/**/*.xml + type-aliases-package: com.gltkorea.icebang.dto + configuration: + map-underscore-to-camel-case: true logging: config: classpath:log4j2-develop.yml \ No newline at end of file From 75a82637a5e4b451c390959a0aeaa9b303b0c771 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Mon, 25 Aug 2025 17:59:54 +0900 Subject: [PATCH 02/12] =?UTF-8?q?chore:=20application-test.yml=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - test를 위한 application-test.yml 작성 --- .../src/main/resources/application-test.yml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/apps/user-service/src/main/resources/application-test.yml b/apps/user-service/src/main/resources/application-test.yml index e69de29b..63217124 100644 --- a/apps/user-service/src/main/resources/application-test.yml +++ b/apps/user-service/src/main/resources/application-test.yml @@ -0,0 +1,34 @@ +# src/test/resources/application-test.yml +spring: + config: + activate: + on-profile: test + + # PostgreSQL 데이터베이스 연결 설정 + datasource: + url: jdbc:postgresql://localhost:5432/pre_process + username: postgres + password: qwer1234 + driver-class-name: org.postgresql.Driver + + hikari: + connection-timeout: 30000 + idle-timeout: 600000 + max-lifetime: 1800000 + maximum-pool-size: 10 + minimum-idle: 5 + pool-name: HikariCP-MyBatis + + # SQL 스크립트 초기화 설정 추가 + sql: + init: + mode: always # 내장 DB가 아니더라도 항상 스크립트를 실행하도록 설정 + +mybatis: + mapper-locations: classpath:mybatis/mapper/**/*.xml + type-aliases-package: com.gltkorea.icebang.dto + configuration: + map-underscore-to-camel-case: true + +logging: + config: classpath:log4j2-test.yml \ No newline at end of file From 02a301c5440f194e857de577c097c26c0e7fb669 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Mon, 25 Aug 2025 18:02:14 +0900 Subject: [PATCH 03/12] test: DBConnectionTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DBConnectionTest를 위한 create-schema.sql, insert-user-data.sql 작성 - DBConnectionTest 코드 작성 --- .../icebang/DatabaseConnectionTest.java | 79 +++++++++++++ .../src/test/resources/sql/create-schema.sql | 104 ++++++++++++++++++ .../test/resources/sql/insert-user-data.sql | 39 +++++++ 3 files changed, 222 insertions(+) create mode 100644 apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java create mode 100644 apps/user-service/src/test/resources/sql/create-schema.sql create mode 100644 apps/user-service/src/test/resources/sql/insert-user-data.sql diff --git a/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java b/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java new file mode 100644 index 00000000..acc2ee3a --- /dev/null +++ b/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java @@ -0,0 +1,79 @@ +package com.gltkorea.icebang; + +import com.gltkorea.icebang.dto.UserDto; +import com.gltkorea.icebang.mapper.UserMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.transaction.annotation.Transactional; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@Import(TestcontainersConfiguration.class) +@AutoConfigureTestDatabase(replace = Replace.NONE) +@ActiveProfiles("test") // application-test.yml 설정을 활성화 +@Transactional // 테스트 후 데이터 롤백 +@Sql(scripts = {"classpath:sql/create-schema.sql", "classpath:sql/insert-user-data.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +class DatabaseConnectionTest { + + @Autowired + private DataSource dataSource; + + @Autowired + private UserMapper userMapper; // JPA Repository 대신 MyBatis Mapper를 주입 + + @Test + @DisplayName("DataSource를 통해 DB 커넥션을 성공적으로 얻을 수 있다.") + void canGetDatabaseConnection() { + try (Connection connection = dataSource.getConnection()) { + assertThat(connection).isNotNull(); + assertThat(connection.isValid(1)).isTrue(); + System.out.println("DB Connection successful: " + connection.getMetaData().getURL()); + } catch (SQLException e) { + org.junit.jupiter.api.Assertions.fail("Failed to get database connection", e); + } + } + + @Test + @DisplayName("MyBatis Mapper를 통해 '홍길동' 사용자를 이메일로 조회") + void findUserByEmailWithMyBatis() { + // given + String testEmail = "hong.gildong@example.com"; + + // when + Optional foundUser = userMapper.findByEmail(testEmail); + + // then + // 사용자가 존재하고, 이름이 '홍길동'인지 확인 + assertThat(foundUser).isPresent(); + assertThat(foundUser.get().getName()).isEqualTo("홍길동"); + System.out.println("Successfully found user with MyBatis: " + foundUser.get().getName()); + } + + @Test + @DisplayName("샘플 데이터가 올바르게 삽입되었는지 확인") + void verifyAllSampleDataInserted() { + // 사용자 데이터 확인 + Optional hong = userMapper.findByEmail("hong.gildong@example.com"); + assertThat(hong).isPresent(); + assertThat(hong.get().getName()).isEqualTo("홍길동"); + + Optional kim = userMapper.findByEmail("kim.chulsu@example.com"); + assertThat(kim).isPresent(); + assertThat(kim.get().getName()).isEqualTo("김철수"); + + System.out.println("샘플 데이터 삽입 성공 - 홍길동, 김철수 확인"); + } +} \ No newline at end of file diff --git a/apps/user-service/src/test/resources/sql/create-schema.sql b/apps/user-service/src/test/resources/sql/create-schema.sql new file mode 100644 index 00000000..b9846fca --- /dev/null +++ b/apps/user-service/src/test/resources/sql/create-schema.sql @@ -0,0 +1,104 @@ +-- 테이블 DROP (재생성을 위해 기존 테이블을 삭제) +DROP TABLE IF EXISTS "ROLE_PERMISSION"; +DROP TABLE IF EXISTS "USER_ROLE"; +DROP TABLE IF EXISTS "PERMISSION"; +DROP TABLE IF EXISTS "ROLE"; +DROP TABLE IF EXISTS "USER_GROUP"; +DROP TABLE IF EXISTS "GROUP_INFO"; +DROP TABLE IF EXISTS "USER"; + + +-- 사용자 정보 +CREATE TABLE "USER" ( + "user_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(100) NULL, + "email" VARCHAR(255) NULL UNIQUE, + "password" VARCHAR(255) NULL, + "phone_number" VARCHAR(50) NULL, + "fax_number" VARCHAR(50) NULL, + "zip_code" VARCHAR(20) NULL, + "main_address" VARCHAR(255) NULL, + "detail_address" VARCHAR(255) NULL, + "recommender_id" VARCHAR(36) NULL, + "resident_number" VARCHAR(100) NULL, + "corporate_number" VARCHAR(100) NULL, + "business_number" VARCHAR(100) NULL, + "type" VARCHAR(50) NULL, + "department" VARCHAR(100) NULL, + "job_title" VARCHAR(50) NULL, + "grade" VARCHAR(50) NULL, + "status" VARCHAR(50) NULL, + "joined_at" TIMESTAMP NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("user_id") +); + +-- 사용자 그룹 정보 +CREATE TABLE "GROUP_INFO" ( + "group_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(255) NULL, + "description" TEXT NULL, + "status" VARCHAR(50) NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("group_id") +); + +-- 사용자-그룹 관계 +CREATE TABLE "USER_GROUP" ( + "user_id" VARCHAR(36) NOT NULL, + "group_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("user_id", "group_id"), + FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), + FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id") +); + +-- 역할 정보 +CREATE TABLE "ROLE" ( + "role_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(50) NULL, + "code" VARCHAR(50) NULL UNIQUE, + "description" VARCHAR(255) NULL, + "status" VARCHAR(50) NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("role_id") +); + +-- 권한 정보 +CREATE TABLE "PERMISSION" ( + "permission_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(50) NULL, + "code" VARCHAR(50) NULL UNIQUE, + "resource" VARCHAR(50) NULL, + "action" VARCHAR(50) NULL, + "description" VARCHAR(255) NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("permission_id") +); + +-- 사용자-역할 관계 +CREATE TABLE "USER_ROLE" ( + "user_id" VARCHAR(36) NOT NULL, + "role_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("user_id", "role_id"), + FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), + FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id") +); + +-- 역할-권한 관계 +CREATE TABLE "ROLE_PERMISSION" ( + "role_id" VARCHAR(36) NOT NULL, + "permission_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("role_id", "permission_id"), + FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), + FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id") +); \ No newline at end of file diff --git a/apps/user-service/src/test/resources/sql/insert-user-data.sql b/apps/user-service/src/test/resources/sql/insert-user-data.sql new file mode 100644 index 00000000..9a190b4e --- /dev/null +++ b/apps/user-service/src/test/resources/sql/insert-user-data.sql @@ -0,0 +1,39 @@ +-- 데이터 삽입 +INSERT INTO "USER" ("user_id", "name", "email", "password", "phone_number", "type", "status", "joined_at") +VALUES + ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '홍길동', 'hong.gildong@example.com', 'hashed_password_1', '010-1234-5678', 'INDIVIDUAL', 'ACTIVE', NOW()), + ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '김철수', 'kim.chulsu@example.com', 'hashed_1b590e829a28', '010-9876-5432', 'INDIVIDUAL', 'ACTIVE', NOW()); + +INSERT INTO "GROUP_INFO" ("group_id", "name", "description", "status") +VALUES + ('0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a', '개발팀', '애플리케이션 개발 그룹', 'ACTIVE'), + ('5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b', '기획팀', '프로젝트 기획 그룹', 'ACTIVE'); + +INSERT INTO "USER_GROUP" ("user_id", "group_id") +VALUES + ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a'), + ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b'); + +INSERT INTO "ROLE" ("role_id", "name", "code", "description", "status") +VALUES + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', '관리자', 'ADMIN', '모든 권한을 가진 역할', 'ACTIVE'), + ('d1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b', '일반 사용자', 'USER', '기본 권한을 가진 역할', 'ACTIVE'); + +INSERT INTO "PERMISSION" ("permission_id", "name", "code", "resource", "action", "description") +VALUES + ('c3f5a2b8-7e1d-4c9a-8b1d-2e3f4a5b6c7d', '사용자 정보 읽기', 'USER_READ', 'USER', 'READ', '사용자 정보 조회 권한'), + ('b5c6a7d8-1e2f-3a4b-5c6d-7e8f9a0b1c2d', '사용자 정보 수정', 'USER_WRITE', 'USER', 'WRITE', '사용자 정보 수정 권한'), + ('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', '로그인', 'AUTH_LOGIN', 'AUTH', 'LOGIN', '로그인 권한'); + +INSERT INTO "USER_ROLE" ("user_id", "role_id") +VALUES + ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', 'e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e'), + ('92d04a8b-185d-4f1b-85d1-9650d99d1234', 'd1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b'); + +INSERT INTO "ROLE_PERMISSION" ("role_id", "permission_id") +VALUES + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', 'c3f5a2b8-7e1d-4c9a-8b1d-2e3f4a5b6c7d'), + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', 'b5c6a7d8-1e2f-3a4b-5c6d-7e8f9a0b1c2d'), + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', 'a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d'), + ('d1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b', 'c3f5a2b8-7e1d-4c9a-8b1d-2e3f4a5b6c7d'), + ('d1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b', 'a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d'); \ No newline at end of file From 3d9f686fce5d67f554afd75265213dc92634a4d5 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Mon, 25 Aug 2025 18:04:30 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20=EB=8B=A4=EC=A4=91=20=EB=8B=A8?= =?UTF-8?q?=EA=B3=84=20=EB=B9=8C=EB=93=9C=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20Dockerfile=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 빌드 스테이지와 실행 스테이지를 분리하여 최종 이미지의 크기를 줄였습니다. - `openjdk:21-jdk-slim` 이미지를 빌드에 사용하고, `openjdk:21-jre-slim` 이미지를 실행에 사용하여 불필요한 JDK 종속성을 제거했습니다. - Docker 레이어 캐싱을 활용하도록 파일 복사 순서를 조정하여 빌드 속도를 개선했습니다. - 빌드 시 테스트를 건너뛰는 옵션(`-x test`)을 추가했습니다. - 최종 JAR 파일명을 `app.jar`로 간소화했습니다. --- apps/user-service/Dockerfile | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/apps/user-service/Dockerfile b/apps/user-service/Dockerfile index e69de29b..3fb9d854 100644 --- a/apps/user-service/Dockerfile +++ b/apps/user-service/Dockerfile @@ -0,0 +1,42 @@ +# 1단계: 빌드 스테이지 +# Java 21 JDK가 포함된 경량 이미지를 사용합니다. +# 이 단계에서 애플리케이션을 빌드합니다. +FROM openjdk:21-jdk-slim AS builder + +# 컨테이너 내부에 작업 디렉토리를 생성하고 설정합니다. +WORKDIR /app + +# Gradle Wrapper, 설정 파일, 소스 코드를 복사합니다. +# Docker의 레이어 캐싱을 활용하여 빌드 속도를 높입니다. +COPY gradlew . +COPY gradle/ gradle/ +COPY build.gradle . +COPY settings.gradle . + +# 애플리케이션 소스 코드를 복사합니다. +COPY src src + +# 애플리케이션을 빌드하여 실행 가능한 JAR 파일을 만듭니다. +# `-x test`는 이미지 빌드 시 테스트를 건너뛰는 명령입니다. +RUN ./gradlew clean build -x test + +--- + +# 2단계: 실행 스테이지 +# 애플리케이션 실행에 필요한 Java 21 JRE만 포함된 경량 이미지를 사용합니다. +FROM openjdk:21-jre-slim + +# 컨테이너 내부의 작업 디렉토리를 설정합니다. +WORKDIR /app + +# 빌드 스테이지에서 생성된 JAR 파일을 복사합니다. +# `--from=builder` 옵션을 사용하여 첫 번째 단계에서 빌드된 JAR만 가져옵니다. +# 파일명은 `group`, `version`에 따라 `glt-korea-0.0.1-SNAPSHOT.jar`가 되므로, +# 이를 `app.jar`라는 간단한 이름으로 변경합니다. +COPY --from=builder /app/build/libs/glt-korea-0.0.1-SNAPSHOT.jar ./app.jar + +# 애플리케이션이 외부 요청을 받을 포트를 노출합니다. +EXPOSE 8080 + +# 컨테이너 시작 시 실행될 명령어를 정의합니다. +CMD ["java", "-jar", "app.jar"] \ No newline at end of file From 7403b1c0e17a76ff8aa79d5254894397de845a4e Mon Sep 17 00:00:00 2001 From: jihukimme Date: Mon, 25 Aug 2025 18:06:15 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20Mybatis=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EA=B8=B0=EB=B3=B8=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 정보 관리를 위한 UserDto 클래스 생성 - Mybatis Mapper 인터페이스(UserMapper) 및 XML 파일 추가 - Spring 컨텍스트에 MapperScanner 설정 - 이를 통해 사용자 데이터를 데이터베이스에서 가져올 수 있는 기반 마련 --- .../icebang/UserServiceApplication.java | 2 ++ .../java/com/gltkorea/icebang/dto/UserDto.java | 13 +++++++++++++ .../com/gltkorea/icebang/mapper/UserMapper.java | 11 +++++++++++ .../resources/mybatis/mapper/UserMapper.xml | 17 +++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java create mode 100644 apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java create mode 100644 apps/user-service/src/main/resources/mybatis/mapper/UserMapper.xml diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/UserServiceApplication.java b/apps/user-service/src/main/java/com/gltkorea/icebang/UserServiceApplication.java index b5fcbef4..c69c1773 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/UserServiceApplication.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/UserServiceApplication.java @@ -1,9 +1,11 @@ package com.gltkorea.icebang; +import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication +@MapperScan("com.gltkorea.icebang.mapper") public class UserServiceApplication { public static void main(String[] args) { diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java new file mode 100644 index 00000000..355192ed --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java @@ -0,0 +1,13 @@ +package com.gltkorea.icebang.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class UserDto { + private String userId; + private String name; + private String email; + // ... 필요한 다른 필드들 +} \ No newline at end of file diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java b/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java new file mode 100644 index 00000000..f220ae54 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java @@ -0,0 +1,11 @@ +package com.gltkorea.icebang.mapper; + +import com.gltkorea.icebang.dto.UserDto; +import org.apache.ibatis.annotations.Mapper; +import java.util.Optional; + +@Mapper // Spring이 MyBatis Mapper로 인식하도록 설정 +public interface UserMapper { + // XML 파일의 id와 메서드 이름을 일치시켜야 합니다. + Optional findByEmail(String email); +} \ No newline at end of file diff --git a/apps/user-service/src/main/resources/mybatis/mapper/UserMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/UserMapper.xml new file mode 100644 index 00000000..68be89f9 --- /dev/null +++ b/apps/user-service/src/main/resources/mybatis/mapper/UserMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file From 36bbf3d105f2b84269813de191ca479a0663b635 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Mon, 25 Aug 2025 18:08:03 +0900 Subject: [PATCH 06/12] =?UTF-8?q?chore:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B4=88=EA=B8=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - create-schema.sql: 애플리케이션에 필요한 데이터베이스 테이블 스키마를 정의 - insert-user-data.sql: 테스트용 사용자 데이터를 초기화 시 삽입 이제 Docker Compose를 사용하여 컨테이너를 실행할 때 데이터베이스가 자동으로 초기화됩니다. --- docker/local/init-scripts/create-schema.sql | 104 ++++++++++++++++++ .../local/init-scripts/insert-user-data.sql | 39 +++++++ 2 files changed, 143 insertions(+) create mode 100644 docker/local/init-scripts/create-schema.sql create mode 100644 docker/local/init-scripts/insert-user-data.sql diff --git a/docker/local/init-scripts/create-schema.sql b/docker/local/init-scripts/create-schema.sql new file mode 100644 index 00000000..b9846fca --- /dev/null +++ b/docker/local/init-scripts/create-schema.sql @@ -0,0 +1,104 @@ +-- 테이블 DROP (재생성을 위해 기존 테이블을 삭제) +DROP TABLE IF EXISTS "ROLE_PERMISSION"; +DROP TABLE IF EXISTS "USER_ROLE"; +DROP TABLE IF EXISTS "PERMISSION"; +DROP TABLE IF EXISTS "ROLE"; +DROP TABLE IF EXISTS "USER_GROUP"; +DROP TABLE IF EXISTS "GROUP_INFO"; +DROP TABLE IF EXISTS "USER"; + + +-- 사용자 정보 +CREATE TABLE "USER" ( + "user_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(100) NULL, + "email" VARCHAR(255) NULL UNIQUE, + "password" VARCHAR(255) NULL, + "phone_number" VARCHAR(50) NULL, + "fax_number" VARCHAR(50) NULL, + "zip_code" VARCHAR(20) NULL, + "main_address" VARCHAR(255) NULL, + "detail_address" VARCHAR(255) NULL, + "recommender_id" VARCHAR(36) NULL, + "resident_number" VARCHAR(100) NULL, + "corporate_number" VARCHAR(100) NULL, + "business_number" VARCHAR(100) NULL, + "type" VARCHAR(50) NULL, + "department" VARCHAR(100) NULL, + "job_title" VARCHAR(50) NULL, + "grade" VARCHAR(50) NULL, + "status" VARCHAR(50) NULL, + "joined_at" TIMESTAMP NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("user_id") +); + +-- 사용자 그룹 정보 +CREATE TABLE "GROUP_INFO" ( + "group_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(255) NULL, + "description" TEXT NULL, + "status" VARCHAR(50) NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("group_id") +); + +-- 사용자-그룹 관계 +CREATE TABLE "USER_GROUP" ( + "user_id" VARCHAR(36) NOT NULL, + "group_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("user_id", "group_id"), + FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), + FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id") +); + +-- 역할 정보 +CREATE TABLE "ROLE" ( + "role_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(50) NULL, + "code" VARCHAR(50) NULL UNIQUE, + "description" VARCHAR(255) NULL, + "status" VARCHAR(50) NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("role_id") +); + +-- 권한 정보 +CREATE TABLE "PERMISSION" ( + "permission_id" VARCHAR(36) NOT NULL, + "name" VARCHAR(50) NULL, + "code" VARCHAR(50) NULL UNIQUE, + "resource" VARCHAR(50) NULL, + "action" VARCHAR(50) NULL, + "description" VARCHAR(255) NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("permission_id") +); + +-- 사용자-역할 관계 +CREATE TABLE "USER_ROLE" ( + "user_id" VARCHAR(36) NOT NULL, + "role_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("user_id", "role_id"), + FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), + FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id") +); + +-- 역할-권한 관계 +CREATE TABLE "ROLE_PERMISSION" ( + "role_id" VARCHAR(36) NOT NULL, + "permission_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("role_id", "permission_id"), + FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), + FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id") +); \ No newline at end of file diff --git a/docker/local/init-scripts/insert-user-data.sql b/docker/local/init-scripts/insert-user-data.sql new file mode 100644 index 00000000..9a190b4e --- /dev/null +++ b/docker/local/init-scripts/insert-user-data.sql @@ -0,0 +1,39 @@ +-- 데이터 삽입 +INSERT INTO "USER" ("user_id", "name", "email", "password", "phone_number", "type", "status", "joined_at") +VALUES + ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '홍길동', 'hong.gildong@example.com', 'hashed_password_1', '010-1234-5678', 'INDIVIDUAL', 'ACTIVE', NOW()), + ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '김철수', 'kim.chulsu@example.com', 'hashed_1b590e829a28', '010-9876-5432', 'INDIVIDUAL', 'ACTIVE', NOW()); + +INSERT INTO "GROUP_INFO" ("group_id", "name", "description", "status") +VALUES + ('0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a', '개발팀', '애플리케이션 개발 그룹', 'ACTIVE'), + ('5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b', '기획팀', '프로젝트 기획 그룹', 'ACTIVE'); + +INSERT INTO "USER_GROUP" ("user_id", "group_id") +VALUES + ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a'), + ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b'); + +INSERT INTO "ROLE" ("role_id", "name", "code", "description", "status") +VALUES + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', '관리자', 'ADMIN', '모든 권한을 가진 역할', 'ACTIVE'), + ('d1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b', '일반 사용자', 'USER', '기본 권한을 가진 역할', 'ACTIVE'); + +INSERT INTO "PERMISSION" ("permission_id", "name", "code", "resource", "action", "description") +VALUES + ('c3f5a2b8-7e1d-4c9a-8b1d-2e3f4a5b6c7d', '사용자 정보 읽기', 'USER_READ', 'USER', 'READ', '사용자 정보 조회 권한'), + ('b5c6a7d8-1e2f-3a4b-5c6d-7e8f9a0b1c2d', '사용자 정보 수정', 'USER_WRITE', 'USER', 'WRITE', '사용자 정보 수정 권한'), + ('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', '로그인', 'AUTH_LOGIN', 'AUTH', 'LOGIN', '로그인 권한'); + +INSERT INTO "USER_ROLE" ("user_id", "role_id") +VALUES + ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', 'e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e'), + ('92d04a8b-185d-4f1b-85d1-9650d99d1234', 'd1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b'); + +INSERT INTO "ROLE_PERMISSION" ("role_id", "permission_id") +VALUES + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', 'c3f5a2b8-7e1d-4c9a-8b1d-2e3f4a5b6c7d'), + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', 'b5c6a7d8-1e2f-3a4b-5c6d-7e8f9a0b1c2d'), + ('e2c3a5f9-8d1a-4b72-9c3f-4e3b2c1d8a1e', 'a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d'), + ('d1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b', 'c3f5a2b8-7e1d-4c9a-8b1d-2e3f4a5b6c7d'), + ('d1a2c3b4-5f6e-7d8c-9a0b-1c2d3e4f5a6b', 'a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d'); \ No newline at end of file From 0eb2ac7109f592aa4fb33dc51c7f6bd3195c851d Mon Sep 17 00:00:00 2001 From: jihukimme Date: Wed, 27 Aug 2025 11:49:28 +0900 Subject: [PATCH 07/12] =?UTF-8?q?refactor:=20=EC=A4=91=EA=B0=84=20?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=EC=9D=98=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=ED=82=A4=20=ED=83=80=EC=9E=85=EC=9D=84=20UUID=EC=97=90?= =?UTF-8?q?=EC=84=9C=20BIGINT=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인조키는 BIGINT(Auto-increment) 타입으로 변경 --- .../src/test/resources/sql/create-schema.sql | 17 ++++++++++------- .../src/test/resources/sql/insert-user-data.sql | 2 +- docker/local/init-scripts/create-schema.sql | 17 ++++++++++------- docker/local/init-scripts/insert-user-data.sql | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/apps/user-service/src/test/resources/sql/create-schema.sql b/apps/user-service/src/test/resources/sql/create-schema.sql index b9846fca..82299617 100644 --- a/apps/user-service/src/test/resources/sql/create-schema.sql +++ b/apps/user-service/src/test/resources/sql/create-schema.sql @@ -36,7 +36,7 @@ CREATE TABLE "USER" ( -- 사용자 그룹 정보 CREATE TABLE "GROUP_INFO" ( - "group_id" VARCHAR(36) NOT NULL, + "group_info_id" VARCHAR(36) NOT NULL, "name" VARCHAR(255) NULL, "description" TEXT NULL, "status" VARCHAR(50) NULL, @@ -47,13 +47,14 @@ CREATE TABLE "GROUP_INFO" ( -- 사용자-그룹 관계 CREATE TABLE "USER_GROUP" ( + "user_group_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 "user_id" VARCHAR(36) NOT NULL, "group_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("user_id", "group_id"), FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), - FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id") + FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id"), + UNIQUE ("user_id", "group_id") -- 중복 방지를 위한 UNIQUE 제약 조건 ); -- 역할 정보 @@ -83,22 +84,24 @@ CREATE TABLE "PERMISSION" ( -- 사용자-역할 관계 CREATE TABLE "USER_ROLE" ( + "user_role_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 "user_id" VARCHAR(36) NOT NULL, "role_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("user_id", "role_id"), FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), - FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id") + FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), + UNIQUE ("user_id", "role_id") -- 중복 방지를 위한 UNIQUE 제약 조건 ); -- 역할-권한 관계 CREATE TABLE "ROLE_PERMISSION" ( + "role_permission_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 "role_id" VARCHAR(36) NOT NULL, "permission_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("role_id", "permission_id"), FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), - FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id") + FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id"), + UNIQUE ("role_id", "permission_id") -- 중복 방지를 위한 UNIQUE 제약 조건 ); \ No newline at end of file diff --git a/apps/user-service/src/test/resources/sql/insert-user-data.sql b/apps/user-service/src/test/resources/sql/insert-user-data.sql index 9a190b4e..02138a2d 100644 --- a/apps/user-service/src/test/resources/sql/insert-user-data.sql +++ b/apps/user-service/src/test/resources/sql/insert-user-data.sql @@ -9,7 +9,7 @@ VALUES ('0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a', '개발팀', '애플리케이션 개발 그룹', 'ACTIVE'), ('5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b', '기획팀', '프로젝트 기획 그룹', 'ACTIVE'); -INSERT INTO "USER_GROUP" ("user_id", "group_id") +INSERT INTO "USER_GROUP_INFO" ("user_id", "group_id") VALUES ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a'), ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b'); diff --git a/docker/local/init-scripts/create-schema.sql b/docker/local/init-scripts/create-schema.sql index b9846fca..82299617 100644 --- a/docker/local/init-scripts/create-schema.sql +++ b/docker/local/init-scripts/create-schema.sql @@ -36,7 +36,7 @@ CREATE TABLE "USER" ( -- 사용자 그룹 정보 CREATE TABLE "GROUP_INFO" ( - "group_id" VARCHAR(36) NOT NULL, + "group_info_id" VARCHAR(36) NOT NULL, "name" VARCHAR(255) NULL, "description" TEXT NULL, "status" VARCHAR(50) NULL, @@ -47,13 +47,14 @@ CREATE TABLE "GROUP_INFO" ( -- 사용자-그룹 관계 CREATE TABLE "USER_GROUP" ( + "user_group_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 "user_id" VARCHAR(36) NOT NULL, "group_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("user_id", "group_id"), FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), - FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id") + FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id"), + UNIQUE ("user_id", "group_id") -- 중복 방지를 위한 UNIQUE 제약 조건 ); -- 역할 정보 @@ -83,22 +84,24 @@ CREATE TABLE "PERMISSION" ( -- 사용자-역할 관계 CREATE TABLE "USER_ROLE" ( + "user_role_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 "user_id" VARCHAR(36) NOT NULL, "role_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("user_id", "role_id"), FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), - FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id") + FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), + UNIQUE ("user_id", "role_id") -- 중복 방지를 위한 UNIQUE 제약 조건 ); -- 역할-권한 관계 CREATE TABLE "ROLE_PERMISSION" ( + "role_permission_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 "role_id" VARCHAR(36) NOT NULL, "permission_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("role_id", "permission_id"), FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), - FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id") + FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id"), + UNIQUE ("role_id", "permission_id") -- 중복 방지를 위한 UNIQUE 제약 조건 ); \ No newline at end of file diff --git a/docker/local/init-scripts/insert-user-data.sql b/docker/local/init-scripts/insert-user-data.sql index 9a190b4e..02138a2d 100644 --- a/docker/local/init-scripts/insert-user-data.sql +++ b/docker/local/init-scripts/insert-user-data.sql @@ -9,7 +9,7 @@ VALUES ('0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a', '개발팀', '애플리케이션 개발 그룹', 'ACTIVE'), ('5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b', '기획팀', '프로젝트 기획 그룹', 'ACTIVE'); -INSERT INTO "USER_GROUP" ("user_id", "group_id") +INSERT INTO "USER_GROUP_INFO" ("user_id", "group_id") VALUES ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a'), ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b'); From 23d2f5216bf8917b22a5560d33efb84dffb7e999 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Wed, 27 Aug 2025 11:51:26 +0900 Subject: [PATCH 08/12] refactor: code formatting --- .../com/gltkorea/icebang/dto/UserDto.java | 10 +- .../gltkorea/icebang/mapper/UserMapper.java | 12 ++- .../icebang/DatabaseConnectionTest.java | 100 +++++++++--------- 3 files changed, 63 insertions(+), 59 deletions(-) diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java b/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java index 355192ed..6763bac9 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/dto/UserDto.java @@ -6,8 +6,8 @@ @Getter @Setter public class UserDto { - private String userId; - private String name; - private String email; - // ... 필요한 다른 필드들 -} \ No newline at end of file + private String userId; + private String name; + private String email; + // ... 필요한 다른 필드들 +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java b/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java index f220ae54..f09a152a 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/mapper/UserMapper.java @@ -1,11 +1,13 @@ package com.gltkorea.icebang.mapper; -import com.gltkorea.icebang.dto.UserDto; -import org.apache.ibatis.annotations.Mapper; import java.util.Optional; +import org.apache.ibatis.annotations.Mapper; + +import com.gltkorea.icebang.dto.UserDto; + @Mapper // Spring이 MyBatis Mapper로 인식하도록 설정 public interface UserMapper { - // XML 파일의 id와 메서드 이름을 일치시켜야 합니다. - Optional findByEmail(String email); -} \ No newline at end of file + // XML 파일의 id와 메서드 이름을 일치시켜야 합니다. + Optional findByEmail(String email); +} diff --git a/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java b/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java index acc2ee3a..a3dd2e77 100644 --- a/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java +++ b/apps/user-service/src/test/java/com/gltkorea/icebang/DatabaseConnectionTest.java @@ -1,7 +1,13 @@ package com.gltkorea.icebang; -import com.gltkorea.icebang.dto.UserDto; -import com.gltkorea.icebang.mapper.UserMapper; +import static org.assertj.core.api.Assertions.assertThat; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Optional; + +import javax.sql.DataSource; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,67 +19,63 @@ import org.springframework.test.context.jdbc.Sql; import org.springframework.transaction.annotation.Transactional; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; +import com.gltkorea.icebang.dto.UserDto; +import com.gltkorea.icebang.mapper.UserMapper; @SpringBootTest @Import(TestcontainersConfiguration.class) @AutoConfigureTestDatabase(replace = Replace.NONE) @ActiveProfiles("test") // application-test.yml 설정을 활성화 @Transactional // 테스트 후 데이터 롤백 -@Sql(scripts = {"classpath:sql/create-schema.sql", "classpath:sql/insert-user-data.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql( + scripts = {"classpath:sql/create-schema.sql", "classpath:sql/insert-user-data.sql"}, + executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) class DatabaseConnectionTest { - @Autowired - private DataSource dataSource; + @Autowired private DataSource dataSource; - @Autowired - private UserMapper userMapper; // JPA Repository 대신 MyBatis Mapper를 주입 + @Autowired private UserMapper userMapper; // JPA Repository 대신 MyBatis Mapper를 주입 - @Test - @DisplayName("DataSource를 통해 DB 커넥션을 성공적으로 얻을 수 있다.") - void canGetDatabaseConnection() { - try (Connection connection = dataSource.getConnection()) { - assertThat(connection).isNotNull(); - assertThat(connection.isValid(1)).isTrue(); - System.out.println("DB Connection successful: " + connection.getMetaData().getURL()); - } catch (SQLException e) { - org.junit.jupiter.api.Assertions.fail("Failed to get database connection", e); - } + @Test + @DisplayName("DataSource를 통해 DB 커넥션을 성공적으로 얻을 수 있다.") + void canGetDatabaseConnection() { + try (Connection connection = dataSource.getConnection()) { + assertThat(connection).isNotNull(); + assertThat(connection.isValid(1)).isTrue(); + System.out.println("DB Connection successful: " + connection.getMetaData().getURL()); + } catch (SQLException e) { + org.junit.jupiter.api.Assertions.fail("Failed to get database connection", e); } + } - @Test - @DisplayName("MyBatis Mapper를 통해 '홍길동' 사용자를 이메일로 조회") - void findUserByEmailWithMyBatis() { - // given - String testEmail = "hong.gildong@example.com"; + @Test + @DisplayName("MyBatis Mapper를 통해 '홍길동' 사용자를 이메일로 조회") + void findUserByEmailWithMyBatis() { + // given + String testEmail = "hong.gildong@example.com"; - // when - Optional foundUser = userMapper.findByEmail(testEmail); + // when + Optional foundUser = userMapper.findByEmail(testEmail); - // then - // 사용자가 존재하고, 이름이 '홍길동'인지 확인 - assertThat(foundUser).isPresent(); - assertThat(foundUser.get().getName()).isEqualTo("홍길동"); - System.out.println("Successfully found user with MyBatis: " + foundUser.get().getName()); - } + // then + // 사용자가 존재하고, 이름이 '홍길동'인지 확인 + assertThat(foundUser).isPresent(); + assertThat(foundUser.get().getName()).isEqualTo("홍길동"); + System.out.println("Successfully found user with MyBatis: " + foundUser.get().getName()); + } - @Test - @DisplayName("샘플 데이터가 올바르게 삽입되었는지 확인") - void verifyAllSampleDataInserted() { - // 사용자 데이터 확인 - Optional hong = userMapper.findByEmail("hong.gildong@example.com"); - assertThat(hong).isPresent(); - assertThat(hong.get().getName()).isEqualTo("홍길동"); + @Test + @DisplayName("샘플 데이터가 올바르게 삽입되었는지 확인") + void verifyAllSampleDataInserted() { + // 사용자 데이터 확인 + Optional hong = userMapper.findByEmail("hong.gildong@example.com"); + assertThat(hong).isPresent(); + assertThat(hong.get().getName()).isEqualTo("홍길동"); - Optional kim = userMapper.findByEmail("kim.chulsu@example.com"); - assertThat(kim).isPresent(); - assertThat(kim.get().getName()).isEqualTo("김철수"); + Optional kim = userMapper.findByEmail("kim.chulsu@example.com"); + assertThat(kim).isPresent(); + assertThat(kim.get().getName()).isEqualTo("김철수"); - System.out.println("샘플 데이터 삽입 성공 - 홍길동, 김철수 확인"); - } -} \ No newline at end of file + System.out.println("샘플 데이터 삽입 성공 - 홍길동, 김철수 확인"); + } +} From 3c2c420a25df8e346bd9858a728a64352a9433a3 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Wed, 27 Aug 2025 12:08:31 +0900 Subject: [PATCH 09/12] =?UTF-8?q?refactor:=20SQL=EB=AC=B8=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/test/resources/sql/create-schema.sql | 48 +++++++++---------- .../test/resources/sql/insert-user-data.sql | 6 +-- docker/local/init-scripts/create-schema.sql | 48 +++++++++---------- .../local/init-scripts/insert-user-data.sql | 6 +-- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/apps/user-service/src/test/resources/sql/create-schema.sql b/apps/user-service/src/test/resources/sql/create-schema.sql index 82299617..4001451c 100644 --- a/apps/user-service/src/test/resources/sql/create-schema.sql +++ b/apps/user-service/src/test/resources/sql/create-schema.sql @@ -3,12 +3,12 @@ DROP TABLE IF EXISTS "ROLE_PERMISSION"; DROP TABLE IF EXISTS "USER_ROLE"; DROP TABLE IF EXISTS "PERMISSION"; DROP TABLE IF EXISTS "ROLE"; -DROP TABLE IF EXISTS "USER_GROUP"; +DROP TABLE IF EXISTS "USER_GROUP_INFO"; DROP TABLE IF EXISTS "GROUP_INFO"; DROP TABLE IF EXISTS "USER"; --- 사용자 정보 +-- 사용자 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "USER" ( "user_id" VARCHAR(36) NOT NULL, "name" VARCHAR(100) NULL, @@ -19,7 +19,7 @@ CREATE TABLE "USER" ( "zip_code" VARCHAR(20) NULL, "main_address" VARCHAR(255) NULL, "detail_address" VARCHAR(255) NULL, - "recommender_id" VARCHAR(36) NULL, + "recommender_id" VARCHAR(36) NULL, -- FK 타입도 UUID로 변경 "resident_number" VARCHAR(100) NULL, "corporate_number" VARCHAR(100) NULL, "business_number" VARCHAR(100) NULL, @@ -34,7 +34,7 @@ CREATE TABLE "USER" ( PRIMARY KEY ("user_id") ); --- 사용자 그룹 정보 +-- 사용자 그룹 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "GROUP_INFO" ( "group_info_id" VARCHAR(36) NOT NULL, "name" VARCHAR(255) NULL, @@ -42,22 +42,22 @@ CREATE TABLE "GROUP_INFO" ( "status" VARCHAR(50) NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("group_id") + PRIMARY KEY ("group_info_id") ); --- 사용자-그룹 관계 -CREATE TABLE "USER_GROUP" ( - "user_group_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 - "user_id" VARCHAR(36) NOT NULL, - "group_id" VARCHAR(36) NOT NULL, - "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), - FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id"), - UNIQUE ("user_id", "group_id") -- 중복 방지를 위한 UNIQUE 제약 조건 +-- 사용자-그룹 관계 (⭐️ PK는 BIGINT, FK는 UUID를 참조) +CREATE TABLE "USER_GROUP_INFO" ( + "user_group_info_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + "user_id" VARCHAR(36) NOT NULL, + "group_info_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), + FOREIGN KEY ("group_info_id") REFERENCES "GROUP_INFO" ("group_info_id"), + UNIQUE ("user_id", "group_info_id") ); --- 역할 정보 +-- 역할 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "ROLE" ( "role_id" VARCHAR(36) NOT NULL, "name" VARCHAR(50) NULL, @@ -69,7 +69,7 @@ CREATE TABLE "ROLE" ( PRIMARY KEY ("role_id") ); --- 권한 정보 +-- 권한 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "PERMISSION" ( "permission_id" VARCHAR(36) NOT NULL, "name" VARCHAR(50) NULL, @@ -82,26 +82,26 @@ CREATE TABLE "PERMISSION" ( PRIMARY KEY ("permission_id") ); --- 사용자-역할 관계 +-- 사용자-역할 관계 (⭐️ PK는 BIGINT, FK는 UUID를 참조) CREATE TABLE "USER_ROLE" ( - "user_role_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 + "user_role_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "user_id" VARCHAR(36) NOT NULL, "role_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), - UNIQUE ("user_id", "role_id") -- 중복 방지를 위한 UNIQUE 제약 조건 + UNIQUE ("user_id", "role_id") ); --- 역할-권한 관계 +-- 역할-권한 관계 (⭐️ PK는 BIGINT, FK는 UUID를 참조) CREATE TABLE "ROLE_PERMISSION" ( - "role_permission_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 + "role_permission_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "role_id" VARCHAR(36) NOT NULL, "permission_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id"), - UNIQUE ("role_id", "permission_id") -- 중복 방지를 위한 UNIQUE 제약 조건 -); \ No newline at end of file + UNIQUE ("role_id", "permission_id") +); diff --git a/apps/user-service/src/test/resources/sql/insert-user-data.sql b/apps/user-service/src/test/resources/sql/insert-user-data.sql index 02138a2d..79487980 100644 --- a/apps/user-service/src/test/resources/sql/insert-user-data.sql +++ b/apps/user-service/src/test/resources/sql/insert-user-data.sql @@ -1,15 +1,15 @@ --- 데이터 삽입 +-- 데이터 삽입 (⭐️ UUID 값을 직접 지정) INSERT INTO "USER" ("user_id", "name", "email", "password", "phone_number", "type", "status", "joined_at") VALUES ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '홍길동', 'hong.gildong@example.com', 'hashed_password_1', '010-1234-5678', 'INDIVIDUAL', 'ACTIVE', NOW()), ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '김철수', 'kim.chulsu@example.com', 'hashed_1b590e829a28', '010-9876-5432', 'INDIVIDUAL', 'ACTIVE', NOW()); -INSERT INTO "GROUP_INFO" ("group_id", "name", "description", "status") +INSERT INTO "GROUP_INFO" ("group_info_id", "name", "description", "status") VALUES ('0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a', '개발팀', '애플리케이션 개발 그룹', 'ACTIVE'), ('5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b', '기획팀', '프로젝트 기획 그룹', 'ACTIVE'); -INSERT INTO "USER_GROUP_INFO" ("user_id", "group_id") +INSERT INTO "USER_GROUP_INFO" ("user_id", "group_info_id") VALUES ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a'), ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b'); diff --git a/docker/local/init-scripts/create-schema.sql b/docker/local/init-scripts/create-schema.sql index 82299617..4001451c 100644 --- a/docker/local/init-scripts/create-schema.sql +++ b/docker/local/init-scripts/create-schema.sql @@ -3,12 +3,12 @@ DROP TABLE IF EXISTS "ROLE_PERMISSION"; DROP TABLE IF EXISTS "USER_ROLE"; DROP TABLE IF EXISTS "PERMISSION"; DROP TABLE IF EXISTS "ROLE"; -DROP TABLE IF EXISTS "USER_GROUP"; +DROP TABLE IF EXISTS "USER_GROUP_INFO"; DROP TABLE IF EXISTS "GROUP_INFO"; DROP TABLE IF EXISTS "USER"; --- 사용자 정보 +-- 사용자 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "USER" ( "user_id" VARCHAR(36) NOT NULL, "name" VARCHAR(100) NULL, @@ -19,7 +19,7 @@ CREATE TABLE "USER" ( "zip_code" VARCHAR(20) NULL, "main_address" VARCHAR(255) NULL, "detail_address" VARCHAR(255) NULL, - "recommender_id" VARCHAR(36) NULL, + "recommender_id" VARCHAR(36) NULL, -- FK 타입도 UUID로 변경 "resident_number" VARCHAR(100) NULL, "corporate_number" VARCHAR(100) NULL, "business_number" VARCHAR(100) NULL, @@ -34,7 +34,7 @@ CREATE TABLE "USER" ( PRIMARY KEY ("user_id") ); --- 사용자 그룹 정보 +-- 사용자 그룹 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "GROUP_INFO" ( "group_info_id" VARCHAR(36) NOT NULL, "name" VARCHAR(255) NULL, @@ -42,22 +42,22 @@ CREATE TABLE "GROUP_INFO" ( "status" VARCHAR(50) NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY ("group_id") + PRIMARY KEY ("group_info_id") ); --- 사용자-그룹 관계 -CREATE TABLE "USER_GROUP" ( - "user_group_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 - "user_id" VARCHAR(36) NOT NULL, - "group_id" VARCHAR(36) NOT NULL, - "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), - FOREIGN KEY ("group_id") REFERENCES "GROUP_INFO" ("group_id"), - UNIQUE ("user_id", "group_id") -- 중복 방지를 위한 UNIQUE 제약 조건 +-- 사용자-그룹 관계 (⭐️ PK는 BIGINT, FK는 UUID를 참조) +CREATE TABLE "USER_GROUP_INFO" ( + "user_group_info_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + "user_id" VARCHAR(36) NOT NULL, + "group_info_id" VARCHAR(36) NOT NULL, + "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), + FOREIGN KEY ("group_info_id") REFERENCES "GROUP_INFO" ("group_info_id"), + UNIQUE ("user_id", "group_info_id") ); --- 역할 정보 +-- 역할 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "ROLE" ( "role_id" VARCHAR(36) NOT NULL, "name" VARCHAR(50) NULL, @@ -69,7 +69,7 @@ CREATE TABLE "ROLE" ( PRIMARY KEY ("role_id") ); --- 권한 정보 +-- 권한 정보 (⭐️ PK를 UUID로 변경) CREATE TABLE "PERMISSION" ( "permission_id" VARCHAR(36) NOT NULL, "name" VARCHAR(50) NULL, @@ -82,26 +82,26 @@ CREATE TABLE "PERMISSION" ( PRIMARY KEY ("permission_id") ); --- 사용자-역할 관계 +-- 사용자-역할 관계 (⭐️ PK는 BIGINT, FK는 UUID를 참조) CREATE TABLE "USER_ROLE" ( - "user_role_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 + "user_role_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "user_id" VARCHAR(36) NOT NULL, "role_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY ("user_id") REFERENCES "USER" ("user_id"), FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), - UNIQUE ("user_id", "role_id") -- 중복 방지를 위한 UNIQUE 제약 조건 + UNIQUE ("user_id", "role_id") ); --- 역할-권한 관계 +-- 역할-권한 관계 (⭐️ PK는 BIGINT, FK는 UUID를 참조) CREATE TABLE "ROLE_PERMISSION" ( - "role_permission_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- 인조 키 추가 + "role_permission_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "role_id" VARCHAR(36) NOT NULL, "permission_id" VARCHAR(36) NOT NULL, "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY ("role_id") REFERENCES "ROLE" ("role_id"), FOREIGN KEY ("permission_id") REFERENCES "PERMISSION" ("permission_id"), - UNIQUE ("role_id", "permission_id") -- 중복 방지를 위한 UNIQUE 제약 조건 -); \ No newline at end of file + UNIQUE ("role_id", "permission_id") +); diff --git a/docker/local/init-scripts/insert-user-data.sql b/docker/local/init-scripts/insert-user-data.sql index 02138a2d..79487980 100644 --- a/docker/local/init-scripts/insert-user-data.sql +++ b/docker/local/init-scripts/insert-user-data.sql @@ -1,15 +1,15 @@ --- 데이터 삽입 +-- 데이터 삽입 (⭐️ UUID 값을 직접 지정) INSERT INTO "USER" ("user_id", "name", "email", "password", "phone_number", "type", "status", "joined_at") VALUES ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '홍길동', 'hong.gildong@example.com', 'hashed_password_1', '010-1234-5678', 'INDIVIDUAL', 'ACTIVE', NOW()), ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '김철수', 'kim.chulsu@example.com', 'hashed_1b590e829a28', '010-9876-5432', 'INDIVIDUAL', 'ACTIVE', NOW()); -INSERT INTO "GROUP_INFO" ("group_id", "name", "description", "status") +INSERT INTO "GROUP_INFO" ("group_info_id", "name", "description", "status") VALUES ('0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a', '개발팀', '애플리케이션 개발 그룹', 'ACTIVE'), ('5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b', '기획팀', '프로젝트 기획 그룹', 'ACTIVE'); -INSERT INTO "USER_GROUP_INFO" ("user_id", "group_id") +INSERT INTO "USER_GROUP_INFO" ("user_id", "group_info_id") VALUES ('86b2414f-8e4d-4c3e-953e-1b6c7003c271', '0b5c1c4e-5e2a-438d-8c1d-1d2a3e3b4d5a'), ('92d04a8b-185d-4f1b-85d1-9650d99d1234', '5c3f7b2c-8a1e-45a8-9d2a-7e7f6a8e9d2b'); From 914723c669f69be3e56960d3d52d64968dea88af Mon Sep 17 00:00:00 2001 From: jihukimme Date: Wed, 27 Aug 2025 16:10:31 +0900 Subject: [PATCH 10/12] =?UTF-8?q?feat:=20=EC=9A=94=EC=B2=AD=20=EC=B6=94?= =?UTF-8?q?=EC=A0=81=EC=9D=84=20=EC=9C=84=ED=95=9C=20LoggingFilter=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 API 요청에 UUID 기반의 Trace ID(`X-Request-ID`)를 주입하는 Filter 구현 - MDC를 통해 모든 로그에 Trace ID가 자동으로 기록되도록 설정 --- .../gltkorea/icebang/config/WebConfig.java | 28 +++++++++++++ .../icebang/filter/LoggingFilter.java | 41 +++++++++++++++++++ .../src/main/resources/log4j2-develop.yml | 4 +- 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java create mode 100644 apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java b/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java new file mode 100644 index 00000000..af198971 --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java @@ -0,0 +1,28 @@ +package com.gltkorea.icebang.config; + +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.time.Duration; + +@Configuration +public class WebConfig { + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder){ + // 1. SimpleClientHttpRequestFactory 객체를 직접 생성 + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + + // 2. 타임아웃 설정 (이 메서드들은 deprecated 아님) + requestFactory.setConnectTimeout(Duration.ofSeconds(5)); + requestFactory.setReadTimeout(Duration.ofSeconds(5)); + + // 3. 빌더에 직접 생성한 requestFactory를 설정 + return builder + .requestFactory(() -> requestFactory) + .build(); + } +} diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java b/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java new file mode 100644 index 00000000..08dfe5eb --- /dev/null +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java @@ -0,0 +1,41 @@ +package com.gltkorea.icebang.filter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.UUID; + +@Component +public class LoggingFilter extends OncePerRequestFilter { + + public static final String TRACE_ID_HEADER = "X-Request-ID"; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + // 다른 시스템에서 이미 전달한 Trace ID가 있는지 확인 + String traceId = request.getHeader(TRACE_ID_HEADER); + + // 없다면 새로 생성 (요청의 시작점) + if (traceId == null || traceId.isEmpty()) { + traceId = UUID.randomUUID().toString(); + } + + MDC.put("traceId", traceId.substring(0,8)); + + // ⭐️ 요청 객체에 attribute로 traceId를 저장하여 컨트롤러 등에서 사용할 수 있게 함 + request.setAttribute("X-Request-ID", traceId); + + // 응답 헤더에 traceId를 넣어주면 클라이언트가 추적하기 용이 + response.setHeader(TRACE_ID_HEADER, traceId); + + filterChain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/apps/user-service/src/main/resources/log4j2-develop.yml b/apps/user-service/src/main/resources/log4j2-develop.yml index 4734a1ce..63f4c280 100644 --- a/apps/user-service/src/main/resources/log4j2-develop.yml +++ b/apps/user-service/src/main/resources/log4j2-develop.yml @@ -9,10 +9,10 @@ Configuration: value: "UTF-8" # 통일된 콘솔 패턴 - 모든 로그에 RequestId 포함 - name: "console-layout-pattern" - value: "%highlight{[%-5level]} [%X{id}] %d{MM-dd HH:mm:ss} [%t] %n %msg%n%n" + value: "%highlight{[%-5level]} [%X{traceId}] %d{MM-dd HH:mm:ss} [%t] %n %msg%n%n" # 파일용 상세 패턴 - RequestId 포함 - name: "file-layout-pattern" - value: "[%X{id}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" + value: "[%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" # 로그 파일 경로들 - name: "info-log" value: ${log-path}/user-service/info.log From b9f58b50954977fa835f6da10c6557c6f3d30072 Mon Sep 17 00:00:00 2001 From: jihukimme Date: Wed, 27 Aug 2025 17:26:23 +0900 Subject: [PATCH 11/12] refactor: Code Formatting --- .../gltkorea/icebang/config/WebConfig.java | 26 +++++----- .../icebang/filter/LoggingFilter.java | 50 ++++++++++--------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java b/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java index af198971..1ed10098 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/config/WebConfig.java @@ -1,28 +1,26 @@ package com.gltkorea.icebang.config; +import java.time.Duration; + import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; -import java.time.Duration; - @Configuration public class WebConfig { - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder){ - // 1. SimpleClientHttpRequestFactory 객체를 직접 생성 - SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + // 1. SimpleClientHttpRequestFactory 객체를 직접 생성 + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); - // 2. 타임아웃 설정 (이 메서드들은 deprecated 아님) - requestFactory.setConnectTimeout(Duration.ofSeconds(5)); - requestFactory.setReadTimeout(Duration.ofSeconds(5)); + // 2. 타임아웃 설정 (이 메서드들은 deprecated 아님) + requestFactory.setConnectTimeout(Duration.ofSeconds(5)); + requestFactory.setReadTimeout(Duration.ofSeconds(5)); - // 3. 빌더에 직접 생성한 requestFactory를 설정 - return builder - .requestFactory(() -> requestFactory) - .build(); - } + // 3. 빌더에 직접 생성한 requestFactory를 설정 + return builder.requestFactory(() -> requestFactory).build(); + } } diff --git a/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java b/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java index 08dfe5eb..e8dda321 100644 --- a/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java +++ b/apps/user-service/src/main/java/com/gltkorea/icebang/filter/LoggingFilter.java @@ -1,41 +1,43 @@ package com.gltkorea.icebang.filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.UUID; + import org.slf4j.MDC; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; -import java.util.UUID; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; @Component public class LoggingFilter extends OncePerRequestFilter { - public static final String TRACE_ID_HEADER = "X-Request-ID"; + public static final String TRACE_ID_HEADER = "X-Request-ID"; - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { + @Override + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { - // 다른 시스템에서 이미 전달한 Trace ID가 있는지 확인 - String traceId = request.getHeader(TRACE_ID_HEADER); + // 다른 시스템에서 이미 전달한 Trace ID가 있는지 확인 + String traceId = request.getHeader(TRACE_ID_HEADER); - // 없다면 새로 생성 (요청의 시작점) - if (traceId == null || traceId.isEmpty()) { - traceId = UUID.randomUUID().toString(); - } + // 없다면 새로 생성 (요청의 시작점) + if (traceId == null || traceId.isEmpty()) { + traceId = UUID.randomUUID().toString(); + } - MDC.put("traceId", traceId.substring(0,8)); + MDC.put("traceId", traceId.substring(0, 8)); - // ⭐️ 요청 객체에 attribute로 traceId를 저장하여 컨트롤러 등에서 사용할 수 있게 함 - request.setAttribute("X-Request-ID", traceId); + // ⭐️ 요청 객체에 attribute로 traceId를 저장하여 컨트롤러 등에서 사용할 수 있게 함 + request.setAttribute("X-Request-ID", traceId); - // 응답 헤더에 traceId를 넣어주면 클라이언트가 추적하기 용이 - response.setHeader(TRACE_ID_HEADER, traceId); + // 응답 헤더에 traceId를 넣어주면 클라이언트가 추적하기 용이 + response.setHeader(TRACE_ID_HEADER, traceId); - filterChain.doFilter(request, response); - } -} \ No newline at end of file + filterChain.doFilter(request, response); + } +} From dfa00f4576617c1b77a4760051586b9a8c3eb84d Mon Sep 17 00:00:00 2001 From: jihukimme Date: Wed, 27 Aug 2025 17:35:48 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20Dockerfile=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/user-service/Dockerfile | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/user-service/Dockerfile b/apps/user-service/Dockerfile index 68b36c3b..b9ac7b3e 100644 --- a/apps/user-service/Dockerfile +++ b/apps/user-service/Dockerfile @@ -1,21 +1,3 @@ -# 애플리케이션 실행에 필요한 Java 21 JRE만 포함된 경량 이미지를 사용합니다. -FROM openjdk:21-jre-slim - -# 컨테이너 내부의 작업 디렉토리를 설정합니다. -WORKDIR /app - -# 빌드 스테이지에서 생성된 JAR 파일을 복사합니다. -# `--from=builder` 옵션을 사용하여 첫 번째 단계에서 빌드된 JAR만 가져옵니다. -# 파일명은 `group`, `version`에 따라 `glt-korea-0.0.1-SNAPSHOT.jar`가 되므로, -# 이를 `app.jar`라는 간단한 이름으로 변경합니다. -COPY --from=builder /app/build/libs/glt-korea-0.0.1-SNAPSHOT.jar ./app.jar - -# 애플리케이션이 외부 요청을 받을 포트를 노출합니다. -EXPOSE 8080 - -# 컨테이너 시작 시 실행될 명령어를 정의합니다. -CMD ["java", "-jar", "app.jar"] -======= FROM eclipse-temurin:21-jre WORKDIR /app